#!/usr/bin/env php
<?php
Phar::mapPhar('codecept.phar');

require_once 'phar://codecept.phar/vendor/codeception/codeception/app.php';

__HALT_COMPILER(); ?>
          codecept.phar    2   vendor/phpseclib/phpseclib/phpseclib/bootstrap.php  a  tn      8   vendor/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php3"  a3"  jX      1   vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.phpe ae h_      1   vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php  a  ߐӦ      0   vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php  a        1   vendor/phpseclib/phpseclib/phpseclib/Net/SSH1.php$^  a$^  *C      8   vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php  a  BΑ      2   vendor/phpseclib/phpseclib/phpseclib/Crypt/RC2.phpw0  aw0  Ií      5   vendor/phpseclib/phpseclib/phpseclib/Crypt/Random.php  a  'Ф      7   vendor/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.phpV  aV  s      7   vendor/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.phpGJ  aGJ  +y      6   vendor/phpseclib/phpseclib/phpseclib/Crypt/Twofish.phpnm  anm  ;,      2   vendor/phpseclib/phpseclib/phpseclib/Crypt/AES.phpp  ap  w      3   vendor/phpseclib/phpseclib/phpseclib/Crypt/Base.phpa  aa  ^S      8   vendor/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.phpU  aU  f[      2   vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.php  a  2ä      2   vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php)  a)  ^      2   vendor/phpseclib/phpseclib/phpseclib/Crypt/RC4.php	  a	  %C$      3   vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.php8  a8  +      2   vendor/phpseclib/phpseclib/phpseclib/File/X509.php;u a;u ?      2   vendor/phpseclib/phpseclib/phpseclib/File/ANSI.php"  a"  .7      :   vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Element.php   a   _*ё      2   vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php)d  a)d  c-M      9   vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php)  a)        B   vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.phpp	  ap	        %   vendor/webmozart/assert/src/Mixin.php+l  a+l  :      8   vendor/webmozart/assert/src/InvalidArgumentException.phpr   ar   tV      &   vendor/webmozart/assert/src/Assert.php(l  a(l  2?      2   vendor/php-webdriver/webdriver/lib/WebDriverBy.php[  a[  	(      5   vendor/php-webdriver/webdriver/lib/WebDriverAlert.php  a  Z=A      =   vendor/php-webdriver/webdriver/lib/WebDriverSearchContext.php   a   \Τ      <   vendor/php-webdriver/webdriver/lib/WebDriverCapabilities.phpA  aA  A^      6   vendor/php-webdriver/webdriver/lib/WebDriverAction.phpb   ab         G   vendor/php-webdriver/webdriver/lib/AbstractWebDriverCheckboxOrRadio.php  a  :      -   vendor/php-webdriver/webdriver/lib/Cookie.phpM  aM  zy      5   vendor/php-webdriver/webdriver/lib/Net/URLChecker.phpq  aq  ġڤ      6   vendor/php-webdriver/webdriver/lib/WebDriverRadios.phpn  an  h      C   vendor/php-webdriver/webdriver/lib/WebDriverNavigationInterface.php   a   vä      6   vendor/php-webdriver/webdriver/lib/WebDriverSelect.php  a  xL-      :   vendor/php-webdriver/webdriver/lib/WebDriverNavigation.php  a  f      4   vendor/php-webdriver/webdriver/lib/WebDriverKeys.php  a  |_qK      8   vendor/php-webdriver/webdriver/lib/WebDriverPlatform.php  a        9   vendor/php-webdriver/webdriver/lib/JavaScriptExecutor.php   a   ⌤      7   vendor/php-webdriver/webdriver/lib/WebDriverOptions.php  a  6      5   vendor/php-webdriver/webdriver/lib/WebDriverPoint.php_  a_        ?   vendor/php-webdriver/webdriver/lib/WebDriverSelectInterface.php@  a@  _      4   vendor/php-webdriver/webdriver/lib/WebDriverWait.php;  a;        A   vendor/php-webdriver/webdriver/lib/Remote/UselessFileDetector.php   a   k&      >   vendor/php-webdriver/webdriver/lib/Remote/RemoteWebElement.phpI$  aI$  ?x6      ?   vendor/php-webdriver/webdriver/lib/Remote/RemoteTouchScreen.php:  a:  `e4      <   vendor/php-webdriver/webdriver/lib/Remote/RemoteKeyboard.php   a   ygҤ      A   vendor/php-webdriver/webdriver/lib/Remote/RemoteExecuteMethod.phpR  aR  m      ;   vendor/php-webdriver/webdriver/lib/Remote/DriverCommand.phpD  aD  Nf      A   vendor/php-webdriver/webdriver/lib/Remote/RemoteTargetLocator.php
  a
  X/      D   vendor/php-webdriver/webdriver/lib/Remote/CustomWebDriverCommand.phpm  am        K   vendor/php-webdriver/webdriver/lib/Remote/Service/DriverCommandExecutor.php  a  `      C   vendor/php-webdriver/webdriver/lib/Remote/Service/DriverService.php
  a
  IZ      E   vendor/php-webdriver/webdriver/lib/Remote/WebDriverCapabilityType.php(  a(  tc)Ѥ      >   vendor/php-webdriver/webdriver/lib/Remote/WebDriverCommand.php_  a_  !Uv      :   vendor/php-webdriver/webdriver/lib/Remote/FileDetector.phpu   au         A   vendor/php-webdriver/webdriver/lib/Remote/HttpCommandExecutor.php>  a>  )      ;   vendor/php-webdriver/webdriver/lib/Remote/ExecuteMethod.php   a   t5f      ?   vendor/php-webdriver/webdriver/lib/Remote/LocalFileDetector.php   a   n.p      B   vendor/php-webdriver/webdriver/lib/Remote/WebDriverBrowserType.php  a  1P_      =   vendor/php-webdriver/webdriver/lib/Remote/RemoteWebDriver.phpO&  aO&  4%[X      9   vendor/php-webdriver/webdriver/lib/Remote/RemoteMouse.phpP  aP  K      :   vendor/php-webdriver/webdriver/lib/Remote/RemoteStatus.php  a  =]      <   vendor/php-webdriver/webdriver/lib/Remote/JsonWireCompat.php>  a>  st      ?   vendor/php-webdriver/webdriver/lib/Remote/WebDriverResponse.php  a  r-      A   vendor/php-webdriver/webdriver/lib/Remote/DesiredCapabilities.php  a  xl      A   vendor/php-webdriver/webdriver/lib/WebDriverExpectedCondition.phpM  aM  5      6   vendor/php-webdriver/webdriver/lib/WebDriverWindow.phpU
  aU
  #?      8   vendor/php-webdriver/webdriver/lib/WebDriverKeyboard.php   a   e%      ?   vendor/php-webdriver/webdriver/lib/WebDriverHasInputDevices.php   a   Dh      =   vendor/php-webdriver/webdriver/lib/WebDriverTargetLocator.phpi  ai  g8פ      A   vendor/php-webdriver/webdriver/lib/Chrome/ChromeDriverService.php  a  Uy      ;   vendor/php-webdriver/webdriver/lib/Chrome/ChromeOptions.phpk  ak  }0W(      B   vendor/php-webdriver/webdriver/lib/Chrome/ChromeDevToolsDriver.php@  a@  )|      :   vendor/php-webdriver/webdriver/lib/Chrome/ChromeDriver.phpL  aL         ;   vendor/php-webdriver/webdriver/lib/Support/XPathEscaper.php  a  /2>      J   vendor/php-webdriver/webdriver/lib/Support/Events/EventFiringWebDriver.php  a  s      K   vendor/php-webdriver/webdriver/lib/Support/Events/EventFiringWebElement.php  a  3=+      T   vendor/php-webdriver/webdriver/lib/Support/Events/EventFiringWebDriverNavigation.phpL  aL  s[ޤ      B   vendor/php-webdriver/webdriver/lib/Internal/WebDriverLocatable.php   a   Fz      8   vendor/php-webdriver/webdriver/lib/WebDriverTimeouts.php  a  D	      =   vendor/php-webdriver/webdriver/lib/WebDriverEventListener.phpr  ar  "      9   vendor/php-webdriver/webdriver/lib/WebDriverDimension.php  a  Z,      :   vendor/php-webdriver/webdriver/lib/WebDriverDispatcher.phpK  aK  Э@      ;   vendor/php-webdriver/webdriver/lib/Local/LocalWebDriver.php  a  Տ%      7   vendor/php-webdriver/webdriver/lib/WebDriverElement.php  a  OI      8   vendor/php-webdriver/webdriver/lib/WebDriverUpAction.php  a  .r      M   vendor/php-webdriver/webdriver/lib/Exception/InvalidCookieDomainException.phpu   au   @8s      E   vendor/php-webdriver/webdriver/lib/Exception/NoAlertOpenException.phpo   ao   W      B   vendor/php-webdriver/webdriver/lib/Exception/ExpectedException.phpj   aj   j驤      P   vendor/php-webdriver/webdriver/lib/Exception/ElementNotInteractableException.phpx   ax   w      N   vendor/php-webdriver/webdriver/lib/Exception/UnsupportedOperationException.phpv   av   :      F   vendor/php-webdriver/webdriver/lib/Exception/UnknownErrorException.phpn   an   8L      F   vendor/php-webdriver/webdriver/lib/Exception/NoSuchCookieException.phpo   ao   e?h      G   vendor/php-webdriver/webdriver/lib/Exception/ScriptTimeoutException.phpo   ao   3C      S   vendor/php-webdriver/webdriver/lib/Exception/IMEEngineActivationFailedException.php{   a{   F      E   vendor/php-webdriver/webdriver/lib/Exception/NoSuchAlertException.phpm   am   W      B   vendor/php-webdriver/webdriver/lib/Exception/NoStringException.phpj   aj   uq      J   vendor/php-webdriver/webdriver/lib/Exception/InvalidSessionIdException.phps   as   >      E   vendor/php-webdriver/webdriver/lib/Exception/XPathLookupException.phpm   am   aTW      F   vendor/php-webdriver/webdriver/lib/Exception/NoSuchWindowException.phpn   an   >      N   vendor/php-webdriver/webdriver/lib/Exception/ElementNotSelectableException.php   a   :       M   vendor/php-webdriver/webdriver/lib/Exception/UnexpectedAlertOpenException.phpu   au         I   vendor/php-webdriver/webdriver/lib/Exception/JavascriptErrorException.phpq   aq   i.      M   vendor/php-webdriver/webdriver/lib/Exception/InvalidElementStateException.phpv   av   sH      K   vendor/php-webdriver/webdriver/lib/Exception/ElementNotVisibleException.phps   as   -m      O   vendor/php-webdriver/webdriver/lib/Exception/StaleElementReferenceException.phpw   aw   ޢR      J   vendor/php-webdriver/webdriver/lib/Exception/IndexOutOfBoundsException.phpr   ar          G   vendor/php-webdriver/webdriver/lib/Exception/UnknownMethodException.phpo   ao   j8      O   vendor/php-webdriver/webdriver/lib/Exception/UnrecognizedExceptionException.phpt   at   tmW      I   vendor/php-webdriver/webdriver/lib/Exception/InvalidSelectorException.phpq   aq   vKr      A   vendor/php-webdriver/webdriver/lib/Exception/TimeoutException.phpi   ai         H   vendor/php-webdriver/webdriver/lib/Exception/NoSuchDocumentException.phps   as   MbФ      O   vendor/php-webdriver/webdriver/lib/Exception/UnableToCaptureScreenException.phpw   aw   L}>      Q   vendor/php-webdriver/webdriver/lib/Exception/ElementClickInterceptedException.phpz   az   hZS      F   vendor/php-webdriver/webdriver/lib/Exception/NoCollectionException.phpn   an   3      G   vendor/php-webdriver/webdriver/lib/Exception/NoSuchElementException.phpo   ao   HA\      J   vendor/php-webdriver/webdriver/lib/Exception/NoSuchCollectionException.phpr   ar   _g      H   vendor/php-webdriver/webdriver/lib/Exception/UnknownCommandException.phpp   ap         K   vendor/php-webdriver/webdriver/lib/Exception/UnexpectedTagNameException.php2  a2  l̃      M   vendor/php-webdriver/webdriver/lib/Exception/InsecureCertificateException.phpv   av   }      N   vendor/php-webdriver/webdriver/lib/Exception/UnexpectedJavascriptException.php|   a|   ۤ      H   vendor/php-webdriver/webdriver/lib/Exception/NoScriptResultException.phpp   ap         G   vendor/php-webdriver/webdriver/lib/Exception/WebDriverCurlException.phpl   al   '_      H   vendor/php-webdriver/webdriver/lib/Exception/NoStringLengthException.phpp   ap   ⬣      K   vendor/php-webdriver/webdriver/lib/Exception/SessionNotCreatedException.phps   as   ~j      G   vendor/php-webdriver/webdriver/lib/Exception/UnknownServerException.phpr   ar   -      I   vendor/php-webdriver/webdriver/lib/Exception/IMENotAvailableException.phpq   aq   (Oe      I   vendor/php-webdriver/webdriver/lib/Exception/InvalidArgumentException.phpq   aq   Z      J   vendor/php-webdriver/webdriver/lib/Exception/DriverServerDiedException.php.  a.  e      E   vendor/php-webdriver/webdriver/lib/Exception/NoSuchFrameException.phpm   am   Κ      L   vendor/php-webdriver/webdriver/lib/Exception/InvalidCoordinatesException.phpt   at   ܤ      C   vendor/php-webdriver/webdriver/lib/Exception/WebDriverException.php  a  #      F   vendor/php-webdriver/webdriver/lib/Exception/NoSuchDriverException.phpn   an         O   vendor/php-webdriver/webdriver/lib/Exception/MoveTargetOutOfBoundsException.phpw   aw   (
~      I   vendor/php-webdriver/webdriver/lib/Exception/NoStringWrapperException.phpq   aq   dKw      K   vendor/php-webdriver/webdriver/lib/Exception/UnableToSetCookieException.phps   as         E   vendor/php-webdriver/webdriver/lib/Exception/NullPointerException.phpm   am   &#      :   vendor/php-webdriver/webdriver/lib/WebDriverCheckboxes.php  a  _EK      <   vendor/php-webdriver/webdriver/lib/Firefox/FirefoxDriver.php  a  xC      C   vendor/php-webdriver/webdriver/lib/Firefox/FirefoxDriverService.phpK  aK  B+      =   vendor/php-webdriver/webdriver/lib/Firefox/FirefoxOptions.php  a  ѓ      A   vendor/php-webdriver/webdriver/lib/Firefox/FirefoxPreferences.phpk  ak  Br      =   vendor/php-webdriver/webdriver/lib/Firefox/FirefoxProfile.phpZ  aZ  ^>      N   vendor/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverTouchScreen.php  a  s'f      O   vendor/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverScrollAction.php  a  A-6B      R   vendor/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverDoubleTapAction.php  a  Q      L   vendor/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverTapAction.php  a  +"8      M   vendor/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverDownAction.php  a        R   vendor/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverLongPressAction.php  a  m%jq      Z   vendor/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverScrollFromElementAction.php7  a7  %dl      Y   vendor/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverFlickFromElementAction.php|  a|  `)Y      N   vendor/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverFlickAction.php  a  ]c      M   vendor/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverMoveAction.php  a  F      N   vendor/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverTouchAction.phpm  am  ߤ      D   vendor/php-webdriver/webdriver/lib/Interactions/WebDriverActions.php  a  a_      I   vendor/php-webdriver/webdriver/lib/Interactions/WebDriverTouchActions.php?
  a?
  7Vc      Q   vendor/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverKeyUpAction.php   a   D      T   vendor/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverSendKeysAction.php  a  	      X   vendor/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverClickAndHoldAction.php  a  pAz      Q   vendor/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverClickAction.php  a  [R_      X   vendor/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverMoveToOffsetAction.php  a  M      W   vendor/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverDoubleClickAction.php  a        U   vendor/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverMouseMoveAction.php  a  T]-      W   vendor/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverKeysRelatedAction.php  a  8	      X   vendor/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverContextClickAction.php  a  1ӌ      Q   vendor/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverMouseAction.php  a  T+      S   vendor/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverKeyDownAction.php   a   4v      Y   vendor/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverButtonReleaseAction.php  a  eV$      U   vendor/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverSingleKeyAction.phpx  ax  43      Q   vendor/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverCoordinates.phpa  aa  H.H      L   vendor/php-webdriver/webdriver/lib/Interactions/WebDriverCompositeAction.php  a  [T      0   vendor/php-webdriver/webdriver/lib/WebDriver.php  a  N      5   vendor/php-webdriver/webdriver/lib/WebDriverMouse.php  a  {z      ?   vendor/php-webdriver/webdriver/lib/WebDriverCommandExecutor.php   a   HO٬      #   vendor/predis/predis/src/Client.php1  a1  Z䨤      ?   vendor/predis/predis/src/Replication/MissingMasterException.php   a         <   vendor/predis/predis/src/Replication/ReplicationStrategy.phpm  am  K      6   vendor/predis/predis/src/Replication/RoleException.php   a   ״K      ,   vendor/predis/predis/src/Session/Handler.phpC  aC  !      ,   vendor/predis/predis/src/ClientInterface.php  a  ?۾      2   vendor/predis/predis/src/Transaction/MultiExec.php]  a]        B   vendor/predis/predis/src/Transaction/AbortedMultiExecException.php  a  5      7   vendor/predis/predis/src/Transaction/MultiExecState.php  a  C      2   vendor/predis/predis/src/Configuration/Options.phpl  al   BM      :   vendor/predis/predis/src/Configuration/OptionInterface.php   a   v	      8   vendor/predis/predis/src/Configuration/ClusterOption.php  a  f:      7   vendor/predis/predis/src/Configuration/PrefixOption.php  a  F=      ;   vendor/predis/predis/src/Configuration/OptionsInterface.php  a  6      <   vendor/predis/predis/src/Configuration/ReplicationOption.php  a  z%      ;   vendor/predis/predis/src/Configuration/ExceptionsOption.php-  a-  g      8   vendor/predis/predis/src/Configuration/ProfileOption.php}  a}  "      B   vendor/predis/predis/src/Configuration/ConnectionFactoryOption.php  a  m"Ƥ      :   vendor/predis/predis/src/Pipeline/ConnectionErrorProof.php	  a	  7      ,   vendor/predis/predis/src/Pipeline/Atomic.php>	  a>	  vjw      3   vendor/predis/predis/src/Pipeline/FireAndForget.phpf  af  j6      .   vendor/predis/predis/src/Pipeline/Pipeline.php  a  |#v      -   vendor/predis/predis/src/Monitor/Consumer.php  a  ;>G      ,   vendor/predis/predis/src/PubSub/Consumer.php	  a	  XW?"      4   vendor/predis/predis/src/PubSub/AbstractConsumer.php  a  }      2   vendor/predis/predis/src/PubSub/DispatcherLoop.php;  a;  %      4   vendor/predis/predis/src/Profile/RedisVersion220.php  a  }$U      4   vendor/predis/predis/src/Profile/RedisVersion200.php*  a*  $z      4   vendor/predis/predis/src/Profile/RedisVersion280.php  a  _ۤ      4   vendor/predis/predis/src/Profile/RedisVersion320.phpF  aF  G.C      1   vendor/predis/predis/src/Profile/RedisProfile.php  a  ;      ,   vendor/predis/predis/src/Profile/Factory.php  a  &r      5   vendor/predis/predis/src/Profile/ProfileInterface.php\  a\  2z      4   vendor/predis/predis/src/Profile/RedisVersion260.php  a  )\R      2   vendor/predis/predis/src/Profile/RedisUnstable.php  a  ͋      4   vendor/predis/predis/src/Profile/RedisVersion240.php(  a(  M`D      4   vendor/predis/predis/src/Profile/RedisVersion300.php  a  ֦      3   vendor/predis/predis/src/ClientContextInterface.php  a  &}      2   vendor/predis/predis/src/NotSupportedException.phpa   aa   n)      ,   vendor/predis/predis/src/PredisException.php^   a^         :   vendor/predis/predis/src/Connection/AbstractConnection.phpQ
  aQ
        A   vendor/predis/predis/src/Connection/PhpiredisStreamConnection.phpj  aj         D   vendor/predis/predis/src/Connection/AggregateConnectionInterface.php  a  lAu      A   vendor/predis/predis/src/Connection/CompositeStreamConnection.php  a  a      8   vendor/predis/predis/src/Connection/WebdisConnection.phpl  al  V<      ;   vendor/predis/predis/src/Connection/ConnectionException.php   a   -      2   vendor/predis/predis/src/Connection/Parameters.phpG  aG  ¿      D   vendor/predis/predis/src/Connection/CompositeConnectionInterface.php  a  ]      ;   vendor/predis/predis/src/Connection/ConnectionInterface.php  a  ^	M      /   vendor/predis/predis/src/Connection/Factory.php"  a"  ^Ť      8   vendor/predis/predis/src/Connection/StreamConnection.php  a  r.      ?   vendor/predis/predis/src/Connection/NodeConnectionInterface.phpm  am  i      8   vendor/predis/predis/src/Connection/FactoryInterface.php;  a;  6.5      A   vendor/predis/predis/src/Connection/PhpiredisSocketConnection.phpv  av  ZK4      ;   vendor/predis/predis/src/Connection/ParametersInterface.php   a   
Y֤      H   vendor/predis/predis/src/Connection/Aggregate/MasterSlaveReplication.phpW  aW  .%      F   vendor/predis/predis/src/Connection/Aggregate/ReplicationInterface.php  a  !      B   vendor/predis/predis/src/Connection/Aggregate/ClusterInterface.php   a   N      ?   vendor/predis/predis/src/Connection/Aggregate/PredisCluster.php  a  'HB      E   vendor/predis/predis/src/Connection/Aggregate/SentinelReplication.phpf'  af'  WC      >   vendor/predis/predis/src/Connection/Aggregate/RedisCluster.php#  a#  b      6   vendor/predis/predis/src/Cluster/StrategyInterface.php?  a?  "      3   vendor/predis/predis/src/Cluster/PredisStrategy.php  a  s      @   vendor/predis/predis/src/Cluster/Hash/HashGeneratorInterface.php   a   !)      /   vendor/predis/predis/src/Cluster/Hash/CRC16.php	  a	  C      2   vendor/predis/predis/src/Cluster/RedisStrategy.php  a  	m      4   vendor/predis/predis/src/Cluster/ClusterStrategy.php#  a#  	@      9   vendor/predis/predis/src/Cluster/Distributor/HashRing.php  a  Ԑh      C   vendor/predis/predis/src/Cluster/Distributor/EmptyRingException.phpl   al         E   vendor/predis/predis/src/Cluster/Distributor/DistributorInterface.php  a  j      ;   vendor/predis/predis/src/Cluster/Distributor/KetamaRing.phpv  av  x      @   vendor/predis/predis/src/Protocol/ProtocolProcessorInterface.php_  a_  i"      7   vendor/predis/predis/src/Protocol/ProtocolException.php   a   5      E   vendor/predis/predis/src/Protocol/Text/CompositeProtocolProcessor.php  a  ,$      <   vendor/predis/predis/src/Protocol/Text/ProtocolProcessor.php  a  {      9   vendor/predis/predis/src/Protocol/Text/ResponseReader.php  a  0p      D   vendor/predis/predis/src/Protocol/Text/Handler/MultiBulkResponse.php	  a	  :d      K   vendor/predis/predis/src/Protocol/Text/Handler/ResponseHandlerInterface.php   a    wQ      ?   vendor/predis/predis/src/Protocol/Text/Handler/BulkResponse.php  a  W0      @   vendor/predis/predis/src/Protocol/Text/Handler/ErrorResponse.php;  a;  LI      B   vendor/predis/predis/src/Protocol/Text/Handler/IntegerResponse.php`  a`  L      N   vendor/predis/predis/src/Protocol/Text/Handler/StreamableMultiBulkResponse.php  a  A-(      A   vendor/predis/predis/src/Protocol/Text/Handler/StatusResponse.php@  a@  %s|      <   vendor/predis/predis/src/Protocol/Text/RequestSerializer.phpQ  aQ  o      @   vendor/predis/predis/src/Protocol/RequestSerializerInterface.php   a   n      =   vendor/predis/predis/src/Protocol/ResponseReaderInterface.php   a   7      '   vendor/predis/predis/src/Autoloader.php  a  윝      5   vendor/predis/predis/src/Response/ServerException.phpb  ab  #      7   vendor/predis/predis/src/Response/ResponseInterface.phpQ   aQ   yZ      =   vendor/predis/predis/src/Response/Iterator/MultiBulkTuple.php>  a>  $JK      @   vendor/predis/predis/src/Response/Iterator/MultiBulkIterator.php  a  7!      8   vendor/predis/predis/src/Response/Iterator/MultiBulk.php  a  #      4   vendor/predis/predis/src/Response/ErrorInterface.php   a   `w      ,   vendor/predis/predis/src/Response/Status.phpR  aR  p|      +   vendor/predis/predis/src/Response/Error.php  a  &ˤ      3   vendor/predis/predis/src/Command/ConnectionEcho.php   a   Bg      5   vendor/predis/predis/src/Command/ZSetRangeByScore.phpy  ay  `®      /   vendor/predis/predis/src/Command/HashLength.php   a   y      4   vendor/predis/predis/src/Command/ZSetCardinality.php   a   UR٤      1   vendor/predis/predis/src/Command/StringBitPos.php   a         4   vendor/predis/predis/src/Command/ZSetReverseRank.php   a   ,      1   vendor/predis/predis/src/Command/ListPushHead.php   a   9      9   vendor/predis/predis/src/Command/HashIncrementByFloat.php   a   N`+      -   vendor/predis/predis/src/Command/HashKeys.php   a   d<      3   vendor/predis/predis/src/Command/ZSetUnionStore.php  a  c/      4   vendor/predis/predis/src/Command/StringSetExpire.php   a   L,      1   vendor/predis/predis/src/Command/ListPushTail.php   a         0   vendor/predis/predis/src/Command/KeyExpireAt.php   a   ^      4   vendor/predis/predis/src/Command/HashIncrementBy.php   a   GHo      ,   vendor/predis/predis/src/Command/SetMove.php   a   RAS      9   vendor/predis/predis/src/Command/ListPopFirstBlocking.phpf  af  ɝդ      5   vendor/predis/predis/src/Command/ConnectionSelect.php   a   =3d      -   vendor/predis/predis/src/Command/HashScan.php  a  74      1   vendor/predis/predis/src/Command/PubSubPubsub.php	  a	  =vΤ      .   vendor/predis/predis/src/Command/KeyRandom.php   a   }3)      1   vendor/predis/predis/src/Command/ServerObject.php   a   9V      3   vendor/predis/predis/src/Command/StringBitCount.php   a   l      8   vendor/predis/predis/src/Command/ListPopLastPushHead.php   a   Ų      2   vendor/predis/predis/src/Command/ScriptCommand.php  a  Ϥ      >   vendor/predis/predis/src/Command/StringSetMultiplePreserve.php   a   ɤ      3   vendor/predis/predis/src/Command/ServerFlushAll.php   a   ː      ,   vendor/predis/predis/src/Command/KeyDump.php   a   jߤ      ?   vendor/predis/predis/src/Command/ServerBackgroundRewriteAOF.php	  a	  j_      .   vendor/predis/predis/src/Command/ListIndex.php   a   ۬ä      /   vendor/predis/predis/src/Command/ServerSave.php   a   {̤      8   vendor/predis/predis/src/Command/ServerFlushDatabase.php   a   G      3   vendor/predis/predis/src/Command/ConnectionAuth.php   a   On      ,   vendor/predis/predis/src/Command/HashSet.php   a   HKޤ      4   vendor/predis/predis/src/Command/PubSubSubscribe.php   a   Qv      .   vendor/predis/predis/src/Command/KeyRename.php   a   E߇Τ      1   vendor/predis/predis/src/Command/ServerScript.php   a   AV^      /   vendor/predis/predis/src/Command/ListRemove.php   a   '      /   vendor/predis/predis/src/Command/SetMembers.php   a   @      1   vendor/predis/predis/src/Command/StringStrlen.php   a   ?      3   vendor/predis/predis/src/Command/ServerLastSave.php   a   eWW      1   vendor/predis/predis/src/Command/StringGetBit.php   a   B      /   vendor/predis/predis/src/Command/HashExists.php   a         9   vendor/predis/predis/src/Command/KeyPreciseTimeToLive.php   a   0&      4   vendor/predis/predis/src/Command/StringDecrement.php   a   KԤ      9   vendor/predis/predis/src/Command/SetIntersectionStore.phpZ  aZ  BW      ,   vendor/predis/predis/src/Command/KeyScan.php  a  p      .   vendor/predis/predis/src/Command/ZSetCount.php   a   /+      4   vendor/predis/predis/src/Command/HashSetMultiple.php  a  U      +   vendor/predis/predis/src/Command/SetPop.php   a   )o¤      4   vendor/predis/predis/src/Command/HashSetPreserve.php   a   q::      ,   vendor/predis/predis/src/Command/ZSetAdd.php\  a\  R      ,   vendor/predis/predis/src/Command/KeySort.phpY  aY  =      8   vendor/predis/predis/src/Command/ListPopLastBlocking.php   a   {,      7   vendor/predis/predis/src/Command/SetDifferenceStore.php   a         2   vendor/predis/predis/src/Command/ServerSlaveOf.php4  a4  JgӤ      6   vendor/predis/predis/src/Command/PubSubUnsubscribe.php   a   |      3   vendor/predis/predis/src/Command/StringBitField.php   a   ٙӤ      3   vendor/predis/predis/src/Command/ServerInfoV26x.phpc  ac  l      2   vendor/predis/predis/src/Command/ServerCommand.php   a   kӤ      2   vendor/predis/predis/src/Command/ListPushTailX.php   a   gjܟ      0   vendor/predis/predis/src/Command/ListPopLast.php   a         :   vendor/predis/predis/src/Command/ZSetRemoveRangeByRank.php   a   !T      0   vendor/predis/predis/src/Command/SetIsMember.php   a   5,      2   vendor/predis/predis/src/Command/KeyTimeToLive.php   a   <:      5   vendor/predis/predis/src/Command/TransactionMulti.php   a   	U      5   vendor/predis/predis/src/Command/TransactionWatch.php*  a*         3   vendor/predis/predis/src/Command/ZSetRangeByLex.php  a  ".       1   vendor/predis/predis/src/Command/ListPopFirst.php   a   L      4   vendor/predis/predis/src/Command/HashGetMultiple.php   a   П      6   vendor/predis/predis/src/Command/StringDecrementBy.php   a   ;      /   vendor/predis/predis/src/Command/HashDelete.php   a          4   vendor/predis/predis/src/Command/StringIncrement.php   a   );wĤ      3   vendor/predis/predis/src/Command/SetCardinality.php   a   ͯ!      -   vendor/predis/predis/src/Command/ZSetScan.php  a  7j      5   vendor/predis/predis/src/Command/KeyPreciseExpire.php   a   |      -   vendor/predis/predis/src/Command/ListTrim.php   a    Q      ;   vendor/predis/predis/src/Command/StringIncrementByFloat.php   a   q놤      /   vendor/predis/predis/src/Command/ServerInfo.php  a  4}ޤ      6   vendor/predis/predis/src/Command/GeospatialGeoDist.php   a   Nv@      5   vendor/predis/predis/src/Command/HashStringLength.php   a   :|r      5   vendor/predis/predis/src/Command/HyperLogLogCount.php   a   .=^      4   vendor/predis/predis/src/Command/SetRandomMember.php   a   `/      7   vendor/predis/predis/src/Command/KeyPreciseExpireAt.php   a   !      5   vendor/predis/predis/src/Command/HyperLogLogMerge.php   a   hs      ,   vendor/predis/predis/src/Command/KeyKeys.php   a         3   vendor/predis/predis/src/Command/ConnectionPing.php   a   <      5   vendor/predis/predis/src/Command/CommandInterface.php  a  'i      /   vendor/predis/predis/src/Command/ServerEval.php   a   e9      /   vendor/predis/predis/src/Command/ListLength.php   a   c9      2   vendor/predis/predis/src/Command/SetDifference.php   a   p      9   vendor/predis/predis/src/Command/ServerBackgroundSave.php   a   B      1   vendor/predis/predis/src/Command/StringSetBit.php   a   :їB      2   vendor/predis/predis/src/Command/ServerSlowlog.php  a  t      5   vendor/predis/predis/src/Command/GeospatialGeoAdd.phpr  ar  퓭      5   vendor/predis/predis/src/Command/GeospatialGeoPos.phpj  aj  Yä      :   vendor/predis/predis/src/Command/ZSetReverseRangeByLex.php   a   cQ      5   vendor/predis/predis/src/Command/ZSetReverseRange.php   a   zh5      4   vendor/predis/predis/src/Command/TransactionExec.php   a   Z-25      ,   vendor/predis/predis/src/Command/KeyMove.php   a   X      4   vendor/predis/predis/src/Command/SetIntersection.php   a         6   vendor/predis/predis/src/Command/KeyRenamePreserve.php   a   .LT      ?   vendor/predis/predis/src/Command/PrefixableCommandInterface.php   a   ū      -   vendor/predis/predis/src/Command/ZSetRank.php   a   h      3   vendor/predis/predis/src/Command/ServerShutdown.php   a         0   vendor/predis/predis/src/Command/StringBitOp.php  a  
      .   vendor/predis/predis/src/Command/KeyExists.php   a   h      @   vendor/predis/predis/src/Command/GeospatialGeoRadiusByMember.php   a   
      1   vendor/predis/predis/src/Command/ZSetLexCount.php   a   J-٤      .   vendor/predis/predis/src/Command/KeyDelete.php   a   }aФ      .   vendor/predis/predis/src/Command/SetRemove.php   a   Wq      .   vendor/predis/predis/src/Command/ZSetScore.php   a   Ť      /   vendor/predis/predis/src/Command/HashGetAll.php$  a$  Q      1   vendor/predis/predis/src/Command/ServerConfig.phpP  aP  r      3   vendor/predis/predis/src/Command/ServerSentinel.php  a  m@      2   vendor/predis/predis/src/Command/ServerEvalSHA.php   a   Jn      7   vendor/predis/predis/src/Command/TransactionUnwatch.php   a         1   vendor/predis/predis/src/Command/ServerClient.php  a        /   vendor/predis/predis/src/Command/ServerTime.php   a   쒤      2   vendor/predis/predis/src/Command/ServerMonitor.php   a   &#$      /   vendor/predis/predis/src/Command/KeyPersist.php   a   ɽ      3   vendor/predis/predis/src/Command/ConnectionQuit.php   a   I      /   vendor/predis/predis/src/Command/HashValues.php   a   UF[      /   vendor/predis/predis/src/Command/ZSetRemove.php   a   z}      .   vendor/predis/predis/src/Command/ListRange.php   a   Ϥ      6   vendor/predis/predis/src/Command/GeospatialGeoHash.phpl  al  qa      ;   vendor/predis/predis/src/Command/ZSetRemoveRangeByScore.php   a   F      /   vendor/predis/predis/src/Command/RawCommand.php  a  6eA      6   vendor/predis/predis/src/Command/StringSetPreserve.php   a   F      -   vendor/predis/predis/src/Command/SetUnion.php   a   X      7   vendor/predis/predis/src/Command/TransactionDiscard.php   a   t      1   vendor/predis/predis/src/Command/StringSubstr.php   a   !      /   vendor/predis/predis/src/Command/KeyMigrate.php  a  [V      .   vendor/predis/predis/src/Command/ZSetRange.php  a  >3      ,   vendor/predis/predis/src/Command/KeyType.php   a         ,   vendor/predis/predis/src/Command/Command.php  a  o[      ;   vendor/predis/predis/src/Command/StringPreciseSetExpire.php   a   hv      @   vendor/predis/predis/src/Command/ListPopLastPushHeadBlocking.php   a   =      ,   vendor/predis/predis/src/Command/SetScan.php  a  E      /   vendor/predis/predis/src/Command/ListInsert.php   a   WtK      /   vendor/predis/predis/src/Command/KeyRestore.php   a   fI?ޤ      3   vendor/predis/predis/src/Command/HyperLogLogAdd.php   a         9   vendor/predis/predis/src/Command/ZSetRemoveRangeByLex.php   a   fb      6   vendor/predis/predis/src/Command/StringIncrementBy.php   a   uS      <   vendor/predis/predis/src/Command/ZSetReverseRangeByScore.php   a   -Ť      2   vendor/predis/predis/src/Command/ListPushHeadX.php   a   _f|      ?   vendor/predis/predis/src/Command/PubSubUnsubscribeByPattern.php   a   a@      3   vendor/predis/predis/src/Command/StringGetRange.php   a         =   vendor/predis/predis/src/Command/PubSubSubscribeByPattern.php   a   t|      2   vendor/predis/predis/src/Command/SetUnionStore.php   a   S-      7   vendor/predis/predis/src/Command/ServerDatabaseSize.php   a   8      2   vendor/predis/predis/src/Command/PubSubPublish.php   a         6   vendor/predis/predis/src/Command/StringGetMultiple.php   a   )ͤ      ,   vendor/predis/predis/src/Command/ListSet.php   a   }      1   vendor/predis/predis/src/Command/StringGetSet.php   a   m      1   vendor/predis/predis/src/Command/StringAppend.php   a   پ      :   vendor/predis/predis/src/Command/ZSetIntersectionStore.php   a   ,_      .   vendor/predis/predis/src/Command/KeyExpire.php   a   4       .   vendor/predis/predis/src/Command/StringGet.php   a         .   vendor/predis/predis/src/Command/StringSet.php   a   p      6   vendor/predis/predis/src/Command/StringSetMultiple.php  a  d      8   vendor/predis/predis/src/Command/GeospatialGeoRadius.php  a  ͐      3   vendor/predis/predis/src/Command/StringSetRange.php   a   e^      +   vendor/predis/predis/src/Command/SetAdd.php   a   Ä      4   vendor/predis/predis/src/Command/ZSetIncrementBy.php   a   K/      ,   vendor/predis/predis/src/Command/HashGet.php   a   @ؤ      A   vendor/predis/predis/src/Command/Processor/ProcessorInterface.php   a   Ɛc      A   vendor/predis/predis/src/Command/Processor/KeyPrefixProcessor.php  a  Fdo      =   vendor/predis/predis/src/Command/Processor/ProcessorChain.php  a  _      9   vendor/predis/predis/src/Collection/Iterator/Keyspace.php  a  Rs      8   vendor/predis/predis/src/Collection/Iterator/HashKey.php  a  Gl      8   vendor/predis/predis/src/Collection/Iterator/ListKey.php  a  !      =   vendor/predis/predis/src/Collection/Iterator/SortedSetKey.php  a  ߚ)      D   vendor/predis/predis/src/Collection/Iterator/CursorBasedIterator.php  a  ʣ騤      7   vendor/predis/predis/src/Collection/Iterator/SetKey.php  a  t      3   vendor/predis/predis/src/CommunicationException.phpC  aC        ,   vendor/predis/predis/src/ClientException.phpZ   aZ   l<      !   vendor/predis/predis/autoload.phpW   aW   f4C      5   vendor/predis/predis/examples/replication_complex.php  a  SQ<      /   vendor/predis/predis/examples/key_prefixing.php
  a
  F0      <   vendor/predis/predis/examples/custom_cluster_distributor.php  a  m)Ӥ      7   vendor/predis/predis/examples/transaction_using_cas.php   a   /T0      (   vendor/predis/predis/examples/shared.php  a  'I      7   vendor/predis/predis/examples/debuggable_connection.php  a  ɤ      =   vendor/predis/predis/examples/redis_collections_iterators.phpR  aR  3oy"      5   vendor/predis/predis/examples/pipelining_commands.phpj  aj  Ҥ      2   vendor/predis/predis/examples/monitor_consumer.php  a  I0      6   vendor/predis/predis/examples/replication_sentinel.phpL  aL         1   vendor/predis/predis/examples/dispatcher_loop.php  a  !1      4   vendor/predis/predis/examples/replication_simple.php-  a-  ǿ      ;   vendor/predis/predis/examples/lua_scripting_abstraction.phpW  aW  mcPg      1   vendor/predis/predis/examples/pubsub_consumer.phpa  aa  ϕ      :   vendor/predis/predis/examples/executing_redis_commands.php(  a(  NY      1   vendor/predis/predis/examples/session_handler.php  a   I      A   vendor/myclabs/deep-copy/src/DeepCopy/TypeMatcher/TypeMatcher.php  a  46      3   vendor/myclabs/deep-copy/src/DeepCopy/deep_copy.php   a   	n      O   vendor/myclabs/deep-copy/src/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php   a   SӤ      E   vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyNameMatcher.php  a  k      A   vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyMatcher.phpj  aj  c$C      9   vendor/myclabs/deep-copy/src/DeepCopy/Matcher/Matcher.phpm   am   aˤ      E   vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyTypeMatcher.php  a  m*      E   vendor/myclabs/deep-copy/src/DeepCopy/Reflection/ReflectionHelper.php  a        2   vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php  a  jJu      ?   vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/TypeFilter.phpf   af   Z.)Ȥ      L   vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Date/DateIntervalFilter.php[  a[  %MQ      F   vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/ShallowCopyFilter.php   a   g      B   vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/ReplaceFilter.php  a  q      L   vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedList.phpn   an         R   vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedListFilter.php  a  &)y      J   vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/ArrayObjectFilter.php  a  !\      ;   vendor/myclabs/deep-copy/src/DeepCopy/Filter/KeepFilter.php   a   g{5      M   vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineProxyFilter.php   a   s()      R   vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.phpC  aC  A      W   vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php  a  h      >   vendor/myclabs/deep-copy/src/DeepCopy/Filter/SetNullFilter.php_  a_  |Gؤ      >   vendor/myclabs/deep-copy/src/DeepCopy/Filter/ReplaceFilter.php"  a"  G      7   vendor/myclabs/deep-copy/src/DeepCopy/Filter/Filter.php|   a|   a]ˤ      B   vendor/myclabs/deep-copy/src/DeepCopy/Exception/CloneException.php   a   Lt      E   vendor/myclabs/deep-copy/src/DeepCopy/Exception/PropertyException.phpx   ax   4      5   vendor/symfony/polyfill-intl-normalizer/bootstrap.php  a  PD      7   vendor/symfony/polyfill-intl-normalizer/bootstrap80.php  a  =r      6   vendor/symfony/polyfill-intl-normalizer/Normalizer.php  a  b"q      L   vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.phpt.  at.  qܤ      X   vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php  a  oe)      R   vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.php=  a=  *o?      T   vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.phpa  aa  R}      F   vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php.  a.  Qs$      .   vendor/symfony/polyfill-intl-idn/bootstrap.php[  a[  ΐ*      )   vendor/symfony/polyfill-intl-idn/Info.php   a   [      (   vendor/symfony/polyfill-intl-idn/Idn.phpB  aB        0   vendor/symfony/polyfill-intl-idn/bootstrap80.php*  a*  ]E)      L   vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php>  a>  NچG      G   vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php  a  8t      A   vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php8  a8  M:P      M   vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php  a  ;qf      =   vendor/symfony/polyfill-intl-idn/Resources/unidata/virama.php  a  /ɤ      =   vendor/symfony/polyfill-intl-idn/Resources/unidata/mapped.php/f a/f  -      <   vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.phṗ ȧ 
q]R      >   vendor/symfony/polyfill-intl-idn/Resources/unidata/ignored.php  a  d      @   vendor/symfony/polyfill-intl-idn/Resources/unidata/deviation.phpK   aK   ë`Ҥ      6   vendor/symfony/css-selector/Parser/ParserInterface.php   a   {偤      :   vendor/symfony/css-selector/Parser/Shortcut/HashParser.phpz  az  M'      ;   vendor/symfony/css-selector/Parser/Shortcut/ClassParser.php~  a~        A   vendor/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php  a  \#̤      =   vendor/symfony/css-selector/Parser/Shortcut/ElementParser.php  a  ,^      2   vendor/symfony/css-selector/Parser/TokenStream.phpF  aF  &T      :   vendor/symfony/css-selector/Parser/Tokenizer/Tokenizer.php  a  S-      B   vendor/symfony/css-selector/Parser/Tokenizer/TokenizerEscaping.php  a  ,      B   vendor/symfony/css-selector/Parser/Tokenizer/TokenizerPatterns.php  a  f      -   vendor/symfony/css-selector/Parser/Reader.phpb  ab  <ڤ      <   vendor/symfony/css-selector/Parser/Handler/StringHandler.phpc  ac  u      <   vendor/symfony/css-selector/Parser/Handler/NumberHandler.php  a  ].R      ?   vendor/symfony/css-selector/Parser/Handler/HandlerInterface.php  a  c n      @   vendor/symfony/css-selector/Parser/Handler/IdentifierHandler.php  a  o      @   vendor/symfony/css-selector/Parser/Handler/WhitespaceHandler.phpU  aU  ۋ      =   vendor/symfony/css-selector/Parser/Handler/CommentHandler.php  a  Ճ      :   vendor/symfony/css-selector/Parser/Handler/HashHandler.php  a  :P       ,   vendor/symfony/css-selector/Parser/Token.phpu  au  @!Ҥ      -   vendor/symfony/css-selector/Parser/Parser.phpC  aC  o*:      4   vendor/symfony/css-selector/CssSelectorConverter.php  a        1   vendor/symfony/css-selector/Node/FunctionNode.php  a  ]뵣      1   vendor/symfony/css-selector/Node/SelectorNode.php  a  [      .   vendor/symfony/css-selector/Node/ClassNode.php  a  O      0   vendor/symfony/css-selector/Node/ElementNode.php  a  *      2   vendor/symfony/css-selector/Node/AttributeNode.php#  a#  &Ó      2   vendor/symfony/css-selector/Node/NodeInterface.php   a   o"F      0   vendor/symfony/css-selector/Node/Specificity.php  a  "&1      1   vendor/symfony/css-selector/Node/NegationNode.php  a  ғ       1   vendor/symfony/css-selector/Node/AbstractNode.phpN  aN  `n      9   vendor/symfony/css-selector/Node/CombinedSelectorNode.php  a        /   vendor/symfony/css-selector/Node/PseudoNode.php  a  (      -   vendor/symfony/css-selector/Node/HashNode.php  a  j)&      8   vendor/symfony/css-selector/Exception/ParseException.php   a   /X      @   vendor/symfony/css-selector/Exception/InternalErrorException.php   a   &O      >   vendor/symfony/css-selector/Exception/SyntaxErrorException.phpn  an        B   vendor/symfony/css-selector/Exception/ExpressionErrorException.php   a   6;      <   vendor/symfony/css-selector/Exception/ExceptionInterface.php   a   B|      0   vendor/symfony/css-selector/XPath/Translator.php  a  =      9   vendor/symfony/css-selector/XPath/TranslatorInterface.phpq  aq  t_6      J   vendor/symfony/css-selector/XPath/Extension/AttributeMatchingExtension.phpb
  ab
  }      B   vendor/symfony/css-selector/XPath/Extension/ExtensionInterface.php  a  ZƼ      A   vendor/symfony/css-selector/XPath/Extension/FunctionExtension.php=  a=  )Z      A   vendor/symfony/css-selector/XPath/Extension/AbstractExtension.php  a  >:      =   vendor/symfony/css-selector/XPath/Extension/HtmlExtension.php  a  vc      =   vendor/symfony/css-selector/XPath/Extension/NodeExtension.php2  a2  
'L|      D   vendor/symfony/css-selector/XPath/Extension/CombinationExtension.php  a  6$n      D   vendor/symfony/css-selector/XPath/Extension/PseudoClassExtension.php  a  zä      /   vendor/symfony/css-selector/XPath/XPathExpr.php  a  ̭F      +   vendor/symfony/polyfill-ctype/bootstrap.php2  a2  a8      '   vendor/symfony/polyfill-ctype/Ctype.phpH	  aH	  ݤ      -   vendor/symfony/polyfill-ctype/bootstrap80.phph  ah  Ky      +   vendor/symfony/polyfill-php73/bootstrap.php  a  AY8Ƥ      '   vendor/symfony/polyfill-php73/Php73.phpn  an  Csl      ?   vendor/symfony/polyfill-php73/Resources/stubs/JsonException.php:   a:   aг      %   vendor/symfony/browser-kit/Client.php4  a4  O      E   vendor/symfony/browser-kit/Test/Constraint/BrowserCookieValueSame.php  a  |9      ?   vendor/symfony/browser-kit/Test/Constraint/BrowserHasCookie.php  a  +N      (   vendor/symfony/browser-kit/CookieJar.php  a  Ѥ      %   vendor/symfony/browser-kit/Cookie.php/  a/  mD      &   vendor/symfony/browser-kit/Request.php  a  I      .   vendor/symfony/browser-kit/AbstractBrowser.phpx   ax   Q 3Y      *   vendor/symfony/browser-kit/HttpBrowser.php&  a&  9       &   vendor/symfony/browser-kit/History.php  a  }0      ?   vendor/symfony/browser-kit/Exception/BadMethodCallException.php   a   Pa      '   vendor/symfony/browser-kit/Response.phpw  aw  
f(      +   vendor/symfony/polyfill-php80/bootstrap.php  a        '   vendor/symfony/polyfill-php80/Php80.php	  a	  {w=٤      ;   vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php  a  pN      <   vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php*   a*   *      E   vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php3   a3   y4%      <   vendor/symfony/polyfill-php80/Resources/stubs/Stringable.phpb   ab   ћ<      .   vendor/symfony/polyfill-mbstring/bootstrap.php  a  NZ^      -   vendor/symfony/polyfill-mbstring/Mbstring.phpJ  aJ  %ز      0   vendor/symfony/polyfill-mbstring/bootstrap80.php   a   Dפ      @   vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.phpT  aT  +      @   vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.php8[  a8[  +R*      F   vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php  a  y_      +   vendor/symfony/process/ExecutableFinder.php  a  >ϸp      "   vendor/symfony/process/Process.phpvd  avd  j¤      &   vendor/symfony/process/InputStream.php  a  ~/V      '   vendor/symfony/process/ProcessUtils.php  a  [      ;   vendor/symfony/process/Exception/ProcessFailedException.phpx  ax  zy      =   vendor/symfony/process/Exception/ProcessTimedOutException.php1  a1  'Z      3   vendor/symfony/process/Exception/LogicException.php   a          =   vendor/symfony/process/Exception/ProcessSignaledException.php  a  Yש      5   vendor/symfony/process/Exception/RuntimeException.php   a   :      =   vendor/symfony/process/Exception/InvalidArgumentException.php   a   +_      7   vendor/symfony/process/Exception/ExceptionInterface.phpy   ay   qVXJ      .   vendor/symfony/process/PhpExecutableFinder.phpA  aA  OZ      -   vendor/symfony/process/Pipes/WindowsPipes.php/  a/  >      *   vendor/symfony/process/Pipes/UnixPipes.php  a  Oˤ      /   vendor/symfony/process/Pipes/PipesInterface.php  a  fQ      .   vendor/symfony/process/Pipes/AbstractPipes.php
  a
  |      %   vendor/symfony/process/PhpProcess.php  a  MW֤      #   vendor/symfony/finder/Gitignore.php  a  4_      %   vendor/symfony/finder/SplFileInfo.php  a  䵵7      3   vendor/symfony/finder/Comparator/DateComparator.php  a        /   vendor/symfony/finder/Comparator/Comparator.php  a        5   vendor/symfony/finder/Comparator/NumberComparator.php  a  fӤ          vendor/symfony/finder/Finder.php*  a*  f         vendor/symfony/finder/Glob.php  a  t'      :   vendor/symfony/finder/Iterator/SizeRangeFilterIterator.phpc  ac  ;      =   vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php  a  0      9   vendor/symfony/finder/Iterator/FileTypeFilterIterator.phpo  ao  2|      <   vendor/symfony/finder/Iterator/FilecontentFilterIterator.php7  a7  o+Ƥ      A   vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php  a        :   vendor/symfony/finder/Iterator/DateRangeFilterIterator.phpv  av  F      9   vendor/symfony/finder/Iterator/FilenameFilterIterator.phpt  at  &oY      ;   vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php  a  8      7   vendor/symfony/finder/Iterator/CustomFilterIterator.phpJ  aJ  K      =   vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php  a  Z      /   vendor/symfony/finder/Iterator/LazyIterator.phpQ  aQ  n]      5   vendor/symfony/finder/Iterator/PathFilterIterator.php  a  =      3   vendor/symfony/finder/Iterator/SortableIterator.phpX	  aX	  5      >   vendor/symfony/finder/Exception/DirectoryNotFoundException.php   a   a)      9   vendor/symfony/finder/Exception/AccessDeniedException.php   a   s      J   vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextContains.phpk  ak  p      P   vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php  a        F   vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextSame.phpb  ab  {      D   vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorExists.phpx  ax        #   vendor/symfony/dom-crawler/Form.php  a  <
      6   vendor/symfony/dom-crawler/Field/TextareaFormField.php  a  4^      4   vendor/symfony/dom-crawler/Field/ChoiceFormField.php  a  缦      .   vendor/symfony/dom-crawler/Field/FormField.php  a  YB      3   vendor/symfony/dom-crawler/Field/InputFormField.php  a  !O      2   vendor/symfony/dom-crawler/Field/FileFormField.php  a  LJh      #   vendor/symfony/dom-crawler/Link.php  a  vۮ      &   vendor/symfony/dom-crawler/Crawler.phpS  aS  jf      $   vendor/symfony/dom-crawler/Image.php  a  
      0   vendor/symfony/dom-crawler/FormFieldRegistry.php
  a
  r      1   vendor/symfony/dom-crawler/AbstractUriElement.php
  a
  *^      2   vendor/symfony/console/Event/ConsoleErrorEvent.php  a        4   vendor/symfony/console/Event/ConsoleCommandEvent.php  a  W      6   vendor/symfony/console/Event/ConsoleTerminateEvent.php{  a{   _y<      -   vendor/symfony/console/Event/ConsoleEvent.php  a  /      ,   vendor/symfony/console/Output/NullOutput.php  a  Z      1   vendor/symfony/console/Output/OutputInterface.php  a  hФ      /   vendor/symfony/console/Output/ConsoleOutput.php		  a		  (D      0   vendor/symfony/console/Output/BufferedOutput.php`  a`  蟗      5   vendor/symfony/console/Output/TrimmedBufferOutput.php  a        8   vendor/symfony/console/Output/ConsoleOutputInterface.php   a   ,ݤ      (   vendor/symfony/console/Output/Output.php	  a	  ?q      .   vendor/symfony/console/Output/StreamOutput.phpx  ax  |	l      6   vendor/symfony/console/Output/ConsoleSectionOutput.php	  a	  ;      #   vendor/symfony/console/Terminal.php
  a
  Js      (   vendor/symfony/console/ConsoleEvents.php   a    v      2   vendor/symfony/console/Helper/InputAwareHelper.phpc  ac        '   vendor/symfony/console/Helper/Table.phpNE  aNE  󙚳      0   vendor/symfony/console/Helper/TableSeparator.php   a         2   vendor/symfony/console/Helper/DescriptorHelper.phpe  ae  2_      -   vendor/symfony/console/Helper/ProgressBar.php,  a,  ܹ      (   vendor/symfony/console/Helper/Dumper.php  a  ܽ      +   vendor/symfony/console/Helper/TableRows.php1  a1  O      +   vendor/symfony/console/Helper/HelperSet.phpg  ag  tդ      (   vendor/symfony/console/Helper/Helper.php  a        1   vendor/symfony/console/Helper/FormatterHelper.phpD  aD  +L      6   vendor/symfony/console/Helper/DebugFormatterHelper.phpt  at  R8      3   vendor/symfony/console/Helper/ProgressIndicator.php  a  15      +   vendor/symfony/console/Helper/TableCell.php,  a,  J      ,   vendor/symfony/console/Helper/TableStyle.php  a  FC      0   vendor/symfony/console/Helper/QuestionHelper.php(  a(        1   vendor/symfony/console/Helper/HelperInterface.php   a         /   vendor/symfony/console/Helper/ProcessHelper.php  a  jLѤ      7   vendor/symfony/console/Helper/SymfonyQuestionHelper.php  a  פ      2   vendor/symfony/console/Question/ChoiceQuestion.php
  a
  F``      8   vendor/symfony/console/Question/ConfirmationQuestion.php  a  yń      ,   vendor/symfony/console/Question/Question.php  a  `      6   vendor/symfony/console/EventListener/ErrorListener.php&  a&  X뮤      &   vendor/symfony/console/Application.phpn  an  qhܤ      -   vendor/symfony/console/Style/SymfonyStyle.php6&  a6&  /X      ,   vendor/symfony/console/Style/OutputStyle.phpX  aX        /   vendor/symfony/console/Style/StyleInterface.php  a        /   vendor/symfony/console/Tester/CommandTester.php  a  8;Ӥ      3   vendor/symfony/console/Tester/ApplicationTester.php  a  z      -   vendor/symfony/console/Tester/TesterTrait.php  a  n      /   vendor/symfony/console/Logger/ConsoleLogger.php  a  \W      .   vendor/symfony/console/Command/ListCommand.php6  a6  c=      0   vendor/symfony/console/Command/LockableTrait.php  a        .   vendor/symfony/console/Command/HelpCommand.php  a  G?~      *   vendor/symfony/console/Command/Command.php!"  a!"  Gj      =   vendor/symfony/console/CommandLoader/FactoryCommandLoader.php  a  m      ?   vendor/symfony/console/CommandLoader/ContainerCommandLoader.phpG  aG  k{UĤ      ?   vendor/symfony/console/CommandLoader/CommandLoaderInterface.phpG  aG  ?      D   vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.phpE
  aE
  /H      :   vendor/symfony/console/Exception/MissingInputException.php   a   S
      ?   vendor/symfony/console/Exception/NamespaceNotFoundException.php   a   n      ;   vendor/symfony/console/Exception/InvalidOptionException.php   a   H      3   vendor/symfony/console/Exception/LogicException.php   a   O\e      5   vendor/symfony/console/Exception/RuntimeException.php   a   ,6      =   vendor/symfony/console/Exception/CommandNotFoundException.php  a  w      =   vendor/symfony/console/Exception/InvalidArgumentException.php   a   ̽Z      7   vendor/symfony/console/Exception/ExceptionInterface.phpy   ay   9[&      F   vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php   a   ]
'¤      4   vendor/symfony/console/Formatter/OutputFormatter.php  a  Èޤ      =   vendor/symfony/console/Formatter/OutputFormatterInterface.php  a  vLդ      B   vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php  a  G      9   vendor/symfony/console/Formatter/OutputFormatterStyle.phpD  aD  E޳      >   vendor/symfony/console/Formatter/OutputFormatterStyleStack.php  a  Fx      4   vendor/symfony/console/Descriptor/TextDescriptor.php"  a"  9H      3   vendor/symfony/console/Descriptor/XmlDescriptor.php/  a/  cޤ      0   vendor/symfony/console/Descriptor/Descriptor.phpi  ai  R      8   vendor/symfony/console/Descriptor/MarkdownDescriptor.php  a  S]      9   vendor/symfony/console/Descriptor/DescriptorInterface.php   a   P~      <   vendor/symfony/console/Descriptor/ApplicationDescription.php	  a	  g      4   vendor/symfony/console/Descriptor/JsonDescriptor.php|  a|  YA      ,   vendor/symfony/console/Input/StringInput.phpB  aB  ./      .   vendor/symfony/console/Input/InputArgument.php!  a!  y      +   vendor/symfony/console/Input/ArrayInput.phpf  af        9   vendor/symfony/console/Input/StreamableInputInterface.php   a   B      *   vendor/symfony/console/Input/ArgvInput.phpr  ar  Z}      &   vendor/symfony/console/Input/Input.phpB  aB  S*      /   vendor/symfony/console/Input/InputInterface.php  a  rrg      0   vendor/symfony/console/Input/InputDefinition.php  a  49      ,   vendor/symfony/console/Input/InputOption.php8  a8  ˤ      4   vendor/symfony/console/Input/InputAwareInterface.php   a   O         vendor/symfony/yaml/Inline.php	M  a	M  F      '   vendor/symfony/yaml/Tag/TaggedValue.phpC  aC  *ʤ         vendor/symfony/yaml/Dumper.php  a  ڄۤ         vendor/symfony/yaml/Escaper.php  a  塍      +   vendor/symfony/yaml/Command/LintCommand.php  a  qS      !   vendor/symfony/yaml/Unescaper.php   a   >      0   vendor/symfony/yaml/Exception/ParseException.php\  a\   e      2   vendor/symfony/yaml/Exception/RuntimeException.php   a   $      /   vendor/symfony/yaml/Exception/DumpException.phps   as   Ƥ      4   vendor/symfony/yaml/Exception/ExceptionInterface.phpv   av   0ʤ         vendor/symfony/yaml/Parser.phpy  ay  --         vendor/symfony/yaml/Yaml.phpI  aI  \]      +   vendor/symfony/polyfill-php72/bootstrap.phpw  aw  HJ3      '   vendor/symfony/polyfill-php72/Php72.php  a  x0s      F   vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php  a  ѡŤ      3   vendor/symfony/event-dispatcher-contracts/Event.php  a  AW      K   vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php  a  Z      B   vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php#  a#  K茤      9   vendor/symfony/event-dispatcher/Debug/WrappedListener.php  a  oQ      <   vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php#  a#  o      4   vendor/symfony/event-dispatcher/LegacyEventProxy.php  a  n?      3   vendor/symfony/event-dispatcher/EventDispatcher.phpj  aj  8      <   vendor/symfony/event-dispatcher/EventSubscriberInterface.php   a   !jcK      M   vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php\  a\  c      K   vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.phpZ  aZ  Ey      >   vendor/symfony/event-dispatcher/LegacyEventDispatcherProxy.php  a  R|%      0   vendor/symfony/event-dispatcher/GenericEvent.phpz  az  p      <   vendor/symfony/event-dispatcher/EventDispatcherInterface.php  a        )   vendor/symfony/event-dispatcher/Event.php  a  ЛJr      ;   vendor/symfony/service-contracts/ServiceSubscriberTrait.php\  a\  <      3   vendor/symfony/service-contracts/ResetInterface.phpy   ay   j      =   vendor/symfony/service-contracts/ServiceProviderInterface.php   a   Rk      <   vendor/symfony/service-contracts/Test/ServiceLocatorTest.php  a  W7|G      ?   vendor/symfony/service-contracts/ServiceSubscriberInterface.php   a   d      8   vendor/symfony/service-contracts/ServiceLocatorTrait.php	  a	  KY         vendor/autoload.php   a   \m      P   vendor/doctrine/instantiator/src/Doctrine/Instantiator/InstantiatorInterface.php   a   Ve      G   vendor/doctrine/instantiator/src/Doctrine/Instantiator/Instantiator.phpI  aI  6      ]   vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/UnexpectedValueException.php  a  B)      ]   vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/InvalidArgumentException.php  a  J      W   vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/ExceptionInterface.phpy   ay   m7      A   vendor/justinrainbow/json-schema/src/JsonSchema/SchemaStorage.php  a  fO      J   vendor/justinrainbow/json-schema/src/JsonSchema/SchemaStorageInterface.php  a  o+}      H   vendor/justinrainbow/json-schema/src/JsonSchema/UriResolverInterface.php   a   J      I   vendor/justinrainbow/json-schema/src/JsonSchema/UriRetrieverInterface.php   a   e      F   vendor/justinrainbow/json-schema/src/JsonSchema/Entity/JsonPointer.php  a  {N      D   vendor/justinrainbow/json-schema/src/JsonSchema/Uri/UriRetriever.phpF  aF  IaD      C   vendor/justinrainbow/json-schema/src/JsonSchema/Uri/UriResolver.php  a  )      T   vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/AbstractRetriever.php   a   [A      R   vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/FileGetContents.php%  a%  5"      G   vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/Curl.php  a  ԧLb      R   vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/PredefinedArray.php,  a,  15      X   vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/UriRetrieverInterface.php   a         ;   vendor/justinrainbow/json-schema/src/JsonSchema/Rfc3339.php  a  f4      K   vendor/justinrainbow/json-schema/src/JsonSchema/Iterator/ObjectIterator.php  a  M      X   vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeCheck/LooseTypeCheck.phpa  aa  	qä      Y   vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeCheck/StrictTypeCheck.php  a  4~      \   vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeCheck/TypeCheckInterface.php  a  +j      S   vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/UndefinedConstraint.phpS"  aS"  :      N   vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/BaseConstraint.php	  a	  wl      N   vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/EnumConstraint.php]  a]  VU<      P   vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ObjectConstraint.php  a  żx      G   vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Factory.php  a  0;      S   vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ConstraintInterface.php  a   Q      P   vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/NumberConstraint.php	  a	  (      P   vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/SchemaConstraint.php0	  a0	  j      P   vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/FormatConstraint.php  a  Tڤ      T   vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/CollectionConstraint.php
  a
  ӯ      N   vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeConstraint.php&  a&  4T      J   vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Constraint.php  a  PFF      P   vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/StringConstraint.php  a  w      ]   vendor/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidSchemaMediaTypeException.phpu   au   =h      R   vendor/justinrainbow/json-schema/src/JsonSchema/Exception/UriResolverException.phpj   aj   >      T   vendor/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidSchemaException.phpl   al   2      Q   vendor/justinrainbow/json-schema/src/JsonSchema/Exception/ValidationException.phpf   af         T   vendor/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidConfigException.phpl   al   A!Lפ      W   vendor/justinrainbow/json-schema/src/JsonSchema/Exception/ResourceNotFoundException.phpo   ao   p      ^   vendor/justinrainbow/json-schema/src/JsonSchema/Exception/UnresolvableJsonPointerException.php   a   u-#1      N   vendor/justinrainbow/json-schema/src/JsonSchema/Exception/RuntimeException.php   a   %      S   vendor/justinrainbow/json-schema/src/JsonSchema/Exception/JsonDecodingException.php  a  \
      W   vendor/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidSourceUriException.phpw   aw   N-[      V   vendor/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidArgumentException.php   a   G      P   vendor/justinrainbow/json-schema/src/JsonSchema/Exception/ExceptionInterface.phpI   aI   %|      =   vendor/justinrainbow/json-schema/src/JsonSchema/Validator.phpv  av  g      >   vendor/phar-io/manifest/src/exceptions/InvalidUrlException.php   a   1      D   vendor/phar-io/manifest/src/exceptions/ManifestDocumentException.php   a   YT      4   vendor/phar-io/manifest/src/exceptions/Exception.phpp   ap   BO      J   vendor/phar-io/manifest/src/exceptions/ManifestDocumentMapperException.php   a   \;/      B   vendor/phar-io/manifest/src/exceptions/ManifestLoaderException.php   a   G#      E   vendor/phar-io/manifest/src/exceptions/ElementCollectionException.php   a         C   vendor/phar-io/manifest/src/exceptions/ManifestElementException.php   a   m}      K   vendor/phar-io/manifest/src/exceptions/ManifestDocumentLoadingException.php(  a(  Vt      J   vendor/phar-io/manifest/src/exceptions/InvalidApplicationNameException.php   a   &_ä      @   vendor/phar-io/manifest/src/exceptions/InvalidEmailException.php   a   ä      6   vendor/phar-io/manifest/src/ManifestDocumentMapper.php\  a\  x囤      -   vendor/phar-io/manifest/src/values/Author.php  a  2G      I   vendor/phar-io/manifest/src/values/BundledComponentCollectionIterator.php  a  ^D      ;   vendor/phar-io/manifest/src/values/CopyrightInformation.php  a  F:      .   vendor/phar-io/manifest/src/values/Library.php   a   1[u      7   vendor/phar-io/manifest/src/values/AuthorCollection.php  a  B{      <   vendor/phar-io/manifest/src/values/PhpVersionRequirement.php  a  #      A   vendor/phar-io/manifest/src/values/BundledComponentCollection.phpH  aH  |?D2      2   vendor/phar-io/manifest/src/values/Requirement.php_   a_   M4J      ?   vendor/phar-io/manifest/src/values/AuthorCollectionIterator.phpW  aW  R      >   vendor/phar-io/manifest/src/values/PhpExtensionRequirement.php'  a'  5      *   vendor/phar-io/manifest/src/values/Url.php  a  s      ,   vendor/phar-io/manifest/src/values/Email.php  a  gHɤ      6   vendor/phar-io/manifest/src/values/ApplicationName.php  a  ^      <   vendor/phar-io/manifest/src/values/RequirementCollection.php  a  `L      2   vendor/phar-io/manifest/src/values/Application.php   a   g      0   vendor/phar-io/manifest/src/values/Extension.php  a  =W}      D   vendor/phar-io/manifest/src/values/RequirementCollectionIterator.php  a  0      /   vendor/phar-io/manifest/src/values/Manifest.php  a  ,ܤ      +   vendor/phar-io/manifest/src/values/Type.phpj  aj  ؤ      .   vendor/phar-io/manifest/src/values/License.phpI  aI  Ӭ      7   vendor/phar-io/manifest/src/values/BundledComponent.php  a  z      3   vendor/phar-io/manifest/src/xml/ManifestElement.php'  a'  \      .   vendor/phar-io/manifest/src/xml/PhpElement.php  a  A$      4   vendor/phar-io/manifest/src/xml/CopyrightElement.php{  a{  0B[      ;   vendor/phar-io/manifest/src/xml/AuthorElementCollection.php   a   Lh2      2   vendor/phar-io/manifest/src/xml/LicenseElement.php  a  ,      4   vendor/phar-io/manifest/src/xml/ManifestDocument.phpU  aU  gV      4   vendor/phar-io/manifest/src/xml/ExtensionElement.php!  a!         .   vendor/phar-io/manifest/src/xml/ExtElement.php   a   ͤ      4   vendor/phar-io/manifest/src/xml/ComponentElement.php  a  >G      3   vendor/phar-io/manifest/src/xml/ContainsElement.php  a  CV      1   vendor/phar-io/manifest/src/xml/AuthorElement.php  a  [      3   vendor/phar-io/manifest/src/xml/RequiresElement.php   a   q      >   vendor/phar-io/manifest/src/xml/ComponentElementCollection.php   a   ԖѤ      2   vendor/phar-io/manifest/src/xml/BundlesElement.php  a  i>      8   vendor/phar-io/manifest/src/xml/ExtElementCollection.php   a   Zb      5   vendor/phar-io/manifest/src/xml/ElementCollection.php  a  pM      2   vendor/phar-io/manifest/src/ManifestSerializer.php`  a`  ,u      .   vendor/phar-io/manifest/src/ManifestLoader.php  a  ~      E   vendor/phar-io/version/src/exceptions/NoPreReleaseSuffixException.php   a   XbpԤ      3   vendor/phar-io/version/src/exceptions/Exception.php~   a~   x|      J   vendor/phar-io/version/src/exceptions/InvalidPreReleaseSuffixException.php   a         A   vendor/phar-io/version/src/exceptions/InvalidVersionException.php   a   |      O   vendor/phar-io/version/src/exceptions/UnsupportedVersionConstraintException.php   a   /O      &   vendor/phar-io/version/src/Version.php  a  ˓      5   vendor/phar-io/version/src/VersionConstraintValue.php  a  
      /   vendor/phar-io/version/src/PreReleaseSuffix.php  a  FА      ,   vendor/phar-io/version/src/VersionNumber.php/  a/  f,w[      6   vendor/phar-io/version/src/VersionConstraintParser.php+
  a+
  ƉČ      Q   vendor/phar-io/version/src/constraints/SpecificMajorAndMinorVersionConstraint.php  a  &q      C   vendor/phar-io/version/src/constraints/OrVersionConstraintGroup.php  a  $      <   vendor/phar-io/version/src/constraints/VersionConstraint.php   a   w_      D   vendor/phar-io/version/src/constraints/AndVersionConstraintGroup.php  a        I   vendor/phar-io/version/src/constraints/SpecificMajorVersionConstraint.php  a  Xx      P   vendor/phar-io/version/src/constraints/GreaterThanOrEqualToVersionConstraint.php  a        D   vendor/phar-io/version/src/constraints/AbstractVersionConstraint.phpK  aK  qB      ?   vendor/phar-io/version/src/constraints/AnyVersionConstraint.php   a   ^      A   vendor/phar-io/version/src/constraints/ExactVersionConstraint.php   a   mV      G   vendor/phpspec/prophecy/src/Prophecy/Prediction/CallTimesPrediction.php  a  'B      B   vendor/phpspec/prophecy/src/Prophecy/Prediction/CallPrediction.php<  a<  B́      F   vendor/phpspec/prophecy/src/Prophecy/Prediction/CallbackPrediction.php  a  #R,      E   vendor/phpspec/prophecy/src/Prophecy/Prediction/NoCallsPrediction.phpv  av  "dp      G   vendor/phpspec/prophecy/src/Prophecy/Prediction/PredictionInterface.php  a  ;      E   vendor/phpspec/prophecy/src/Prophecy/Comparator/ClosureComparator.php  a        ;   vendor/phpspec/prophecy/src/Prophecy/Comparator/Factory.php  a  L      F   vendor/phpspec/prophecy/src/Prophecy/Comparator/ProphecyComparator.phpN  aN  #X      8   vendor/phpspec/prophecy/src/Prophecy/Util/StringUtil.php&  a&  
H      8   vendor/phpspec/prophecy/src/Prophecy/Util/ExportUtil.php4  a4  H      F   vendor/phpspec/prophecy/src/Prophecy/Promise/ReturnArgumentPromise.php  a  \      @   vendor/phpspec/prophecy/src/Prophecy/Promise/CallbackPromise.php  a  B      A   vendor/phpspec/prophecy/src/Prophecy/Promise/PromiseInterface.php   a   /c      >   vendor/phpspec/prophecy/src/Prophecy/Promise/ReturnPromise.php  a  ^-5      =   vendor/phpspec/prophecy/src/Prophecy/Promise/ThrowPromise.php  a  жҤ      0   vendor/phpspec/prophecy/src/Prophecy/Prophet.php8	  a8	  7      H   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/ObjectStateToken.php=  a=  Ḗ      L   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/ArrayEveryEntryToken.php[  a[  j      A   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/TypeToken.php>  a>  mӤ      F   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/AnyValuesToken.php  a  aN      M   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/ApproximateValueToken.php6  a6  #x      E   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/CallbackToken.php  a  Ǥ      K   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/IdenticalValueToken.php  a  A      G   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/LogicalNotToken.phpR  aR  M      G   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/LogicalAndToken.php  a  Ф      G   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/ArrayCountToken.php  a  ߖ      K   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/StringContainsToken.php  a  vѤ      G   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/ArrayEntryToken.php  a  >v[      G   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/ExactValueToken.phpL  aL  8H      D   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/InArrayToken.phpn  an  }H      E   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/AnyValueToken.php  a  %&|      G   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/NotInArrayToken.phps  as        F   vendor/phpspec/prophecy/src/Prophecy/Argument/Token/TokenInterface.php   a   V]稤      C   vendor/phpspec/prophecy/src/Prophecy/Argument/ArgumentsWildcard.phpp  ap  ˤ      J   vendor/phpspec/prophecy/src/Prophecy/Prophecy/ProphecySubjectInterface.php   a   Њ/      @   vendor/phpspec/prophecy/src/Prophecy/Prophecy/MethodProphecy.php  a  !l      @   vendor/phpspec/prophecy/src/Prophecy/Prophecy/ObjectProphecy.php  a  d      C   vendor/phpspec/prophecy/src/Prophecy/Prophecy/RevealerInterface.phpz   az         :   vendor/phpspec/prophecy/src/Prophecy/Prophecy/Revealer.phpb  ab  Z	      C   vendor/phpspec/prophecy/src/Prophecy/Prophecy/ProphecyInterface.phpr   ar   +hڤ      R   vendor/phpspec/prophecy/src/Prophecy/PhpDocumentor/MethodTagRetrieverInterface.php"  a"  !]      N   vendor/phpspec/prophecy/src/Prophecy/PhpDocumentor/LegacyClassTagRetriever.php  a  ӥq      H   vendor/phpspec/prophecy/src/Prophecy/PhpDocumentor/ClassTagRetriever.phpm  am  qLu      T   vendor/phpspec/prophecy/src/Prophecy/PhpDocumentor/ClassAndInterfaceTagRetriever.php  a  iM:c      1   vendor/phpspec/prophecy/src/Prophecy/Argument.php#  a#  Y5[      8   vendor/phpspec/prophecy/src/Prophecy/Call/CallCenter.php  a  wL      2   vendor/phpspec/prophecy/src/Prophecy/Call/Call.php  a  (>      >   vendor/phpspec/prophecy/src/Prophecy/Doubler/NameGenerator.php  a  [K      N   vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ReflectionInterface.php_   a_   ~      G   vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassCreator.php8  a8  c1      I   vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ClassNode.php
	  a
	  Rm      J   vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/MethodNode.php  a  {*      P   vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ArgumentTypeNode.php   a   8)Sդ      N   vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ReturnTypeNode.phpV  aV  eݎ      P   vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/TypeNodeAbstract.php   a   >c      L   vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ArgumentNode.php  a  6'ᬤ      L   vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/TypeHintReference.php  a  c#ܤ      M   vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassCodeGenerator.php<  a<   d      F   vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassMirror.php  a  x¤      >   vendor/phpspec/prophecy/src/Prophecy/Doubler/CachedDoubler.phpt  at  L      ;   vendor/phpspec/prophecy/src/Prophecy/Doubler/LazyDouble.php  a  lE5      8   vendor/phpspec/prophecy/src/Prophecy/Doubler/Doubler.php  a  2B`      @   vendor/phpspec/prophecy/src/Prophecy/Doubler/DoubleInterface.phpQ   aQ   o̊ʤ      H   vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/KeywordPatch.phpV  aV  l2I      [   vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ReflectionClassNewInstancePatch.php  a  kS      S   vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/DisableConstructorPatch.php7  a7  L#      N   vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/HhvmExceptionPatch.php  a  6Ǥ      J   vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/MagicCallPatch.php  a  X<O      O   vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ClassPatchInterface.php  a        P   vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php  a  ;      L   vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/TraversablePatch.php  a  KK&N      J   vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ThrowablePatch.php  a  -;      L   vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/SplFileInfoPatch.php  a        W   vendor/phpspec/prophecy/src/Prophecy/Exception/Prediction/FailedPredictionException.php   a   |D      Q   vendor/phpspec/prophecy/src/Prophecy/Exception/Prediction/PredictionException.php   a         [   vendor/phpspec/prophecy/src/Prophecy/Exception/Prediction/UnexpectedCallsCountException.php  a  R      V   vendor/phpspec/prophecy/src/Prophecy/Exception/Prediction/UnexpectedCallsException.php  a  f~      N   vendor/phpspec/prophecy/src/Prophecy/Exception/Prediction/NoCallsException.php   a   wi@      P   vendor/phpspec/prophecy/src/Prophecy/Exception/Prediction/AggregateException.php  a  R3k      <   vendor/phpspec/prophecy/src/Prophecy/Exception/Exception.php`   a`         S   vendor/phpspec/prophecy/src/Prophecy/Exception/Prophecy/MethodProphecyException.php  a  @      M   vendor/phpspec/prophecy/src/Prophecy/Exception/Prophecy/ProphecyException.php   a   _n      S   vendor/phpspec/prophecy/src/Prophecy/Exception/Prophecy/ObjectProphecyException.php  a  e      O   vendor/phpspec/prophecy/src/Prophecy/Exception/Call/UnexpectedCallException.phpV  aV  h0J+      W   vendor/phpspec/prophecy/src/Prophecy/Exception/Doubler/MethodNotExtendableException.php  a  	      P   vendor/phpspec/prophecy/src/Prophecy/Exception/Doubler/ClassCreatorException.phpu  au  Тy      K   vendor/phpspec/prophecy/src/Prophecy/Exception/Doubler/DoublerException.php   a   m      O   vendor/phpspec/prophecy/src/Prophecy/Exception/Doubler/ClassMirrorException.phpj  aj  g&      U   vendor/phpspec/prophecy/src/Prophecy/Exception/Doubler/ReturnByReferenceException.php  a  R      U   vendor/phpspec/prophecy/src/Prophecy/Exception/Doubler/InterfaceNotFoundException.php   a   
l      J   vendor/phpspec/prophecy/src/Prophecy/Exception/Doubler/DoubleException.php   a   '}      R   vendor/phpspec/prophecy/src/Prophecy/Exception/Doubler/MethodNotFoundException.phpN  aN  K]      Q   vendor/phpspec/prophecy/src/Prophecy/Exception/Doubler/ClassNotFoundException.php;  a;  I}      K   vendor/phpspec/prophecy/src/Prophecy/Exception/InvalidArgumentException.php   a   Șh         vendor/composer/installed.php6h  a6h  UZ,      "   vendor/composer/autoload_files.php  a  }      !   vendor/composer/autoload_real.php  a  5      %   vendor/composer/autoload_classmap.phpi ai _(         vendor/composer/ClassLoader.php  a  d_      #   vendor/composer/autoload_static.php( a( |"      "   vendor/composer/platform_check.php  a  t      !   vendor/composer/autoload_psr4.php  a  O`      %   vendor/composer/InstalledVersions.php`  a`  Ǉ      '   vendor/composer/autoload_namespaces.php   a   Zsq      *   vendor/composer/ca-bundle/src/CaBundle.php$  a$  oQE      /   vendor/softcreatr/jsonpath/src/AccessHelper.phpA  aA  L      6   vendor/softcreatr/jsonpath/src/Filters/IndexFilter.phpR  aR  3qV      6   vendor/softcreatr/jsonpath/src/Filters/SliceFilter.php-  a-  sݤ      ;   vendor/softcreatr/jsonpath/src/Filters/QueryMatchFilter.php  a  d      9   vendor/softcreatr/jsonpath/src/Filters/AbstractFilter.php  a        <   vendor/softcreatr/jsonpath/src/Filters/QueryResultFilter.php  a  =      8   vendor/softcreatr/jsonpath/src/Filters/IndexesFilter.php  a        :   vendor/softcreatr/jsonpath/src/Filters/RecursiveFilter.phpf  af  ˥      0   vendor/softcreatr/jsonpath/src/JSONPathLexer.php  a  ۽      4   vendor/softcreatr/jsonpath/src/JSONPathException.php   a   ahT      +   vendor/softcreatr/jsonpath/src/JSONPath.php  a  t      0   vendor/softcreatr/jsonpath/src/JSONPathToken.php  a  #M      /   vendor/psr/container/src/ContainerInterface.php   a         7   vendor/psr/container/src/NotFoundExceptionInterface.phpq   aq   R      8   vendor/psr/container/src/ContainerExceptionInterface.phpN   aN   L      1   vendor/psr/http-message/src/ResponseInterface.php  a        0   vendor/psr/http-message/src/RequestInterface.php  a  V      6   vendor/psr/http-message/src/ServerRequestInterface.phpo  ao  
$h      0   vendor/psr/http-message/src/MessageInterface.php  a  )t      /   vendor/psr/http-message/src/StreamInterface.php  a  h\l      5   vendor/psr/http-message/src/UploadedFileInterface.phpz  az  9b      ,   vendor/psr/http-message/src/UriInterface.php|  a|  k      .   vendor/guzzlehttp/promises/src/EachPromise.php  a  +bz      5   vendor/guzzlehttp/promises/src/TaskQueueInterface.php   a   ]-Ɩ      (   vendor/guzzlehttp/promises/src/Utils.phpz  az  *9E      *   vendor/guzzlehttp/promises/src/Promise.php}  a}  2/      4   vendor/guzzlehttp/promises/src/functions_include.phph   ah   ʏ      ,   vendor/guzzlehttp/promises/src/Coroutine.php  a  Z齤      5   vendor/guzzlehttp/promises/src/RejectionException.php  a  Y      %   vendor/guzzlehttp/promises/src/Is.php:  a:  ĭ-      2   vendor/guzzlehttp/promises/src/RejectedPromise.php@  a@  I      3   vendor/guzzlehttp/promises/src/FulfilledPromise.php  a  擤      8   vendor/guzzlehttp/promises/src/CancellationException.phpd   ad   ,/      ,   vendor/guzzlehttp/promises/src/functions.php  a  D6      '   vendor/guzzlehttp/promises/src/Each.php3  a3  C(+      )   vendor/guzzlehttp/promises/src/Create.php(  a(        3   vendor/guzzlehttp/promises/src/PromiseInterface.php  a  &	      4   vendor/guzzlehttp/promises/src/PromisorInterface.phpi   ai   42x      ,   vendor/guzzlehttp/promises/src/TaskQueue.php  a  \      5   vendor/guzzlehttp/promises/src/AggregateException.php   a         +   vendor/guzzlehttp/psr7/src/MessageTrait.php  a  
      *   vendor/guzzlehttp/psr7/src/LimitStream.php  a  ۯ      $   vendor/guzzlehttp/psr7/src/Utils.phpL  aL  6?      +   vendor/guzzlehttp/psr7/src/AppendStream.php  a  3{V      *   vendor/guzzlehttp/psr7/src/UriResolver.php  a  >R      "   vendor/guzzlehttp/psr7/src/Uri.phpK*  aK*        &   vendor/guzzlehttp/psr7/src/Request.phpF	  aF	  %      3   vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php@  a@  '¤      ,   vendor/guzzlehttp/psr7/src/CachingStream.php  a  |%      ,   vendor/guzzlehttp/psr7/src/InflateStream.php  a  X      +   vendor/guzzlehttp/psr7/src/BufferStream.php:  a:        )   vendor/guzzlehttp/psr7/src/PumpStream.phpu  au  gʂ      0   vendor/guzzlehttp/psr7/src/functions_include.php]   a]   ɤ      %   vendor/guzzlehttp/psr7/src/Header.php  a  (YDȤ      .   vendor/guzzlehttp/psr7/src/MultipartStream.phpe
  ae
  _s(      $   vendor/guzzlehttp/psr7/src/Query.php
  a
  YO      ,   vendor/guzzlehttp/psr7/src/ServerRequest.php:  a:  V	      &   vendor/guzzlehttp/psr7/src/Rfc7230.php   a   ݤ      +   vendor/guzzlehttp/psr7/src/UploadedFile.php  a  +aC      +   vendor/guzzlehttp/psr7/src/NoSeekStream.php=  a=  %TH      ,   vendor/guzzlehttp/psr7/src/UriNormalizer.php
  a
  d%      &   vendor/guzzlehttp/psr7/src/Message.php  a  3ˑ      ,   vendor/guzzlehttp/psr7/src/StreamWrapper.php  a  2?[      '   vendor/guzzlehttp/psr7/src/MimeType.phpS  aS        %   vendor/guzzlehttp/psr7/src/Stream.php=  a=  8֤      -   vendor/guzzlehttp/psr7/src/DroppingStream.php2  a2  ´      '   vendor/guzzlehttp/psr7/src/FnStream.php  a        (   vendor/guzzlehttp/psr7/src/functions.php=
  a=
  AC 9      '   vendor/guzzlehttp/psr7/src/Response.php  a  ?$A      -   vendor/guzzlehttp/psr7/src/LazyOpenStream.php  a  :@      '   vendor/guzzlehttp/guzzle/src/Client.php6#  a6#  .9      1   vendor/guzzlehttp/guzzle/src/MessageFormatter.php  a  J^e      0   vendor/guzzlehttp/guzzle/src/ClientInterface.php  a  _:      ,   vendor/guzzlehttp/guzzle/src/UriTemplate.php]  a]  &      &   vendor/guzzlehttp/guzzle/src/Utils.php_  a_  ֤      -   vendor/guzzlehttp/guzzle/src/HandlerStack.php  a  X{ '      1   vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php  a  -O}      1   vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php  a  J      8   vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php  a  &      5   vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php  a  H9      :   vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.phpH  aH  ?I      +   vendor/guzzlehttp/guzzle/src/Middleware.php  a        /   vendor/guzzlehttp/guzzle/src/RequestOptions.php  a  W{      2   vendor/guzzlehttp/guzzle/src/functions_include.phpa   aa   j      %   vendor/guzzlehttp/guzzle/src/Pool.php  a  Mܘ      0   vendor/guzzlehttp/guzzle/src/RetryMiddleware.php  a  $ͤ      .   vendor/guzzlehttp/guzzle/src/TransferStats.php  a  /c      =   vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php   a   u      3   vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php9  a9  :\      4   vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.phpv  av  9f      4   vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.phpi2  ai2  E3      6   vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php^-  a^-  I!      4   vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php  a  ׋      9   vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.phpt  at  x      .   vendor/guzzlehttp/guzzle/src/Handler/Proxy.php  a  ˤ      6   vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php  a        3   vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php  a  vꓤ      ;   vendor/guzzlehttp/guzzle/src/Exception/RequestException.php	  a	  <(Ĥ      D   vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.phpd   ad   Bu      :   vendor/guzzlehttp/guzzle/src/Exception/ServerException.phpa   aa   eby      ;   vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php  a  հ      :   vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php   a   Zs~o      <   vendor/guzzlehttp/guzzle/src/Exception/TransferException.phpx   ax   'B      ?   vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.phpc  ac  )k-      C   vendor/guzzlehttp/guzzle/src/Exception/InvalidArgumentException.php   a   co      8   vendor/guzzlehttp/guzzle/src/Exception/SeekException.php  a  ZM%]      :   vendor/guzzlehttp/guzzle/src/Exception/ClientException.phpa   aa   c C      *   vendor/guzzlehttp/guzzle/src/functions.php]  a]  D      1   vendor/phpunit/php-file-iterator/src/Iterator.php  a  ]0      0   vendor/phpunit/php-file-iterator/src/Factory.php  a  mZ      /   vendor/phpunit/php-file-iterator/src/Facade.php  a  Ѥ      1   vendor/phpunit/php-text-template/src/Template.php  a  I      *   vendor/phpunit/php-timer/src/Exception.phpc   ac   yB}      &   vendor/phpunit/php-timer/src/Timer.phpp  ap  Z+      1   vendor/phpunit/php-timer/src/RuntimeException.php   a    [x%      9   vendor/phpunit/phpunit/src/Runner/NullTestResultCache.php  a        <   vendor/phpunit/phpunit/src/Runner/DefaultTestResultCache.php	  a	  XN      5   vendor/phpunit/phpunit/src/Runner/TestSuiteSorter.php  a  ,I      /   vendor/phpunit/phpunit/src/Runner/Exception.php   a   	Um      2   vendor/phpunit/phpunit/src/Runner/PhptTestCase.php8  a8  !WM      5   vendor/phpunit/phpunit/src/Runner/TestSuiteLoader.php  a  sC      4   vendor/phpunit/phpunit/src/Runner/BaseTestRunner.php  a  *NS      -   vendor/phpunit/phpunit/src/Runner/Version.php  a  >!c      5   vendor/phpunit/phpunit/src/Runner/TestResultCache.php  a        =   vendor/phpunit/phpunit/src/Runner/StandardTestSuiteLoader.php  a  ֲ      G   vendor/phpunit/phpunit/src/Runner/Filter/ExcludeGroupFilterIterator.php  a  Jߤ      ?   vendor/phpunit/phpunit/src/Runner/Filter/NameFilterIterator.phpq  aq  !`\      4   vendor/phpunit/phpunit/src/Runner/Filter/Factory.php0  a0  [)r      @   vendor/phpunit/phpunit/src/Runner/Filter/GroupFilterIterator.php  a  +ޤ      G   vendor/phpunit/phpunit/src/Runner/Filter/IncludeGroupFilterIterator.php  a  m      8   vendor/phpunit/phpunit/src/Runner/Hook/AfterTestHook.php   a   #C      B   vendor/phpunit/phpunit/src/Runner/Hook/AfterSuccessfulTestHook.php   a   YQ      >   vendor/phpunit/phpunit/src/Runner/Hook/BeforeFirstTestHook.php   a   D      ?   vendor/phpunit/phpunit/src/Runner/Hook/AfterTestFailureHook.php   a   榽      >   vendor/phpunit/phpunit/src/Runner/Hook/TestListenerAdapter.php  a  Ze      <   vendor/phpunit/phpunit/src/Runner/Hook/AfterLastTestHook.php   a         ?   vendor/phpunit/phpunit/src/Runner/Hook/AfterSkippedTestHook.php   a   =      =   vendor/phpunit/phpunit/src/Runner/Hook/AfterRiskyTestHook.php   a         9   vendor/phpunit/phpunit/src/Runner/Hook/BeforeTestHook.php   a   ^U      3   vendor/phpunit/phpunit/src/Runner/Hook/TestHook.phpf   af   Ǫ      B   vendor/phpunit/phpunit/src/Runner/Hook/AfterIncompleteTestHook.php   a   |M?      ?   vendor/phpunit/phpunit/src/Runner/Hook/AfterTestWarningHook.php   a   	      /   vendor/phpunit/phpunit/src/Runner/Hook/Hook.phpU   aU   |      =   vendor/phpunit/phpunit/src/Runner/Hook/AfterTestErrorHook.php   a   -      :   vendor/phpunit/phpunit/src/Runner/ResultCacheExtension.php	  a	  ߤ      (   vendor/phpunit/phpunit/src/Exception.phpx   ax   (
l      3   vendor/phpunit/phpunit/src/Framework/TestResult.php'H  a'H        ;   vendor/phpunit/phpunit/src/Framework/IncompleteTestCase.php  a  p&      9   vendor/phpunit/phpunit/src/Framework/ExceptionWrapper.php  a  lJ      5   vendor/phpunit/phpunit/src/Framework/Error/Notice.phpp   ap   &2L      6   vendor/phpunit/phpunit/src/Framework/Error/Warning.phpq   aq   UCH      9   vendor/phpunit/phpunit/src/Framework/Error/Deprecated.phpt   at   s      4   vendor/phpunit/phpunit/src/Framework/Error/Error.php]  a]  \#v      G   vendor/phpunit/phpunit/src/Framework/InvalidParameterGroupException.php   a   eOq      =   vendor/phpunit/phpunit/src/Framework/Constraint/Attribute.phpB  aB  7J-n      ;   vendor/phpunit/phpunit/src/Framework/Constraint/IsFalse.php  a  [      B   vendor/phpunit/phpunit/src/Framework/Constraint/StringContains.phpA  aA        >   vendor/phpunit/phpunit/src/Framework/Constraint/FileExists.php  a  ې      D   vendor/phpunit/phpunit/src/Framework/Constraint/ExceptionMessage.php  a   ͐U      K   vendor/phpunit/phpunit/src/Framework/Constraint/TraversableContainsOnly.phpx  ax  \      <   vendor/phpunit/phpunit/src/Framework/Constraint/Callback.php  a  .2      >   vendor/phpunit/phpunit/src/Framework/Constraint/IsReadable.php  a        =   vendor/phpunit/phpunit/src/Framework/Constraint/Exception.php  a  ◤      ?   vendor/phpunit/phpunit/src/Framework/Constraint/ArrayHasKey.php  a  N̤      B   vendor/phpunit/phpunit/src/Framework/Constraint/StringEndsWith.php  a  .      >   vendor/phpunit/phpunit/src/Framework/Constraint/IsWritable.php  a  Ȥ      ;   vendor/phpunit/phpunit/src/Framework/Constraint/IsEmpty.php  a        :   vendor/phpunit/phpunit/src/Framework/Constraint/IsTrue.php  a  $o      ?   vendor/phpunit/phpunit/src/Framework/Constraint/GreaterThan.php  a  P3l`      9   vendor/phpunit/phpunit/src/Framework/Constraint/Count.php  a  }      >   vendor/phpunit/phpunit/src/Framework/Constraint/IsAnything.php  a        >   vendor/phpunit/phpunit/src/Framework/Constraint/LogicalAnd.php  a  mb      ?   vendor/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php  a  {ˤ      L   vendor/phpunit/phpunit/src/Framework/Constraint/TraversableContainsEqual.php  a  `]Ԥ      >   vendor/phpunit/phpunit/src/Framework/Constraint/LogicalXor.php  a  ޞ      :   vendor/phpunit/phpunit/src/Framework/Constraint/IsJson.php  a  &e      A   vendor/phpunit/phpunit/src/Framework/Constraint/ExceptionCode.php  a  |      @   vendor/phpunit/phpunit/src/Framework/Constraint/IsInstanceOf.php  a  U1      K   vendor/phpunit/phpunit/src/Framework/Constraint/ClassHasStaticAttribute.php  a  <٤      P   vendor/phpunit/phpunit/src/Framework/Constraint/TraversableContainsIdentical.php  a  A      S   vendor/phpunit/phpunit/src/Framework/Constraint/JsonMatchesErrorMessageProvider.php  a  ˤ      :   vendor/phpunit/phpunit/src/Framework/Constraint/IsType.php~	  a~	  q6      >   vendor/phpunit/phpunit/src/Framework/Constraint/LogicalNot.php<  a<  yid      :   vendor/phpunit/phpunit/src/Framework/Constraint/IsNull.php  a  Sʤ      C   vendor/phpunit/phpunit/src/Framework/Constraint/DirectoryExists.php  a  C/      E   vendor/phpunit/phpunit/src/Framework/Constraint/RegularExpression.php  a  l      U   vendor/phpunit/phpunit/src/Framework/Constraint/ExceptionMessageRegularExpression.php  a  J      <   vendor/phpunit/phpunit/src/Framework/Constraint/SameSize.php   a   
      F   vendor/phpunit/phpunit/src/Framework/Constraint/ObjectHasAttribute.php)  a)  Ɲ      ?   vendor/phpunit/phpunit/src/Framework/Constraint/JsonMatches.php  a        >   vendor/phpunit/phpunit/src/Framework/Constraint/IsInfinite.php,  a,  )%)      9   vendor/phpunit/phpunit/src/Framework/Constraint/IsNan.php  a  WTŤ      E   vendor/phpunit/phpunit/src/Framework/Constraint/ClassHasAttribute.php  a  $p      G   vendor/phpunit/phpunit/src/Framework/Constraint/TraversableContains.phpP  aP  0      >   vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php  a  ?      =   vendor/phpunit/phpunit/src/Framework/Constraint/Composite.php  a  ¤      <   vendor/phpunit/phpunit/src/Framework/Constraint/LessThan.php  a  }      D   vendor/phpunit/phpunit/src/Framework/Constraint/StringStartsWith.phpb  ab  N       ;   vendor/phpunit/phpunit/src/Framework/Constraint/IsEqual.php  a  F      ?   vendor/phpunit/phpunit/src/Framework/Constraint/ArraySubset.php5  a5  dEȪ      R   vendor/phpunit/phpunit/src/Framework/Constraint/StringMatchesFormatDescription.php  a  m      <   vendor/phpunit/phpunit/src/Framework/Constraint/IsFinite.php$  a$  ȺX      =   vendor/phpunit/phpunit/src/Framework/Constraint/LogicalOr.phpj  aj  )橷      4   vendor/phpunit/phpunit/src/Framework/TestBuilder.php  a  M@8'      =   vendor/phpunit/phpunit/src/Framework/MockObject/MockClass.php  a        A   vendor/phpunit/phpunit/src/Framework/MockObject/MockMethodSet.phpB  aB  +RY      N   vendor/phpunit/phpunit/src/Framework/MockObject/Rule/ConsecutiveParameters.php  a  =      K   vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtLeastOnce.php  a  (ˊ      E   vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedCount.php  a  _      C   vendor/phpunit/phpunit/src/Framework/MockObject/Rule/Parameters.phpL
  aL
  !      L   vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtLeastCount.php  a  0$      H   vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvocationOrder.php  a  Ĥ      F   vendor/phpunit/phpunit/src/Framework/MockObject/Rule/AnyParameters.phpv  av  >xZ      G   vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtIndex.php  a  )      K   vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtMostCount.php  a  ɲv$      H   vendor/phpunit/phpunit/src/Framework/MockObject/Rule/AnyInvokedCount.php  a  ΂      C   vendor/phpunit/phpunit/src/Framework/MockObject/Rule/MethodName.php  a  e      G   vendor/phpunit/phpunit/src/Framework/MockObject/Rule/ParametersRule.php  a   s%      Q   vendor/phpunit/phpunit/src/Framework/MockObject/Generator/proxied_method_void.tpl}  a}  &      K   vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_method.tplM  aM  7i      P   vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_method_void.tpl  a   Τ      I   vendor/phpunit/phpunit/src/Framework/MockObject/Generator/trait_class.tplQ   aQ   <Ȥ      R   vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_static_method.tpl   a    4R      I   vendor/phpunit/phpunit/src/Framework/MockObject/Generator/deprecation.tpl;   a;   O5s      H   vendor/phpunit/phpunit/src/Framework/MockObject/Generator/wsdl_class.tpl   a         I   vendor/phpunit/phpunit/src/Framework/MockObject/Generator/wsdl_method.tpl<   a<   i      L   vendor/phpunit/phpunit/src/Framework/MockObject/Generator/proxied_method.tpl  a  񻕤      J   vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_class.tpl   a   wZ      >   vendor/phpunit/phpunit/src/Framework/MockObject/MockMethod.php&  a&  Wd      B   vendor/phpunit/phpunit/src/Framework/MockObject/Builder/Match_.php   a         M   vendor/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationStubber.php  a  ź[      L   vendor/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationMocker.php  a  /      K   vendor/phpunit/phpunit/src/Framework/MockObject/Builder/ParametersMatch.php   a   *      K   vendor/phpunit/phpunit/src/Framework/MockObject/Builder/MethodNameMatch.php   a   gG      @   vendor/phpunit/phpunit/src/Framework/MockObject/Builder/Stub.php   a   vl      D   vendor/phpunit/phpunit/src/Framework/MockObject/Builder/Identity.php   a    j      8   vendor/phpunit/phpunit/src/Framework/MockObject/Stub.phpp  ap  5.      >   vendor/phpunit/phpunit/src/Framework/MockObject/MockObject.php  a        K   vendor/phpunit/phpunit/src/Framework/MockObject/Api/UnmockedCloneMethod.php   a   8F      I   vendor/phpunit/phpunit/src/Framework/MockObject/Api/MockedCloneMethod.php   a   |ҭ      ;   vendor/phpunit/phpunit/src/Framework/MockObject/Api/Api.php:  a:  M      >   vendor/phpunit/phpunit/src/Framework/MockObject/Api/Method.phpo  ao  _Ť      =   vendor/phpunit/phpunit/src/Framework/MockObject/Generator.phpT  aT  qH      >   vendor/phpunit/phpunit/src/Framework/MockObject/Verifiable.php   a   9      ?   vendor/phpunit/phpunit/src/Framework/MockObject/MockBuilder.php  a  rǤ      >   vendor/phpunit/phpunit/src/Framework/MockObject/Invocation.php
  a
  A      H   vendor/phpunit/phpunit/src/Framework/MockObject/MethodNameConstraint.php\  a\  Mä      G   vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnCallback.php  a  pN4      C   vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnStub.php$  a$        B   vendor/phpunit/phpunit/src/Framework/MockObject/Stub/Exception.php\  a\  ag      I   vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ConsecutiveCalls.php  a        =   vendor/phpunit/phpunit/src/Framework/MockObject/Stub/Stub.php  a  tv~      G   vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnArgument.phpU  aU  8      H   vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnReference.phpG  aG  E      C   vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnSelf.php  a  䫣      G   vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnValueMap.php  a  Ǎ,b      E   vendor/phpunit/phpunit/src/Framework/MockObject/InvocationHandler.php
  a
  I)      <   vendor/phpunit/phpunit/src/Framework/MockObject/MockType.php   a   Rթ      F   vendor/phpunit/phpunit/src/Framework/MockObject/ConfigurableMethod.php  a  f      G   vendor/phpunit/phpunit/src/Framework/MockObject/Exception/Exception.php   a   CE      T   vendor/phpunit/phpunit/src/Framework/MockObject/Exception/BadMethodCallException.php   a   -W      l   vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ConfigurableMethodsAlreadyInitializedException.php   a   h      N   vendor/phpunit/phpunit/src/Framework/MockObject/Exception/RuntimeException.php   a   Dͤ      ^   vendor/phpunit/phpunit/src/Framework/MockObject/Exception/IncompatibleReturnValueException.php   a   p-*      =   vendor/phpunit/phpunit/src/Framework/MockObject/MockTrait.php  a  h      ;   vendor/phpunit/phpunit/src/Framework/MockObject/Matcher.phpl  al  L0      1   vendor/phpunit/phpunit/src/Framework/TestCase.php  a  ܀(      2   vendor/phpunit/phpunit/src/Framework/TestSuite.php-  a-  fƤ      7   vendor/phpunit/phpunit/src/Framework/SelfDescribing.php   a   ú]      8   vendor/phpunit/phpunit/src/Framework/WarningTestCase.phpU  aU  $Q      4   vendor/phpunit/phpunit/src/Framework/TestFailure.php  a  =u      J   vendor/phpunit/phpunit/src/Framework/TestListenerDefaultImplementation.phpH  aH  'I՘      8   vendor/phpunit/phpunit/src/Framework/SkippedTestCase.php  a  >Dd      7   vendor/phpunit/phpunit/src/Framework/IncompleteTest.phpe   ae   K(      4   vendor/phpunit/phpunit/src/Framework/SkippedTest.phpb   ab         >   vendor/phpunit/phpunit/src/Framework/DataProviderTestSuite.php  a        5   vendor/phpunit/phpunit/src/Framework/TestListener.phpG  aG  K      -   vendor/phpunit/phpunit/src/Framework/Test.php   a   p      9   vendor/phpunit/phpunit/src/Framework/Assert/Functions.phpY  aY  l      K   vendor/phpunit/phpunit/src/Framework/Exception/PHPTAssertionFailedError.php  a  mf      A   vendor/phpunit/phpunit/src/Framework/Exception/RiskyTestError.php~   a~   V      C   vendor/phpunit/phpunit/src/Framework/Exception/SkippedTestError.php   a   ,R76      L   vendor/phpunit/phpunit/src/Framework/Exception/NoChildTestSuiteException.php   a         R   vendor/phpunit/phpunit/src/Framework/Exception/CoveredCodeNotExecutedException.php   a   ؤ      R   vendor/phpunit/phpunit/src/Framework/Exception/UnintentionallyCoveredCodeError.php   a   jOƤ      H   vendor/phpunit/phpunit/src/Framework/Exception/SkippedTestSuiteError.php   a   XeƲ      <   vendor/phpunit/phpunit/src/Framework/Exception/Exception.php  a  ð      O   vendor/phpunit/phpunit/src/Framework/Exception/InvalidDataProviderException.php   a   Ś	      H   vendor/phpunit/phpunit/src/Framework/Exception/SyntheticSkippedError.php   a   N^      :   vendor/phpunit/phpunit/src/Framework/Exception/Warning.php   a   7Uޤ      S   vendor/phpunit/phpunit/src/Framework/Exception/MissingCoversAnnotationException.php   a   [Q      G   vendor/phpunit/phpunit/src/Framework/Exception/AssertionFailedError.php   a         O   vendor/phpunit/phpunit/src/Framework/Exception/InvalidCoversTargetException.php   a   T      F   vendor/phpunit/phpunit/src/Framework/Exception/IncompleteTestError.php   a   ߀铤      >   vendor/phpunit/phpunit/src/Framework/Exception/OutputError.php   a   )ä      K   vendor/phpunit/phpunit/src/Framework/Exception/InvalidArgumentException.php  a  {Ǥ      A   vendor/phpunit/phpunit/src/Framework/Exception/SyntheticError.php  a  ?V      H   vendor/phpunit/phpunit/src/Framework/Exception/CodeCoverageException.phpz   az   v      M   vendor/phpunit/phpunit/src/Framework/Exception/ExpectationFailedException.php4  a4  ~KeC      /   vendor/phpunit/phpunit/src/Framework/Assert.phpJ  aJ  ׏      :   vendor/phpunit/phpunit/src/Framework/TestSuiteIterator.php*  a*  P+      8   vendor/phpunit/phpunit/src/Util/TextTestListRenderer.php  a  V      :   vendor/phpunit/phpunit/src/Util/ConfigurationGenerator.phpo  ao  lʤ      -   vendor/phpunit/phpunit/src/Util/Blacklist.phpz  az  Qx      9   vendor/phpunit/phpunit/src/Util/PHP/WindowsPhpProcess.php  a        9   vendor/phpunit/phpunit/src/Util/PHP/DefaultPhpProcess.php  a  |c֤      =   vendor/phpunit/phpunit/src/Util/PHP/Template/PhptTestCase.tpl&  a&  T      ?   vendor/phpunit/phpunit/src/Util/PHP/Template/TestCaseMethod.tpl+
  a+
  Ig      >   vendor/phpunit/phpunit/src/Util/PHP/Template/TestCaseClass.tpl	  a	  M      :   vendor/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php  a  Τ      ?   vendor/phpunit/phpunit/src/Util/XdebugFilterScriptGenerator.php  a  '"      1   vendor/phpunit/phpunit/src/Util/Configuration.php`  a`  ~$      -   vendor/phpunit/phpunit/src/Util/Exception.php   a   m/r      ;   vendor/phpunit/phpunit/src/Util/InvalidDataSetException.php   a   qշ      (   vendor/phpunit/phpunit/src/Util/Json.php  a  [      *   vendor/phpunit/phpunit/src/Util/Getopt.phpV  aV  S.      0   vendor/phpunit/phpunit/src/Util/ErrorHandler.php/
  a/
  .      .   vendor/phpunit/phpunit/src/Util/Filesystem.php  a        +   vendor/phpunit/phpunit/src/Util/Printer.php  a  F      0   vendor/phpunit/phpunit/src/Util/Log/TeamCity.php  a  $>m      -   vendor/phpunit/phpunit/src/Util/Log/JUnit.php   a   9jFN      *   vendor/phpunit/phpunit/src/Util/Filter.php  a  #L)      .   vendor/phpunit/phpunit/src/Util/FileLoader.php3  a3  R       '   vendor/phpunit/phpunit/src/Util/Xml.php  a  _      )   vendor/phpunit/phpunit/src/Util/Color.php^  a^  ʤ      5   vendor/phpunit/phpunit/src/Util/RegularExpression.phpP  aP  _      7   vendor/phpunit/phpunit/src/Util/Annotation/DocBlock.phpN1  aN1  I      7   vendor/phpunit/phpunit/src/Util/Annotation/Registry.phpI  aI  	o      (   vendor/phpunit/phpunit/src/Util/Type.php?  a?  LM$      (   vendor/phpunit/phpunit/src/Util/Test.phpI  aI  -@      /   vendor/phpunit/phpunit/src/Util/GlobalState.php}  a}        7   vendor/phpunit/phpunit/src/Util/XmlTestListRenderer.php3  a3  q      =   vendor/phpunit/phpunit/src/Util/VersionComparisonOperator.php  a  =B      :   vendor/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php  a        <   vendor/phpunit/phpunit/src/Util/TestDox/XmlResultPrinter.php  a  ׁ%      =   vendor/phpunit/phpunit/src/Util/TestDox/HtmlResultPrinter.phpO  aO  )L|      =   vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php*  a*  !Jx      =   vendor/phpunit/phpunit/src/Util/TestDox/TextResultPrinter.php  a  qu      9   vendor/phpunit/phpunit/src/Util/TestDox/ResultPrinter.php  a  h]S      :   vendor/phpunit/phpunit/src/Util/TestDox/NamePrettifier.php  a  _       0   vendor/phpunit/phpunit/src/TextUI/TestRunner.php
  a
  S>      /   vendor/phpunit/phpunit/src/TextUI/Exception.php   a   VR      3   vendor/phpunit/phpunit/src/TextUI/ResultPrinter.php(  a(  J      *   vendor/phpunit/phpunit/src/TextUI/Help.php%  a%        -   vendor/phpunit/phpunit/src/TextUI/Command.phpc  ac  
פ      2   vendor/phpunit/php-token-stream/src/Token/Util.php   a   ~"      C   vendor/phpunit/php-token-stream/src/Token/Stream/CachingFactory.php  a        4   vendor/phpunit/php-token-stream/src/Token/Stream.phpc"  ac"  żԤ      -   vendor/phpunit/php-token-stream/src/Token.phpH  aH  ]3      6   vendor/phpunit/php-code-coverage/src/Driver/Xdebug.php  a  n      6   vendor/phpunit/php-code-coverage/src/Driver/Driver.phpW  aW  !      4   vendor/phpunit/php-code-coverage/src/Driver/PCOV.php  a  1      6   vendor/phpunit/php-code-coverage/src/Driver/PHPDBG.php  a  b      -   vendor/phpunit/php-code-coverage/src/Util.php  a  	ɤ      5   vendor/phpunit/php-code-coverage/src/CodeCoverage.phpE  aE  Ť      7   vendor/phpunit/php-code-coverage/src/Node/Directory.php:  a:  l̤      6   vendor/phpunit/php-code-coverage/src/Node/Iterator.phpK  aK  lZU      5   vendor/phpunit/php-code-coverage/src/Node/Builder.php
  a
        :   vendor/phpunit/php-code-coverage/src/Node/AbstractNode.phpU  aU  h֤      2   vendor/phpunit/php-code-coverage/src/Node/File.php%  a%  fѤ      0   vendor/phpunit/php-code-coverage/src/Version.phpu  au  P¤      /   vendor/phpunit/php-code-coverage/src/Filter.php3
  a3
        4   vendor/phpunit/php-code-coverage/src/Report/Text.php=  a=  %'(      3   vendor/phpunit/php-code-coverage/src/Report/PHP.php  a  0t      :   vendor/phpunit/php-code-coverage/src/Report/Xml/Source.php  a  VЁ      =   vendor/phpunit/php-code-coverage/src/Report/Xml/Directory.php   a   v͆      D   vendor/phpunit/php-code-coverage/src/Report/Xml/BuildInformation.php  a  Y~|'      :   vendor/phpunit/php-code-coverage/src/Report/Xml/Totals.php  a  Cj      8   vendor/phpunit/php-code-coverage/src/Report/Xml/Node.php  a  6      :   vendor/phpunit/php-code-coverage/src/Report/Xml/Report.php  a  Wɚ      :   vendor/phpunit/php-code-coverage/src/Report/Xml/Facade.phpE  aE  P\>      <   vendor/phpunit/php-code-coverage/src/Report/Xml/Coverage.phpZ  aZ  ![      8   vendor/phpunit/php-code-coverage/src/Report/Xml/Unit.phpq  aq  B      :   vendor/phpunit/php-code-coverage/src/Report/Xml/Method.php  a  d:      8   vendor/phpunit/php-code-coverage/src/Report/Xml/File.php  a  ?8      9   vendor/phpunit/php-code-coverage/src/Report/Xml/Tests.php0  a0  p٤      ;   vendor/phpunit/php-code-coverage/src/Report/Xml/Project.php=  a=  ER      =   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer.phpv  av        ;   vendor/phpunit/php-code-coverage/src/Report/Html/Facade.php4  a4  y/      G   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Directory.php>	  a>	  Xˤ      G   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Dashboard.php  a  zQ      Q   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/file.html.dist
  a
  f"      V   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/dashboard.html.distG  aG  l      X   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/method_item.html.dist  a  s:      [   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/icons/file-directory.svg   a   Z      V   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/icons/file-code.svg0  a0  QUU      V   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/directory.html.dist  a  GM      V   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/file_item.html.distt  at        X   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/css/bootstrap.min.cssn` an` Ӥ      S   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/css/octicons.cssX   aX   '#      P   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/css/style.css  a  v      T   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/css/nv.d3.min.cssX%  aX%  0,      Q   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/css/custom.css    a              [   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/directory_item.html.distA  aA  ds      S   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/js/jquery.min.jsQX aQX Q[      V   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/js/bootstrap.min.js  a  '^      R   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/js/nv.d3.min.jsR aR <Ms      S   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/js/popper.min.jsR  aR  Z\      O   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/js/d3.min.jsP aP hb      M   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/js/file.js  a  b䆤      Y   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/coverage_bar.html.dist'  a'  O}      B   vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/File.php'  a'  ǡ      6   vendor/phpunit/php-code-coverage/src/Report/Clover.php  a  -6      6   vendor/phpunit/php-code-coverage/src/Report/Crap4j.php  a  U;n      R   vendor/phpunit/php-code-coverage/src/Exception/CoveredCodeNotExecutedException.php   a   pk      <   vendor/phpunit/php-code-coverage/src/Exception/Exception.phpm   am   *>ݤ      S   vendor/phpunit/php-code-coverage/src/Exception/MissingCoversAnnotationException.php   a         V   vendor/phpunit/php-code-coverage/src/Exception/UnintentionallyCoveredCodeException.php  a  QB      C   vendor/phpunit/php-code-coverage/src/Exception/RuntimeException.php   a   x)ޤ      K   vendor/phpunit/php-code-coverage/src/Exception/InvalidArgumentException.php  a  Mv      0   vendor/theseer/tokenizer/src/TokenCollection.php  a  O      *   vendor/theseer/tokenizer/src/Tokenizer.php9  a9  >_/      *   vendor/theseer/tokenizer/src/Exception.phpf   af         9   vendor/theseer/tokenizer/src/TokenCollectionException.phpt   at   u      .   vendor/theseer/tokenizer/src/XMLSerializer.php  a  O      -   vendor/theseer/tokenizer/src/NamespaceUri.php  a  X      &   vendor/theseer/tokenizer/src/Token.php  a  X      6   vendor/theseer/tokenizer/src/NamespaceUriException.phpq   aq   )0U         vendor/hoa/event/Source.php\   a\            vendor/hoa/event/Listener.php  a  *>      %   vendor/hoa/event/Test/Unit/Source.php   a   VbJ      '   vendor/hoa/event/Test/Unit/Listener.php  a   1      (   vendor/hoa/event/Test/Unit/Exception.phpC  aC  g%L      %   vendor/hoa/event/Test/Unit/Bucket.php  a  ^      &   vendor/hoa/event/Test/Unit/Listens.php  a  *]o      )   vendor/hoa/event/Test/Unit/Listenable.php,  a,  '5      $   vendor/hoa/event/Test/Unit/Event.phpH  aH  {._֤         vendor/hoa/event/Exception.php   a   x샤         vendor/hoa/event/Bucket.php  a  v         vendor/hoa/event/Listens.php~  a~  w         vendor/hoa/event/Listenable.php   a   
         vendor/hoa/event/Event.php	  a	  x`c         vendor/hoa/ustring/Search.php  a  OIV      &   vendor/hoa/ustring/Test/Unit/Issue.php?  a?  h      '   vendor/hoa/ustring/Test/Unit/Search.php  a  Ԡݤ      (   vendor/hoa/ustring/Test/Unit/Ustring.phpD  aD            vendor/hoa/ustring/Exception.php   a   H      !   vendor/hoa/ustring/Bin/Tocode.php  a  xHӤ      #   vendor/hoa/ustring/Bin/Fromcode.php  a  s          vendor/hoa/ustring/Ustring.php.  a.  42[C          vendor/hoa/protocol/Protocol.php	  a	  o      *   vendor/hoa/protocol/Test/Unit/Protocol.php{  a{  ݹw      )   vendor/hoa/protocol/Test/Unit/Wrapper.php1A  a1A  C      +   vendor/hoa/protocol/Test/Unit/Exception.phpI  aI  	A      .   vendor/hoa/protocol/Test/Unit/Node/Library.php  a  T/5      +   vendor/hoa/protocol/Test/Unit/Node/Node.php  a  SĤ         vendor/hoa/protocol/Wrapper.php  a  ?"      !   vendor/hoa/protocol/Exception.php   a   E      #   vendor/hoa/protocol/Bin/Resolve.php  a  vh      $   vendor/hoa/protocol/Node/Library.php  a  kO      !   vendor/hoa/protocol/Node/Node.php  a        :   vendor/hoa/stream/Test/Integration/Filter/LateComputed.phpD  aD  B0      4   vendor/hoa/stream/Test/Integration/Filter/Filter.phpg
  ag
        -   vendor/hoa/stream/Test/Integration/Stream.phpe  ae  ;\      )   vendor/hoa/stream/Test/Unit/Exception.phpb  ab  :      9   vendor/hoa/stream/Test/Unit/Wrapper/IWrapper/IWrapper.php  a  )W      7   vendor/hoa/stream/Test/Unit/Wrapper/IWrapper/Stream.phpv  av   ڛ      5   vendor/hoa/stream/Test/Unit/Wrapper/IWrapper/File.phpp  ap  j_      /   vendor/hoa/stream/Test/Unit/Wrapper/Wrapper.php	  a	  W&      1   vendor/hoa/stream/Test/Unit/Wrapper/Exception.phpg  ag  O      0   vendor/hoa/stream/Test/Unit/IStream/Statable.php  a  =      1   vendor/hoa/stream/Test/Unit/IStream/Touchable.php#  a#  IL      *   vendor/hoa/stream/Test/Unit/IStream/In.php  a  -      2   vendor/hoa/stream/Test/Unit/IStream/Structural.php  a  ` ֤      +   vendor/hoa/stream/Test/Unit/IStream/Out.php  a         1   vendor/hoa/stream/Test/Unit/IStream/Pointable.php  a  Zg      .   vendor/hoa/stream/Test/Unit/IStream/Stream.php[  a[  [¹      2   vendor/hoa/stream/Test/Unit/IStream/Bufferable.php  a  7פ      0   vendor/hoa/stream/Test/Unit/IStream/Lockable.php   a   :6,      0   vendor/hoa/stream/Test/Unit/IStream/Pathable.php  a  ε.      &   vendor/hoa/stream/Test/Unit/Bucket.php	  a	  隞o      '   vendor/hoa/stream/Test/Unit/Context.php	  a	        0   vendor/hoa/stream/Test/Unit/Filter/Exception.phpa  aa  ]BT      -   vendor/hoa/stream/Test/Unit/Filter/Filter.php  a        ,   vendor/hoa/stream/Test/Unit/Filter/Basic.php  a  ;ODn      &   vendor/hoa/stream/Test/Unit/Stream.php8  a8  >      )   vendor/hoa/stream/Test/Unit/Composite.php  a  쑤         vendor/hoa/stream/Exception.php   a   '<Y      /   vendor/hoa/stream/Wrapper/IWrapper/IWrapper.php  a  wzY      -   vendor/hoa/stream/Wrapper/IWrapper/Stream.phpr  ar  _2      +   vendor/hoa/stream/Wrapper/IWrapper/File.php  a  +Ĥ      %   vendor/hoa/stream/Wrapper/Wrapper.php  a  lD      '   vendor/hoa/stream/Wrapper/Exception.php   a   }%m      &   vendor/hoa/stream/IStream/Statable.php  a        '   vendor/hoa/stream/IStream/Touchable.php  a  "CҤ          vendor/hoa/stream/IStream/In.php7  a7  ņky      (   vendor/hoa/stream/IStream/Structural.php<  a<  gPg      !   vendor/hoa/stream/IStream/Out.php6  a6  -ˤ      '   vendor/hoa/stream/IStream/Pointable.php^  a^  ;L      $   vendor/hoa/stream/IStream/Stream.php   a   k|8      (   vendor/hoa/stream/IStream/Bufferable.phpQ  aQ  a±      &   vendor/hoa/stream/IStream/Lockable.php3  a3  <       &   vendor/hoa/stream/IStream/Pathable.php   a   FP         vendor/hoa/stream/Bucket.php  a  u]X         vendor/hoa/stream/Context.php  a  VIj      )   vendor/hoa/stream/Filter/LateComputed.php4  a4        &   vendor/hoa/stream/Filter/Exception.php   a   ŵa      #   vendor/hoa/stream/Filter/Filter.phpq	  aq	  +[      "   vendor/hoa/stream/Filter/Basic.php  a  2         vendor/hoa/stream/Stream.php  a  Si         vendor/hoa/stream/Composite.php1  a1  o"פ         vendor/hoa/exception/Idle.php  a        '   vendor/hoa/exception/Test/Unit/Idle.php  a        ,   vendor/hoa/exception/Test/Unit/Exception.php  a  A      (   vendor/hoa/exception/Test/Unit/Group.php+  a+  Mc      (   vendor/hoa/exception/Test/Unit/Error.php  a  ݤ      "   vendor/hoa/exception/Exception.php  a  G         vendor/hoa/exception/Group.phpH	  aH	  A         vendor/hoa/exception/Error.php  a  M         vendor/hoa/file/Generic.phpj  aj  1Ƥ         vendor/hoa/file/Directory.php
  a
  a          vendor/hoa/file/SplFileInfo.php  a  H+         vendor/hoa/file/Finder.php   a   ţ         vendor/hoa/file/Read.php  a  W)J         vendor/hoa/file/Watcher.phpI  aI  ':         vendor/hoa/file/ReadWrite.phpa  aa  8         vendor/hoa/file/Write.php<	  a<	   S      "   vendor/hoa/file/Temporary/Read.php  a  Cv.      '   vendor/hoa/file/Temporary/ReadWrite.php  a  R      #   vendor/hoa/file/Temporary/Write.php5	  a5	  q      '   vendor/hoa/file/Temporary/Temporary.php  a  _芤         vendor/hoa/file/Link/Read.php  a  F'      "   vendor/hoa/file/Link/ReadWrite.php  a  (#         vendor/hoa/file/Link/Write.php*	  a*	           vendor/hoa/file/Link/Link.php  a  ֤      '   vendor/hoa/file/Exception/Exception.php   a   (      .   vendor/hoa/file/Exception/FileDoesNotExist.php}   a}   c@         vendor/hoa/file/File.phpx  ax  /k         vendor/hoa/console/Console.php  a  n      (   vendor/hoa/console/Test/Unit/Console.php  a  EN<      &   vendor/hoa/console/Test/Unit/Mouse.php
  a
  x      &   vendor/hoa/console/Test/Unit/Input.php|  a|  L@      %   vendor/hoa/console/Test/Unit/Tput.php"  a"  h#      '   vendor/hoa/console/Test/Unit/Output.php  a  ΝM$      '   vendor/hoa/console/Test/Unit/Window.php  a  h{      *   vendor/hoa/console/Test/Unit/GetOption.php_  a_  sB      '   vendor/hoa/console/Test/Unit/Parser.php  a  d      2   vendor/hoa/console/Test/Unit/Readline/Password.php  a  e0      A   vendor/hoa/console/Test/Unit/Readline/Autocompleter/Aggregate.phpx  ax        <   vendor/hoa/console/Test/Unit/Readline/Autocompleter/Word.php~  a~  sܕ      <   vendor/hoa/console/Test/Unit/Readline/Autocompleter/Path.php{  a{  {      '   vendor/hoa/console/Test/Unit/Cursor.phpE4  aE4  0e          vendor/hoa/console/Exception.php   a   q$|         vendor/hoa/console/Mouse.php
  a
  4U      "   vendor/hoa/console/Bin/Termcap.php?
  a?
  ߤ         vendor/hoa/console/Input.php  a  Z         vendor/hoa/console/Tput.php/  a/  b      $   vendor/hoa/console/Chrome/Editor.php  a  G)      "   vendor/hoa/console/Chrome/Text.php  a  1{      '   vendor/hoa/console/Chrome/Exception.php   a   `D!      #   vendor/hoa/console/Chrome/Pager.php_  a_           vendor/hoa/console/Output.php{  a{  t3         vendor/hoa/console/Window.phpv  av  2i      %   vendor/hoa/console/Dispatcher/Kit.php  a  kh          vendor/hoa/console/Processus.phpY(  aY(  ڤ          vendor/hoa/console/GetOption.php  a  ݤ         vendor/hoa/console/Parser.php  a  LC      (   vendor/hoa/console/Readline/Password.php   a   0ڤ      (   vendor/hoa/console/Readline/Readline.php;  a;  uGɤ      ;   vendor/hoa/console/Readline/Autocompleter/Autocompleter.php:  a:  e      7   vendor/hoa/console/Readline/Autocompleter/Aggregate.php  a  ᤤ      2   vendor/hoa/console/Readline/Autocompleter/Word.php  a  K̤      2   vendor/hoa/console/Readline/Autocompleter/Path.php  a  >         vendor/hoa/console/Cursor.php&#  a&#  (WҤ          vendor/hoa/iterator/Multiple.phpF  aF  g2      )   vendor/hoa/iterator/CallbackGenerator.php  a  	Ԥ      !   vendor/hoa/iterator/Directory.php  a  ̇vФ      *   vendor/hoa/iterator/Test/Unit/Multiple.php  a  $6=      3   vendor/hoa/iterator/Test/Unit/CallbackGenerator.php  a  {      +   vendor/hoa/iterator/Test/Unit/Directory.php  a  [      -   vendor/hoa/iterator/Test/Unit/SplFileInfo.php.  a.  y      ,   vendor/hoa/iterator/Test/Unit/FileSystem.php  a  Vc&      0   vendor/hoa/iterator/Test/Unit/CallbackFilter.php?  a?  K      (   vendor/hoa/iterator/Test/Unit/Append.php  a  ܙפ      /   vendor/hoa/iterator/Test/Unit/Demultiplexer.php  a  O      &   vendor/hoa/iterator/Test/Unit/Mock.php<  a<  Ŝ%X      %   vendor/hoa/iterator/Test/Unit/Map.phpc  ac  X      '   vendor/hoa/iterator/Test/Unit/Limit.php  a  һ      )   vendor/hoa/iterator/Test/Unit/Counter.phpP  aP  Ċs      2   vendor/hoa/iterator/Test/Unit/IteratorIterator.php  a  ޹      (   vendor/hoa/iterator/Test/Unit/Filter.php"  a"  o%
      *   vendor/hoa/iterator/Test/Unit/Repeater.php  a  ZK      3   vendor/hoa/iterator/Test/Unit/RegularExpression.php  a  Gä      *   vendor/hoa/iterator/Test/Unit/Infinite.php  a  ;      *   vendor/hoa/iterator/Test/Unit/NoRewind.phpS  aS        +   vendor/hoa/iterator/Test/Unit/Lookahead.phpJ	  aJ	  v      ,   vendor/hoa/iterator/Test/Unit/Lookbehind.phpO	  aO	  퍤      (   vendor/hoa/iterator/Test/Unit/Buffer.php   a         #   vendor/hoa/iterator/SplFileInfo.php  a   .      !   vendor/hoa/iterator/Aggregate.php}   a}   u6          vendor/hoa/iterator/Iterator.php   a   `      "   vendor/hoa/iterator/FileSystem.php~  a~  ^      &   vendor/hoa/iterator/CallbackFilter.php   a   lf      !   vendor/hoa/iterator/Exception.php   a   Isq         vendor/hoa/iterator/Append.phps   as   ?3      %   vendor/hoa/iterator/Demultiplexer.php  a  v         vendor/hoa/iterator/Glob.phpo   ao   S{         vendor/hoa/iterator/Mock.phpp   ap   ZW{         vendor/hoa/iterator/Map.phpo   ao   ]դ         vendor/hoa/iterator/Outer.phpu   au   /         vendor/hoa/iterator/Limit.phpq   aq            vendor/hoa/iterator/Counter.php4  a4        (   vendor/hoa/iterator/IteratorIterator.php   a   t         vendor/hoa/iterator/Filter.php|   a|   VX      +   vendor/hoa/iterator/Recursive/Directory.php  a  el¤      +   vendor/hoa/iterator/Recursive/Recursive.php   a         *   vendor/hoa/iterator/Recursive/Iterator.php   a   Ҥ      0   vendor/hoa/iterator/Recursive/CallbackFilter.php   a   Ń      &   vendor/hoa/iterator/Recursive/Mock.php  a  >j      %   vendor/hoa/iterator/Recursive/Map.php   a   *\      (   vendor/hoa/iterator/Recursive/Filter.php   a   o      3   vendor/hoa/iterator/Recursive/RegularExpression.php/  a/  
e3          vendor/hoa/iterator/Repeater.php`  a`  <T          vendor/hoa/iterator/Seekable.php{   a{   ;      )   vendor/hoa/iterator/RegularExpression.php@  a@  댤          vendor/hoa/iterator/Infinite.phpw   aw   N          vendor/hoa/iterator/NoRewind.phpw   aw   If      !   vendor/hoa/iterator/Lookahead.php  a  H'=      "   vendor/hoa/iterator/Lookbehind.php  a  JE|         vendor/hoa/iterator/Buffer.php  a  %      0   vendor/hoa/consistency/Test/Unit/Consistency.php  a  UT      .   vendor/hoa/consistency/Test/Unit/Xcallable.php  a  $      .   vendor/hoa/consistency/Test/Unit/Exception.phpO  aO  D1K      /   vendor/hoa/consistency/Test/Unit/Autoloader.phpf  af  w?      &   vendor/hoa/consistency/Consistency.phpy  ay  ͑Ф      $   vendor/hoa/consistency/Xcallable.php  a        $   vendor/hoa/consistency/Exception.php   a   [      "   vendor/hoa/consistency/Prelude.php  a        %   vendor/hoa/consistency/Autoloader.php  a  LC      4   vendor/ralouphie/getallheaders/src/getallheaders.phpO  aO  }r      >   vendor/codeception/module-sequence/src/Codeception/Util/sq.php4  a4  &      F   vendor/codeception/module-sequence/src/Codeception/Module/Sequence.php  a  'V      H   vendor/codeception/module-mongodb/src/Codeception/Lib/Driver/MongoDb.php  a  u*      D   vendor/codeception/module-mongodb/src/Codeception/Module/MongoDb.php:  a:        D   vendor/codeception/module-asserts/src/Codeception/Module/Asserts.phpi  ai  a      L   vendor/codeception/module-asserts/src/Codeception/Module/AbstractAsserts.php  a  h      ?   vendor/codeception/phpunit-wrapper/src/ResultPrinter/Report.php  a  8      P   vendor/codeception/phpunit-wrapper/src/ResultPrinter/template/scenario.html.dist  a  S&      Q   vendor/codeception/phpunit-wrapper/src/ResultPrinter/template/scenarios.html.dist  a  yZ,      M   vendor/codeception/phpunit-wrapper/src/ResultPrinter/template/suite.html.dist3   a3   |      P   vendor/codeception/phpunit-wrapper/src/ResultPrinter/template/substeps.html.dist#  a#  ͠w      W   vendor/codeception/phpunit-wrapper/src/ResultPrinter/template/scenario_header.html.dist3   a3   ʤ      L   vendor/codeception/phpunit-wrapper/src/ResultPrinter/template/step.html.distb   ab   d      L   vendor/codeception/phpunit-wrapper/src/ResultPrinter/template/fail.html.dist;   a;   ˟      =   vendor/codeception/phpunit-wrapper/src/ResultPrinter/HTML.php%  a%  qߤ      ;   vendor/codeception/phpunit-wrapper/src/ResultPrinter/UI.php  a  Ug      3   vendor/codeception/phpunit-wrapper/src/Listener.php  a  |:D      <   vendor/codeception/phpunit-wrapper/src/DispatcherWrapper.php  a  ,      B   vendor/codeception/phpunit-wrapper/src/Constraint/WebDriverNot.php  a  N      B   vendor/codeception/phpunit-wrapper/src/Constraint/JsonContains.php  a  cL      :   vendor/codeception/phpunit-wrapper/src/Constraint/Page.php   a   e-      @   vendor/codeception/phpunit-wrapper/src/Constraint/CrawlerNot.phpK  aK  z      >   vendor/codeception/phpunit-wrapper/src/Constraint/JsonType.php  a        =   vendor/codeception/phpunit-wrapper/src/Constraint/Crawler.php1  a1  ,      ?   vendor/codeception/phpunit-wrapper/src/Constraint/WebDriver.php	  a	  ۄ      >   vendor/codeception/phpunit-wrapper/src/NonFinal/TestRunner.php[  a[  	6      F   vendor/codeception/phpunit-wrapper/src/NonFinal/NameFilterIterator.php  a  :      9   vendor/codeception/phpunit-wrapper/src/NonFinal/JUnit.php'.  a'.  91/      3   vendor/codeception/phpunit-wrapper/src/TestCase.php  a  Y,Q      9   vendor/codeception/phpunit-wrapper/src/ConsolePrinter.phpv  av  97MP      >   vendor/codeception/phpunit-wrapper/src/phpunit7-interfaces.php  a  *      6   vendor/codeception/phpunit-wrapper/src/Log/PhpUnit.php  a  .      4   vendor/codeception/phpunit-wrapper/src/Log/JUnit.php  a  h      8   vendor/codeception/phpunit-wrapper/src/ResultPrinter.php
  a
  ǅ      ;   vendor/codeception/phpunit-wrapper/src/phpunit5-loggers.phpK  aK         1   vendor/codeception/phpunit-wrapper/src/Runner.phpY  aY  (T3      5   vendor/codeception/phpunit-wrapper/src/FilterTest.php=  a=  f      /   vendor/codeception/phpunit-wrapper/src/shim.php  a  VaY      /   vendor/codeception/phpunit-wrapper/src/Init.php  a  ̤      ;   vendor/codeception/phpunit-wrapper/src/Overrides/Filter.phpN  aN  X6      /   vendor/codeception/phpunit-wrapper/RoboFile.php  a  XQs      V   vendor/codeception/module-webdriver/src/Codeception/Lib/Interfaces/SessionSnapshot.php  a  _y      V   vendor/codeception/module-webdriver/src/Codeception/Lib/Interfaces/ScreenshotSaver.phph  ah  h      H   vendor/codeception/module-webdriver/src/Codeception/Module/WebDriver.php a $/      U   vendor/codeception/module-webdriver/src/Codeception/Exception/ConnectionException.php`   a`   LA      @   vendor/codeception/module-rest/src/Codeception/Util/JsonType.php"  a"  eN      A   vendor/codeception/module-rest/src/Codeception/Util/JsonArray.php:  a:  .      >   vendor/codeception/module-rest/src/Codeception/Step/AsJson.php  a  Ԭw      >   vendor/codeception/module-rest/src/Codeception/Module/REST.php   a   f      H   vendor/codeception/module-queue/src/Codeception/Lib/Interfaces/Queue.php^  a^  ^=      C   vendor/codeception/module-queue/src/Codeception/Lib/Driver/Iron.php	  a	  Tc      H   vendor/codeception/module-queue/src/Codeception/Lib/Driver/AmazonSQS.php[  a[  >d      J   vendor/codeception/module-queue/src/Codeception/Lib/Driver/Pheanstalk4.php  a  Lx      H   vendor/codeception/module-queue/src/Codeception/Lib/Driver/Beanstalk.php:  a:  Ѥ      @   vendor/codeception/module-queue/src/Codeception/Module/Queue.php,  a,  Ń      @   vendor/codeception/module-redis/src/Codeception/Module/Redis.phpR  aR  =      1   vendor/codeception/stub/src/Test/Feature/Stub.php(  a(  w$֤      $   vendor/codeception/stub/src/Stub.phpPW  aPW  kjL      -   vendor/codeception/stub/src/Stub/Expected.php  a  !l      3   vendor/codeception/stub/src/Stub/ConsecutiveMap.phpU  aU  桤      2   vendor/codeception/stub/src/Stub/StubMarshaler.php  a  Oo      $   vendor/codeception/stub/RoboFile.php4  a4  (      <   vendor/codeception/module-ftp/src/Codeception/Module/FTP.phpM^  aM^  ]       F   vendor/codeception/module-memcache/src/Codeception/Module/Memcache.php  a        <   vendor/codeception/module-cli/src/Codeception/Module/Cli.php  a  b      >   vendor/codeception/module-amqp/src/Codeception/Module/AMQP.php/  a/  Up      M   vendor/codeception/module-phpbrowser/src/Codeception/Lib/Connector/Guzzle.phpk.  ak.        J   vendor/codeception/module-phpbrowser/src/Codeception/Module/PhpBrowser.php  a  5/u:      F   vendor/codeception/lib-asserts/src/Codeception/Util/Shared/Asserts.php  a  +Ĥ      O   vendor/codeception/lib-asserts/src/Codeception/Util/Shared/InheritedAsserts.php  a  ڙ      B   vendor/codeception/module-db/src/Codeception/Lib/Interfaces/Db.php<	  a<	  Δ/פ      >   vendor/codeception/module-db/src/Codeception/Lib/Driver/Db.php"  a"        A   vendor/codeception/module-db/src/Codeception/Lib/Driver/MySql.php  a  _d(      ?   vendor/codeception/module-db/src/Codeception/Lib/Driver/Oci.phpA  aA  sM      B   vendor/codeception/module-db/src/Codeception/Lib/Driver/SqlSrv.phpi
  ai
  G8      F   vendor/codeception/module-db/src/Codeception/Lib/Driver/PostgreSql.phph  ah  99      B   vendor/codeception/module-db/src/Codeception/Lib/Driver/Sqlite.php
  a
  }l      @   vendor/codeception/module-db/src/Codeception/Lib/DbPopulator.php  a  jC      :   vendor/codeception/module-db/src/Codeception/Module/Db.php+~  a+~  7X蠤      /   vendor/codeception/codeception/ext/Recorder.php>T  a>T  `U      0   vendor/codeception/codeception/ext/RunBefore.php  a  J      5   vendor/codeception/codeception/ext/SimpleReporter.php  a        2   vendor/codeception/codeception/ext/DotReporter.php
  a
  |hq      0   vendor/codeception/codeception/ext/RunFailed.php	  a	  K      -   vendor/codeception/codeception/ext/Logger.php  a  t9      1   vendor/codeception/codeception/ext/RunProcess.php  a  '*      E   vendor/codeception/codeception/src/Codeception/Lib/Interfaces/API.phpb   ab   D^Ǥ      R   vendor/codeception/codeception/src/Codeception/Lib/Interfaces/DoctrineProvider.phpu   au   '      P   vendor/codeception/codeception/src/Codeception/Lib/Interfaces/ElementLocator.php  a  N      H   vendor/codeception/codeception/src/Codeception/Lib/Interfaces/Remote.php  a  bW      Q   vendor/codeception/codeception/src/Codeception/Lib/Interfaces/DependsOnModule.php_  a_  Ī      U   vendor/codeception/codeception/src/Codeception/Lib/Interfaces/ConflictsWithModule.php   a   hГ      L   vendor/codeception/codeception/src/Codeception/Lib/Interfaces/DataMapper.phpf  af  ?j      N   vendor/codeception/codeception/src/Codeception/Lib/Interfaces/PartedModule.php  a  T      Q   vendor/codeception/codeception/src/Codeception/Lib/Interfaces/PageSourceSaver.php_  a_  蹉      Q   vendor/codeception/codeception/src/Codeception/Lib/Interfaces/RequiresPackage.php   a   Q      N   vendor/codeception/codeception/src/Codeception/Lib/Interfaces/MultiSession.php  a  )wb      E   vendor/codeception/codeception/src/Codeception/Lib/Interfaces/Web.phpRo  aRo  _      N   vendor/codeception/codeception/src/Codeception/Lib/Interfaces/ActiveRecord.phpA  aA  NŤ      E   vendor/codeception/codeception/src/Codeception/Lib/Interfaces/ORM.php?   a?   Τ      F   vendor/codeception/codeception/src/Codeception/Lib/ModuleContainer.phpC  aC  ~      9   vendor/codeception/codeception/src/Codeception/Lib/Di.phpA  aA  @q      =   vendor/codeception/codeception/src/Codeception/Lib/Friend.php  a  [      H   vendor/codeception/codeception/src/Codeception/Lib/Generator/Actions.phpQ  aQ  8      H   vendor/codeception/codeception/src/Codeception/Lib/Generator/Feature.php  a  L<      F   vendor/codeception/codeception/src/Codeception/Lib/Generator/Actor.phpA  aA  g-      K   vendor/codeception/codeception/src/Codeception/Lib/Generator/StepObject.php  a  `      P   vendor/codeception/codeception/src/Codeception/Lib/Generator/GherkinSnippets.php  a  ;      Q   vendor/codeception/codeception/src/Codeception/Lib/Generator/Shared/Classname.php  a  /!      K   vendor/codeception/codeception/src/Codeception/Lib/Generator/PageObject.php  a        G   vendor/codeception/codeception/src/Codeception/Lib/Generator/Helper.php  a  yi6      E   vendor/codeception/codeception/src/Codeception/Lib/Generator/Cept.php  a  uA      E   vendor/codeception/codeception/src/Codeception/Lib/Generator/Test.phpJ  aJ  A:      E   vendor/codeception/codeception/src/Codeception/Lib/Generator/Cest.php  a  9      F   vendor/codeception/codeception/src/Codeception/Lib/Generator/Group.phpB  aB  +b      I   vendor/codeception/codeception/src/Codeception/Lib/Generator/Snapshot.php  a  	ۤ      K   vendor/codeception/codeception/src/Codeception/Lib/Actor/Shared/Comment.php  a  `      I   vendor/codeception/codeception/src/Codeception/Lib/Actor/Shared/Retry.php  a  ^      J   vendor/codeception/codeception/src/Codeception/Lib/Actor/Shared/Friend.php  a  tG      I   vendor/codeception/codeception/src/Codeception/Lib/Actor/Shared/Pause.php  a  ^=*P      H   vendor/codeception/codeception/src/Codeception/Lib/Console/Colorizer.phpQ  aQ  z	      J   vendor/codeception/codeception/src/Codeception/Lib/Console/DiffFactory.phpB  aB  j      M   vendor/codeception/codeception/src/Codeception/Lib/Console/MessageFactory.php  a  ߻W      J   vendor/codeception/codeception/src/Codeception/Lib/Console/ReplHistory.php  a  a	      F   vendor/codeception/codeception/src/Codeception/Lib/Console/Message.php&  a&  )X      E   vendor/codeception/codeception/src/Codeception/Lib/Console/Output.php  a  cJ¤      C   vendor/codeception/codeception/src/Codeception/Lib/ParamsLoader.php&  a&  "X      C   vendor/codeception/codeception/src/Codeception/Lib/GroupManager.php  a        `   vendor/codeception/codeception/src/Codeception/Lib/Connector/Shared/PhpSuperGlobalsConverter.php  a  .      C   vendor/codeception/codeception/src/Codeception/Lib/Notification.php  a  <      =   vendor/codeception/codeception/src/Codeception/Lib/Parser.php  a  ըi      I   vendor/codeception/codeception/src/Codeception/Event/PrintResultEvent.php  a  Ok0ä      J   vendor/codeception/codeception/src/Codeception/Event/DispatcherWrapper.php  a  r      B   vendor/codeception/codeception/src/Codeception/Event/StepEvent.phpb  ab  6T      B   vendor/codeception/codeception/src/Codeception/Event/FailEvent.php  a  7w      B   vendor/codeception/codeception/src/Codeception/Event/TestEvent.php~  a~  
      C   vendor/codeception/codeception/src/Codeception/Event/SuiteEvent.php  a   o      8   vendor/codeception/codeception/src/Codeception/Actor.php  a  g	i      L   vendor/codeception/codeception/src/Codeception/Test/Interfaces/Dependent.phpo   ao   Nx      N   vendor/codeception/codeception/src/Codeception/Test/Interfaces/Descriptive.php   a   ֙      H   vendor/codeception/codeception/src/Codeception/Test/Interfaces/Plain.phpn   an   E      K   vendor/codeception/codeception/src/Codeception/Test/Interfaces/Reported.php   a   G"+      Q   vendor/codeception/codeception/src/Codeception/Test/Interfaces/StrictCoverage.php   a         Q   vendor/codeception/codeception/src/Codeception/Test/Interfaces/ScenarioDriven.phpD  aD  &<      @   vendor/codeception/codeception/src/Codeception/Test/Metadata.php  a  *      >   vendor/codeception/codeception/src/Codeception/Test/Loader.php^  a^        B   vendor/codeception/codeception/src/Codeception/Test/Descriptor.php2  a2  r      N   vendor/codeception/codeception/src/Codeception/Test/Loader/LoaderInterface.php   a   F      F   vendor/codeception/codeception/src/Codeception/Test/Loader/Gherkin.php  a  hW      C   vendor/codeception/codeception/src/Codeception/Test/Loader/Cept.php  a  Nގ      C   vendor/codeception/codeception/src/Codeception/Test/Loader/Unit.php
  a
  v      C   vendor/codeception/codeception/src/Codeception/Test/Loader/Cest.php  a  h""n      ?   vendor/codeception/codeception/src/Codeception/Test/Gherkin.php  a  ்      <   vendor/codeception/codeception/src/Codeception/Test/Cept.php2  a2  }ai      N   vendor/codeception/codeception/src/Codeception/Test/Feature/ScenarioLoader.phpC  aC  N<      P   vendor/codeception/codeception/src/Codeception/Test/Feature/AssertionCounter.php  a  /	y      Q   vendor/codeception/codeception/src/Codeception/Test/Feature/MetadataCollector.php  a  Y      K   vendor/codeception/codeception/src/Codeception/Test/Feature/ErrorLogger.php  a   ҥ      L   vendor/codeception/codeception/src/Codeception/Test/Feature/CodeCoverage.php  a  We      W   vendor/codeception/codeception/src/Codeception/Test/Feature/IgnoreIfMetadataBlocked.php  a  B      <   vendor/codeception/codeception/src/Codeception/Test/Test.php  a  !      <   vendor/codeception/codeception/src/Codeception/Test/Unit.php  a  ͿZ=      <   vendor/codeception/codeception/src/Codeception/Test/Cest.php  a  =      9   vendor/codeception/codeception/src/Codeception/Events.phpC  aC  2      >   vendor/codeception/codeception/src/Codeception/GroupObject.php  a  Djf      ;   vendor/codeception/codeception/src/Codeception/Codecept.phpX   aX   E'      @   vendor/codeception/codeception/src/Codeception/Configuration.phpb  ab  p      O   vendor/codeception/codeception/src/Codeception/Util/ArrayContainsComparator.php  a  ڤ      D   vendor/codeception/codeception/src/Codeception/Util/PathResolver.php  a  e]\      @   vendor/codeception/codeception/src/Codeception/Util/Fixtures.php  a  ` դ      =   vendor/codeception/codeception/src/Codeception/Util/Debug.php  a  ۼr      B   vendor/codeception/codeception/src/Codeception/Util/FileSystem.phpW	  aW	  -2p      @   vendor/codeception/codeception/src/Codeception/Util/Autoload.php  a        ;   vendor/codeception/codeception/src/Codeception/Util/Uri.php,  a,  <       D   vendor/codeception/codeception/src/Codeception/Util/XmlStructure.phpZ	  aZ	  KPT      I   vendor/codeception/codeception/src/Codeception/Util/Shared/Namespaces.php  a  1u      @   vendor/codeception/codeception/src/Codeception/Util/Template.php5  a5  qn      =   vendor/codeception/codeception/src/Codeception/Util/Maybe.phpF  aF  `/      <   vendor/codeception/codeception/src/Codeception/Util/Soap.phpn  an  4uK      <   vendor/codeception/codeception/src/Codeception/Util/Stub.php  a  x55      F   vendor/codeception/codeception/src/Codeception/Util/ActionSequence.php  a  2      H   vendor/codeception/codeception/src/Codeception/Util/ReflectionHelper.php  a  ѕ      ;   vendor/codeception/codeception/src/Codeception/Util/Xml.phpz  az  ~HE      R   vendor/codeception/codeception/src/Codeception/Util/ReflectionPropertyAccessor.php  a  ը      B   vendor/codeception/codeception/src/Codeception/Util/Annotation.php=  a=  
      ?   vendor/codeception/codeception/src/Codeception/Util/Locator.php3(  a3(  ۪      B   vendor/codeception/codeception/src/Codeception/Util/XmlBuilder.phpE  aE  OȤ      ?   vendor/codeception/codeception/src/Codeception/Step/Comment.php
  a
  m      =   vendor/codeception/codeception/src/Codeception/Step/Retry.phpM	  aM	  n      >   vendor/codeception/codeception/src/Codeception/Step/Action.phpX   aX   yM      <   vendor/codeception/codeception/src/Codeception/Step/Skip.php|  a|  k@      =   vendor/codeception/codeception/src/Codeception/Step/TryTo.php  a  Dcv      A   vendor/codeception/codeception/src/Codeception/Step/Assertion.phpy   ay   ֝?      @   vendor/codeception/codeception/src/Codeception/Step/Executor.php  a  8 O      B   vendor/codeception/codeception/src/Codeception/Step/Incomplete.php  a  }Ȯ      E   vendor/codeception/codeception/src/Codeception/Step/GeneratedStep.php   a   @      Q   vendor/codeception/codeception/src/Codeception/Step/Argument/PasswordArgument.php  a  ѡǤ      P   vendor/codeception/codeception/src/Codeception/Step/Argument/FormattedOutput.php  a  5lf      A   vendor/codeception/codeception/src/Codeception/Step/Condition.phpy   ay   k      L   vendor/codeception/codeception/src/Codeception/Step/ConditionalAssertion.php  a  ~      <   vendor/codeception/codeception/src/Codeception/Step/Meta.php  a  Pf      >   vendor/codeception/codeception/src/Codeception/Application.php  a  ƈdL      @   vendor/codeception/codeception/src/Codeception/TestInterface.php   a         8   vendor/codeception/codeception/src/Codeception/Suite.php  a  ݿ      K   vendor/codeception/codeception/src/Codeception/Coverage/SuiteSubscriber.php  a  l҃      B   vendor/codeception/codeception/src/Codeception/Coverage/Filter.php  a  ͱl      R   vendor/codeception/codeception/src/Codeception/Coverage/PhpCodeCoverageFactory.php  a  UC_      S   vendor/codeception/codeception/src/Codeception/Coverage/Subscriber/RemoteServer.php  a  y      L   vendor/codeception/codeception/src/Codeception/Coverage/Subscriber/Local.phpr  ar  e      N   vendor/codeception/codeception/src/Codeception/Coverage/Subscriber/Printer.php3  a3  5t      R   vendor/codeception/codeception/src/Codeception/Coverage/Subscriber/LocalServer.php&  a&  58      ;   vendor/codeception/codeception/src/Codeception/Scenario.php#  a#  ?      <   vendor/codeception/codeception/src/Codeception/Extension.php  a  .      G   vendor/codeception/codeception/src/Codeception/Command/GenerateCept.php  a  zfɤ      B   vendor/codeception/codeception/src/Codeception/Command/Console.php  a  p      M   vendor/codeception/codeception/src/Codeception/Command/GeneratePageObject.php  a  .      J   vendor/codeception/codeception/src/Codeception/Command/GherkinSnippets.php  a  T֤      @   vendor/codeception/codeception/src/Codeception/Command/Clean.php0  a0  )Ť      D   vendor/codeception/codeception/src/Codeception/Command/Bootstrap.php  a  A      A   vendor/codeception/codeception/src/Codeception/Command/DryRun.php  a  bvܤ      M   vendor/codeception/codeception/src/Codeception/Command/CompletionFallback.php  a  	S      >   vendor/codeception/codeception/src/Codeception/Command/Run.phpg  ag  2{%      H   vendor/codeception/codeception/src/Codeception/Command/Shared/Config.php  a  lD      L   vendor/codeception/codeception/src/Codeception/Command/Shared/FileSystem.php  a  pd?.      G   vendor/codeception/codeception/src/Codeception/Command/Shared/Style.php  a  eAO      M   vendor/codeception/codeception/src/Codeception/Command/GenerateStepObject.php=
  a=
  [      E   vendor/codeception/codeception/src/Codeception/Command/Completion.php
  a
  K|      G   vendor/codeception/codeception/src/Codeception/Command/GherkinSteps.phpZ  aZ        G   vendor/codeception/codeception/src/Codeception/Command/GenerateCest.php  a  0f      K   vendor/codeception/codeception/src/Codeception/Command/GenerateSnapshot.php  a        I   vendor/codeception/codeception/src/Codeception/Command/GenerateHelper.php  a  X      J   vendor/codeception/codeception/src/Codeception/Command/GenerateFeature.php  a  б      @   vendor/codeception/codeception/src/Codeception/Command/Build.php  a  Τ      G   vendor/codeception/codeception/src/Codeception/Command/GenerateTest.php  a  e      N   vendor/codeception/codeception/src/Codeception/Command/GenerateEnvironment.php=  a=  U      I   vendor/codeception/codeception/src/Codeception/Command/ConfigValidate.php  a  R      E   vendor/codeception/codeception/src/Codeception/Command/SelfUpdate.php#  a#  դ      H   vendor/codeception/codeception/src/Codeception/Command/GenerateGroup.php  a  4gE      ?   vendor/codeception/codeception/src/Codeception/Command/Init.php  a  g~
      L   vendor/codeception/codeception/src/Codeception/Command/GenerateScenarios.php  a  4r      H   vendor/codeception/codeception/src/Codeception/Command/GenerateSuite.php  a  &x      9   vendor/codeception/codeception/src/Codeception/Module.phpg"  ag"  vϤ      7   vendor/codeception/codeception/src/Codeception/Step.php	)  a	)   }֤      ?   vendor/codeception/codeception/src/Codeception/SuiteManager.php  a  S;w"      F   vendor/codeception/codeception/src/Codeception/Template/Acceptance.phpW  aW  +\Ԥ      E   vendor/codeception/codeception/src/Codeception/Template/Bootstrap.phpC  aC  լ      D   vendor/codeception/codeception/src/Codeception/Template/Upgrade4.phpI
  aI
  p      ?   vendor/codeception/codeception/src/Codeception/Template/Api.php  a  ]82      @   vendor/codeception/codeception/src/Codeception/Template/Unit.php?  a?  C      ;   vendor/codeception/codeception/src/Codeception/Snapshot.phpM  aM  T~      R   vendor/codeception/codeception/src/Codeception/Exception/ModuleConfigException.php  a  4      K   vendor/codeception/codeception/src/Codeception/Exception/ParseException.phpT   aT   g¤      L   vendor/codeception/codeception/src/Codeception/Exception/ElementNotFound.php  a  g&ݤ      L   vendor/codeception/codeception/src/Codeception/Exception/RemoteException.php   a   I~      Q   vendor/codeception/codeception/src/Codeception/Exception/TestRuntimeException.phpa   aa   ݜ      L   vendor/codeception/codeception/src/Codeception/Exception/ContentNotFound.phpr   ar   .秤      S   vendor/codeception/codeception/src/Codeception/Exception/ConfigurationException.php\   a\   L      O   vendor/codeception/codeception/src/Codeception/Exception/TestParseException.php  a  Sű      S   vendor/codeception/codeception/src/Codeception/Exception/ModuleRequireException.php  a  1      L   vendor/codeception/codeception/src/Codeception/Exception/ModuleException.php  a  J      V   vendor/codeception/codeception/src/Codeception/Exception/MalformedLocatorException.php  a  -m      W   vendor/codeception/codeception/src/Codeception/Exception/ConditionalAssertionFailed.php}   a}   v      T   vendor/codeception/codeception/src/Codeception/Exception/ModuleConflictException.php  a  7      O   vendor/codeception/codeception/src/Codeception/Exception/ExtensionException.php  a  <)      O   vendor/codeception/codeception/src/Codeception/Exception/InjectionException.phpX   aX   Bh      ?   vendor/codeception/codeception/src/Codeception/InitTemplate.php(  a(  V$a      I   vendor/codeception/codeception/src/Codeception/Subscriber/AutoRebuild.php  a  zc      M   vendor/codeception/codeception/src/Codeception/Subscriber/ExtensionLoader.php  a  P      E   vendor/codeception/codeception/src/Codeception/Subscriber/Console.phpP  aP  b      J   vendor/codeception/codeception/src/Codeception/Subscriber/Dependencies.php  a  uL&      I   vendor/codeception/codeception/src/Codeception/Subscriber/PrepareTest.phpM  aM  xrc      G   vendor/codeception/codeception/src/Codeception/Subscriber/Bootstrap.php  a  Z      Q   vendor/codeception/codeception/src/Codeception/Subscriber/Shared/StaticEvents.php   a   S      M   vendor/codeception/codeception/src/Codeception/Subscriber/BeforeAfterTest.php  a  oT      J   vendor/codeception/codeception/src/Codeception/Subscriber/ErrorHandler.php]  a]  4a      Q   vendor/codeception/codeception/src/Codeception/Subscriber/GracefulTermination.php  a  2V      D   vendor/codeception/codeception/src/Codeception/Subscriber/Module.phpl	  al	  p      F   vendor/codeception/codeception/src/Codeception/Subscriber/FailFast.php  a  	      I   vendor/codeception/codeception/src/Codeception/CustomCommandInterface.php   a   g<a_      :   vendor/codeception/codeception/src/Codeception/Example.php
  a
        +   vendor/codeception/codeception/autoload.php  a  Ҥ      &   vendor/codeception/codeception/app.php  a  +1Ȥ      '   vendor/codeception/codeception/shim.php4  a4  |0      ,   vendor/codeception/codeception/functions.php  a  f7      <   vendor/codeception/module-apc/src/Codeception/Module/Apc.php  a  B%      J   vendor/codeception/module-filesystem/src/Codeception/Module/Filesystem.phpJ  aJ  Ý7      >   vendor/codeception/module-soap/src/Codeception/Module/SOAP.php8  a8  6o      H   vendor/codeception/lib-innerbrowser/src/Codeception/Lib/InnerBrowser.php a H      E   vendor/codeception/lib-innerbrowser/src/Codeception/Lib/Framework.php  a  F      E   vendor/codeception/lib-innerbrowser/src/Codeception/Util/HttpCode.php  a  nr)      V   vendor/codeception/lib-innerbrowser/src/Codeception/Exception/ExternalUrlException.php[   a[   @Ť      6   vendor/phpdocumentor/reflection-docblock/src/Utils.phpO  aO  sx@      9   vendor/phpdocumentor/reflection-docblock/src/DocBlock.php		  a		  (Ƥ      I   vendor/phpdocumentor/reflection-docblock/src/DocBlockFactoryInterface.php`  a`  WAWˤ      D   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Serializer.php
  a
  xo      E   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Description.php  a  )I      G   vendor/phpdocumentor/reflection-docblock/src/DocBlock/ExampleFinder.php	  a	  v\1       L   vendor/phpdocumentor/reflection-docblock/src/DocBlock/DescriptionFactory.php  a  @Wz      E   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Source.php^  a^  _      E   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Author.php  a  ,      F   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Generic.php  a  c&      F   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Return_.php,  a,  F      D   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Param.phpj  aj        D   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Since.php  a  j=      H   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter.php   a   DU      E   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Covers.phpW  aW  m      C   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Var_.php]	  a]	  .W      J   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TagWithType.phpX  aX  Н4      L   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyWrite.phpk	  ak	  +      S   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/StaticMethod.php   a   |~      F   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/BaseTag.phpc  ac  >U      I   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/InvalidTag.phpt	  at	  {i      B   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/See.php  a        C   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Link.php  a         F   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Version.phpW  aW  렴X      E   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Throws.php-  a-  GR      I   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Deprecated.php  a  ͒      C   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Uses.php6  a6  
}ä      G   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Property.php`	  a`	  i      E   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Method.php;  a;        N   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Fqsen.phpm  am        L   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Url.php\  a\  k1b      R   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Reference.php   a   6t      K   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyRead.phpi	  ai	  hl      F   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Example.php  a  DJ      W   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/AlignFormatter.phpq  aq  ?9      ]   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/PassthroughFormatter.phpr  ar  e-      =   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tag.php\  a\        L   vendor/phpdocumentor/reflection-docblock/src/DocBlock/StandardTagFactory.phpf  af  8ܤ      D   vendor/phpdocumentor/reflection-docblock/src/DocBlock/TagFactory.php  a  ~      H   vendor/phpdocumentor/reflection-docblock/src/Exception/PcreException.php  a  *Ǹ      @   vendor/phpdocumentor/reflection-docblock/src/DocBlockFactory.php  a  yҤ      5   vendor/phpdocumentor/type-resolver/src/PseudoType.php   a   ۔Ӥ      7   vendor/phpdocumentor/type-resolver/src/TypeResolver.php/  a/  ֨      8   vendor/phpdocumentor/type-resolver/src/FqsenResolver.php  a  [הA      H   vendor/phpdocumentor/type-resolver/src/PseudoTypes/HtmlEscapedString.php  a  c      E   vendor/phpdocumentor/type-resolver/src/PseudoTypes/CallableString.php  a  #      F   vendor/phpdocumentor/type-resolver/src/PseudoTypes/LowercaseString.php  a  [      N   vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyLowercaseString.php  a  t<      E   vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyString.php  a  d0;      D   vendor/phpdocumentor/type-resolver/src/PseudoTypes/NumericString.php  a  <      F   vendor/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.php  a  M8      D   vendor/phpdocumentor/type-resolver/src/PseudoTypes/LiteralString.php  a  EɃ      =   vendor/phpdocumentor/type-resolver/src/PseudoTypes/False_.php  a  ̅ˤ      B   vendor/phpdocumentor/type-resolver/src/PseudoTypes/TraitString.php  a  5c$      <   vendor/phpdocumentor/type-resolver/src/PseudoTypes/True_.php  a  4	      /   vendor/phpdocumentor/type-resolver/src/Type.php   a   QQ      :   vendor/phpdocumentor/type-resolver/src/Types/Callable_.php   a   Nsɤ      @   vendor/phpdocumentor/type-resolver/src/Types/InterfaceString.php  a  N      6   vendor/phpdocumentor/type-resolver/src/Types/Self_.php   a   d#      ;   vendor/phpdocumentor/type-resolver/src/Types/Expression.php  a  9      7   vendor/phpdocumentor/type-resolver/src/Types/Mixed_.php   a   ٶ      :   vendor/phpdocumentor/type-resolver/src/Types/Iterable_.php  a        =   vendor/phpdocumentor/type-resolver/src/Types/Intersection.php
  a
  C      9   vendor/phpdocumentor/type-resolver/src/Types/Nullable.php  a  4Jo      6   vendor/phpdocumentor/type-resolver/src/Types/Null_.php   a   yTZ      7   vendor/phpdocumentor/type-resolver/src/Types/Float_.php   a   }s      <   vendor/phpdocumentor/type-resolver/src/Types/ClassString.php  a  Ep      ?   vendor/phpdocumentor/type-resolver/src/Types/AggregatedType.php  a  ikLg      6   vendor/phpdocumentor/type-resolver/src/Types/Void_.php   a   \      :   vendor/phpdocumentor/type-resolver/src/Types/Resource_.php   a   v!      8   vendor/phpdocumentor/type-resolver/src/Types/Boolean.php   a   L      ?   vendor/phpdocumentor/type-resolver/src/Types/ContextFactory.php  a  r      5   vendor/phpdocumentor/type-resolver/src/Types/This.php   a    r
      8   vendor/phpdocumentor/type-resolver/src/Types/Context.phpV  aV  Aݭ      7   vendor/phpdocumentor/type-resolver/src/Types/Array_.php   a   60w      8   vendor/phpdocumentor/type-resolver/src/Types/Parent_.php   a   cMxR      9   vendor/phpdocumentor/type-resolver/src/Types/ArrayKey.php  a  j([      =   vendor/phpdocumentor/type-resolver/src/Types/AbstractList.php  a  ꭄ      8   vendor/phpdocumentor/type-resolver/src/Types/String_.php   a   -Y      8   vendor/phpdocumentor/type-resolver/src/Types/Static_.php   a         8   vendor/phpdocumentor/type-resolver/src/Types/Integer.php   a   A      8   vendor/phpdocumentor/type-resolver/src/Types/Object_.php*  a*  hi4      9   vendor/phpdocumentor/type-resolver/src/Types/Compound.php  a  j50      ;   vendor/phpdocumentor/type-resolver/src/Types/Collection.php  a  1      7   vendor/phpdocumentor/type-resolver/src/Types/Scalar.php   a   t      7   vendor/phpdocumentor/type-resolver/src/Types/Never_.php   a   =      4   vendor/phpdocumentor/reflection-common/src/Fqsen.php  a  ' w      7   vendor/phpdocumentor/reflection-common/src/Location.php  a  eV      =   vendor/phpdocumentor/reflection-common/src/ProjectFactory.php   a   ޳
      6   vendor/phpdocumentor/reflection-common/src/Element.php   a   9J      3   vendor/phpdocumentor/reflection-common/src/File.php   a   )      6   vendor/phpdocumentor/reflection-common/src/Project.php   a   ޗ      +   vendor/padraic/phar-updater/src/Updater.php   a   vu      >   vendor/padraic/phar-updater/src/Strategy/StrategyInterface.php.  a.   c:      8   vendor/padraic/phar-updater/src/Strategy/ShaStrategy.phpc  ac        ;   vendor/padraic/phar-updater/src/Strategy/GithubStrategy.php  a  73      1   vendor/padraic/phar-updater/src/VersionParser.php&
  a&
  'p      B   vendor/padraic/phar-updater/src/Exception/HttpRequestException.phpo   ao   D      A   vendor/padraic/phar-updater/src/Exception/FilesystemException.phpn   an          B   vendor/padraic/phar-updater/src/Exception/JsonParsingException.phpo   ao   Z?      >   vendor/padraic/phar-updater/src/Exception/RuntimeException.php   a   Ћ      B   vendor/padraic/phar-updater/src/Exception/NoSignatureException.phpo   ao   "}<      F   vendor/padraic/phar-updater/src/Exception/InvalidArgumentException.php   a   b"1      @   vendor/padraic/phar-updater/src/Exception/ExceptionInterface.phpX   aX   cu,      :   vendor/padraic/humbug_get_contents/src/FileGetContents.php"  a"  _a      4   vendor/padraic/humbug_get_contents/src/functions.php  a  Kg@      3   vendor/padraic/humbug_get_contents/src/function.php  a  n      <   vendor/behat/gherkin/src/Behat/Gherkin/Cache/MemoryCache.php.  a.  &cm      ?   vendor/behat/gherkin/src/Behat/Gherkin/Cache/CacheInterface.php
  a
  E      :   vendor/behat/gherkin/src/Behat/Gherkin/Cache/FileCache.phpG  aG  ¤      A   vendor/behat/gherkin/src/Behat/Gherkin/Loader/LoaderInterface.php   a   EZb      @   vendor/behat/gherkin/src/Behat/Gherkin/Loader/YamlFileLoader.php  a  S
o      =   vendor/behat/gherkin/src/Behat/Gherkin/Loader/ArrayLoader.php`  a`  5lM      C   vendor/behat/gherkin/src/Behat/Gherkin/Loader/GherkinFileLoader.php  a  ۤ      D   vendor/behat/gherkin/src/Behat/Gherkin/Loader/AbstractFileLoader.php  a  R      I   vendor/behat/gherkin/src/Behat/Gherkin/Loader/CucumberNDJsonAstLoader.phpW  aW        E   vendor/behat/gherkin/src/Behat/Gherkin/Loader/FileLoaderInterface.php   a   =      A   vendor/behat/gherkin/src/Behat/Gherkin/Loader/DirectoryLoader.php  a  ܯG      @   vendor/behat/gherkin/src/Behat/Gherkin/Node/ExampleTableNode.php  a  3      8   vendor/behat/gherkin/src/Behat/Gherkin/Node/StepNode.php  a  Ii      A   vendor/behat/gherkin/src/Behat/Gherkin/Node/ScenarioInterface.php   a   A9p      ;   vendor/behat/gherkin/src/Behat/Gherkin/Node/FeatureNode.php  a  	      <   vendor/behat/gherkin/src/Behat/Gherkin/Node/ScenarioNode.php  a  B      <   vendor/behat/gherkin/src/Behat/Gherkin/Node/PyStringNode.php?  a?  O      F   vendor/behat/gherkin/src/Behat/Gherkin/Node/StepContainerInterface.php   a   '~      =   vendor/behat/gherkin/src/Behat/Gherkin/Node/NodeInterface.php   a   q!z      >   vendor/behat/gherkin/src/Behat/Gherkin/Node/BackgroundNode.php  a  1      C   vendor/behat/gherkin/src/Behat/Gherkin/Node/TaggedNodeInterface.php   a   %,      A   vendor/behat/gherkin/src/Behat/Gherkin/Node/ArgumentInterface.phpi   ai   \      E   vendor/behat/gherkin/src/Behat/Gherkin/Node/ScenarioLikeInterface.php   a   x      D   vendor/behat/gherkin/src/Behat/Gherkin/Node/KeywordNodeInterface.php   a   n      9   vendor/behat/gherkin/src/Behat/Gherkin/Node/TableNode.php$  a$  #aJ      ;   vendor/behat/gherkin/src/Behat/Gherkin/Node/OutlineNode.phpe  ae  ?      ;   vendor/behat/gherkin/src/Behat/Gherkin/Node/ExampleNode.php  a  c|      2   vendor/behat/gherkin/src/Behat/Gherkin/Gherkin.php  a  yB      <   vendor/behat/gherkin/src/Behat/Gherkin/Filter/RoleFilter.phpY  aY  :{      A   vendor/behat/gherkin/src/Behat/Gherkin/Filter/NarrativeFilter.php  a        >   vendor/behat/gherkin/src/Behat/Gherkin/Filter/SimpleFilter.php  a  <      A   vendor/behat/gherkin/src/Behat/Gherkin/Filter/LineRangeFilter.php:	  a:	        ;   vendor/behat/gherkin/src/Behat/Gherkin/Filter/TagFilter.php	  a	  (      <   vendor/behat/gherkin/src/Behat/Gherkin/Filter/NameFilter.php  a  S-      H   vendor/behat/gherkin/src/Behat/Gherkin/Filter/ComplexFilterInterface.php$  a$  Q=Ϥ      =   vendor/behat/gherkin/src/Behat/Gherkin/Filter/PathsFilter.php  a  {6ݤ      <   vendor/behat/gherkin/src/Behat/Gherkin/Filter/LineFilter.php  a  s      H   vendor/behat/gherkin/src/Behat/Gherkin/Filter/FeatureFilterInterface.php   a         A   vendor/behat/gherkin/src/Behat/Gherkin/Filter/FilterInterface.php   a   sH      ?   vendor/behat/gherkin/src/Behat/Gherkin/Filter/ComplexFilter.phpe  ae        B   vendor/behat/gherkin/src/Behat/Gherkin/Exception/NodeException.php   a   t      >   vendor/behat/gherkin/src/Behat/Gherkin/Exception/Exception.phpK   aK         D   vendor/behat/gherkin/src/Behat/Gherkin/Exception/ParserException.php   a   dK      C   vendor/behat/gherkin/src/Behat/Gherkin/Exception/LexerException.php   a   U      C   vendor/behat/gherkin/src/Behat/Gherkin/Exception/CacheException.php   a   J񼩤      0   vendor/behat/gherkin/src/Behat/Gherkin/Lexer.php%  a%  ~,      1   vendor/behat/gherkin/src/Behat/Gherkin/Parser.php3  a3  N       D   vendor/behat/gherkin/src/Behat/Gherkin/Keywords/CucumberKeywords.php  a  F      A   vendor/behat/gherkin/src/Behat/Gherkin/Keywords/ArrayKeywords.php  a  e      G   vendor/behat/gherkin/src/Behat/Gherkin/Keywords/CachedArrayKeywords.php   a   KP      E   vendor/behat/gherkin/src/Behat/Gherkin/Keywords/KeywordsInterface.phpZ  aZ  [D      B   vendor/behat/gherkin/src/Behat/Gherkin/Keywords/KeywordsDumper.php  a  *ä          vendor/behat/gherkin/libpath.php   a   trnǤ         vendor/behat/gherkin/i18n.php  a  9/      *   vendor/sebastian/exporter/src/Exporter.phph  ah  K!f      :   vendor/sebastian/global-state/src/exceptions/Exception.phpi   ai   7X      A   vendor/sebastian/global-state/src/exceptions/RuntimeException.php   a   XB      /   vendor/sebastian/global-state/src/Blacklist.php  a  㳆      2   vendor/sebastian/global-state/src/CodeExporter.php  a  ;"ɤ      .   vendor/sebastian/global-state/src/Restorer.phpn
  an
  t.      .   vendor/sebastian/global-state/src/Snapshot.php@  a@  c      &   vendor/sebastian/type/src/VoidType.phpB  aB  uTM*      &   vendor/sebastian/type/src/NullType.phpB  aB  l.      *   vendor/sebastian/type/src/CallableType.phpQ  aQ  ޙԤ      /   vendor/sebastian/type/src/GenericObjectType.phpS  aS  `@      *   vendor/sebastian/type/src/IterableType.php  a  BKZ      1   vendor/sebastian/type/src/exception/Exception.phpb   ab   +      8   vendor/sebastian/type/src/exception/RuntimeException.php   a   h      )   vendor/sebastian/type/src/UnknownType.php,  a,  `       "   vendor/sebastian/type/src/Type.phpB  aB  5      (   vendor/sebastian/type/src/SimpleType.php  a  0      &   vendor/sebastian/type/src/TypeName.php  a  ߩk      (   vendor/sebastian/type/src/ObjectType.php  a  RX      :   vendor/sebastian/diff/src/Output/DiffOnlyOutputBuilder.php(  a(  u\      ?   vendor/sebastian/diff/src/Output/DiffOutputBuilderInterface.php   a   2S      =   vendor/sebastian/diff/src/Output/UnifiedDiffOutputBuilder.php  a  9      C   vendor/sebastian/diff/src/Output/StrictUnifiedDiffOutputBuilder.phpm  am  Q      ?   vendor/sebastian/diff/src/Output/AbstractChunkOutputBuilder.php6  a6  u@      $   vendor/sebastian/diff/src/Differ.php  a  \U      O   vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php3  a3  Eɑ      #   vendor/sebastian/diff/src/Chunk.php  a  li      M   vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php  a        @   vendor/sebastian/diff/src/LongestCommonSubsequenceCalculator.php   a    )      "   vendor/sebastian/diff/src/Line.php  a  F.G      "   vendor/sebastian/diff/src/Diff.php.  a.  |      1   vendor/sebastian/diff/src/Exception/Exception.phpc   ac   (ip      >   vendor/sebastian/diff/src/Exception/ConfigurationException.php  a  F      @   vendor/sebastian/diff/src/Exception/InvalidArgumentException.php   a   b      $   vendor/sebastian/diff/src/Parser.php&  a&  ^oA      (   vendor/sebastian/version/src/Version.phpu  au  *>      4   vendor/sebastian/recursion-context/src/Exception.phpX   aX   N3      2   vendor/sebastian/recursion-context/src/Context.phpR  aR  ^k_      C   vendor/sebastian/recursion-context/src/InvalidArgumentException.php   a   >_F      ?   vendor/sebastian/resource-operations/src/ResourceOperations.php  a  }      7   vendor/sebastian/resource-operations/build/generate.php  a  d      3   vendor/sebastian/object-reflector/src/Exception.phpo   ao         9   vendor/sebastian/object-reflector/src/ObjectReflector.phpC  aC  "      B   vendor/sebastian/object-reflector/src/InvalidArgumentException.php   a   ]ˤ      4   vendor/sebastian/object-enumerator/src/Exception.phpV   aV   c      5   vendor/sebastian/object-enumerator/src/Enumerator.phpi  ai  禷      C   vendor/sebastian/object-enumerator/src/InvalidArgumentException.php   a         ,   vendor/sebastian/environment/src/Console.php	  a	  S      ,   vendor/sebastian/environment/src/Runtime.phpi  ai  {!      4   vendor/sebastian/environment/src/OperatingSystem.php  a  -      +   vendor/sebastian/comparator/src/Factory.php  a  w      3   vendor/sebastian/comparator/src/ArrayComparator.phpi  ai  r      .   vendor/sebastian/comparator/src/Comparator.php  a  Rl      6   vendor/sebastian/comparator/src/DateTimeComparator.php  a        5   vendor/sebastian/comparator/src/NumericComparator.phpZ  aZ  ,      2   vendor/sebastian/comparator/src/TypeComparator.php  a        5   vendor/sebastian/comparator/src/ComparisonFailure.php  a  S      8   vendor/sebastian/comparator/src/MockObjectComparator.phpE  aE  `rќ      4   vendor/sebastian/comparator/src/ScalarComparator.php  a  (<      5   vendor/sebastian/comparator/src/DOMNodeComparator.php  a  B9      7   vendor/sebastian/comparator/src/ExceptionComparator.php  a  0ڤ      4   vendor/sebastian/comparator/src/DoubleComparator.php)  a)        4   vendor/sebastian/comparator/src/ObjectComparator.phpq  aq  Mm      >   vendor/sebastian/comparator/src/SplObjectStorageComparator.phpm  am  5      6   vendor/sebastian/comparator/src/ResourceComparator.php  a  T2      8   vendor/sebastian/code-unit-reverse-lookup/src/Wizard.phpZ  aZ        G   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exchange/AMQPExchangeType.php   a   o      5   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Package.phpg   ag         D   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/SocketConstants.php  a  VĄߤ      ?   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/BigInteger.php\  a\        ?   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/MiscHelper.phpC  aC  B      @   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/DebugHelper.php3  a3  r¤      J   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/MethodMap080.php  a  P6Ф      E   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/Wait091.php  a  UG      E   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/Wait080.php
  a
  lw      I   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/Protocol080.phpM  aM  =^      J   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/MethodMap091.php  a  vqF      I   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/Protocol091.php5  a5  ]?=      ;   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Assert.php7  a7  q      A   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Message/AMQPMessage.php  a        K   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AbstractConnection.phpF  aF  0      M   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPStreamConnection.php  a  [.      W   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Connection/Heartbeat/PCNTLHeartbeatSender.phpj  aj  Py	      M   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPSocketConnection.php  a        N   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPLazySSLConnection.phpZ  aZ  -ʤ      Q   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPLazySocketConnection.phpc  ac  )<u      J   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPSSLConnection.php  a  4c      K   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPLazyConnection.phpZ  aZ  TK־      A   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AbstractClient.phpj  aj  O      <   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPArray.phpl  al  Uۤ      ?   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/Constants080.phpq  aq  ԛ      =   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPWriter.php  a  r;ޤ      I   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPAbstractCollection.php   a   ޛd      <   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPTable.php  a  m;      >   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPDecimal.phpq  aq  ~Z      <   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/Constants.php  a  Ly      ?   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/Constants091.php	  a	  F=¤      @   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/IO/AbstractIO.php2  a2  9p      >   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/IO/SocketIO.php  a  Fg      >   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/IO/StreamIO.php  a  *d      =   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPReader.phpx!  ax!  /      T   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPHeartbeatMissedException.phpu   au   渖      U   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPConnectionClosedException.phpp   ap   h      S   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPNotImplementedException.phpk   ak   d4а      K   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPNoDataException.phpf   af   ? ,ͤ      U   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPEmptyDeliveryTagException.phpm   am   ֔      V   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPConnectionBlockedException.php=  a=  _{      G   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPIOException.phpw   aw   f5      M   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPDataReadException.phpe   ae   w068      R   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPChannelClosedException.phpj   aj   읦      T   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPProtocolChannelException.phpm   am   N!      P   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPBasicCancelException.php_  a_  <      Q   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPInvalidFrameException.phpi   ai   M      K   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPIOWaitException.phpc   ac   M      J   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPLogicException.php   a   J_      P   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPOutOfBoundsException.php   a         O   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPOutOfRangeException.php   a   |#Ǥ      K   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPSocketException.phpc   ac   bҤ      T   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPInvalidArgumentException.php   a   ,DΤ      N   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPExceptionInterface.phpM   aM   "Wܤ      L   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPTimeoutException.php  a  Mf      M   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPProtocolException.php  a        L   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPRuntimeException.php   a   A      E   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Channel/AbstractChannel.php$  a$  V:      A   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Channel/AMQPChannel.phpnW  anW  ܙ      <?php






if (extension_loaded('mbstring')) {

 
 if (version_compare(PHP_VERSION, '8.0.0') < 0 && ini_get('mbstring.func_overload') & 2) {
throw new \UnexpectedValueException(
'Overloading of string functions using mbstring.func_overload ' .
'is not supported by phpseclib.'
);
}
}
<?php
















namespace phpseclib\Net\SFTP;

use phpseclib\Crypt\RSA;
use phpseclib\Net\SFTP;








class Stream
{







static $instances;







var $sftp;







var $path;







var $mode;







var $pos;







var $size;







var $entries;







var $eof;









var $context;







var $notification;








static function register($protocol = 'sftp')
{
if (in_array($protocol, stream_get_wrappers(), true)) {
return false;
}
return stream_wrapper_register($protocol, get_called_class());
}






function __construct()
{
if (defined('NET_SFTP_STREAM_LOGGING')) {
echo "__construct()\r\n";
}
}













function _parse_path($path)
{
$orig = $path;
extract(parse_url($path) + array('port' => 22));
if (isset($query)) {
$path.= '?' . $query;
} elseif (preg_match('/(\?|\?#)$/', $orig)) {
$path.= '?';
}
if (isset($fragment)) {
$path.= '#' . $fragment;
} elseif ($orig[strlen($orig) - 1] == '#') {
$path.= '#';
}

if (!isset($host)) {
return false;
}

if (isset($this->context)) {
$context = stream_context_get_params($this->context);
if (isset($context['notification'])) {
$this->notification = $context['notification'];
}
}

if ($host[0] == '$') {
$host = substr($host, 1);
global ${$host};
if (($$host instanceof SFTP) === false) {
return false;
}
$this->sftp = $$host;
} else {
if (isset($this->context)) {
$context = stream_context_get_options($this->context);
}
if (isset($context[$scheme]['session'])) {
$sftp = $context[$scheme]['session'];
}
if (isset($context[$scheme]['sftp'])) {
$sftp = $context[$scheme]['sftp'];
}
if (isset($sftp) && $sftp instanceof SFTP) {
$this->sftp = $sftp;
return $path;
}
if (isset($context[$scheme]['username'])) {
$user = $context[$scheme]['username'];
}
if (isset($context[$scheme]['password'])) {
$pass = $context[$scheme]['password'];
}
if (isset($context[$scheme]['privkey']) && $context[$scheme]['privkey'] instanceof RSA) {
$pass = $context[$scheme]['privkey'];
}

if (!isset($user) || !isset($pass)) {
return false;
}


 if (isset(self::$instances[$host][$port][$user][(string) $pass])) {
$this->sftp = self::$instances[$host][$port][$user][(string) $pass];
} else {
$this->sftp = new SFTP($host, $port);
$this->sftp->disableStatCache();
if (isset($this->notification) && is_callable($this->notification)) {









call_user_func($this->notification, STREAM_NOTIFY_CONNECT, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0);
call_user_func($this->notification, STREAM_NOTIFY_AUTH_REQUIRED, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0);
if (!$this->sftp->login($user, $pass)) {
call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_ERR, 'Login Failure', NET_SSH2_MSG_USERAUTH_FAILURE, 0, 0);
return false;
}
call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_INFO, 'Login Success', NET_SSH2_MSG_USERAUTH_SUCCESS, 0, 0);
} else {
if (!$this->sftp->login($user, $pass)) {
return false;
}
}
self::$instances[$host][$port][$user][(string) $pass] = $this->sftp;
}
}

return $path;
}











function _stream_open($path, $mode, $options, &$opened_path)
{
$path = $this->_parse_path($path);

if ($path === false) {
return false;
}
$this->path = $path;

$this->size = $this->sftp->size($path);
$this->mode = preg_replace('#[bt]$#', '', $mode);
$this->eof = false;

if ($this->size === false) {
if ($this->mode[0] == 'r') {
return false;
} else {
$this->sftp->touch($path);
$this->size = 0;
}
} else {
switch ($this->mode[0]) {
case 'x':
return false;
case 'w':
$this->sftp->truncate($path, 0);
$this->size = 0;
}
}

$this->pos = $this->mode[0] != 'a' ? 0 : $this->size;

return true;
}








function _stream_read($count)
{
switch ($this->mode) {
case 'w':
case 'a':
case 'x':
case 'c':
return false;
}


 
 
 
 

$result = $this->sftp->get($this->path, false, $this->pos, $count);
if (isset($this->notification) && is_callable($this->notification)) {
if ($result === false) {
call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0);
return 0;
}

 call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($result), $this->size);
}

if (empty($result)) { 
 $this->eof = true;
return false;
}
$this->pos+= strlen($result);

return $result;
}








function _stream_write($data)
{
switch ($this->mode) {
case 'r':
return false;
}

$result = $this->sftp->put($this->path, $data, SFTP::SOURCE_STRING, $this->pos);
if (isset($this->notification) && is_callable($this->notification)) {
if (!$result) {
call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0);
return 0;
}

 call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($data), strlen($data));
}

if ($result === false) {
return false;
}
$this->pos+= strlen($data);
if ($this->pos > $this->size) {
$this->size = $this->pos;
}
$this->eof = false;
return strlen($data);
}







function _stream_tell()
{
return $this->pos;
}














function _stream_eof()
{
return $this->eof;
}









function _stream_seek($offset, $whence)
{
switch ($whence) {
case SEEK_SET:
if ($offset < 0) {
return false;
}
break;
case SEEK_CUR:
$offset+= $this->pos;
break;
case SEEK_END:
$offset+= $this->size;
}

$this->pos = $offset;
$this->eof = false;
return true;
}










function _stream_metadata($path, $option, $var)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}


 
 
 switch ($option) {
case 1: 
 $time = isset($var[0]) ? $var[0] : null;
$atime = isset($var[1]) ? $var[1] : null;
return $this->sftp->touch($path, $time, $atime);
case 2: 
 case 3: 
 return false;
case 4: 
 return $this->sftp->chown($path, $var);
case 5: 
 return $this->sftp->chgrp($path, $var);
case 6: 
 return $this->sftp->chmod($path, $var) !== false;
}
}








function _stream_cast($cast_as)
{
return $this->sftp->fsock;
}








function _stream_lock($operation)
{
return false;
}













function _rename($path_from, $path_to)
{
$path1 = parse_url($path_from);
$path2 = parse_url($path_to);
unset($path1['path'], $path2['path']);
if ($path1 != $path2) {
return false;
}

$path_from = $this->_parse_path($path_from);
$path_to = parse_url($path_to);
if ($path_from === false) {
return false;
}

$path_to = $path_to['path']; 
 
 
 if (!$this->sftp->rename($path_from, $path_to)) {
if ($this->sftp->stat($path_to)) {
return $this->sftp->delete($path_to, true) && $this->sftp->rename($path_from, $path_to);
}
return false;
}

return true;
}

























function _dir_opendir($path, $options)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}
$this->pos = 0;
$this->entries = $this->sftp->nlist($path);
return $this->entries !== false;
}







function _dir_readdir()
{
if (isset($this->entries[$this->pos])) {
return $this->entries[$this->pos++];
}
return false;
}







function _dir_rewinddir()
{
$this->pos = 0;
return true;
}







function _dir_closedir()
{
return true;
}












function _mkdir($path, $mode, $options)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}

return $this->sftp->mkdir($path, $mode, $options & STREAM_MKDIR_RECURSIVE);
}














function _rmdir($path, $options)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}

return $this->sftp->rmdir($path);
}









function _stream_flush()
{
return true;
}







function _stream_stat()
{
$results = $this->sftp->stat($this->path);
if ($results === false) {
return false;
}
return $results;
}








function _unlink($path)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}

return $this->sftp->delete($path, false);
}













function _url_stat($path, $flags)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}

$results = $flags & STREAM_URL_STAT_LINK ? $this->sftp->lstat($path) : $this->sftp->stat($path);
if ($results === false) {
return false;
}

return $results;
}








function _stream_truncate($new_size)
{
if (!$this->sftp->truncate($this->path, $new_size)) {
return false;
}

$this->eof = false;
$this->size = $new_size;

return true;
}













function _stream_set_option($option, $arg1, $arg2)
{
return false;
}






function _stream_close()
{
}
















function __call($name, $arguments)
{
if (defined('NET_SFTP_STREAM_LOGGING')) {
echo $name . '(';
$last = count($arguments) - 1;
foreach ($arguments as $i => $argument) {
var_export($argument);
if ($i != $last) {
echo ',';
}
}
echo ")\r\n";
}
$name = '_' . $name;
if (!method_exists($this, $name)) {
return false;
}
return call_user_func_array(array($this, $name), $arguments);
}
}
<?php
















































namespace phpseclib\Net;

use phpseclib\Crypt\Base;
use phpseclib\Crypt\Blowfish;
use phpseclib\Crypt\Hash;
use phpseclib\Crypt\Random;
use phpseclib\Crypt\RC4;
use phpseclib\Crypt\Rijndael;
use phpseclib\Crypt\RSA;
use phpseclib\Crypt\TripleDES;
use phpseclib\Crypt\Twofish;
use phpseclib\Math\BigInteger; 
use phpseclib\System\SSH\Agent;







define('NET_SSH2_COMPRESSION_NONE', 1);



define('NET_SSH2_COMPRESSION_ZLIB', 2);



define('NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH', 3);









class SSH2
{






const MASK_CONSTRUCTOR = 0x00000001;
const MASK_CONNECTED = 0x00000002;
const MASK_LOGIN_REQ = 0x00000004;
const MASK_LOGIN = 0x00000008;
const MASK_SHELL = 0x00000010;
const MASK_WINDOW_ADJUST = 0x00000020;


















const CHANNEL_EXEC = 1; 
 const CHANNEL_SHELL = 2;
const CHANNEL_SUBSYSTEM = 3;
const CHANNEL_AGENT_FORWARD = 4;
const CHANNEL_KEEP_ALIVE = 5;









const LOG_SIMPLE = 1;



const LOG_COMPLEX = 2;



const LOG_REALTIME = 3;



const LOG_REALTIME_FILE = 4;



const LOG_MAX_SIZE = 1048576; 
 








const READ_SIMPLE = 1;



const READ_REGEX = 2;






const READ_NEXT = 3;








var $identifier;







var $fsock;










var $bitmap = 0;









var $errors = array();








var $server_identifier = false;








var $kex_algorithms = false;








var $kex_algorithm = false;








var $kex_dh_group_size_min = 1536;








var $kex_dh_group_size_preferred = 2048;








var $kex_dh_group_size_max = 4096;








var $server_host_key_algorithms = false;








var $encryption_algorithms_client_to_server = false;








var $encryption_algorithms_server_to_client = false;








var $mac_algorithms_client_to_server = false;








var $mac_algorithms_server_to_client = false;








var $compression_algorithms_client_to_server = false;








var $compression_algorithms_server_to_client = false;








var $languages_server_to_client = false;








var $languages_client_to_server = false;








var $preferred = array();
















var $encrypt_block_size = 8;









var $decrypt_block_size = 8;








var $decrypt = false;








var $encrypt = false;








var $hmac_create = false;








var $hmac_check = false;












var $hmac_size = false;








var $server_public_host_key;














var $session_id = false;










var $exchange_hash = false;








var $message_numbers = array();








var $disconnect_reasons = array();








var $channel_open_failure_reasons = array();









var $terminal_modes = array();









var $channel_extended_data_type_codes = array();










var $send_seq_no = 0;










var $get_seq_no = 0;











var $server_channels = array();












var $channel_buffers = array();










var $channel_status = array();










var $packet_size_client_to_server = array();








var $message_number_log = array();








var $message_log = array();











var $window_size = 0x7FFFFFFF;













var $window_resize = 0x40000000;










var $window_size_server_to_client = array();










var $window_size_client_to_server = array();










var $signature = '';










var $signature_format = '';








var $interactiveBuffer = '';











var $log_size;







var $timeout;







var $curTimeout;







var $keepAlive;








var $realtime_log_file;








var $realtime_log_size;








var $signature_validated = false;







var $realtime_log_wrap;







var $quiet_mode = false;







var $last_packet;







var $exit_status;








var $request_pty = false;







var $in_request_pty_exec = false;







var $in_subsystem;







var $stdErrorLog;








var $last_interactive_response = '';








var $keyboard_requests_responses = array();












var $banner_message = '';








var $is_timeout = false;








var $log_boundary = ':';








var $log_long_width = 65;








var $log_short_width = 16;









var $host;









var $port;










var $windowColumns = 80;










var $windowRows = 24;









var $crypto_engine = false;







var $agent;







var $send_id_string_first = true;







var $send_kex_first = true;







var $bad_key_size_fix = false;







var $retry_connect = false;







var $binary_packet_buffer = false;







var $preferred_signature_format = false;







var $auth = array();








var $auth_methods_to_continue = null;







var $compress = NET_SSH2_COMPRESSION_NONE;







var $decompress = NET_SSH2_COMPRESSION_NONE;







var $compress_context;







var $decompress_context;







var $regenerate_compression_context = false;







var $regenerate_decompression_context = false;







var $smartMFA = true;













function __construct($host, $port = 22, $timeout = 10)
{
$this->message_numbers = array(
1 => 'NET_SSH2_MSG_DISCONNECT',
2 => 'NET_SSH2_MSG_IGNORE',
3 => 'NET_SSH2_MSG_UNIMPLEMENTED',
4 => 'NET_SSH2_MSG_DEBUG',
5 => 'NET_SSH2_MSG_SERVICE_REQUEST',
6 => 'NET_SSH2_MSG_SERVICE_ACCEPT',
20 => 'NET_SSH2_MSG_KEXINIT',
21 => 'NET_SSH2_MSG_NEWKEYS',
30 => 'NET_SSH2_MSG_KEXDH_INIT',
31 => 'NET_SSH2_MSG_KEXDH_REPLY',
50 => 'NET_SSH2_MSG_USERAUTH_REQUEST',
51 => 'NET_SSH2_MSG_USERAUTH_FAILURE',
52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS',
53 => 'NET_SSH2_MSG_USERAUTH_BANNER',

80 => 'NET_SSH2_MSG_GLOBAL_REQUEST',
81 => 'NET_SSH2_MSG_REQUEST_SUCCESS',
82 => 'NET_SSH2_MSG_REQUEST_FAILURE',
90 => 'NET_SSH2_MSG_CHANNEL_OPEN',
91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION',
92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE',
93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST',
94 => 'NET_SSH2_MSG_CHANNEL_DATA',
95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA',
96 => 'NET_SSH2_MSG_CHANNEL_EOF',
97 => 'NET_SSH2_MSG_CHANNEL_CLOSE',
98 => 'NET_SSH2_MSG_CHANNEL_REQUEST',
99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS',
100 => 'NET_SSH2_MSG_CHANNEL_FAILURE'
);
$this->disconnect_reasons = array(
1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT',
2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR',
3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED',
4 => 'NET_SSH2_DISCONNECT_RESERVED',
5 => 'NET_SSH2_DISCONNECT_MAC_ERROR',
6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR',
7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE',
8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED',
9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE',
10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST',
11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION',
12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS',
13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER',
14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE',
15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME'
);
$this->channel_open_failure_reasons = array(
1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED'
);
$this->terminal_modes = array(
0 => 'NET_SSH2_TTY_OP_END'
);
$this->channel_extended_data_type_codes = array(
1 => 'NET_SSH2_EXTENDED_DATA_STDERR'
);

$this->_define_array(
$this->message_numbers,
$this->disconnect_reasons,
$this->channel_open_failure_reasons,
$this->terminal_modes,
$this->channel_extended_data_type_codes,
array(60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'),
array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'),
array(60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST',
61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE'),

 array(30 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST_OLD',
31 => 'NET_SSH2_MSG_KEXDH_GEX_GROUP',
32 => 'NET_SSH2_MSG_KEXDH_GEX_INIT',
33 => 'NET_SSH2_MSG_KEXDH_GEX_REPLY',
34 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST'),

 array(30 => 'NET_SSH2_MSG_KEX_ECDH_INIT',
31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY')
);

if (is_resource($host)) {
$this->fsock = $host;
return;
}

if (is_string($host)) {
$this->host = $host;
$this->port = $port;
$this->timeout = $timeout;
}
}










function setCryptoEngine($engine)
{
$this->crypto_engine = $engine;
}










function sendIdentificationStringFirst()
{
$this->send_id_string_first = true;
}










function sendIdentificationStringLast()
{
$this->send_id_string_first = false;
}










function sendKEXINITFirst()
{
$this->send_kex_first = true;
}










function sendKEXINITLast()
{
$this->send_kex_first = false;
}







function _connect()
{
if ($this->bitmap & self::MASK_CONSTRUCTOR) {
return false;
}

$this->bitmap |= self::MASK_CONSTRUCTOR;

$this->curTimeout = $this->timeout;

$this->last_packet = microtime(true);

if (!is_resource($this->fsock)) {
$start = microtime(true);

 
 
 $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->curTimeout == 0 ? 100000 : $this->curTimeout);
if (!$this->fsock) {
$host = $this->host . ':' . $this->port;
user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"));
return false;
}
$elapsed = microtime(true) - $start;

if ($this->curTimeout) {
$this->curTimeout-= $elapsed;
if ($this->curTimeout < 0) {
$this->is_timeout = true;
return false;
}
}
}

$this->identifier = $this->_generate_identifier();

if ($this->send_id_string_first) {
fputs($this->fsock, $this->identifier . "\r\n");
}








$data = '';
while (!feof($this->fsock) && !preg_match('#(.*)^(SSH-(\d\.\d+).*)#ms', $data, $matches)) {
$line = '';
while (true) {
if ($this->curTimeout) {
if ($this->curTimeout < 0) {
$this->is_timeout = true;
return false;
}
$read = array($this->fsock);
$write = $except = null;
$start = microtime(true);
$sec = floor($this->curTimeout);
$usec = 1000000 * ($this->curTimeout - $sec);

 
 if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
$this->is_timeout = true;
return false;
}
$elapsed = microtime(true) - $start;
$this->curTimeout-= $elapsed;
}

$temp = stream_get_line($this->fsock, 255, "\n");
if (strlen($temp) == 255) {
continue;
}
if ($temp === false) {
return false;
}

$line.= "$temp\n";


 
 
 
 


 
 

break;
}

$data.= $line;
}

if (feof($this->fsock)) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}

$extra = $matches[1];

if (defined('NET_SSH2_LOGGING')) {
$this->_append_log('<-', $matches[0]);
$this->_append_log('->', $this->identifier . "\r\n");
}

$this->server_identifier = trim($temp, "\r\n");
if (strlen($extra)) {
$this->errors[] = $data;
}

if (version_compare($matches[3], '1.99', '<')) {
user_error("Cannot connect to SSH $matches[3] servers");
return false;
}

if (!$this->send_id_string_first) {
fputs($this->fsock, $this->identifier . "\r\n");
}

if (!$this->send_kex_first) {
$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}

if (!strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
user_error('Expected SSH_MSG_KEXINIT');
return false;
}

if (!$this->_key_exchange($response)) {
return false;
}
}

if ($this->send_kex_first && !$this->_key_exchange()) {
return false;
}

$this->bitmap|= self::MASK_CONNECTED;

return true;
}









function _generate_identifier()
{
$identifier = 'SSH-2.0-phpseclib_2.0';

$ext = array();
if (function_exists('sodium_crypto_box_publickey_from_secretkey')) {
$ext[] = 'libsodium';
}

if (extension_loaded('openssl')) {
$ext[] = 'openssl';
} elseif (extension_loaded('mcrypt')) {
$ext[] = 'mcrypt';
}

if (extension_loaded('gmp')) {
$ext[] = 'gmp';
} elseif (extension_loaded('bcmath')) {
$ext[] = 'bcmath';
}

if (!empty($ext)) {
$identifier .= ' (' . implode(', ', $ext) . ')';
}

return $identifier;
}







function _key_exchange($kexinit_payload_server = false)
{
$preferred = $this->preferred;
$send_kex = true;

$kex_algorithms = isset($preferred['kex']) ?
$preferred['kex'] :
$this->getSupportedKEXAlgorithms();
$server_host_key_algorithms = isset($preferred['hostkey']) ?
$preferred['hostkey'] :
$this->getSupportedHostKeyAlgorithms();
$s2c_encryption_algorithms = isset($preferred['server_to_client']['crypt']) ?
$preferred['server_to_client']['crypt'] :
$this->getSupportedEncryptionAlgorithms();
$c2s_encryption_algorithms = isset($preferred['client_to_server']['crypt']) ?
$preferred['client_to_server']['crypt'] :
$this->getSupportedEncryptionAlgorithms();
$s2c_mac_algorithms = isset($preferred['server_to_client']['mac']) ?
$preferred['server_to_client']['mac'] :
$this->getSupportedMACAlgorithms();
$c2s_mac_algorithms = isset($preferred['client_to_server']['mac']) ?
$preferred['client_to_server']['mac'] :
$this->getSupportedMACAlgorithms();
$s2c_compression_algorithms = isset($preferred['server_to_client']['comp']) ?
$preferred['server_to_client']['comp'] :
$this->getSupportedCompressionAlgorithms();
$c2s_compression_algorithms = isset($preferred['client_to_server']['comp']) ?
$preferred['client_to_server']['comp'] :
$this->getSupportedCompressionAlgorithms();


 switch (true) {
case $this->server_identifier == 'SSH-2.0-SSHD':
case substr($this->server_identifier, 0, 13) == 'SSH-2.0-DLINK':
if (!isset($preferred['server_to_client']['mac'])) {
$s2c_mac_algorithms = array_values(array_diff(
$s2c_mac_algorithms,
array('hmac-sha1-96', 'hmac-md5-96')
));
}
if (!isset($preferred['client_to_server']['mac'])) {
$c2s_mac_algorithms = array_values(array_diff(
$c2s_mac_algorithms,
array('hmac-sha1-96', 'hmac-md5-96')
));
}
}

$str_kex_algorithms = implode(',', $kex_algorithms);
$str_server_host_key_algorithms = implode(',', $server_host_key_algorithms);
$encryption_algorithms_server_to_client = implode(',', $s2c_encryption_algorithms);
$encryption_algorithms_client_to_server = implode(',', $c2s_encryption_algorithms);
$mac_algorithms_server_to_client = implode(',', $s2c_mac_algorithms);
$mac_algorithms_client_to_server = implode(',', $c2s_mac_algorithms);
$compression_algorithms_server_to_client = implode(',', $s2c_compression_algorithms);
$compression_algorithms_client_to_server = implode(',', $c2s_compression_algorithms);

$client_cookie = Random::string(16);

$kexinit_payload_client = pack(
'Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN',
NET_SSH2_MSG_KEXINIT,
$client_cookie,
strlen($str_kex_algorithms),
$str_kex_algorithms,
strlen($str_server_host_key_algorithms),
$str_server_host_key_algorithms,
strlen($encryption_algorithms_client_to_server),
$encryption_algorithms_client_to_server,
strlen($encryption_algorithms_server_to_client),
$encryption_algorithms_server_to_client,
strlen($mac_algorithms_client_to_server),
$mac_algorithms_client_to_server,
strlen($mac_algorithms_server_to_client),
$mac_algorithms_server_to_client,
strlen($compression_algorithms_client_to_server),
$compression_algorithms_client_to_server,
strlen($compression_algorithms_server_to_client),
$compression_algorithms_server_to_client,
0,
'',
0,
'',
0,
0
);

if ($kexinit_payload_server === false) {
if (!$this->_send_binary_packet($kexinit_payload_client)) {
return false;
}

$kexinit_payload_server = $this->_get_binary_packet();
if ($kexinit_payload_server === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}

if (!strlen($kexinit_payload_server) || ord($kexinit_payload_server[0]) != NET_SSH2_MSG_KEXINIT) {
user_error('Expected SSH_MSG_KEXINIT');
return false;
}

$send_kex = false;
}

$response = $kexinit_payload_server;
$this->_string_shift($response, 1); 
 $server_cookie = $this->_string_shift($response, 16);

if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));

if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length']));

if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));

if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));

if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));

if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));

if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));

if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));

if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));

if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));

if (!strlen($response)) {
return false;
}
extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1)));
$first_kex_packet_follows = $first_kex_packet_follows != 0;

if ($send_kex && !$this->_send_binary_packet($kexinit_payload_client)) {
return false;
}


 
 
 $decrypt = $this->_array_intersect_first($s2c_encryption_algorithms, $this->encryption_algorithms_server_to_client);
$decryptKeyLength = $this->_encryption_algorithm_to_key_size($decrypt);
if ($decryptKeyLength === null) {
user_error('No compatible server to client encryption algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}

$encrypt = $this->_array_intersect_first($c2s_encryption_algorithms, $this->encryption_algorithms_client_to_server);
$encryptKeyLength = $this->_encryption_algorithm_to_key_size($encrypt);
if ($encryptKeyLength === null) {
user_error('No compatible client to server encryption algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}


 $this->kex_algorithm = $kex_algorithm = $this->_array_intersect_first($kex_algorithms, $this->kex_algorithms);
if ($kex_algorithm === false) {
user_error('No compatible key exchange algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}

$server_host_key_algorithm = $this->_array_intersect_first($server_host_key_algorithms, $this->server_host_key_algorithms);
if ($server_host_key_algorithm === false) {
user_error('No compatible server host key algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}

$mac_algorithm_in = $this->_array_intersect_first($s2c_mac_algorithms, $this->mac_algorithms_server_to_client);
if ($mac_algorithm_in === false) {
user_error('No compatible server to client message authentication algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}

$compression_map = array(
'none' => NET_SSH2_COMPRESSION_NONE,
'zlib' => NET_SSH2_COMPRESSION_ZLIB,
'zlib@openssh.com' => NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH
);

$compression_algorithm_out = $this->_array_intersect_first($c2s_compression_algorithms, $this->compression_algorithms_client_to_server);
if ($compression_algorithm_out === false) {
user_error('No compatible client to server compression algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$this->compress = $compression_map[$compression_algorithm_out];

$compression_algorithm_in = $this->_array_intersect_first($s2c_compression_algorithms, $this->compression_algorithms_server_to_client);
if ($compression_algorithm_in === false) {
user_error('No compatible server to client compression algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$this->decompress = $compression_map[$compression_algorithm_in];


 $exchange_hash_rfc4419 = '';

if ($kex_algorithm === 'curve25519-sha256@libssh.org') {
$x = Random::string(32);
$eBytes = sodium_crypto_box_publickey_from_secretkey($x);
$clientKexInitMessage = 'NET_SSH2_MSG_KEX_ECDH_INIT';
$serverKexReplyMessage = 'NET_SSH2_MSG_KEX_ECDH_REPLY';
$kexHash = new Hash('sha256');
} else {
if (strpos($kex_algorithm, 'diffie-hellman-group-exchange') === 0) {
$dh_group_sizes_packed = pack(
'NNN',
$this->kex_dh_group_size_min,
$this->kex_dh_group_size_preferred,
$this->kex_dh_group_size_max
);
$packet = pack(
'Ca*',
NET_SSH2_MSG_KEXDH_GEX_REQUEST,
$dh_group_sizes_packed
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$this->_updateLogHistory('UNKNOWN (34)', 'NET_SSH2_MSG_KEXDH_GEX_REQUEST');

$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
if ($type != NET_SSH2_MSG_KEXDH_GEX_GROUP) {
user_error('Expected SSH_MSG_KEX_DH_GEX_GROUP');
return false;
}
$this->_updateLogHistory('NET_SSH2_MSG_KEXDH_REPLY', 'NET_SSH2_MSG_KEXDH_GEX_GROUP');

if (strlen($response) < 4) {
return false;
}
extract(unpack('NprimeLength', $this->_string_shift($response, 4)));
$primeBytes = $this->_string_shift($response, $primeLength);
$prime = new BigInteger($primeBytes, -256);

if (strlen($response) < 4) {
return false;
}
extract(unpack('NgLength', $this->_string_shift($response, 4)));
$gBytes = $this->_string_shift($response, $gLength);
$g = new BigInteger($gBytes, -256);

$exchange_hash_rfc4419 = pack(
'a*Na*Na*',
$dh_group_sizes_packed,
$primeLength,
$primeBytes,
$gLength,
$gBytes
);

$clientKexInitMessage = 'NET_SSH2_MSG_KEXDH_GEX_INIT';
$serverKexReplyMessage = 'NET_SSH2_MSG_KEXDH_GEX_REPLY';
} else {
switch ($kex_algorithm) {

 
 case 'diffie-hellman-group1-sha1':
$prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
'020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
'4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF';
break;

 case 'diffie-hellman-group14-sha1':
$prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
'020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
'4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
'98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
'9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
'3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF';
break;
}

 
 $g = new BigInteger(2);
$prime = new BigInteger($prime, 16);
$clientKexInitMessage = 'NET_SSH2_MSG_KEXDH_INIT';
$serverKexReplyMessage = 'NET_SSH2_MSG_KEXDH_REPLY';
}

switch ($kex_algorithm) {
case 'diffie-hellman-group-exchange-sha256':
$kexHash = new Hash('sha256');
break;
default:
$kexHash = new Hash('sha1');
}








$one = new BigInteger(1);
$keyLength = min($kexHash->getLength(), max($encryptKeyLength, $decryptKeyLength));
$max = $one->bitwise_leftShift(16 * $keyLength); 
 $max = $max->subtract($one);

$x = $one->random($one, $max);
$e = $g->modPow($x, $prime);

$eBytes = $e->toBytes(true);
}
$data = pack('CNa*', constant($clientKexInitMessage), strlen($eBytes), $eBytes);

if (!$this->_send_binary_packet($data)) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
switch ($clientKexInitMessage) {
case 'NET_SSH2_MSG_KEX_ECDH_INIT':
$this->_updateLogHistory('NET_SSH2_MSG_KEXDH_INIT', 'NET_SSH2_MSG_KEX_ECDH_INIT');
break;
case 'NET_SSH2_MSG_KEXDH_GEX_INIT':
$this->_updateLogHistory('UNKNOWN (32)', 'NET_SSH2_MSG_KEXDH_GEX_INIT');
}

$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));

if ($type != constant($serverKexReplyMessage)) {
user_error("Expected $serverKexReplyMessage");
return false;
}
switch ($serverKexReplyMessage) {
case 'NET_SSH2_MSG_KEX_ECDH_REPLY':
$this->_updateLogHistory('NET_SSH2_MSG_KEXDH_REPLY', 'NET_SSH2_MSG_KEX_ECDH_REPLY');
break;
case 'NET_SSH2_MSG_KEXDH_GEX_REPLY':
$this->_updateLogHistory('UNKNOWN (33)', 'NET_SSH2_MSG_KEXDH_GEX_REPLY');
}

if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']);

if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$public_key_format = $this->_string_shift($server_public_host_key, $temp['length']);

if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$fBytes = $this->_string_shift($response, $temp['length']);

if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->signature = $this->_string_shift($response, $temp['length']);

if (strlen($this->signature) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($this->signature, 4));
$this->signature_format = $this->_string_shift($this->signature, $temp['length']);

if ($kex_algorithm === 'curve25519-sha256@libssh.org') {
if (strlen($fBytes) !== 32) {
user_error('Received curve25519 public key of invalid length.');
return false;
}
$key = new BigInteger(sodium_crypto_scalarmult($x, $fBytes), 256);

 
 
 
 
 if (extension_loaded('sodium') || extension_loaded('libsodium')) {
sodium_memzero($x);
}
} else {
$f = new BigInteger($fBytes, -256);
$key = $f->modPow($x, $prime);
}
$keyBytes = $key->toBytes(true);

$this->exchange_hash = pack(
'Na*Na*Na*Na*Na*a*Na*Na*Na*',
strlen($this->identifier),
$this->identifier,
strlen($this->server_identifier),
$this->server_identifier,
strlen($kexinit_payload_client),
$kexinit_payload_client,
strlen($kexinit_payload_server),
$kexinit_payload_server,
strlen($this->server_public_host_key),
$this->server_public_host_key,
$exchange_hash_rfc4419,
strlen($eBytes),
$eBytes,
strlen($fBytes),
$fBytes,
strlen($keyBytes),
$keyBytes
);

$this->exchange_hash = $kexHash->hash($this->exchange_hash);

if ($this->session_id === false) {
$this->session_id = $this->exchange_hash;
}

switch ($server_host_key_algorithm) {
case 'ssh-dss':
$expected_key_format = 'ssh-dss';
break;

 
 
 default:
$expected_key_format = 'ssh-rsa';
}

if ($public_key_format != $expected_key_format || $this->signature_format != $server_host_key_algorithm) {
switch (true) {
case $this->signature_format == $server_host_key_algorithm:
case $server_host_key_algorithm != 'rsa-sha2-256' && $server_host_key_algorithm != 'rsa-sha2-512':
case $this->signature_format != 'ssh-rsa':
user_error('Server Host Key Algorithm Mismatch');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
}

$packet = pack(
'C',
NET_SSH2_MSG_NEWKEYS
);

if (!$this->_send_binary_packet($packet)) {
return false;
}

$response = $this->_get_binary_packet();

if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}

if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));

if ($type != NET_SSH2_MSG_NEWKEYS) {
user_error('Expected SSH_MSG_NEWKEYS');
return false;
}

$keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);

$this->encrypt = $this->_encryption_algorithm_to_crypt_instance($encrypt);
if ($this->encrypt) {
if ($this->crypto_engine) {
$this->encrypt->setPreferredEngine($this->crypto_engine);
}
if ($this->encrypt->block_size) {
$this->encrypt_block_size = $this->encrypt->block_size;
}
$this->encrypt->enableContinuousBuffer();
$this->encrypt->disablePadding();

if ($this->encrypt->getBlockLength()) {
$this->encrypt_block_size = $this->encrypt->getBlockLength() >> 3;
}

$iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id);
while ($this->encrypt_block_size > strlen($iv)) {
$iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
}
$this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));

$key = $kexHash->hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id);
while ($encryptKeyLength > strlen($key)) {
$key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
}
$this->encrypt->setKey(substr($key, 0, $encryptKeyLength));

$this->encrypt->name = $decrypt;
}

$this->decrypt = $this->_encryption_algorithm_to_crypt_instance($decrypt);
if ($this->decrypt) {
if ($this->crypto_engine) {
$this->decrypt->setPreferredEngine($this->crypto_engine);
}
if ($this->decrypt->block_size) {
$this->decrypt_block_size = $this->decrypt->block_size;
}
$this->decrypt->enableContinuousBuffer();
$this->decrypt->disablePadding();

if ($this->decrypt->getBlockLength()) {
$this->decrypt_block_size = $this->decrypt->getBlockLength() >> 3;
}

$iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id);
while ($this->decrypt_block_size > strlen($iv)) {
$iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
}
$this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));

$key = $kexHash->hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id);
while ($decryptKeyLength > strlen($key)) {
$key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
}
$this->decrypt->setKey(substr($key, 0, $decryptKeyLength));

$this->decrypt->name = $decrypt;
}








if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') {
$this->encrypt->encrypt(str_repeat("\0", 1536));
}
if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') {
$this->decrypt->decrypt(str_repeat("\0", 1536));
}

$mac_algorithm_out = $this->_array_intersect_first($c2s_mac_algorithms, $this->mac_algorithms_client_to_server);
if ($mac_algorithm_out === false) {
user_error('No compatible client to server message authentication algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}

$createKeyLength = 0; 
 switch ($mac_algorithm_out) {
case 'hmac-sha2-256':
$this->hmac_create = new Hash('sha256');
$createKeyLength = 32;
break;
case 'hmac-sha1':
$this->hmac_create = new Hash('sha1');
$createKeyLength = 20;
break;
case 'hmac-sha1-96':
$this->hmac_create = new Hash('sha1-96');
$createKeyLength = 20;
break;
case 'hmac-md5':
$this->hmac_create = new Hash('md5');
$createKeyLength = 16;
break;
case 'hmac-md5-96':
$this->hmac_create = new Hash('md5-96');
$createKeyLength = 16;
}
$this->hmac_create->name = $mac_algorithm_out;

$checkKeyLength = 0;
$this->hmac_size = 0;
switch ($mac_algorithm_in) {
case 'hmac-sha2-256':
$this->hmac_check = new Hash('sha256');
$checkKeyLength = 32;
$this->hmac_size = 32;
break;
case 'hmac-sha1':
$this->hmac_check = new Hash('sha1');
$checkKeyLength = 20;
$this->hmac_size = 20;
break;
case 'hmac-sha1-96':
$this->hmac_check = new Hash('sha1-96');
$checkKeyLength = 20;
$this->hmac_size = 12;
break;
case 'hmac-md5':
$this->hmac_check = new Hash('md5');
$checkKeyLength = 16;
$this->hmac_size = 16;
break;
case 'hmac-md5-96':
$this->hmac_check = new Hash('md5-96');
$checkKeyLength = 16;
$this->hmac_size = 12;
}
$this->hmac_check->name = $mac_algorithm_in;

$key = $kexHash->hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id);
while ($createKeyLength > strlen($key)) {
$key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
}
$this->hmac_create->setKey(substr($key, 0, $createKeyLength));

$key = $kexHash->hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id);
while ($checkKeyLength > strlen($key)) {
$key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
}
$this->hmac_check->setKey(substr($key, 0, $checkKeyLength));

$this->regenerate_compression_context = $this->regenerate_decompression_context = true;

return true;
}








function _encryption_algorithm_to_key_size($algorithm)
{
if ($this->bad_key_size_fix && $this->_bad_algorithm_candidate($algorithm)) {
return 16;
}

switch ($algorithm) {
case 'none':
return 0;
case 'aes128-cbc':
case 'aes128-ctr':
case 'arcfour':
case 'arcfour128':
case 'blowfish-cbc':
case 'blowfish-ctr':
case 'twofish128-cbc':
case 'twofish128-ctr':
return 16;
case '3des-cbc':
case '3des-ctr':
case 'aes192-cbc':
case 'aes192-ctr':
case 'twofish192-cbc':
case 'twofish192-ctr':
return 24;
case 'aes256-cbc':
case 'aes256-ctr':
case 'arcfour256':
case 'twofish-cbc':
case 'twofish256-cbc':
case 'twofish256-ctr':
return 32;
}
return null;
}









function _encryption_algorithm_to_crypt_instance($algorithm)
{
switch ($algorithm) {
case '3des-cbc':
return new TripleDES();
case '3des-ctr':
return new TripleDES(Base::MODE_CTR);
case 'aes256-cbc':
case 'aes192-cbc':
case 'aes128-cbc':
return new Rijndael();
case 'aes256-ctr':
case 'aes192-ctr':
case 'aes128-ctr':
return new Rijndael(Base::MODE_CTR);
case 'blowfish-cbc':
return new Blowfish();
case 'blowfish-ctr':
return new Blowfish(Base::MODE_CTR);
case 'twofish128-cbc':
case 'twofish192-cbc':
case 'twofish256-cbc':
case 'twofish-cbc':
return new Twofish();
case 'twofish128-ctr':
case 'twofish192-ctr':
case 'twofish256-ctr':
return new Twofish(Base::MODE_CTR);
case 'arcfour':
case 'arcfour128':
case 'arcfour256':
return new RC4();
}
return null;
}










function _bad_algorithm_candidate($algorithm)
{
switch ($algorithm) {
case 'arcfour256':
case 'aes192-ctr':
case 'aes256-ctr':
return true;
}

return false;
}











function login($username)
{
$args = func_get_args();
$this->auth[] = $args;


 
 if (substr($this->server_identifier, 0, 15) != 'SSH-2.0-CoreFTP' && $this->auth_methods_to_continue === null) {
if ($this->_login($username)) {
return true;
}
if (count($args) == 1) {
return false;
}
}
return call_user_func_array(array(&$this, '_login'), $args);
}









function _login($username)
{
if (!($this->bitmap & self::MASK_CONSTRUCTOR)) {
if (!$this->_connect()) {
return false;
}
}

$args = array_slice(func_get_args(), 1);
if (empty($args)) {
return $this->_login_helper($username);
}

while (count($args)) {
if (!$this->auth_methods_to_continue || !$this->smartMFA) {
$newargs = $args;
$args = array();
} else {
$newargs = array();
foreach ($this->auth_methods_to_continue as $method) {
switch ($method) {
case 'publickey':
foreach ($args as $key => $arg) {
if (is_object($arg)) {
$newargs[] = $arg;
unset($args[$key]);
break;
}
}
break;
case 'keyboard-interactive':
$hasArray = $hasString = false;
foreach ($args as $arg) {
if ($hasArray || is_array($arg)) {
$hasArray = true;
break;
}
if ($hasString || is_string($arg)) {
$hasString = true;
break;
}
}
if ($hasArray && $hasString) {
foreach ($args as $key => $arg) {
if (is_array($arg)) {
$newargs[] = $arg;
break 2;
}
}
}
case 'password':
foreach ($args as $key => $arg) {
$newargs[] = $arg;
unset($args[$key]);
break;
}
}
}
}

foreach ($newargs as $arg) {
if ($this->_login_helper($username, $arg)) {
return true;
}
}
}
return false;
}











function _login_helper($username, $password = null)
{
if (!($this->bitmap & self::MASK_CONNECTED)) {
return false;
}

if (!($this->bitmap & self::MASK_LOGIN_REQ)) {
$packet = pack(
'CNa*',
NET_SSH2_MSG_SERVICE_REQUEST,
strlen('ssh-userauth'),
'ssh-userauth'
);

if (!$this->_send_binary_packet($packet)) {
return false;
}

$response = $this->_get_binary_packet();
if ($response === false) {
if ($this->retry_connect) {
$this->retry_connect = false;
if (!$this->_connect()) {
return false;
}
return $this->_login_helper($username, $password);
}
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}

if (strlen($response) < 4) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));

if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) {
user_error('Expected SSH_MSG_SERVICE_ACCEPT');
return false;
}
$this->bitmap |= self::MASK_LOGIN_REQ;
}

if (strlen($this->last_interactive_response)) {
return !is_string($password) && !is_array($password) ? false : $this->_keyboard_interactive_process($password);
}

if ($password instanceof RSA) {
return $this->_privatekey_login($username, $password);
} elseif ($password instanceof Agent) {
return $this->_ssh_agent_login($username, $password);
}

if (is_array($password)) {
if ($this->_keyboard_interactive_login($username, $password)) {
$this->bitmap |= self::MASK_LOGIN;
return true;
}
return false;
}

if (!isset($password)) {
$packet = pack(
'CNa*Na*Na*',
NET_SSH2_MSG_USERAUTH_REQUEST,
strlen($username),
$username,
strlen('ssh-connection'),
'ssh-connection',
strlen('none'),
'none'
);

if (!$this->_send_binary_packet($packet)) {
return false;
}

$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}

if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));

switch ($type) {
case NET_SSH2_MSG_USERAUTH_SUCCESS:
$this->bitmap |= self::MASK_LOGIN;
return true;
case NET_SSH2_MSG_USERAUTH_FAILURE:
extract(unpack('Nmethodlistlen', $this->_string_shift($response, 4)));
$this->auth_methods_to_continue = explode(',', $this->_string_shift($response, $methodlistlen));
default:
return false;
}
}

$packet = pack(
'CNa*Na*Na*CNa*',
NET_SSH2_MSG_USERAUTH_REQUEST,
strlen($username),
$username,
strlen('ssh-connection'),
'ssh-connection',
strlen('password'),
'password',
0,
strlen($password),
$password
);


 if (!defined('NET_SSH2_LOGGING')) {
$logged = null;
} else {
$logged = pack(
'CNa*Na*Na*CNa*',
NET_SSH2_MSG_USERAUTH_REQUEST,
strlen('username'),
'username',
strlen('ssh-connection'),
'ssh-connection',
strlen('password'),
'password',
0,
strlen('password'),
'password'
);
}

if (!$this->_send_binary_packet($packet, $logged)) {
return false;
}

$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}

if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));

switch ($type) {
case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: 
 $this->_updateLogHistory('UNKNOWN (60)', 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ');
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . $this->_string_shift($response, $length);
return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
case NET_SSH2_MSG_USERAUTH_FAILURE:

 
 if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$auth_methods = explode(',', $this->_string_shift($response, $length));
$this->auth_methods_to_continue = $auth_methods;
if (!strlen($response)) {
return false;
}
extract(unpack('Cpartial_success', $this->_string_shift($response, 1)));
$partial_success = $partial_success != 0;

if (!$partial_success && in_array('keyboard-interactive', $auth_methods)) {
if ($this->_keyboard_interactive_login($username, $password)) {
$this->bitmap |= self::MASK_LOGIN;
return true;
}
return false;
}
return false;
case NET_SSH2_MSG_USERAUTH_SUCCESS:
$this->bitmap |= self::MASK_LOGIN;
return true;
}

return false;
}











function _keyboard_interactive_login($username, $password)
{
$packet = pack(
'CNa*Na*Na*Na*Na*',
NET_SSH2_MSG_USERAUTH_REQUEST,
strlen($username),
$username,
strlen('ssh-connection'),
'ssh-connection',
strlen('keyboard-interactive'),
'keyboard-interactive',
0,
'',
0,
''
);

if (!$this->_send_binary_packet($packet)) {
return false;
}

return $this->_keyboard_interactive_process($password);
}







function _keyboard_interactive_process()
{
$responses = func_get_args();

if (strlen($this->last_interactive_response)) {
$response = $this->last_interactive_response;
} else {
$orig = $response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
}

if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));

switch ($type) {
case NET_SSH2_MSG_USERAUTH_INFO_REQUEST:
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$this->_string_shift($response, $length); 
 if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$this->_string_shift($response, $length); 
 if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$this->_string_shift($response, $length); 
 if (strlen($response) < 4) {
return false;
}
extract(unpack('Nnum_prompts', $this->_string_shift($response, 4)));

for ($i = 0; $i < count($responses); $i++) {
if (is_array($responses[$i])) {
foreach ($responses[$i] as $key => $value) {
$this->keyboard_requests_responses[$key] = $value;
}
unset($responses[$i]);
}
}
$responses = array_values($responses);

if (isset($this->keyboard_requests_responses)) {
for ($i = 0; $i < $num_prompts; $i++) {
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));

 $prompt = $this->_string_shift($response, $length);

 foreach ($this->keyboard_requests_responses as $key => $value) {
if (substr($prompt, 0, strlen($key)) == $key) {
$responses[] = $value;
break;
}
}
}
}


 if (strlen($this->last_interactive_response)) {
$this->last_interactive_response = '';
} else {
$this->_updateLogHistory('UNKNOWN (60)', 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST');
}

if (!count($responses) && $num_prompts) {
$this->last_interactive_response = $orig;
return false;
}






 $packet = $logged = pack('CN', NET_SSH2_MSG_USERAUTH_INFO_RESPONSE, count($responses));
for ($i = 0; $i < count($responses); $i++) {
$packet.= pack('Na*', strlen($responses[$i]), $responses[$i]);
$logged.= pack('Na*', strlen('dummy-answer'), 'dummy-answer');
}

if (!$this->_send_binary_packet($packet, $logged)) {
return false;
}

$this->_updateLogHistory('UNKNOWN (61)', 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE');







 
 return $this->_keyboard_interactive_process();
case NET_SSH2_MSG_USERAUTH_SUCCESS:
return true;
case NET_SSH2_MSG_USERAUTH_FAILURE:
extract(unpack('Nmethodlistlen', $this->_string_shift($response, 4)));
$this->auth_methods_to_continue = explode(',', $this->_string_shift($response, $methodlistlen));
return false;
}

return false;
}









function _ssh_agent_login($username, $agent)
{
$this->agent = $agent;
$keys = $agent->requestIdentities();
foreach ($keys as $key) {
if ($this->_privatekey_login($username, $key)) {
return true;
}
}

return false;
}











function _privatekey_login($username, $privatekey)
{

 $publickey = $privatekey->getPublicKey(RSA::PUBLIC_FORMAT_RAW);
if ($publickey === false) {
return false;
}

$publickey = array(
'e' => $publickey['e']->toBytes(true),
'n' => $publickey['n']->toBytes(true)
);
$publickey = pack(
'Na*Na*Na*',
strlen('ssh-rsa'),
'ssh-rsa',
strlen($publickey['e']),
$publickey['e'],
strlen($publickey['n']),
$publickey['n']
);

switch ($this->signature_format) {
case 'rsa-sha2-512':
$hash = 'sha512';
$signatureType = 'rsa-sha2-512';
break;
case 'rsa-sha2-256':
$hash = 'sha256';
$signatureType = 'rsa-sha2-256';
break;

 default:
$hash = 'sha1';
$signatureType = 'ssh-rsa';
}

$part1 = pack(
'CNa*Na*Na*',
NET_SSH2_MSG_USERAUTH_REQUEST,
strlen($username),
$username,
strlen('ssh-connection'),
'ssh-connection',
strlen('publickey'),
'publickey'
);
$part2 = pack('Na*Na*', strlen($signatureType), $signatureType, strlen($publickey), $publickey);

$packet = $part1 . chr(0) . $part2;
if (!$this->_send_binary_packet($packet)) {
return false;
}

$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}

if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));

switch ($type) {
case NET_SSH2_MSG_USERAUTH_FAILURE:
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nmethodlistlen', $this->_string_shift($response, 4)));
$this->auth_methods_to_continue = explode(',', $this->_string_shift($response, $methodlistlen));
$this->errors[] = 'SSH_MSG_USERAUTH_FAILURE';
return false;
case NET_SSH2_MSG_USERAUTH_PK_OK:

 
 $this->_updateLogHistory('UNKNOWN (60)', 'NET_SSH2_MSG_USERAUTH_PK_OK');
break;
case NET_SSH2_MSG_USERAUTH_SUCCESS:
$this->bitmap |= self::MASK_LOGIN;
return true;
default:
user_error('Unexpected response to publickey authentication pt 1');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}

$packet = $part1 . chr(1) . $part2;
$privatekey->setSignatureMode(RSA::SIGNATURE_PKCS1);
$privatekey->setHash($hash);
$signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet));
$signature = pack('Na*Na*', strlen($signatureType), $signatureType, strlen($signature), $signature);
$packet.= pack('Na*', strlen($signature), $signature);

if (!$this->_send_binary_packet($packet)) {
return false;
}

$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}

if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));

switch ($type) {
case NET_SSH2_MSG_USERAUTH_FAILURE:

 extract(unpack('Nmethodlistlen', $this->_string_shift($response, 4)));
$this->auth_methods_to_continue = explode(',', $this->_string_shift($response, $methodlistlen));
return false;
case NET_SSH2_MSG_USERAUTH_SUCCESS:
$this->bitmap |= self::MASK_LOGIN;
return true;
}

user_error('Unexpected response to publickey authentication pt 2');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}










function setTimeout($timeout)
{
$this->timeout = $this->curTimeout = $timeout;
}









function setKeepAlive($interval)
{
$this->keepAlive = $interval;
}






function getStdError()
{
return $this->stdErrorLog;
}












function exec($command, $callback = null)
{
$this->curTimeout = $this->timeout;
$this->is_timeout = false;
$this->stdErrorLog = '';

if (!$this->isAuthenticated()) {
return false;
}

if ($this->in_request_pty_exec) {
user_error('If you want to run multiple exec()\'s you will need to disable (and re-enable if appropriate) a PTY for each one.');
return false;
}


 
 
 
 $this->window_size_server_to_client[self::CHANNEL_EXEC] = $this->window_size;

 
 $packet_size = 0x4000;

$packet = pack(
'CNa*N3',
NET_SSH2_MSG_CHANNEL_OPEN,
strlen('session'),
'session',
self::CHANNEL_EXEC,
$this->window_size_server_to_client[self::CHANNEL_EXEC],
$packet_size
);

if (!$this->_send_binary_packet($packet)) {
return false;
}

$this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_OPEN;

$response = $this->_get_channel_packet(self::CHANNEL_EXEC);
if ($response === false) {
return false;
}

if ($this->request_pty === true) {
$terminal_modes = pack('C', NET_SSH2_TTY_OP_END);
$packet = pack(
'CNNa*CNa*N5a*',
NET_SSH2_MSG_CHANNEL_REQUEST,
$this->server_channels[self::CHANNEL_EXEC],
strlen('pty-req'),
'pty-req',
1,
strlen('vt100'),
'vt100',
$this->windowColumns,
$this->windowRows,
0,
0,
strlen($terminal_modes),
$terminal_modes
);

if (!$this->_send_binary_packet($packet)) {
return false;
}

$this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST;
if (!$this->_get_channel_packet(self::CHANNEL_EXEC)) {
user_error('Unable to request pseudo-terminal');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}

$this->in_request_pty_exec = true;
}


 
 
 
 


 
 
 $packet = pack(
'CNNa*CNa*',
NET_SSH2_MSG_CHANNEL_REQUEST,
$this->server_channels[self::CHANNEL_EXEC],
strlen('exec'),
'exec',
1,
strlen($command),
$command
);
if (!$this->_send_binary_packet($packet)) {
return false;
}

$this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST;

$response = $this->_get_channel_packet(self::CHANNEL_EXEC);
if ($response === false) {
return false;
}

$this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_DATA;

if ($callback === false || $this->in_request_pty_exec) {
return true;
}

$output = '';
while (true) {
$temp = $this->_get_channel_packet(self::CHANNEL_EXEC);
switch (true) {
case $temp === true:
return is_callable($callback) ? true : $output;
case $temp === false:
return false;
default:
if (is_callable($callback)) {
if (call_user_func($callback, $temp) === true) {
$this->_close_channel(self::CHANNEL_EXEC);
return true;
}
} else {
$output.= $temp;
}
}
}
}









function _initShell()
{
if ($this->in_request_pty_exec === true) {
return true;
}

$this->window_size_server_to_client[self::CHANNEL_SHELL] = $this->window_size;
$packet_size = 0x4000;

$packet = pack(
'CNa*N3',
NET_SSH2_MSG_CHANNEL_OPEN,
strlen('session'),
'session',
self::CHANNEL_SHELL,
$this->window_size_server_to_client[self::CHANNEL_SHELL],
$packet_size
);

if (!$this->_send_binary_packet($packet)) {
return false;
}

$this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_OPEN;

$response = $this->_get_channel_packet(self::CHANNEL_SHELL);
if ($response === false) {
return false;
}

$terminal_modes = pack('C', NET_SSH2_TTY_OP_END);
$packet = pack(
'CNNa*CNa*N5a*',
NET_SSH2_MSG_CHANNEL_REQUEST,
$this->server_channels[self::CHANNEL_SHELL],
strlen('pty-req'),
'pty-req',
1,
strlen('vt100'),
'vt100',
$this->windowColumns,
$this->windowRows,
0,
0,
strlen($terminal_modes),
$terminal_modes
);

if (!$this->_send_binary_packet($packet)) {
return false;
}

$this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_REQUEST;

if (!$this->_get_channel_packet(self::CHANNEL_SHELL)) {
user_error('Unable to request pseudo-terminal');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}

$packet = pack(
'CNNa*C',
NET_SSH2_MSG_CHANNEL_REQUEST,
$this->server_channels[self::CHANNEL_SHELL],
strlen('shell'),
'shell',
1
);
if (!$this->_send_binary_packet($packet)) {
return false;
}

$response = $this->_get_channel_packet(self::CHANNEL_SHELL);
if ($response === false) {
return false;
}

$this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_DATA;

$this->bitmap |= self::MASK_SHELL;

return true;
}









function _get_interactive_channel()
{
switch (true) {
case $this->in_subsystem:
return self::CHANNEL_SUBSYSTEM;
case $this->in_request_pty_exec:
return self::CHANNEL_EXEC;
default:
return self::CHANNEL_SHELL;
}
}







function _get_open_channel()
{
$channel = self::CHANNEL_EXEC;
do {
if (isset($this->channel_status[$channel]) && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_OPEN) {
return $channel;
}
} while ($channel++ < self::CHANNEL_SUBSYSTEM);

return false;
}













function read($expect = '', $mode = self::READ_SIMPLE)
{
$this->curTimeout = $this->timeout;
$this->is_timeout = false;

if (!$this->isAuthenticated()) {
user_error('Operation disallowed prior to login()');
return false;
}

if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
}

$channel = $this->_get_interactive_channel();

if ($mode == self::READ_NEXT) {
return $this->_get_channel_packet($channel);
}

$match = $expect;
while (true) {
if ($mode == self::READ_REGEX) {
preg_match($expect, substr($this->interactiveBuffer, -1024), $matches);
$match = isset($matches[0]) ? $matches[0] : '';
}
$pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false;
if ($pos !== false) {
return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match));
}
$response = $this->_get_channel_packet($channel);
if (is_bool($response)) {
$this->in_request_pty_exec = false;
return $response ? $this->_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer)) : false;
}

$this->interactiveBuffer.= $response;
}
}









function write($cmd)
{
if (!$this->isAuthenticated()) {
user_error('Operation disallowed prior to login()');
return false;
}

if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
}

return $this->_send_channel_packet($this->_get_interactive_channel(), $cmd);
}















function startSubsystem($subsystem)
{
$this->window_size_server_to_client[self::CHANNEL_SUBSYSTEM] = $this->window_size;

$packet = pack(
'CNa*N3',
NET_SSH2_MSG_CHANNEL_OPEN,
strlen('session'),
'session',
self::CHANNEL_SUBSYSTEM,
$this->window_size,
0x4000
);

if (!$this->_send_binary_packet($packet)) {
return false;
}

$this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_OPEN;

$response = $this->_get_channel_packet(self::CHANNEL_SUBSYSTEM);
if ($response === false) {
return false;
}

$packet = pack(
'CNNa*CNa*',
NET_SSH2_MSG_CHANNEL_REQUEST,
$this->server_channels[self::CHANNEL_SUBSYSTEM],
strlen('subsystem'),
'subsystem',
1,
strlen($subsystem),
$subsystem
);
if (!$this->_send_binary_packet($packet)) {
return false;
}

$this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_REQUEST;

$response = $this->_get_channel_packet(self::CHANNEL_SUBSYSTEM);

if ($response === false) {
return false;
}

$this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_DATA;

$this->bitmap |= self::MASK_SHELL;
$this->in_subsystem = true;

return true;
}








function stopSubsystem()
{
$this->in_subsystem = false;
$this->_close_channel(self::CHANNEL_SUBSYSTEM);
return true;
}








function reset()
{
$this->_close_channel($this->_get_interactive_channel());
}








function isTimeout()
{
return $this->is_timeout;
}






function disconnect()
{
$this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
if (isset($this->realtime_log_file) && is_resource($this->realtime_log_file)) {
fclose($this->realtime_log_file);
}
}









function __destruct()
{
$this->disconnect();
}







function isConnected()
{
return (bool) ($this->bitmap & self::MASK_CONNECTED);
}







function isAuthenticated()
{
return (bool) ($this->bitmap & self::MASK_LOGIN);
}









function ping()
{
if (!$this->isAuthenticated()) {
if (!empty($this->auth)) {
return $this->_reconnect();
}
return false;
}

$this->window_size_server_to_client[self::CHANNEL_KEEP_ALIVE] = $this->window_size;
$packet_size = 0x4000;
$packet = pack(
'CNa*N3',
NET_SSH2_MSG_CHANNEL_OPEN,
strlen('session'),
'session',
self::CHANNEL_KEEP_ALIVE,
$this->window_size_server_to_client[self::CHANNEL_KEEP_ALIVE],
$packet_size
);

if (!@$this->_send_binary_packet($packet)) {
return $this->_reconnect();
}

$this->channel_status[self::CHANNEL_KEEP_ALIVE] = NET_SSH2_MSG_CHANNEL_OPEN;

$response = @$this->_get_channel_packet(self::CHANNEL_KEEP_ALIVE);
if ($response !== false) {
$this->_close_channel(self::CHANNEL_KEEP_ALIVE);
return true;
}

return $this->_reconnect();
}







function _reconnect()
{
$this->_reset_connection(NET_SSH2_DISCONNECT_CONNECTION_LOST);
$this->retry_connect = true;
if (!$this->_connect()) {
return false;
}
foreach ($this->auth as $auth) {
$result = call_user_func_array(array(&$this, 'login'), $auth);
}
return $result;
}







function _reset_connection($reason)
{
$this->_disconnect($reason);
$this->decrypt = $this->encrypt = false;
$this->decrypt_block_size = $this->encrypt_block_size = 8;
$this->hmac_check = $this->hmac_create = false;
$this->hmac_size = false;
$this->session_id = false;
$this->retry_connect = true;
$this->get_seq_no = $this->send_seq_no = 0;
}










function _get_binary_packet($skip_channel_filter = false)
{
if ($skip_channel_filter) {
$read = array($this->fsock);
$write = $except = null;

if (!$this->curTimeout) {
if ($this->keepAlive <= 0) {
@stream_select($read, $write, $except, null);
} else {
if (!@stream_select($read, $write, $except, $this->keepAlive) && !count($read)) {
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_IGNORE, 0));
return $this->_get_binary_packet(true);
}
}
} else {
if ($this->curTimeout < 0) {
$this->is_timeout = true;
return true;
}

$read = array($this->fsock);
$write = $except = null;

$start = microtime(true);

if ($this->keepAlive > 0 && $this->keepAlive < $this->curTimeout) {
if (!@stream_select($read, $write, $except, $this->keepAlive) && !count($read)) {
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_IGNORE, 0));
$elapsed = microtime(true) - $start;
$this->curTimeout-= $elapsed;
return $this->_get_binary_packet(true);
}
$elapsed = microtime(true) - $start;
$this->curTimeout-= $elapsed;
}

$sec = floor($this->curTimeout);
$usec = 1000000 * ($this->curTimeout - $sec);


 if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
$this->is_timeout = true;
return true;
}
$elapsed = microtime(true) - $start;
$this->curTimeout-= $elapsed;
}
}

if (!is_resource($this->fsock) || feof($this->fsock)) {
$this->bitmap = 0;
user_error('Connection closed (by server) prematurely ' . $elapsed . 's');
return false;
}

$start = microtime(true);
$raw = stream_get_contents($this->fsock, $this->decrypt_block_size);

if (!strlen($raw)) {
user_error('No data received from server');
return false;
}

if ($this->decrypt !== false) {
$raw = $this->decrypt->decrypt($raw);
}
if ($raw === false) {
user_error('Unable to decrypt content');
return false;
}

if (strlen($raw) < 5) {
return false;
}
extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5)));

$remaining_length = $packet_length + 4 - $this->decrypt_block_size;


 
 
 if ($remaining_length < -$this->decrypt_block_size || $remaining_length > 0x9000 || $remaining_length % $this->decrypt_block_size != 0) {
if (!$this->bad_key_size_fix && $this->_bad_algorithm_candidate($this->decrypt->name) && !($this->bitmap & SSH2::MASK_LOGIN)) {
$this->bad_key_size_fix = true;
$this->_reset_connection(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
return false;
}
user_error('Invalid size');
return false;
}

$buffer = '';
while ($remaining_length > 0) {
$temp = stream_get_contents($this->fsock, $remaining_length);
if ($temp === false || feof($this->fsock)) {
$this->bitmap = 0;
user_error('Error reading from socket');
return false;
}
$buffer.= $temp;
$remaining_length-= strlen($temp);
}

$stop = microtime(true);
if (strlen($buffer)) {
$raw.= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer;
}

$payload = $this->_string_shift($raw, $packet_length - $padding_length - 1);
$padding = $this->_string_shift($raw, $padding_length); 

if ($this->hmac_check !== false) {
$hmac = stream_get_contents($this->fsock, $this->hmac_size);
if ($hmac === false || strlen($hmac) != $this->hmac_size) {
$this->bitmap = 0;
user_error('Error reading socket');
return false;
} elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
user_error('Invalid HMAC');
return false;
}
}

switch ($this->decompress) {
case NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH:
if (!$this->isAuthenticated()) {
break;
}
case NET_SSH2_COMPRESSION_ZLIB:
if ($this->regenerate_decompression_context) {
$this->regenerate_decompression_context = false;

$cmf = ord($payload[0]);
$cm = $cmf & 0x0F;
if ($cm != 8) { 
 user_error("Only CM = 8 ('deflate') is supported ($cm)");
}
$cinfo = ($cmf & 0xF0) >> 4;
if ($cinfo > 7) {
user_error("CINFO above 7 is not allowed ($cinfo)");
}
$windowSize = 1 << ($cinfo + 8);

$flg = ord($payload[1]);

 if ((($cmf << 8) | $flg) % 31) {
user_error('fcheck failed');
}
$fdict = boolval($flg & 0x20);
$flevel = ($flg & 0xC0) >> 6;

$this->decompress_context = inflate_init(ZLIB_ENCODING_RAW, array('window' => $cinfo + 8));
$payload = substr($payload, 2);
}
if ($this->decompress_context) {
$payload = inflate_add($this->decompress_context, $payload, ZLIB_PARTIAL_FLUSH);
}
}

$this->get_seq_no++;

if (defined('NET_SSH2_LOGGING')) {
$current = microtime(true);
$message_number = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN (' . ord($payload[0]) . ')';
$message_number = '<- ' . $message_number .
' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)';
$this->_append_log($message_number, $payload);
$this->last_packet = $current;
}

return $this->_filter($payload, $skip_channel_filter);
}










function _filter($payload, $skip_channel_filter)
{
switch (ord($payload[0])) {
case NET_SSH2_MSG_DISCONNECT:
$this->_string_shift($payload, 1);
if (strlen($payload) < 8) {
return false;
}
extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8)));
$this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . $this->_string_shift($payload, $length);
$this->bitmap = 0;
return false;
case NET_SSH2_MSG_IGNORE:
$payload = $this->_get_binary_packet($skip_channel_filter);
break;
case NET_SSH2_MSG_DEBUG:
$this->_string_shift($payload, 2);
if (strlen($payload) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
$this->errors[] = 'SSH_MSG_DEBUG: ' . $this->_string_shift($payload, $length);
$payload = $this->_get_binary_packet($skip_channel_filter);
break;
case NET_SSH2_MSG_UNIMPLEMENTED:
return false;
case NET_SSH2_MSG_KEXINIT:
if ($this->session_id !== false) {
$this->send_kex_first = false;
if (!$this->_key_exchange($payload)) {
$this->bitmap = 0;
return false;
}
$payload = $this->_get_binary_packet($skip_channel_filter);
}
}


 if (($this->bitmap & self::MASK_CONNECTED) && !$this->isAuthenticated() && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
$this->_string_shift($payload, 1);
if (strlen($payload) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
$this->banner_message = $this->_string_shift($payload, $length);
$payload = $this->_get_binary_packet();
}


 if (($this->bitmap & self::MASK_CONNECTED) && $this->isAuthenticated()) {
if (is_bool($payload)) {
return $payload;
}

switch (ord($payload[0])) {
case NET_SSH2_MSG_CHANNEL_REQUEST:
if (strlen($payload) == 31) {
extract(unpack('cpacket_type/Nchannel/Nlength', $payload));
if (substr($payload, 9, $length) == 'keepalive@openssh.com' && isset($this->server_channels[$channel])) {
if (ord(substr($payload, 9 + $length))) { 
 $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_SUCCESS, $this->server_channels[$channel]));
}
$payload = $this->_get_binary_packet($skip_channel_filter);
}
}
break;
case NET_SSH2_MSG_CHANNEL_DATA:
case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
case NET_SSH2_MSG_CHANNEL_CLOSE:
case NET_SSH2_MSG_CHANNEL_EOF:
if (!$skip_channel_filter && !empty($this->server_channels)) {
$this->binary_packet_buffer = $payload;
$this->_get_channel_packet(true);
$payload = $this->_get_binary_packet();
}
break;
case NET_SSH2_MSG_GLOBAL_REQUEST: 
 if (strlen($payload) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
$this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . $this->_string_shift($payload, $length);

if (!$this->_send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE))) {
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}

$payload = $this->_get_binary_packet($skip_channel_filter);
break;
case NET_SSH2_MSG_CHANNEL_OPEN: 
 $this->_string_shift($payload, 1);
if (strlen($payload) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
$data = $this->_string_shift($payload, $length);
if (strlen($payload) < 4) {
return false;
}
extract(unpack('Nserver_channel', $this->_string_shift($payload, 4)));
switch ($data) {
case 'auth-agent':
case 'auth-agent@openssh.com':
if (isset($this->agent)) {
$new_channel = self::CHANNEL_AGENT_FORWARD;

if (strlen($payload) < 8) {
return false;
}
extract(unpack('Nremote_window_size', $this->_string_shift($payload, 4)));
extract(unpack('Nremote_maximum_packet_size', $this->_string_shift($payload, 4)));

$this->packet_size_client_to_server[$new_channel] = $remote_window_size;
$this->window_size_server_to_client[$new_channel] = $remote_maximum_packet_size;
$this->window_size_client_to_server[$new_channel] = $this->window_size;

$packet_size = 0x4000;

$packet = pack(
'CN4',
NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,
$server_channel,
$new_channel,
$packet_size,
$packet_size
);

$this->server_channels[$new_channel] = $server_channel;
$this->channel_status[$new_channel] = NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION;
if (!$this->_send_binary_packet($packet)) {
return false;
}
}
break;
default:
$packet = pack(
'CN3a*Na*',
NET_SSH2_MSG_REQUEST_FAILURE,
$server_channel,
NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED,
0,
'',
0,
''
);

if (!$this->_send_binary_packet($packet)) {
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
}
$payload = $this->_get_binary_packet($skip_channel_filter);
break;
case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST:
$this->_string_shift($payload, 1);
if (strlen($payload) < 8) {
return false;
}
extract(unpack('Nchannel', $this->_string_shift($payload, 4)));
extract(unpack('Nwindow_size', $this->_string_shift($payload, 4)));
$this->window_size_client_to_server[$channel]+= $window_size;

$payload = ($this->bitmap & self::MASK_WINDOW_ADJUST) ? true : $this->_get_binary_packet($skip_channel_filter);
}
}

return $payload;
}








function enableQuietMode()
{
$this->quiet_mode = true;
}








function disableQuietMode()
{
$this->quiet_mode = false;
}









function isQuietModeEnabled()
{
return $this->quiet_mode;
}






function enablePTY()
{
$this->request_pty = true;
}






function disablePTY()
{
if ($this->in_request_pty_exec) {
$this->_close_channel(self::CHANNEL_EXEC);
$this->in_request_pty_exec = false;
}
$this->request_pty = false;
}









function isPTYEnabled()
{
return $this->request_pty;
}











function _get_channel_packet($client_channel, $skip_extended = false)
{
if (!empty($this->channel_buffers[$client_channel])) {
switch ($this->channel_status[$client_channel]) {
case NET_SSH2_MSG_CHANNEL_REQUEST:
foreach ($this->channel_buffers[$client_channel] as $i => $packet) {
switch (ord($packet[0])) {
case NET_SSH2_MSG_CHANNEL_SUCCESS:
case NET_SSH2_MSG_CHANNEL_FAILURE:
unset($this->channel_buffers[$client_channel][$i]);
return substr($packet, 1);
}
}
break;
default:
return substr(array_shift($this->channel_buffers[$client_channel]), 1);
}
}

while (true) {
if ($this->binary_packet_buffer !== false) {
$response = $this->binary_packet_buffer;
$this->binary_packet_buffer = false;
} else {
$response = $this->_get_binary_packet(true);
if ($response === true && $this->is_timeout) {
if ($client_channel == self::CHANNEL_EXEC && !$this->request_pty) {
$this->_close_channel($client_channel);
}
return true;
}
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
}

if ($client_channel == -1 && $response === true) {
return true;
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));

if (strlen($response) < 4) {
return false;
}
if ($type == NET_SSH2_MSG_CHANNEL_OPEN) {
extract(unpack('Nlength', $this->_string_shift($response, 4)));
} else {
extract(unpack('Nchannel', $this->_string_shift($response, 4)));
}


 if (isset($channel) && isset($this->channel_status[$channel]) && isset($this->window_size_server_to_client[$channel])) {
$this->window_size_server_to_client[$channel]-= strlen($response);


 if ($this->window_size_server_to_client[$channel] < 0) {

 
 $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$channel], $this->window_resize);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$this->window_size_server_to_client[$channel]+= $this->window_resize;
}

switch ($type) {
case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:






 if (strlen($response) < 8) {
return false;
}
extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8)));
$data = $this->_string_shift($response, $length);
$this->stdErrorLog.= $data;
if ($skip_extended || $this->quiet_mode) {
continue 2;
}
if ($client_channel == $channel && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA) {
return $data;
}
$this->channel_buffers[$channel][] = chr($type) . $data;

continue 2;
case NET_SSH2_MSG_CHANNEL_REQUEST:
if ($this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_CLOSE) {
continue 2;
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$value = $this->_string_shift($response, $length);
switch ($value) {
case 'exit-signal':
$this->_string_shift($response, 1);
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length);
$this->_string_shift($response, 1);
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
if ($length) {
$this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length);
}

$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));

$this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF;

continue 3;
case 'exit-status':
if (strlen($response) < 5) {
return false;
}
extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5)));
$this->exit_status = $exit_status;


 

continue 3;
default:

 
 continue 3;
}
}

switch ($this->channel_status[$channel]) {
case NET_SSH2_MSG_CHANNEL_OPEN:
switch ($type) {
case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nserver_channel', $this->_string_shift($response, 4)));
$this->server_channels[$channel] = $server_channel;
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nwindow_size', $this->_string_shift($response, 4)));
if ($window_size < 0) {
$window_size&= 0x7FFFFFFF;
$window_size+= 0x80000000;
}
$this->window_size_client_to_server[$channel] = $window_size;
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Npacket_size_client_to_server', $this->_string_shift($response, 4));
$this->packet_size_client_to_server[$channel] = $temp['packet_size_client_to_server'];
$result = $client_channel == $channel ? true : $this->_get_channel_packet($client_channel, $skip_extended);
$this->_on_channel_open();
return $result;
case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE:
user_error('Unable to open channel');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
default:
if ($client_channel == $channel) {
user_error('Unexpected response to open request');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
return $this->_get_channel_packet($client_channel, $skip_extended);
}
break;
case NET_SSH2_MSG_CHANNEL_REQUEST:
switch ($type) {
case NET_SSH2_MSG_CHANNEL_SUCCESS:
return true;
case NET_SSH2_MSG_CHANNEL_FAILURE:
return false;
case NET_SSH2_MSG_CHANNEL_DATA:
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$data = $this->_string_shift($response, $length);
$this->channel_buffers[$channel][] = chr($type) . $data;
return $this->_get_channel_packet($client_channel, $skip_extended);
default:
user_error('Unable to fulfill channel request');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
case NET_SSH2_MSG_CHANNEL_CLOSE:
return $type == NET_SSH2_MSG_CHANNEL_CLOSE ? true : $this->_get_channel_packet($client_channel, $skip_extended);
}
}



switch ($type) {
case NET_SSH2_MSG_CHANNEL_DATA:









if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$data = $this->_string_shift($response, $length);

if ($channel == self::CHANNEL_AGENT_FORWARD) {
$agent_response = $this->agent->_forward_data($data);
if (!is_bool($agent_response)) {
$this->_send_channel_packet($channel, $agent_response);
}
break;
}

if ($client_channel == $channel) {
return $data;
}
$this->channel_buffers[$channel][] = chr($type) . $data;
break;
case NET_SSH2_MSG_CHANNEL_CLOSE:
$this->curTimeout = 5;

if ($this->bitmap & self::MASK_SHELL) {
$this->bitmap&= ~self::MASK_SHELL;
}
if ($this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_EOF) {
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
}

$this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_CLOSE;
if ($client_channel == $channel) {
return true;
}
case NET_SSH2_MSG_CHANNEL_EOF:
break;
default:
user_error("Error reading channel data ($type)");
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
}
}












function _send_binary_packet($data, $logged = null)
{
if (!is_resource($this->fsock) || feof($this->fsock)) {
$this->bitmap = 0;
user_error('Connection closed prematurely');
return false;
}

if (!isset($logged)) {
$logged = $data;
}

switch ($this->compress) {
case NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH:
if (!$this->isAuthenticated()) {
break;
}
case NET_SSH2_COMPRESSION_ZLIB:
if (!$this->regenerate_compression_context) {
$header = '';
} else {
$this->regenerate_compression_context = false;
$this->compress_context = deflate_init(ZLIB_ENCODING_RAW, ['window' => 15]);
$header = "\x78\x9C";
}
if ($this->compress_context) {
$data = $header . deflate_add($this->compress_context, $data, ZLIB_PARTIAL_FLUSH);
}
}


 $packet_length = strlen($data) + 9;

 $packet_length+= (($this->encrypt_block_size - 1) * $packet_length) % $this->encrypt_block_size;

 $padding_length = $packet_length - strlen($data) - 5;
$padding = Random::string($padding_length);


 $packet = pack('NCa*', $packet_length - 4, $padding_length, $data . $padding);

$hmac = $this->hmac_create !== false ? $this->hmac_create->hash(pack('Na*', $this->send_seq_no, $packet)) : '';
$this->send_seq_no++;

if ($this->encrypt !== false) {
$packet = $this->encrypt->encrypt($packet);
}

$packet.= $hmac;

$start = microtime(true);
$result = strlen($packet) == @fputs($this->fsock, $packet);
$stop = microtime(true);

if (defined('NET_SSH2_LOGGING')) {
$current = microtime(true);
$message_number = isset($this->message_numbers[ord($logged[0])]) ? $this->message_numbers[ord($logged[0])] : 'UNKNOWN (' . ord($logged[0]) . ')';
$message_number = '-> ' . $message_number .
' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)';
$this->_append_log($message_number, $logged);
$this->last_packet = $current;
}

return $result;
}










function _append_log($message_number, $message)
{

 if (strlen($message_number) > 2) {
$this->_string_shift($message);
}

switch (NET_SSH2_LOGGING) {

 case self::LOG_SIMPLE:
$this->message_number_log[] = $message_number;
break;

 case self::LOG_COMPLEX:
$this->message_number_log[] = $message_number;
$this->log_size+= strlen($message);
$this->message_log[] = $message;
while ($this->log_size > self::LOG_MAX_SIZE) {
$this->log_size-= strlen(array_shift($this->message_log));
array_shift($this->message_number_log);
}
break;

 
 
 case self::LOG_REALTIME:
switch (PHP_SAPI) {
case 'cli':
$start = $stop = "\r\n";
break;
default:
$start = '<pre>';
$stop = '</pre>';
}
echo $start . $this->_format_log(array($message), array($message_number)) . $stop;
@flush();
@ob_flush();
break;

 
 
 
 case self::LOG_REALTIME_FILE:
if (!isset($this->realtime_log_file)) {

 $filename = self::LOG_REALTIME_FILENAME;
$fp = fopen($filename, 'w');
$this->realtime_log_file = $fp;
}
if (!is_resource($this->realtime_log_file)) {
break;
}
$entry = $this->_format_log(array($message), array($message_number));
if ($this->realtime_log_wrap) {
$temp = "<<< START >>>\r\n";
$entry.= $temp;
fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp));
}
$this->realtime_log_size+= strlen($entry);
if ($this->realtime_log_size > self::LOG_MAX_SIZE) {
fseek($this->realtime_log_file, 0);
$this->realtime_log_size = strlen($entry);
$this->realtime_log_wrap = true;
}
fputs($this->realtime_log_file, $entry);
}
}











function _send_channel_packet($client_channel, $data)
{
while (strlen($data)) {
if (!$this->window_size_client_to_server[$client_channel]) {
$this->bitmap^= self::MASK_WINDOW_ADJUST;

 $this->_get_channel_packet(-1);
$this->bitmap^= self::MASK_WINDOW_ADJUST;
}





$max_size = min(
$this->packet_size_client_to_server[$client_channel],
$this->window_size_client_to_server[$client_channel]
);

$temp = $this->_string_shift($data, $max_size);
$packet = pack(
'CN2a*',
NET_SSH2_MSG_CHANNEL_DATA,
$this->server_channels[$client_channel],
strlen($temp),
$temp
);
$this->window_size_client_to_server[$client_channel]-= strlen($temp);
if (!$this->_send_binary_packet($packet)) {
return false;
}
}

return true;
}













function _close_channel($client_channel, $want_reply = false)
{


$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));

if (!$want_reply) {
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel]));
}

$this->channel_status[$client_channel] = NET_SSH2_MSG_CHANNEL_CLOSE;

$this->curTimeout = 5;

while (!is_bool($this->_get_channel_packet($client_channel))) {
}

if ($this->is_timeout) {
$this->disconnect();
}

if ($want_reply) {
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel]));
}

if ($this->bitmap & self::MASK_SHELL) {
$this->bitmap&= ~self::MASK_SHELL;
}
}








function _disconnect($reason)
{
if ($this->bitmap & self::MASK_CONNECTED) {
$data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, '');
$this->_send_binary_packet($data);
}

$this->bitmap = 0;
if (is_resource($this->fsock) && get_resource_type($this->fsock) == 'stream') {
fclose($this->fsock);
}

return false;
}











function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}










function _define_array()
{
$args = func_get_args();
foreach ($args as $arg) {
foreach ($arg as $key => $value) {
if (!defined($value)) {
define($value, $key);
} else {
break 2;
}
}
}
}









function getLog()
{
if (!defined('NET_SSH2_LOGGING')) {
return false;
}

switch (NET_SSH2_LOGGING) {
case self::LOG_SIMPLE:
return $this->message_number_log;
case self::LOG_COMPLEX:
$log = $this->_format_log($this->message_log, $this->message_number_log);
return PHP_SAPI == 'cli' ? $log : '<pre>' . $log . '</pre>';
default:
return false;
}
}









function _format_log($message_log, $message_number_log)
{
$output = '';
for ($i = 0; $i < count($message_log); $i++) {
$output.= $message_number_log[$i] . "\r\n";
$current_log = $message_log[$i];
$j = 0;
do {
if (strlen($current_log)) {
$output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0  ';
}
$fragment = $this->_string_shift($current_log, $this->log_short_width);
$hex = substr(preg_replace_callback('#.#s', array($this, '_format_log_helper'), $fragment), strlen($this->log_boundary));

 
 
 $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment);
$output.= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n";
$j++;
} while (strlen($current_log));
$output.= "\r\n";
}

return $output;
}










function _format_log_helper($matches)
{
return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT);
}










function _on_channel_open()
{
if (isset($this->agent)) {
$this->agent->_on_channel_open($this);
}
}










function _array_intersect_first($array1, $array2)
{
foreach ($array1 as $value) {
if (in_array($value, $array2)) {
return $value;
}
}
return false;
}







function getErrors()
{
return $this->errors;
}







function getLastError()
{
$count = count($this->errors);

if ($count > 0) {
return $this->errors[$count - 1];
}
}







function getServerIdentification()
{
$this->_connect();

return $this->server_identifier;
}







function getKexAlgorithms()
{
$this->_connect();

return $this->kex_algorithms;
}







function getServerHostKeyAlgorithms()
{
$this->_connect();

return $this->server_host_key_algorithms;
}







function getEncryptionAlgorithmsClient2Server()
{
$this->_connect();

return $this->encryption_algorithms_client_to_server;
}







function getEncryptionAlgorithmsServer2Client()
{
$this->_connect();

return $this->encryption_algorithms_server_to_client;
}







function getMACAlgorithmsClient2Server()
{
$this->_connect();

return $this->mac_algorithms_client_to_server;
}







function getMACAlgorithmsServer2Client()
{
$this->_connect();

return $this->mac_algorithms_server_to_client;
}







function getCompressionAlgorithmsClient2Server()
{
$this->_connect();

return $this->compression_algorithms_client_to_server;
}







function getCompressionAlgorithmsServer2Client()
{
$this->_connect();

return $this->compression_algorithms_server_to_client;
}







function getLanguagesServer2Client()
{
$this->_connect();

return $this->languages_server_to_client;
}







function getLanguagesClient2Server()
{
$this->_connect();

return $this->languages_client_to_server;
}







function getServerAlgorithms()
{
$this->_connect();

return array(
'kex' => $this->kex_algorithms,
'hostkey' => $this->server_host_key_algorithms,
'client_to_server' => array(
'crypt' => $this->encryption_algorithms_client_to_server,
'mac' => $this->mac_algorithms_client_to_server,
'comp' => $this->compression_algorithms_client_to_server,
'lang' => $this->languages_client_to_server
),
'server_to_client' => array(
'crypt' => $this->encryption_algorithms_server_to_client,
'mac' => $this->mac_algorithms_server_to_client,
'comp' => $this->compression_algorithms_server_to_client,
'lang' => $this->languages_server_to_client
)
);
}







function getSupportedKEXAlgorithms()
{
$kex_algorithms = array(

 
 
 'curve25519-sha256@libssh.org',

'diffie-hellman-group-exchange-sha256',
 'diffie-hellman-group-exchange-sha1', 


 
 'diffie-hellman-group14-sha1', 
 'diffie-hellman-group1-sha1', 
 );

if (!function_exists('sodium_crypto_box_publickey_from_secretkey')) {
$kex_algorithms = array_diff(
$kex_algorithms,
array('curve25519-sha256@libssh.org')
);
}

return $kex_algorithms;
}







function getSupportedHostKeyAlgorithms()
{
return array(
'rsa-sha2-256', 
 'rsa-sha2-512', 
 'ssh-rsa', 
 'ssh-dss' 
 );
}







function getSupportedEncryptionAlgorithms()
{
$algos = array(

 'arcfour256',
'arcfour128',




 'aes128-ctr', 
 'aes192-ctr', 
 'aes256-ctr', 

'twofish128-ctr', 
 'twofish192-ctr', 
 'twofish256-ctr', 

'aes128-cbc', 
 'aes192-cbc', 
 'aes256-cbc', 

'twofish128-cbc', 
 'twofish192-cbc', 
 'twofish256-cbc',
'twofish-cbc', 
 

'blowfish-ctr', 

'blowfish-cbc', 

'3des-ctr', 

'3des-cbc', 


 );

if ($this->crypto_engine) {
$engines = array($this->crypto_engine);
} else {
$engines = array(
Base::ENGINE_OPENSSL,
Base::ENGINE_MCRYPT,
Base::ENGINE_INTERNAL
);
}

$ciphers = array();
foreach ($engines as $engine) {
foreach ($algos as $algo) {
$obj = $this->_encryption_algorithm_to_crypt_instance($algo);
if ($obj instanceof Rijndael) {
$obj->setKeyLength(preg_replace('#[^\d]#', '', $algo));
}
switch ($algo) {
case 'arcfour128':
case 'arcfour256':
if ($engine != Base::ENGINE_INTERNAL) {
continue 2;
}
}
if ($obj->isValidEngine($engine)) {
$algos = array_diff($algos, array($algo));
$ciphers[] = $algo;
}
}
}

return $ciphers;
}







function getSupportedMACAlgorithms()
{
return array(

 'hmac-sha2-256',

'hmac-sha1-96', 
 'hmac-sha1', 
 'hmac-md5-96', 
 'hmac-md5', 
 
 );
}







function getSupportedCompressionAlgorithms()
{
$algos = array('none'); 
 if (function_exists('deflate_init')) {
$algos[] = 'zlib@openssh.com'; 
 $algos[] = 'zlib';
}
return $algos;
}









function getAlgorithmsNegotiated()
{
$this->_connect();

$compression_map = array(
NET_SSH2_COMPRESSION_NONE => 'none',
NET_SSH2_COMPRESSION_ZLIB => 'zlib',
NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH => 'zlib@openssh.com'
);

return array(
'kex' => $this->kex_algorithm,
'hostkey' => $this->signature_format,
'client_to_server' => array(
'crypt' => $this->encrypt->name,
'mac' => $this->hmac_create->name,
'comp' => $compression_map[$this->compress],
),
'server_to_client' => array(
'crypt' => $this->decrypt->name,
'mac' => $this->hmac_check->name,
'comp' => $compression_map[$this->decompress],
)
);
}








function setPreferredAlgorithms($methods)
{
$preferred = $methods;

if (isset($preferred['kex'])) {
$preferred['kex'] = array_intersect(
$preferred['kex'],
$this->getSupportedKEXAlgorithms()
);
}

if (isset($preferred['hostkey'])) {
$preferred['hostkey'] = array_intersect(
$preferred['hostkey'],
$this->getSupportedHostKeyAlgorithms()
);
}

$keys = array('client_to_server', 'server_to_client');
foreach ($keys as $key) {
if (isset($preferred[$key])) {
$a = &$preferred[$key];
if (isset($a['crypt'])) {
$a['crypt'] = array_intersect(
$a['crypt'],
$this->getSupportedEncryptionAlgorithms()
);
}
if (isset($a['comp'])) {
$a['comp'] = array_intersect(
$a['comp'],
$this->getSupportedCompressionAlgorithms()
);
}
if (isset($a['mac'])) {
$a['mac'] = array_intersect(
$a['mac'],
$this->getSupportedMACAlgorithms()
);
}
}
}

$keys = array(
'kex',
'hostkey',
'client_to_server/crypt',
'client_to_server/comp',
'client_to_server/mac',
'server_to_client/crypt',
'server_to_client/comp',
'server_to_client/mac',
);
foreach ($keys as $key) {
$p = $preferred;
$m = $methods;

$subkeys = explode('/', $key);
foreach ($subkeys as $subkey) {
if (!isset($p[$subkey])) {
continue 2;
}
$p = $p[$subkey];
$m = $m[$subkey];
}

if (count($p) != count($m)) {
$diff = array_diff($m, $p);
$msg = count($diff) == 1 ?
' is not a supported algorithm' :
' are not supported algorithms';
user_error(implode(', ', $diff) . $msg);
return false;
}
}

$this->preferred = $preferred;
}










function getBannerMessage()
{
return $this->banner_message;
}










function getServerPublicHostKey()
{
if (!($this->bitmap & self::MASK_CONSTRUCTOR)) {
if (!$this->_connect()) {
return false;
}
}

$signature = $this->signature;
$server_public_host_key = $this->server_public_host_key;

if (strlen($server_public_host_key) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4)));
$this->_string_shift($server_public_host_key, $length);

if ($this->signature_validated) {
return $this->bitmap ?
$this->signature_format . ' ' . base64_encode($this->server_public_host_key) :
false;
}

$this->signature_validated = true;

switch ($this->signature_format) {
case 'ssh-dss':
$zero = new BigInteger();

if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$p = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);

if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$q = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);

if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$g = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);

if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$y = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);




$temp = unpack('Nlength', $this->_string_shift($signature, 4));
if ($temp['length'] != 40) {
user_error('Invalid signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}

$r = new BigInteger($this->_string_shift($signature, 20), 256);
$s = new BigInteger($this->_string_shift($signature, 20), 256);

switch (true) {
case $r->equals($zero):
case $r->compare($q) >= 0:
case $s->equals($zero):
case $s->compare($q) >= 0:
user_error('Invalid signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}

$w = $s->modInverse($q);

$u1 = $w->multiply(new BigInteger(sha1($this->exchange_hash), 16));
list(, $u1) = $u1->divide($q);

$u2 = $w->multiply($r);
list(, $u2) = $u2->divide($q);

$g = $g->modPow($u1, $p);
$y = $y->modPow($u2, $p);

$v = $g->multiply($y);
list(, $v) = $v->divide($p);
list(, $v) = $v->divide($q);

if (!$v->equals($r)) {
user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}

break;
case 'ssh-rsa':
case 'rsa-sha2-256':
case 'rsa-sha2-512':
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$e = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);

if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$rawN = $this->_string_shift($server_public_host_key, $temp['length']);
$n = new BigInteger($rawN, -256);
$nLength = strlen(ltrim($rawN, "\0"));






























if (strlen($signature) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($signature, 4));
$s = new BigInteger($this->_string_shift($signature, $temp['length']), 256);


 
 



if ($s->compare(new BigInteger()) < 0 || $s->compare($n->subtract(new BigInteger(1))) > 0) {
user_error('Invalid signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}

$s = $s->modPow($e, $n);
$s = $s->toBytes();

switch ($this->signature_format) {
case 'rsa-sha2-512':
$hash = 'sha512';
break;
case 'rsa-sha2-256':
$hash = 'sha256';
break;

 default:
$hash = 'sha1';
}
$hashObj = new Hash($hash);
switch ($this->signature_format) {
case 'rsa-sha2-512':
$h = pack('N5a*', 0x00305130, 0x0D060960, 0x86480165, 0x03040203, 0x05000440, $hashObj->hash($this->exchange_hash));
break;
case 'rsa-sha2-256':
$h = pack('N5a*', 0x00303130, 0x0D060960, 0x86480165, 0x03040201, 0x05000420, $hashObj->hash($this->exchange_hash));
break;

 default:
$hash = 'sha1';
$h = pack('N4a*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, $hashObj->hash($this->exchange_hash));
}
$h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h;

if ($s != $h) {
user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}
break;
default:
user_error('Unsupported signature format');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}

return $this->signature_format . ' ' . base64_encode($this->server_public_host_key);
}







function getExitStatus()
{
if (is_null($this->exit_status)) {
return false;
}
return $this->exit_status;
}







function getWindowColumns()
{
return $this->windowColumns;
}







function getWindowRows()
{
return $this->windowRows;
}







function setWindowColumns($value)
{
$this->windowColumns = $value;
}







function setWindowRows($value)
{
$this->windowRows = $value;
}








function setWindowSize($columns = 80, $rows = 24)
{
$this->windowColumns = $columns;
$this->windowRows = $rows;
}








function _updateLogHistory($old, $new)
{
if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == self::LOG_COMPLEX) {
$this->message_number_log[count($this->message_number_log) - 1] = str_replace(
$old,
$new,
$this->message_number_log[count($this->message_number_log) - 1]
);
}
}







function getAuthMethodsToContinue()
{
return $this->auth_methods_to_continue;
}




function enableSmartMFA()
{
$this->smartMFA = true;
}




function disableSmartMFA()
{
$this->smartMFA = false;
}
}
<?php


































namespace phpseclib\Net;








class SFTP extends SSH2
{









const CHANNEL = 0x100;








const SOURCE_LOCAL_FILE = 1;




 const SOURCE_STRING = 2;




const SOURCE_CALLBACK = 16;



const RESUME = 4;



const RESUME_START = 8;









var $packet_types = array();








var $status_codes = array();











var $use_request_id = false;











var $packet_type = -1;








var $packet_buffer = '';








var $extensions = array();








var $version;








var $defaultVersion;








var $preferredVersion = 3;









var $pwd = false;








var $packet_type_log = array();








var $packet_log = array();









var $sftp_errors = array();













var $stat_cache = array();









var $max_sftp_packet;









var $use_stat_cache = true;









var $sortOptions = array();













var $canonicalize_paths = true;








var $requestBuffer = array();









var $preserveTime = false;














var $allow_arbitrary_length_packets = false;









var $channel_close = false;







var $partial_init = false;












function __construct($host, $port = 22, $timeout = 10)
{
parent::__construct($host, $port, $timeout);

$this->max_sftp_packet = 1 << 15;

$this->packet_types = array(
1 => 'NET_SFTP_INIT',
2 => 'NET_SFTP_VERSION',
3 => 'NET_SFTP_OPEN',
4 => 'NET_SFTP_CLOSE',
5 => 'NET_SFTP_READ',
6 => 'NET_SFTP_WRITE',
7 => 'NET_SFTP_LSTAT',
9 => 'NET_SFTP_SETSTAT',
10 => 'NET_SFTP_FSETSTAT',
11 => 'NET_SFTP_OPENDIR',
12 => 'NET_SFTP_READDIR',
13 => 'NET_SFTP_REMOVE',
14 => 'NET_SFTP_MKDIR',
15 => 'NET_SFTP_RMDIR',
16 => 'NET_SFTP_REALPATH',
17 => 'NET_SFTP_STAT',
18 => 'NET_SFTP_RENAME',
19 => 'NET_SFTP_READLINK',
20 => 'NET_SFTP_SYMLINK',
21 => 'NET_SFTP_LINK',

101=> 'NET_SFTP_STATUS',
102=> 'NET_SFTP_HANDLE',
103=> 'NET_SFTP_DATA',
104=> 'NET_SFTP_NAME',
105=> 'NET_SFTP_ATTRS',

200=> 'NET_SFTP_EXTENDED'
);
$this->status_codes = array(
0 => 'NET_SFTP_STATUS_OK',
1 => 'NET_SFTP_STATUS_EOF',
2 => 'NET_SFTP_STATUS_NO_SUCH_FILE',
3 => 'NET_SFTP_STATUS_PERMISSION_DENIED',
4 => 'NET_SFTP_STATUS_FAILURE',
5 => 'NET_SFTP_STATUS_BAD_MESSAGE',
6 => 'NET_SFTP_STATUS_NO_CONNECTION',
7 => 'NET_SFTP_STATUS_CONNECTION_LOST',
8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED',
9 => 'NET_SFTP_STATUS_INVALID_HANDLE',
10 => 'NET_SFTP_STATUS_NO_SUCH_PATH',
11 => 'NET_SFTP_STATUS_FILE_ALREADY_EXISTS',
12 => 'NET_SFTP_STATUS_WRITE_PROTECT',
13 => 'NET_SFTP_STATUS_NO_MEDIA',
14 => 'NET_SFTP_STATUS_NO_SPACE_ON_FILESYSTEM',
15 => 'NET_SFTP_STATUS_QUOTA_EXCEEDED',
16 => 'NET_SFTP_STATUS_UNKNOWN_PRINCIPAL',
17 => 'NET_SFTP_STATUS_LOCK_CONFLICT',
18 => 'NET_SFTP_STATUS_DIR_NOT_EMPTY',
19 => 'NET_SFTP_STATUS_NOT_A_DIRECTORY',
20 => 'NET_SFTP_STATUS_INVALID_FILENAME',
21 => 'NET_SFTP_STATUS_LINK_LOOP',
22 => 'NET_SFTP_STATUS_CANNOT_DELETE',
23 => 'NET_SFTP_STATUS_INVALID_PARAMETER',
24 => 'NET_SFTP_STATUS_FILE_IS_A_DIRECTORY',
25 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_CONFLICT',
26 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_REFUSED',
27 => 'NET_SFTP_STATUS_DELETE_PENDING',
28 => 'NET_SFTP_STATUS_FILE_CORRUPT',
29 => 'NET_SFTP_STATUS_OWNER_INVALID',
30 => 'NET_SFTP_STATUS_GROUP_INVALID',
31 => 'NET_SFTP_STATUS_NO_MATCHING_BYTE_RANGE_LOCK'
);

 
 $this->attributes = array(
0x00000001 => 'NET_SFTP_ATTR_SIZE',
0x00000002 => 'NET_SFTP_ATTR_UIDGID', 
 0x00000080 => 'NET_SFTP_ATTR_OWNERGROUP', 
 0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS',
0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME',
0x00000010 => 'NET_SFTP_ATTR_CREATETIME', 
 0x00000020 => 'NET_SFTP_ATTR_MODIFYTIME',
0x00000040 => 'NET_SFTP_ATTR_ACL',
0x00000100 => 'NET_SFTP_ATTR_SUBSECOND_TIMES',
0x00000200 => 'NET_SFTP_ATTR_BITS', 
 0x00000400 => 'NET_SFTP_ATTR_ALLOCATION_SIZE', 
 0x00000800 => 'NET_SFTP_ATTR_TEXT_HINT',
0x00001000 => 'NET_SFTP_ATTR_MIME_TYPE',
0x00002000 => 'NET_SFTP_ATTR_LINK_COUNT',
0x00004000 => 'NET_SFTP_ATTR_UNTRANSLATED_NAME',
0x00008000 => 'NET_SFTP_ATTR_CTIME',

 
 
 
 (-1 << 31) & 0xFFFFFFFF => 'NET_SFTP_ATTR_EXTENDED'
);
$this->open_flags = array(
0x00000001 => 'NET_SFTP_OPEN_READ',
0x00000002 => 'NET_SFTP_OPEN_WRITE',
0x00000004 => 'NET_SFTP_OPEN_APPEND',
0x00000008 => 'NET_SFTP_OPEN_CREATE',
0x00000010 => 'NET_SFTP_OPEN_TRUNCATE',
0x00000020 => 'NET_SFTP_OPEN_EXCL',
0x00000040 => 'NET_SFTP_OPEN_TEXT' 
 );

 
 $this->open_flags5 = array(

 0x00000000 => 'NET_SFTP_OPEN_CREATE_NEW',
0x00000001 => 'NET_SFTP_OPEN_CREATE_TRUNCATE',
0x00000002 => 'NET_SFTP_OPEN_OPEN_EXISTING',
0x00000003 => 'NET_SFTP_OPEN_OPEN_OR_CREATE',
0x00000004 => 'NET_SFTP_OPEN_TRUNCATE_EXISTING',

 0x00000008 => 'NET_SFTP_OPEN_APPEND_DATA', 
 0x00000010 => 'NET_SFTP_OPEN_APPEND_DATA_ATOMIC',
0x00000020 => 'NET_SFTP_OPEN_TEXT_MODE',
0x00000040 => 'NET_SFTP_OPEN_BLOCK_READ',
0x00000080 => 'NET_SFTP_OPEN_BLOCK_WRITE',
0x00000100 => 'NET_SFTP_OPEN_BLOCK_DELETE',
0x00000200 => 'NET_SFTP_OPEN_BLOCK_ADVISORY',
0x00000400 => 'NET_SFTP_OPEN_NOFOLLOW',
0x00000800 => 'NET_SFTP_OPEN_DELETE_ON_CLOSE',
0x00001000 => 'NET_SFTP_OPEN_ACCESS_AUDIT_ALARM_INFO',
0x00002000 => 'NET_SFTP_OPEN_ACCESS_BACKUP',
0x00004000 => 'NET_SFTP_OPEN_BACKUP_STREAM',
0x00008000 => 'NET_SFTP_OPEN_OVERRIDE_OWNER',
);

 
 $this->file_types = array(
1 => 'NET_SFTP_TYPE_REGULAR',
2 => 'NET_SFTP_TYPE_DIRECTORY',
3 => 'NET_SFTP_TYPE_SYMLINK',
4 => 'NET_SFTP_TYPE_SPECIAL',
5 => 'NET_SFTP_TYPE_UNKNOWN',

 
 6 => 'NET_SFTP_TYPE_SOCKET',
7 => 'NET_SFTP_TYPE_CHAR_DEVICE',
8 => 'NET_SFTP_TYPE_BLOCK_DEVICE',
9 => 'NET_SFTP_TYPE_FIFO'
);
$this->_define_array(
$this->packet_types,
$this->status_codes,
$this->attributes,
$this->open_flags,
$this->open_flags5,
$this->file_types
);

if (!defined('NET_SFTP_QUEUE_SIZE')) {
define('NET_SFTP_QUEUE_SIZE', 32);
}
if (!defined('NET_SFTP_UPLOAD_QUEUE_SIZE')) {
define('NET_SFTP_UPLOAD_QUEUE_SIZE', 1024);
}
}







function _precheck()
{
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
return false;
}

if ($this->pwd === false) {
return $this->_init_sftp_connection();
}

return true;
}







function _partial_init_sftp_connection()
{
$this->window_size_server_to_client[self::CHANNEL] = $this->window_size;

$packet = pack(
'CNa*N3',
NET_SSH2_MSG_CHANNEL_OPEN,
strlen('session'),
'session',
self::CHANNEL,
$this->window_size,
0x4000
);

if (!$this->_send_binary_packet($packet)) {
return false;
}

$this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_OPEN;

$response = $this->_get_channel_packet(self::CHANNEL, true);
if ($response === false) {
return false;
} elseif ($response === true && $this->isTimeout()) {
return false;
}

$packet = pack(
'CNNa*CNa*',
NET_SSH2_MSG_CHANNEL_REQUEST,
$this->server_channels[self::CHANNEL],
strlen('subsystem'),
'subsystem',
1,
strlen('sftp'),
'sftp'
);
if (!$this->_send_binary_packet($packet)) {
return false;
}

$this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;

$response = $this->_get_channel_packet(self::CHANNEL, true);
if ($response === false) {

 $command = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" .
"test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n" .
"exec sftp-server";

 
 $packet = pack(
'CNNa*CNa*',
NET_SSH2_MSG_CHANNEL_REQUEST,
$this->server_channels[self::CHANNEL],
strlen('exec'),
'exec',
1,
strlen($command),
$command
);
if (!$this->_send_binary_packet($packet)) {
return false;
}

$this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;

$response = $this->_get_channel_packet(self::CHANNEL, true);
if ($response === false) {
return false;
}
} elseif ($response === true && $this->isTimeout()) {
return false;
}

$this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA;

if (!$this->_send_sftp_packet(NET_SFTP_INIT, "\0\0\0\3")) {
return false;
}

$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_VERSION) {
user_error('Expected SSH_FXP_VERSION');
return false;
}

$this->use_request_id = true;

if (strlen($response) < 4) {
return false;
}
extract(unpack('Nversion', $this->_string_shift($response, 4)));
$this->defaultVersion = $version;
while (!empty($response)) {
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$key = $this->_string_shift($response, $length);
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$value = $this->_string_shift($response, $length);
$this->extensions[$key] = $value;
}

$this->partial_init = true;

return true;
}







function _init_sftp_connection()
{
if (!$this->partial_init && !$this->_partial_init_sftp_connection()) {
return false;
}
























$this->version = $this->defaultVersion;
if (isset($this->extensions['versions']) && (!$this->preferredVersion || $this->preferredVersion != $this->version)) {
$versions = explode(',', $this->extensions['versions']);
$supported = array(6, 5, 4);
if ($this->preferredVersion) {
$supported = array_diff($supported, array($this->preferredVersion));
array_unshift($supported, $this->preferredVersion);
}
foreach ($supported as $ver) {
if (in_array($ver, $versions)) {
if ($ver === $this->version) {
break;
}
$this->version = (int) $ver;
$packet = pack('Na*Na*', strlen('version-select'), 'version-select', strlen($ver), $ver);
if (!$this->_send_sftp_packet(NET_SFTP_EXTENDED, $packet)) {
return false;
}
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}

if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->_logError($response, $status);
return false;
}

break;
}
}
}















if ($this->version < 2 || $this->version > 6) {
return false;
}

$this->pwd = $this->_realpath('.');

$this->_update_stat_cache($this->pwd, array());

return true;
}






function disableStatCache()
{
$this->use_stat_cache = false;
}






function enableStatCache()
{
$this->use_stat_cache = true;
}






function clearStatCache()
{
$this->stat_cache = array();
}






function enablePathCanonicalization()
{
$this->canonicalize_paths = true;
}






function disablePathCanonicalization()
{
$this->canonicalize_paths = false;
}






function enableArbitraryLengthPackets()
{
$this->allow_arbitrary_length_packets = true;
}






function disableArbitraryLengthPackets()
{
$this->allow_arbitrary_length_packets = false;
}







function pwd()
{
if (!$this->_precheck()) {
return false;
}

return $this->pwd;
}








function _logError($response, $status = -1)
{
if ($status == -1) {
if (strlen($response) < 4) {
return;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
}

$error = $this->status_codes[$status];

if ($this->version > 2 || strlen($response) < 4) {
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$this->sftp_errors[] = $error . ': ' . $this->_string_shift($response, $length);
} else {
$this->sftp_errors[] = $error;
}
}











function realpath($path)
{
if (!$this->_precheck()) {
return false;
}

return $this->_realpath($path);
}















function _realpath($path)
{
if (!$this->canonicalize_paths) {
return $path;
}

if ($this->pwd === false) {

 if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($path), $path))) {
return false;
}

$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_NAME:

 
 
 $this->_string_shift($response, 4); 
 if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
return $this->_string_shift($response, $length);
case NET_SFTP_STATUS:
$this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
return false;
}
}

if (!strlen($path) || $path[0] != '/') {
$path = $this->pwd . '/' . $path;
}

$path = explode('/', $path);
$new = array();
foreach ($path as $dir) {
if (!strlen($dir)) {
continue;
}
switch ($dir) {
case '..':
array_pop($new);
case '.':
break;
default:
$new[] = $dir;
}
}

return '/' . implode('/', $new);
}








function chdir($dir)
{
if (!$this->_precheck()) {
return false;
}


 if ($dir === '') {
$dir = './';

 } elseif ($dir[strlen($dir) - 1] != '/') {
$dir.= '/';
}

$dir = $this->_realpath($dir);


 if ($this->use_stat_cache && is_array($this->_query_stat_cache($dir))) {
$this->pwd = $dir;
return true;
}


 
 
 

if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
return false;
}


 $response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_HANDLE:
$handle = substr($response, 4);
break;
case NET_SFTP_STATUS:
$this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
}

if (!$this->_close_handle($handle)) {
return false;
}

$this->_update_stat_cache($dir, array());

$this->pwd = $dir;
return true;
}









function nlist($dir = '.', $recursive = false)
{
return $this->_nlist_helper($dir, $recursive, '');
}










function _nlist_helper($dir, $recursive, $relativeDir)
{
$files = $this->_list($dir, false);

if (!$recursive || $files === false) {
return $files;
}

$result = array();
foreach ($files as $value) {
if ($value == '.' || $value == '..') {
if ($relativeDir == '') {
$result[] = $value;
}
continue;
}
if (is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $value)))) {
$temp = $this->_nlist_helper($dir . '/' . $value, true, $relativeDir . $value . '/');
$temp = is_array($temp) ? $temp : array();
$result = array_merge($result, $temp);
} else {
$result[] = $relativeDir . $value;
}
}

return $result;
}









function rawlist($dir = '.', $recursive = false)
{
$files = $this->_list($dir, true);
if (!$recursive || $files === false) {
return $files;
}

static $depth = 0;

foreach ($files as $key => $value) {
if ($depth != 0 && $key == '..') {
unset($files[$key]);
continue;
}
$is_directory = false;
if ($key != '.' && $key != '..') {
if ($this->use_stat_cache) {
$is_directory = is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $key)));
} else {
$stat = $this->lstat($dir . '/' . $key);
$is_directory = $stat && $stat['type'] === NET_SFTP_TYPE_DIRECTORY;
}
}

if ($is_directory) {
$depth++;
$files[$key] = $this->rawlist($dir . '/' . $key, true);
$depth--;
} else {
$files[$key] = (object) $value;
}
}

return $files;
}









function _list($dir, $raw = true)
{
if (!$this->_precheck()) {
return false;
}

$dir = $this->_realpath($dir . '/');
if ($dir === false) {
return false;
}


 if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
return false;
}

$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_HANDLE:

 
 
 $handle = substr($response, 4);
break;
case NET_SFTP_STATUS:

 $this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
}

$this->_update_stat_cache($dir, array());

$contents = array();
while (true) {

 
 
 if (!$this->_send_sftp_packet(NET_SFTP_READDIR, pack('Na*', strlen($handle), $handle))) {
return false;
}

$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_NAME:
if (strlen($response) < 4) {
return false;
}
extract(unpack('Ncount', $this->_string_shift($response, 4)));
for ($i = 0; $i < $count; $i++) {
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$shortname = $this->_string_shift($response, $length);

 
 if ($this->version < 4) {
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$longname = $this->_string_shift($response, $length);
}
$attributes = $this->_parseAttributes($response);
if (!isset($attributes['type']) && $this->version < 4) {
$fileType = $this->_parseLongname($longname);
if ($fileType) {
$attributes['type'] = $fileType;
}
}
$contents[$shortname] = $attributes + array('filename' => $shortname);

if (isset($attributes['type']) && $attributes['type'] == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) {
$this->_update_stat_cache($dir . '/' . $shortname, array());
} else {
if ($shortname == '..') {
$temp = $this->_realpath($dir . '/..') . '/.';
} else {
$temp = $dir . '/' . $shortname;
}
$this->_update_stat_cache($temp, (object) array('lstat' => $attributes));
}

 
 }
break;
case NET_SFTP_STATUS:
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_EOF) {
$this->_logError($response, $status);
return false;
}
break 2;
default:
user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
return false;
}
}

if (!$this->_close_handle($handle)) {
return false;
}

if (count($this->sortOptions)) {
uasort($contents, array(&$this, '_comparator'));
}

return $raw ? $contents : array_map('strval', array_keys($contents));
}











function _comparator($a, $b)
{
switch (true) {
case $a['filename'] === '.' || $b['filename'] === '.':
if ($a['filename'] === $b['filename']) {
return 0;
}
return $a['filename'] === '.' ? -1 : 1;
case $a['filename'] === '..' || $b['filename'] === '..':
if ($a['filename'] === $b['filename']) {
return 0;
}
return $a['filename'] === '..' ? -1 : 1;
case isset($a['type']) && $a['type'] === NET_SFTP_TYPE_DIRECTORY:
if (!isset($b['type'])) {
return 1;
}
if ($b['type'] !== $a['type']) {
return -1;
}
break;
case isset($b['type']) && $b['type'] === NET_SFTP_TYPE_DIRECTORY:
return 1;
}
foreach ($this->sortOptions as $sort => $order) {
if (!isset($a[$sort]) || !isset($b[$sort])) {
if (isset($a[$sort])) {
return -1;
}
if (isset($b[$sort])) {
return 1;
}
return 0;
}
switch ($sort) {
case 'filename':
$result = strcasecmp($a['filename'], $b['filename']);
if ($result) {
return $order === SORT_DESC ? -$result : $result;
}
break;
case 'permissions':
case 'mode':
$a[$sort]&= 07777;
$b[$sort]&= 07777;
default:
if ($a[$sort] === $b[$sort]) {
break;
}
return $order === SORT_ASC ? $a[$sort] - $b[$sort] : $b[$sort] - $a[$sort];
}
}
}





















function setListOrder()
{
$this->sortOptions = array();
$args = func_get_args();
if (empty($args)) {
return;
}
$len = count($args) & 0x7FFFFFFE;
for ($i = 0; $i < $len; $i+=2) {
$this->sortOptions[$args[$i]] = $args[$i + 1];
}
if (!count($this->sortOptions)) {
$this->sortOptions = array('bogus' => true);
}
}










function size($filename)
{
$result = $this->stat($filename);
if ($result === false) {
return false;
}
return isset($result['size']) ? $result['size'] : -1;
}








function _update_stat_cache($path, $value)
{
if ($this->use_stat_cache === false) {
return;
}


 $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));

$temp = &$this->stat_cache;
$max = count($dirs) - 1;
foreach ($dirs as $i => $dir) {

 
 
 if (is_object($temp)) {
$temp = array();
}
if (!isset($temp[$dir])) {
$temp[$dir] = array();
}
if ($i === $max) {
if (is_object($temp[$dir]) && is_object($value)) {
if (!isset($value->stat) && isset($temp[$dir]->stat)) {
$value->stat = $temp[$dir]->stat;
}
if (!isset($value->lstat) && isset($temp[$dir]->lstat)) {
$value->lstat = $temp[$dir]->lstat;
}
}
$temp[$dir] = $value;
break;
}
$temp = &$temp[$dir];
}
}








function _remove_from_stat_cache($path)
{
$dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));

$temp = &$this->stat_cache;
$max = count($dirs) - 1;
foreach ($dirs as $i => $dir) {
if (!is_array($temp)) {
return false;
}
if ($i === $max) {
unset($temp[$dir]);
return true;
}
if (!isset($temp[$dir])) {
return false;
}
$temp = &$temp[$dir];
}
}










function _query_stat_cache($path)
{
$dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));

$temp = &$this->stat_cache;
foreach ($dirs as $dir) {
if (!is_array($temp)) {
return null;
}
if (!isset($temp[$dir])) {
return null;
}
$temp = &$temp[$dir];
}
return $temp;
}










function stat($filename)
{
if (!$this->_precheck()) {
return false;
}

$filename = $this->_realpath($filename);
if ($filename === false) {
return false;
}

if ($this->use_stat_cache) {
$result = $this->_query_stat_cache($filename);
if (is_array($result) && isset($result['.']) && isset($result['.']->stat)) {
return $result['.']->stat;
}
if (is_object($result) && isset($result->stat)) {
return $result->stat;
}
}

$stat = $this->_stat($filename, NET_SFTP_STAT);
if ($stat === false) {
$this->_remove_from_stat_cache($filename);
return false;
}
if (isset($stat['type'])) {
if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
$filename.= '/.';
}
$this->_update_stat_cache($filename, (object) array('stat' => $stat));
return $stat;
}

$pwd = $this->pwd;
$stat['type'] = $this->chdir($filename) ?
NET_SFTP_TYPE_DIRECTORY :
NET_SFTP_TYPE_REGULAR;
$this->pwd = $pwd;

if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
$filename.= '/.';
}
$this->_update_stat_cache($filename, (object) array('stat' => $stat));

return $stat;
}










function lstat($filename)
{
if (!$this->_precheck()) {
return false;
}

$filename = $this->_realpath($filename);
if ($filename === false) {
return false;
}

if ($this->use_stat_cache) {
$result = $this->_query_stat_cache($filename);
if (is_array($result) && isset($result['.']) && isset($result['.']->lstat)) {
return $result['.']->lstat;
}
if (is_object($result) && isset($result->lstat)) {
return $result->lstat;
}
}

$lstat = $this->_stat($filename, NET_SFTP_LSTAT);
if ($lstat === false) {
$this->_remove_from_stat_cache($filename);
return false;
}
if (isset($lstat['type'])) {
if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
$filename.= '/.';
}
$this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
return $lstat;
}

$stat = $this->_stat($filename, NET_SFTP_STAT);

if ($lstat != $stat) {
$lstat = array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK));
$this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
return $stat;
}

$pwd = $this->pwd;
$lstat['type'] = $this->chdir($filename) ?
NET_SFTP_TYPE_DIRECTORY :
NET_SFTP_TYPE_REGULAR;
$this->pwd = $pwd;

if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
$filename.= '/.';
}
$this->_update_stat_cache($filename, (object) array('lstat' => $lstat));

return $lstat;
}












function _stat($filename, $type)
{

 $packet = pack('Na*', strlen($filename), $filename);
if (!$this->_send_sftp_packet($type, $packet)) {
return false;
}

$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_ATTRS:
return $this->_parseAttributes($response);
case NET_SFTP_STATUS:
$this->_logError($response);
return false;
}

user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
return false;
}









function truncate($filename, $new_size)
{
$attr = pack('N3', NET_SFTP_ATTR_SIZE, $new_size / 4294967296, $new_size); 

return $this->_setstat($filename, $attr, false);
}












function touch($filename, $time = null, $atime = null)
{
if (!$this->_precheck()) {
return false;
}

$filename = $this->_realpath($filename);
if ($filename === false) {
return false;
}

if (!isset($time)) {
$time = time();
}
if (!isset($atime)) {
$atime = $time;
}

if ($this->version < 4) {
$attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $atime, $time);
} else {
$attr = pack(
'N5',
NET_SFTP_ATTR_ACCESSTIME | NET_SFTP_ATTR_MODIFYTIME,
$atime / 4294967296,
$atime,
$time / 4294967296,
$time
);
}

$packet = pack('Na*', strlen($filename), $filename);
$packet.= $this->version >= 5 ?
pack('N2', 0, NET_SFTP_OPEN_OPEN_EXISTING) :
pack('N', NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_EXCL);
$packet.= $attr;

if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
return false;
}

$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_HANDLE:
return $this->_close_handle(substr($response, 4));
case NET_SFTP_STATUS:
$this->_logError($response);
break;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
}

return $this->_setstat($filename, $attr, false);
}

















function chown($filename, $uid, $recursive = false)
{

















$attr = $this->version < 4 ?

 
 pack('N3', NET_SFTP_ATTR_UIDGID, $uid, -1) :

 
 
 
 pack('NNa*Na*', NET_SFTP_ATTR_OWNERGROUP, strlen($uid), $uid, 0, '');

return $this->_setstat($filename, $attr, $recursive);
}

















function chgrp($filename, $gid, $recursive = false)
{
$attr = $this->version < 4 ?
pack('N3', NET_SFTP_ATTR_UIDGID, $gid, -1) :
pack('NNa*Na*', NET_SFTP_ATTR_OWNERGROUP, 0, '', strlen($gid), $gid);

return $this->_setstat($filename, $attr, $recursive);
}













function chmod($mode, $filename, $recursive = false)
{
if (is_string($mode) && is_int($filename)) {
$temp = $mode;
$mode = $filename;
$filename = $temp;
}

$attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
if (!$this->_setstat($filename, $attr, $recursive)) {
return false;
}
if ($recursive) {
return true;
}

$filename = $this->realpath($filename);

 
 
 $packet = pack('Na*', strlen($filename), $filename);
if (!$this->_send_sftp_packet(NET_SFTP_STAT, $packet)) {
return false;
}

$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_ATTRS:
$attrs = $this->_parseAttributes($response);
return $attrs['permissions'];
case NET_SFTP_STATUS:
$this->_logError($response);
return false;
}

user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
return false;
}










function _setstat($filename, $attr, $recursive)
{
if (!$this->_precheck()) {
return false;
}

$filename = $this->_realpath($filename);
if ($filename === false) {
return false;
}

$this->_remove_from_stat_cache($filename);

if ($recursive) {
$i = 0;
$result = $this->_setstat_recursive($filename, $attr, $i);
$this->_read_put_responses($i);
return $result;
}

$packet = $this->version >= 4 ?
pack('Na*a*Ca*', strlen($filename), $filename, substr($attr, 0, 4), NET_SFTP_TYPE_UNKNOWN, substr($attr, 4)) :
pack('Na*a*', strlen($filename), $filename, $attr);
if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, $packet)) {
return false;
}








$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}

if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->_logError($response, $status);
return false;
}

return true;
}












function _setstat_recursive($path, $attr, &$i)
{
if (!$this->_read_put_responses($i)) {
return false;
}
$i = 0;
$entries = $this->_list($path, true);

if ($entries === false) {
return $this->_setstat($path, $attr, false);
}


 
 if (empty($entries)) {
return false;
}

unset($entries['.'], $entries['..']);
foreach ($entries as $filename => $props) {
if (!isset($props['type'])) {
return false;
}

$temp = $path . '/' . $filename;
if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) {
if (!$this->_setstat_recursive($temp, $attr, $i)) {
return false;
}
} else {
$packet = $this->version >= 4 ?
pack('Na*Ca*', strlen($temp), $temp, NET_SFTP_TYPE_UNKNOWN, $attr) :
pack('Na*a*', strlen($temp), $temp, $attr);
if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, $packet)) {
return false;
}

$i++;

if ($i >= NET_SFTP_QUEUE_SIZE) {
if (!$this->_read_put_responses($i)) {
return false;
}
$i = 0;
}
}
}

$packet = $this->version >= 4 ?
pack('Na*Ca*', strlen($temp), $temp, NET_SFTP_TYPE_UNKNOWN, $attr) :
pack('Na*a*', strlen($temp), $temp, $attr);
if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, $packet)) {
return false;
}

$i++;

if ($i >= NET_SFTP_QUEUE_SIZE) {
if (!$this->_read_put_responses($i)) {
return false;
}
$i = 0;
}

return true;
}








function readlink($link)
{
if (!$this->_precheck()) {
return false;
}

$link = $this->_realpath($link);

if (!$this->_send_sftp_packet(NET_SFTP_READLINK, pack('Na*', strlen($link), $link))) {
return false;
}

$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_NAME:
break;
case NET_SFTP_STATUS:
$this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
return false;
}

if (strlen($response) < 4) {
return false;
}
extract(unpack('Ncount', $this->_string_shift($response, 4)));

 if (!$count) {
return false;
}

if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
return $this->_string_shift($response, $length);
}











function symlink($target, $link)
{
if (!$this->_precheck()) {
return false;
}


 $link = $this->_realpath($link);








if ($this->version == 6) {
$type = NET_SFTP_LINK;
$packet = pack('Na*Na*C', strlen($link), $link, strlen($target), $target, 1);
} else {
$type = NET_SFTP_SYMLINK;














$packet = substr($this->server_identifier, 0, 15) == 'SSH-2.0-OpenSSH' ?
pack('Na*Na*', strlen($target), $target, strlen($link), $link) :
pack('Na*Na*', strlen($link), $link, strlen($target), $target);
}
if (!$this->_send_sftp_packet($type, $packet)) {
return false;
}

$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}

if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->_logError($response, $status);
return false;
}

return true;
}










function mkdir($dir, $mode = -1, $recursive = false)
{
if (!$this->_precheck()) {
return false;
}

$dir = $this->_realpath($dir);

if ($recursive) {
$dirs = explode('/', preg_replace('#/(?=/)|/$#', '', $dir));
if (empty($dirs[0])) {
array_shift($dirs);
$dirs[0] = '/' . $dirs[0];
}
for ($i = 0; $i < count($dirs); $i++) {
$temp = array_slice($dirs, 0, $i + 1);
$temp = implode('/', $temp);
$result = $this->_mkdir_helper($temp, $mode);
}
return $result;
}

return $this->_mkdir_helper($dir, $mode);
}









function _mkdir_helper($dir, $mode)
{

 if (!$this->_send_sftp_packet(NET_SFTP_MKDIR, pack('Na*a*', strlen($dir), $dir, "\0\0\0\0"))) {
return false;
}

$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}

if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->_logError($response, $status);
return false;
}

if ($mode !== -1) {
$this->chmod($mode, $dir);
}

return true;
}








function rmdir($dir)
{
if (!$this->_precheck()) {
return false;
}

$dir = $this->_realpath($dir);
if ($dir === false) {
return false;
}

if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($dir), $dir))) {
return false;
}

$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}

if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {

 $this->_logError($response, $status);
return false;
}

$this->_remove_from_stat_cache($dir);

 
 
 

return true;
}















































function put($remote_file, $data, $mode = self::SOURCE_STRING, $start = -1, $local_start = -1, $progressCallback = null)
{
if (!$this->_precheck()) {
return false;
}

$remote_file = $this->_realpath($remote_file);
if ($remote_file === false) {
return false;
}

$this->_remove_from_stat_cache($remote_file);

if ($this->version >= 5) {
$flags = NET_SFTP_OPEN_OPEN_OR_CREATE;
} else {
$flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE;

 
 
 }

if ($start >= 0) {
$offset = $start;
} elseif ($mode & self::RESUME) {

 $size = $this->size($remote_file);
$offset = $size !== false ? $size : 0;
} else {
$offset = 0;
if ($this->version >= 5) {
$flags = NET_SFTP_OPEN_CREATE_TRUNCATE;
} else {
$flags|= NET_SFTP_OPEN_TRUNCATE;
}
}

$packet = pack('Na*', strlen($remote_file), $remote_file);
$packet.= $this->version >= 5 ?
pack('N3', 0, $flags, 0) :
pack('N2', $flags, 0);
if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
return false;
}

$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_HANDLE:
$handle = substr($response, 4);
break;
case NET_SFTP_STATUS:
$this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
}


 $dataCallback = false;
switch (true) {
case $mode & self::SOURCE_CALLBACK:
if (!is_callable($data)) {
user_error("\$data should be is_callable() if you specify SOURCE_CALLBACK flag");
}
$dataCallback = $data;

 break;
case is_resource($data):
$mode = $mode & ~self::SOURCE_LOCAL_FILE;
$info = stream_get_meta_data($data);
if ($info['wrapper_type'] == 'PHP' && $info['stream_type'] == 'Input') {
$fp = fopen('php://memory', 'w+');
stream_copy_to_stream($data, $fp);
rewind($fp);
} else {
$fp = $data;
}
break;
case $mode & self::SOURCE_LOCAL_FILE:
if (!is_file($data)) {
user_error("$data is not a valid file");
return false;
}
$fp = @fopen($data, 'rb');
if (!$fp) {
return false;
}
}

if (isset($fp)) {
$stat = fstat($fp);
$size = !empty($stat) ? $stat['size'] : 0;

if ($local_start >= 0) {
fseek($fp, $local_start);
$size-= $local_start;
}
} elseif ($dataCallback) {
$size = 0;
} else {
$size = strlen($data);
}

$sent = 0;
$size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size;

$sftp_packet_size = $this->max_sftp_packet;

 $sftp_packet_size-= strlen($handle) + 25;
$i = $j = 0;
while ($dataCallback || ($size === 0 || $sent < $size)) {
if ($dataCallback) {
$temp = call_user_func($dataCallback, $sftp_packet_size);
if (is_null($temp)) {
break;
}
} else {
$temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size);
if ($temp === false || $temp === '') {
break;
}
}

$subtemp = $offset + $sent;
$packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp);
if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet, $j)) {
if ($mode & self::SOURCE_LOCAL_FILE) {
fclose($fp);
}
return false;
}
$sent+= strlen($temp);
if (is_callable($progressCallback)) {
call_user_func($progressCallback, $sent);
}

$i++;
$j++;

if ($i == NET_SFTP_UPLOAD_QUEUE_SIZE) {
if (!$this->_read_put_responses($i)) {
$i = 0;
break;
}
$i = 0;
}
}

$result = $this->_close_handle($handle);

if (!$this->_read_put_responses($i)) {
if ($mode & self::SOURCE_LOCAL_FILE) {
fclose($fp);
}
$this->_close_handle($handle);
return false;
}

if ($mode & SFTP::SOURCE_LOCAL_FILE) {
if (isset($fp) && is_resource($fp)) {
fclose($fp);
}

if ($this->preserveTime) {
$stat = stat($data);
if ($this->version < 4) {
$attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $stat['atime'], $stat['mtime']);
} else {
$attr = pack(
'N5',
NET_SFTP_ATTR_ACCESSTIME | NET_SFTP_ATTR_MODIFYTIME,
$stat['atime'] / 4294967296,
$stat['atime'],
$stat['mtime'] / 4294967296,
$stat['mtime']
);
}

if (!$this->_setstat($remote_file, $attr, false)) {
user_error('Error setting file time');
}
}
}

return $result;
}











function _read_put_responses($i)
{
while ($i--) {
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}

if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->_logError($response, $status);
break;
}
}

return $i < 0;
}








function _close_handle($handle)
{
if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
return false;
}


 
 $response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}

if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->_logError($response, $status);
return false;
}

return true;
}


















function get($remote_file, $local_file = false, $offset = 0, $length = -1, $progressCallback = null)
{
if (!$this->_precheck()) {
return false;
}

$remote_file = $this->_realpath($remote_file);
if ($remote_file === false) {
return false;
}

$packet = pack('Na*', strlen($remote_file), $remote_file);
$packet.= $this->version >= 5 ?
pack('N3', 0, NET_SFTP_OPEN_OPEN_EXISTING, 0) :
pack('N2', NET_SFTP_OPEN_READ, 0);
if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
return false;
}

$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_HANDLE:
$handle = substr($response, 4);
break;
case NET_SFTP_STATUS: 
 $this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
}

if (is_resource($local_file)) {
$fp = $local_file;
$stat = fstat($fp);
$res_offset = $stat['size'];
} else {
$res_offset = 0;
if ($local_file !== false && !is_callable($local_file)) {
$fp = fopen($local_file, 'wb');
if (!$fp) {
return false;
}
} else {
$content = '';
}
}

$fclose_check = $local_file !== false && !is_callable($local_file) && !is_resource($local_file);

$start = $offset;
$read = 0;
while (true) {
$i = 0;

while ($i < NET_SFTP_QUEUE_SIZE && ($length < 0 || $read < $length)) {
$tempoffset = $start + $read;

$packet_size = $length > 0 ? min($this->max_sftp_packet, $length - $read) : $this->max_sftp_packet;

$packet = pack('Na*N3', strlen($handle), $handle, $tempoffset / 4294967296, $tempoffset, $packet_size);
if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet, $i)) {
if ($fclose_check) {
fclose($fp);
}
return false;
}
$packet = null;
$read+= $packet_size;
$i++;
}

if (!$i) {
break;
}

$packets_sent = $i - 1;

$clear_responses = false;
while ($i > 0) {
$i--;

if ($clear_responses) {
$this->_get_sftp_packet($packets_sent - $i);
continue;
} else {
$response = $this->_get_sftp_packet($packets_sent - $i);
}

switch ($this->packet_type) {
case NET_SFTP_DATA:
$temp = substr($response, 4);
$offset+= strlen($temp);
if ($local_file === false) {
$content.= $temp;
} elseif (is_callable($local_file)) {
$local_file($temp);
} else {
fputs($fp, $temp);
}
if (is_callable($progressCallback)) {
call_user_func($progressCallback, $offset);
}
$temp = null;
break;
case NET_SFTP_STATUS:

 $this->_logError($response);
$clear_responses = true; 
 break;
default:
if ($fclose_check) {
fclose($fp);
}

 if ($this->channel_close) {
$this->partial_init = false;
$this->_init_sftp_connection();
return false;
} else {
user_error('Expected SSH_FX_DATA or SSH_FXP_STATUS');
}
}
$response = null;
}

if ($clear_responses) {
break;
}
}

if ($length > 0 && $length <= $offset - $start) {
if ($local_file === false) {
$content = substr($content, 0, $length);
} else {
ftruncate($fp, $length + $res_offset);
}
}

if ($fclose_check) {
fclose($fp);

if ($this->preserveTime) {
$stat = $this->stat($remote_file);
touch($local_file, $stat['mtime'], $stat['atime']);
}
}

if (!$this->_close_handle($handle)) {
return false;
}


 return isset($content) ? $content : true;
}









function delete($path, $recursive = true)
{
if (!$this->_precheck()) {
return false;
}

if (is_object($path)) {

 $path = (string) $path;
}

if (!is_string($path) || $path == '') {
return false;
}

$path = $this->_realpath($path);
if ($path === false) {
return false;
}


 if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($path), $path))) {
return false;
}

$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}


 if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->_logError($response, $status);
if (!$recursive) {
return false;
}
$i = 0;
$result = $this->_delete_recursive($path, $i);
$this->_read_put_responses($i);
return $result;
}

$this->_remove_from_stat_cache($path);

return true;
}











function _delete_recursive($path, &$i)
{
if (!$this->_read_put_responses($i)) {
return false;
}
$i = 0;
$entries = $this->_list($path, true);


 
 if (empty($entries)) {
return false;
}

unset($entries['.'], $entries['..']);
foreach ($entries as $filename => $props) {
if (!isset($props['type'])) {
return false;
}

$temp = $path . '/' . $filename;
if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) {
if (!$this->_delete_recursive($temp, $i)) {
return false;
}
} else {
if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($temp), $temp))) {
return false;
}
$this->_remove_from_stat_cache($temp);

$i++;

if ($i >= NET_SFTP_QUEUE_SIZE) {
if (!$this->_read_put_responses($i)) {
return false;
}
$i = 0;
}
}
}

if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($path), $path))) {
return false;
}
$this->_remove_from_stat_cache($path);

$i++;

if ($i >= NET_SFTP_QUEUE_SIZE) {
if (!$this->_read_put_responses($i)) {
return false;
}
$i = 0;
}

return true;
}








function file_exists($path)
{
if ($this->use_stat_cache) {
if (!$this->_precheck()) {
return false;
}

$path = $this->_realpath($path);

$result = $this->_query_stat_cache($path);

if (isset($result)) {

 return $result !== false;
}
}

return $this->stat($path) !== false;
}








function is_dir($path)
{
$result = $this->_get_stat_cache_prop($path, 'type');
if ($result === false) {
return false;
}
return $result === NET_SFTP_TYPE_DIRECTORY;
}








function is_file($path)
{
$result = $this->_get_stat_cache_prop($path, 'type');
if ($result === false) {
return false;
}
return $result === NET_SFTP_TYPE_REGULAR;
}








function is_link($path)
{
$result = $this->_get_lstat_cache_prop($path, 'type');
if ($result === false) {
return false;
}
return $result === NET_SFTP_TYPE_SYMLINK;
}








function is_readable($path)
{
if (!$this->_precheck()) {
return false;
}

$path = $this->_realpath($path);

$packet = pack('Na*N2', strlen($path), $path, NET_SFTP_OPEN_READ, 0);
if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
return false;
}

$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_HANDLE:
return true;
case NET_SFTP_STATUS: 
 return false;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
}
}








function is_writable($path)
{
if (!$this->_precheck()) {
return false;
}

$path = $this->_realpath($path);

$packet = pack('Na*N2', strlen($path), $path, NET_SFTP_OPEN_WRITE, 0);
if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
return false;
}

$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_HANDLE:
return true;
case NET_SFTP_STATUS: 
 return false;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
}
}










function is_writeable($path)
{
return $this->is_writable($path);
}








function fileatime($path)
{
return $this->_get_stat_cache_prop($path, 'atime');
}








function filemtime($path)
{
return $this->_get_stat_cache_prop($path, 'mtime');
}








function fileperms($path)
{
return $this->_get_stat_cache_prop($path, 'permissions');
}








function fileowner($path)
{
return $this->_get_stat_cache_prop($path, 'uid');
}








function filegroup($path)
{
return $this->_get_stat_cache_prop($path, 'gid');
}








function filesize($path)
{
return $this->_get_stat_cache_prop($path, 'size');
}








function filetype($path)
{
$type = $this->_get_stat_cache_prop($path, 'type');
if ($type === false) {
return false;
}

switch ($type) {
case NET_SFTP_TYPE_BLOCK_DEVICE:
return 'block';
case NET_SFTP_TYPE_CHAR_DEVICE:
return 'char';
case NET_SFTP_TYPE_DIRECTORY:
return 'dir';
case NET_SFTP_TYPE_FIFO:
return 'fifo';
case NET_SFTP_TYPE_REGULAR:
return 'file';
case NET_SFTP_TYPE_SYMLINK:
return 'link';
default:
return false;
}
}











function _get_stat_cache_prop($path, $prop)
{
return $this->_get_xstat_cache_prop($path, $prop, 'stat');
}











function _get_lstat_cache_prop($path, $prop)
{
return $this->_get_xstat_cache_prop($path, $prop, 'lstat');
}












function _get_xstat_cache_prop($path, $prop, $type)
{
if (!$this->_precheck()) {
return false;
}

if ($this->use_stat_cache) {
$path = $this->_realpath($path);

$result = $this->_query_stat_cache($path);

if (is_object($result) && isset($result->$type)) {
return $result->{$type}[$prop];
}
}

$result = $this->$type($path);

if ($result === false || !isset($result[$prop])) {
return false;
}

return $result[$prop];
}











function rename($oldname, $newname)
{
if (!$this->_precheck()) {
return false;
}

$oldname = $this->_realpath($oldname);
$newname = $this->_realpath($newname);
if ($oldname === false || $newname === false) {
return false;
}


 $packet = pack('Na*Na*', strlen($oldname), $oldname, strlen($newname), $newname);
if ($this->version >= 5) {









$packet.= "\0\0\0\0";
}
if (!$this->_send_sftp_packet(NET_SFTP_RENAME, $packet)) {
return false;
}

$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}


 if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->_logError($response, $status);
return false;
}


 
 
 $this->_remove_from_stat_cache($oldname);
$this->_remove_from_stat_cache($newname);

return true;
}












function _parseTime($key, $flags, &$response)
{
if (strlen($response) < 8) {
user_error('Malformed file attributes');
return array();
}
$attr = array();
$attr[$key] = hexdec(bin2hex($this->_string_shift($response, 8)));
if ($flags & NET_SFTP_ATTR_SUBSECOND_TIMES) {
$attr+= extract(unpack('N' . $key . '_nseconds', $this->_string_shift($response, 4)));
}
return $attr;
}










function _parseAttributes(&$response)
{
if ($this->version >= 4) {
$length = 5;
$format = 'Nflags/Ctype';
} else {
$length = 4;
$format = 'Nflags';
}

$attr = array();
if (strlen($response) < $length) {
user_error('Malformed file attributes');
return array();
}
extract(unpack($format, $this->_string_shift($response, $length)));
if (isset($type)) {
$attr['type'] = $type;
}
foreach ($this->attributes as $key => $value) {
switch ($flags & $key) {
case NET_SFTP_ATTR_UIDGID:
if ($this->version > 3) {
continue 2;
}
break;
case NET_SFTP_ATTR_CREATETIME:
case NET_SFTP_ATTR_MODIFYTIME:
case NET_SFTP_ATTR_ACL:
case NET_SFTP_ATTR_OWNERGROUP:
case NET_SFTP_ATTR_SUBSECOND_TIMES:
if ($this->version < 4) {
continue 2;
}
break;
case NET_SFTP_ATTR_BITS:
if ($this->version < 5) {
continue 2;
}
break;
case NET_SFTP_ATTR_ALLOCATION_SIZE:
case NET_SFTP_ATTR_TEXT_HINT:
case NET_SFTP_ATTR_MIME_TYPE:
case NET_SFTP_ATTR_LINK_COUNT:
case NET_SFTP_ATTR_UNTRANSLATED_NAME:
case NET_SFTP_ATTR_CTIME:
if ($this->version < 6) {
continue 2;
}
}
switch ($flags & $key) {
case NET_SFTP_ATTR_SIZE: 
 
 
 
 
 
 
 $attr['size'] = hexdec(bin2hex($this->_string_shift($response, 8)));
break;
case NET_SFTP_ATTR_UIDGID: 
 if (strlen($response) < 8) {
user_error('Malformed file attributes');
return $attr;
}
$attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8));
break;
case NET_SFTP_ATTR_PERMISSIONS: 
 if (strlen($response) < 4) {
user_error('Malformed file attributes');
return $attr;
}
$attr+= unpack('Npermissions', $this->_string_shift($response, 4));

 
 $attr+= array('mode' => $attr['permissions']);
$fileType = $this->_parseMode($attr['permissions']);
if ($fileType !== false) {
$attr+= array('type' => $fileType);
}
break;
case NET_SFTP_ATTR_ACCESSTIME: 
 if ($this->version >= 4) {
$attr+= $this->_parseTime('atime', $flags, $response);
break;
}
if (strlen($response) < 8) {
user_error('Malformed file attributes');
return $attr;
}
$attr+= unpack('Natime/Nmtime', $this->_string_shift($response, 8));
break;
case NET_SFTP_ATTR_CREATETIME: 
 $attr+= $this->_parseTime('createtime', $flags, $response);
break;
case NET_SFTP_ATTR_MODIFYTIME: 
 $attr+= $this->_parseTime('mtime', $flags, $response);
break;
case NET_SFTP_ATTR_ACL: 
 
 
 
 if (strlen($response) < 4) {
user_error('Malformed file attributes');
return $attr;
}
extract(unpack('Ncount', $this->_string_shift($response, 4)));
for ($i = 0; $i < $count; $i++) {
if (strlen($response) < 16) {
user_error('Malformed file attributes');
return $attr;
}
extract(unpack('Ntype/Nflag/Nmask/Nlength', $this->_string_shift($response, 16)));
if (strlen($response) < $length) {
user_error('Malformed file attributes');
return $attr;
}
$this->_string_shift($response, $length); 
 }
break;
case NET_SFTP_ATTR_OWNERGROUP: 
 if (strlen($response) < 4) {
user_error('Malformed file attributes');
return $attr;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
if (strlen($response) < $length) {
user_error('Malformed file attributes');
return $attr;
}
$attr['owner'] = $this->_string_shift($response, $length);

if (strlen($response) < 4) {
user_error('Malformed file attributes');
return $attr;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
if (strlen($response) < $length) {
user_error('Malformed file attributes');
return $attr;
}
$attr['group'] = $this->_string_shift($response, $length);
break;
case NET_SFTP_ATTR_SUBSECOND_TIMES: 
 break;
case NET_SFTP_ATTR_BITS: 
 
 
 
 
 
 if (strlen($response) < 8) {
user_error('Malformed file attributes');
return $attr;
}
extract(unpack('Nattrib-bits/Nattrib-bits-valid', $this->_string_shift($response, 8)));
break;
case NET_SFTP_ATTR_ALLOCATION_SIZE: 
 
 
 
 $attr['allocation-size'] = hexdec(bin2hex($this->_string_shift($response, 8)));
break;
case NET_SFTP_ATTR_TEXT_HINT: 
 
 
 
 extract(unpack('Ctext-hint', $this->_string_shift($response)));
break;
case NET_SFTP_ATTR_MIME_TYPE: 
 
 if (strlen($response) < 4) {
user_error('Malformed file attributes');
return $attr;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
if (strlen($response) < $length) {
user_error('Malformed file attributes');
return $attr;
}
$attr['mime-type'] = $this->_string_shift($response, $length);
break;
case NET_SFTP_ATTR_LINK_COUNT: 
 
 if (strlen($response) < 4) {
user_error('Malformed file attributes');
return $attr;
}
$attr+= unpack('Nlink-count', $this->_string_shift($response, 4));
break;
case NET_SFTP_ATTR_UNTRANSLATED_NAME:
 
 if (strlen($response) < 4) {
user_error('Malformed file attributes');
return $attr;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
if (strlen($response) < $length) {
user_error('Malformed file attributes');
return $attr;
}
$attr['untranslated-name'] = $this->_string_shift($response, $length);
break;
case NET_SFTP_ATTR_CTIME: 
 
 
 $attr+= $this->_parseTime('ctime', $flags, $response);
break;
case NET_SFTP_ATTR_EXTENDED: 
 if (strlen($response) < 4) {
user_error('Malformed file attributes');
return $attr;
}
extract(unpack('Ncount', $this->_string_shift($response, 4)));
for ($i = 0; $i < $count; $i++) {
if (strlen($response) < 4) {
user_error('Malformed file attributes');
return $attr;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$key = $this->_string_shift($response, $length);
if (strlen($response) < 4) {
user_error('Malformed file attributes');
return $attr;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$attr[$key] = $this->_string_shift($response, $length);
}
}
}
return $attr;
}










function _parseMode($mode)
{

 
 switch ($mode & 0170000) {
 case 0000000: 
 return false;
case 0040000:
return NET_SFTP_TYPE_DIRECTORY;
case 0100000:
return NET_SFTP_TYPE_REGULAR;
case 0120000:
return NET_SFTP_TYPE_SYMLINK;

 
 case 0010000: 
 return NET_SFTP_TYPE_FIFO;
case 0020000: 
 return NET_SFTP_TYPE_CHAR_DEVICE;
case 0060000: 
 return NET_SFTP_TYPE_BLOCK_DEVICE;
case 0140000: 
 return NET_SFTP_TYPE_SOCKET;
case 0160000: 
 
 
 return NET_SFTP_TYPE_SPECIAL;
default:
return NET_SFTP_TYPE_UNKNOWN;
}
}
















function _parseLongname($longname)
{

 
 if (preg_match('#^[^/]([r-][w-][xstST-]){3}#', $longname)) {
switch ($longname[0]) {
case '-':
return NET_SFTP_TYPE_REGULAR;
case 'd':
return NET_SFTP_TYPE_DIRECTORY;
case 'l':
return NET_SFTP_TYPE_SYMLINK;
default:
return NET_SFTP_TYPE_SPECIAL;
}
}

return false;
}














function _send_sftp_packet($type, $data, $request_id = 1)
{

 
 $this->curTimeout = $this->timeout;

$packet = $this->use_request_id ?
pack('NCNa*', strlen($data) + 5, $type, $request_id, $data) :
pack('NCa*', strlen($data) + 1, $type, $data);

$start = strtok(microtime(), ' ') + strtok(''); 
 $result = $this->_send_channel_packet(self::CHANNEL, $packet);
$stop = strtok(microtime(), ' ') + strtok('');

if (defined('NET_SFTP_LOGGING')) {
$packet_type = '-> ' . $this->packet_types[$type] .
' (' . round($stop - $start, 4) . 's)';
if (NET_SFTP_LOGGING == self::LOG_REALTIME) {
switch (PHP_SAPI) {
case 'cli':
$start = $stop = "\r\n";
break;
default:
$start = '<pre>';
$stop = '</pre>';
}
echo $start . $this->_format_log(array($data), array($packet_type)) . $stop;
@flush();
@ob_flush();
} else {
$this->packet_type_log[] = $packet_type;
if (NET_SFTP_LOGGING == self::LOG_COMPLEX) {
$this->packet_log[] = $data;
}
}
}

return $result;
}







function _reset_connection($reason)
{
parent::_reset_connection($reason);
$this->use_request_id = false;
$this->pwd = false;
$this->requestBuffer = array();
}














function _get_sftp_packet($request_id = null)
{
$this->channel_close = false;

if (isset($request_id) && isset($this->requestBuffer[$request_id])) {
$this->packet_type = $this->requestBuffer[$request_id]['packet_type'];
$temp = $this->requestBuffer[$request_id]['packet'];
unset($this->requestBuffer[$request_id]);
return $temp;
}


 
 $this->curTimeout = $this->timeout;

$start = strtok(microtime(), ' ') + strtok(''); 


 while (strlen($this->packet_buffer) < 4) {
$temp = $this->_get_channel_packet(self::CHANNEL, true);
if ($temp === true) {
if ($this->channel_status[self::CHANNEL] === NET_SSH2_MSG_CHANNEL_CLOSE) {
$this->channel_close = true;
}
$this->packet_type = false;
$this->packet_buffer = '';
return false;
}
if ($temp === false) {
return false;
}
$this->packet_buffer.= $temp;
}
if (strlen($this->packet_buffer) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($this->packet_buffer, 4)));
$tempLength = $length;
$tempLength-= strlen($this->packet_buffer);


 if (!$this->allow_arbitrary_length_packets && !$this->use_request_id && $tempLength > 256 * 1024) {
user_error('Invalid SFTP packet size');
return false;
}


 while ($tempLength > 0) {
$temp = $this->_get_channel_packet(self::CHANNEL, true);
if (is_bool($temp)) {
$this->packet_type = false;
$this->packet_buffer = '';
return false;
}
$this->packet_buffer.= $temp;
$tempLength-= strlen($temp);
}

$stop = strtok(microtime(), ' ') + strtok('');

$this->packet_type = ord($this->_string_shift($this->packet_buffer));

if ($this->use_request_id) {
extract(unpack('Npacket_id', $this->_string_shift($this->packet_buffer, 4))); 
 $length-= 5; 
 } else {
$length-= 1; 
 }

$packet = $this->_string_shift($this->packet_buffer, $length);

if (defined('NET_SFTP_LOGGING')) {
$packet_type = '<- ' . $this->packet_types[$this->packet_type] .
' (' . round($stop - $start, 4) . 's)';
if (NET_SFTP_LOGGING == self::LOG_REALTIME) {
switch (PHP_SAPI) {
case 'cli':
$start = $stop = "\r\n";
break;
default:
$start = '<pre>';
$stop = '</pre>';
}
echo $start . $this->_format_log(array($packet), array($packet_type)) . $stop;
@flush();
@ob_flush();
} else {
$this->packet_type_log[] = $packet_type;
if (NET_SFTP_LOGGING == self::LOG_COMPLEX) {
$this->packet_log[] = $packet;
}
}
}

if (isset($request_id) && $this->use_request_id && $packet_id != $request_id) {
$this->requestBuffer[$packet_id] = array(
'packet_type' => $this->packet_type,
'packet' => $packet
);
return $this->_get_sftp_packet($request_id);
}

return $packet;
}









function getSFTPLog()
{
if (!defined('NET_SFTP_LOGGING')) {
return false;
}

switch (NET_SFTP_LOGGING) {
case self::LOG_COMPLEX:
return $this->_format_log($this->packet_log, $this->packet_type_log);
break;

 default:
return $this->packet_type_log;
}
}







function getSFTPErrors()
{
return $this->sftp_errors;
}







function getLastSFTPError()
{
return count($this->sftp_errors) ? $this->sftp_errors[count($this->sftp_errors) - 1] : '';
}







function getSupportedVersions()
{
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
return false;
}

if (!$this->partial_init) {
$this->_partial_init_sftp_connection();
}

$temp = array('version' => $this->defaultVersion);
if (isset($this->extensions['versions'])) {
$temp['extensions'] = $this->extensions['versions'];
}
return $temp;
}







function getNegotiatedVersion()
{
if (!$this->_precheck()) {
return false;
}

return $this->version;
}











function setPreferredVersion($version)
{
$this->preferredVersion = $version;
}








function _disconnect($reason)
{
$this->pwd = false;
parent::_disconnect($reason);
}






function enableDatePreservation()
{
$this->preserveTime = true;
}






function disableDatePreservation()
{
$this->preserveTime = false;
}
}
<?php































namespace phpseclib\Net;








class SCP
{







const SOURCE_LOCAL_FILE = 1;



const SOURCE_STRING = 2;










const MODE_SSH1 = 1;



const MODE_SSH2 = 2;








var $ssh;







var $packet_size;







var $mode;










function __construct($ssh)
{
if ($ssh instanceof SSH2) {
$this->mode = self::MODE_SSH2;
} elseif ($ssh instanceof SSH1) {
$this->packet_size = 50000;
$this->mode = self::MODE_SSH1;
} else {
return;
}

$this->ssh = $ssh;
}






















function put($remote_file, $data, $mode = self::SOURCE_STRING, $callback = null)
{
if (!isset($this->ssh)) {
return false;
}

if (empty($remote_file)) {
user_error('remote_file cannot be blank', E_USER_NOTICE);
return false;
}

if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { 
 return false;
}

$temp = $this->_receive();
if ($temp !== chr(0)) {
return false;
}

if ($this->mode == self::MODE_SSH2) {
$this->packet_size = $this->ssh->packet_size_client_to_server[SSH2::CHANNEL_EXEC] - 4;
}

$remote_file = basename($remote_file);

if ($mode == self::SOURCE_STRING) {
$size = strlen($data);
} else {
if (!is_file($data)) {
user_error("$data is not a valid file", E_USER_NOTICE);
return false;
}

$fp = @fopen($data, 'rb');
if (!$fp) {
return false;
}
$size = filesize($data);
}

$this->_send('C0644 ' . $size . ' ' . $remote_file . "\n");

$temp = $this->_receive();
if ($temp !== chr(0)) {
return false;
}

$sent = 0;
while ($sent < $size) {
$temp = $mode & self::SOURCE_STRING ? substr($data, $sent, $this->packet_size) : fread($fp, $this->packet_size);
$this->_send($temp);
$sent+= strlen($temp);

if (is_callable($callback)) {
call_user_func($callback, $sent);
}
}
$this->_close();

if ($mode != self::SOURCE_STRING) {
fclose($fp);
}

return true;
}













function get($remote_file, $local_file = false)
{
if (!isset($this->ssh)) {
return false;
}

if (!$this->ssh->exec('scp -f ' . escapeshellarg($remote_file), false)) { 
 return false;
}

$this->_send("\0");

if (!preg_match('#(?<perms>[^ ]+) (?<size>\d+) (?<name>.+)#', rtrim($this->_receive()), $info)) {
return false;
}

$this->_send("\0");

$size = 0;

if ($local_file !== false) {
$fp = @fopen($local_file, 'wb');
if (!$fp) {
return false;
}
}

$content = '';
while ($size < $info['size']) {
$data = $this->_receive();

 $size+= strlen($data);

if ($local_file === false) {
$content.= $data;
} else {
fputs($fp, $data);
}
}

$this->_close();

if ($local_file !== false) {
fclose($fp);
return true;
}

return $content;
}







function _send($data)
{
switch ($this->mode) {
case self::MODE_SSH2:
$this->ssh->_send_channel_packet(SSH2::CHANNEL_EXEC, $data);
break;
case self::MODE_SSH1:
$data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($data), $data);
$this->ssh->_send_binary_packet($data);
}
}







function _receive()
{
switch ($this->mode) {
case self::MODE_SSH2:
return $this->ssh->_get_channel_packet(SSH2::CHANNEL_EXEC, true);
case self::MODE_SSH1:
if (!$this->ssh->bitmap) {
return false;
}
while (true) {
$response = $this->ssh->_get_binary_packet();
switch ($response[SSH1::RESPONSE_TYPE]) {
case NET_SSH1_SMSG_STDOUT_DATA:
if (strlen($response[SSH1::RESPONSE_DATA]) < 4) {
return false;
}
extract(unpack('Nlength', $response[SSH1::RESPONSE_DATA]));
return $this->ssh->_string_shift($response[SSH1::RESPONSE_DATA], $length);
case NET_SSH1_SMSG_STDERR_DATA:
break;
case NET_SSH1_SMSG_EXITSTATUS:
$this->ssh->_send_binary_packet(chr(NET_SSH1_CMSG_EXIT_CONFIRMATION));
fclose($this->ssh->fsock);
$this->ssh->bitmap = 0;
return false;
default:
user_error('Unknown packet received', E_USER_NOTICE);
return false;
}
}
}
}






function _close()
{
switch ($this->mode) {
case self::MODE_SSH2:
$this->ssh->_close_channel(SSH2::CHANNEL_EXEC, true);
break;
case self::MODE_SSH1:
$this->ssh->disconnect();
}
}
}
<?php















































namespace phpseclib\Net;

use phpseclib\Crypt\DES;
use phpseclib\Crypt\Random;
use phpseclib\Crypt\TripleDES;
use phpseclib\Math\BigInteger;








class SSH1
{











const CIPHER_NONE = 0;





const CIPHER_IDEA = 1;



const CIPHER_DES = 2;





const CIPHER_3DES = 3;






const CIPHER_BROKEN_TSS = 4;















const CIPHER_RC4 = 5;






const CIPHER_BLOWFISH = 6;











const AUTH_RHOSTS = 1;



const AUTH_RSA = 2;





const AUTH_PASSWORD = 3;



const AUTH_RHOSTS_RSA = 4;








const TTY_OP_END = 0;








const RESPONSE_TYPE = 1;







const RESPONSE_DATA = 2;







const MASK_CONSTRUCTOR = 0x00000001;
const MASK_CONNECTED = 0x00000002;
const MASK_LOGIN = 0x00000004;
const MASK_SHELL = 0x00000008;









const LOG_SIMPLE = 1;



const LOG_COMPLEX = 2;



const LOG_REALTIME = 3;



const LOG_REALTIME_FILE = 4;









const READ_SIMPLE = 1;



const READ_REGEX = 2;








var $identifier = 'SSH-1.5-phpseclib';







var $fsock;







var $crypto = false;










var $bitmap = 0;










var $server_key_public_exponent;










var $server_key_public_modulus;










var $host_key_public_exponent;










var $host_key_public_modulus;










var $supported_ciphers = array(
self::CIPHER_NONE => 'No encryption',
self::CIPHER_IDEA => 'IDEA in CFB mode',
self::CIPHER_DES => 'DES in CBC mode',
self::CIPHER_3DES => 'Triple-DES in CBC mode',
self::CIPHER_BROKEN_TSS => 'TRI\'s Simple Stream encryption CBC',
self::CIPHER_RC4 => 'RC4',
self::CIPHER_BLOWFISH => 'Blowfish'
);










var $supported_authentications = array(
self::AUTH_RHOSTS => '.rhosts or /etc/hosts.equiv',
self::AUTH_RSA => 'pure RSA authentication',
self::AUTH_PASSWORD => 'password authentication',
self::AUTH_RHOSTS_RSA => '.rhosts with RSA host authentication'
);








var $server_identification = '';








var $protocol_flags = array();








var $protocol_flag_log = array();








var $message_log = array();








var $realtime_log_file;








var $realtime_log_size;








var $realtime_log_wrap;








var $interactiveBuffer = '';







var $timeout;







var $curTimeout;







var $log_boundary = ':';







var $log_long_width = 65;







var $log_short_width = 16;









var $host;









var $port;














var $connectionTimeout;









var $cipher;













function __construct($host, $port = 22, $timeout = 10, $cipher = self::CIPHER_3DES)
{
$this->protocol_flags = array(
1 => 'NET_SSH1_MSG_DISCONNECT',
2 => 'NET_SSH1_SMSG_PUBLIC_KEY',
3 => 'NET_SSH1_CMSG_SESSION_KEY',
4 => 'NET_SSH1_CMSG_USER',
9 => 'NET_SSH1_CMSG_AUTH_PASSWORD',
10 => 'NET_SSH1_CMSG_REQUEST_PTY',
12 => 'NET_SSH1_CMSG_EXEC_SHELL',
13 => 'NET_SSH1_CMSG_EXEC_CMD',
14 => 'NET_SSH1_SMSG_SUCCESS',
15 => 'NET_SSH1_SMSG_FAILURE',
16 => 'NET_SSH1_CMSG_STDIN_DATA',
17 => 'NET_SSH1_SMSG_STDOUT_DATA',
18 => 'NET_SSH1_SMSG_STDERR_DATA',
19 => 'NET_SSH1_CMSG_EOF',
20 => 'NET_SSH1_SMSG_EXITSTATUS',
33 => 'NET_SSH1_CMSG_EXIT_CONFIRMATION'
);

$this->_define_array($this->protocol_flags);

$this->host = $host;
$this->port = $port;
$this->connectionTimeout = $timeout;
$this->cipher = $cipher;
}







function _connect()
{
$this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout);
if (!$this->fsock) {
user_error(rtrim("Cannot connect to {$this->host}:{$this->port}. Error $errno. $errstr"));
return false;
}

$this->server_identification = $init_line = fgets($this->fsock, 255);

if (defined('NET_SSH1_LOGGING')) {
$this->_append_log('<-', $this->server_identification);
$this->_append_log('->', $this->identifier . "\r\n");
}

if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
user_error('Can only connect to SSH servers');
return false;
}
if ($parts[1][0] != 1) {
user_error("Cannot connect to SSH $parts[1] servers");
return false;
}

fputs($this->fsock, $this->identifier."\r\n");

$response = $this->_get_binary_packet();
if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) {
user_error('Expected SSH_SMSG_PUBLIC_KEY');
return false;
}

$anti_spoofing_cookie = $this->_string_shift($response[self::RESPONSE_DATA], 8);

$this->_string_shift($response[self::RESPONSE_DATA], 4);

if (strlen($response[self::RESPONSE_DATA]) < 2) {
return false;
}
$temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
$server_key_public_exponent = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
$this->server_key_public_exponent = $server_key_public_exponent;

if (strlen($response[self::RESPONSE_DATA]) < 2) {
return false;
}
$temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
$server_key_public_modulus = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);

$this->server_key_public_modulus = $server_key_public_modulus;

$this->_string_shift($response[self::RESPONSE_DATA], 4);

if (strlen($response[self::RESPONSE_DATA]) < 2) {
return false;
}
$temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
$host_key_public_exponent = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
$this->host_key_public_exponent = $host_key_public_exponent;

if (strlen($response[self::RESPONSE_DATA]) < 2) {
return false;
}
$temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
$host_key_public_modulus = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);

$this->host_key_public_modulus = $host_key_public_modulus;

$this->_string_shift($response[self::RESPONSE_DATA], 4);


 if (strlen($response[self::RESPONSE_DATA]) < 4) {
return false;
}
extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[self::RESPONSE_DATA], 4)));

foreach ($this->supported_ciphers as $mask => $name) {
if (($supported_ciphers_mask & (1 << $mask)) == 0) {
unset($this->supported_ciphers[$mask]);
}
}


 if (strlen($response[self::RESPONSE_DATA]) < 4) {
return false;
}
extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[self::RESPONSE_DATA], 4)));
foreach ($this->supported_authentications as $mask => $name) {
if (($supported_authentications_mask & (1 << $mask)) == 0) {
unset($this->supported_authentications[$mask]);
}
}

$session_id = pack('H*', md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie));

$session_key = Random::string(32);
$double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0));

if ($server_key_public_modulus->compare($host_key_public_modulus) < 0) {
$double_encrypted_session_key = $this->_rsa_crypt(
$double_encrypted_session_key,
array(
$server_key_public_exponent,
$server_key_public_modulus
)
);
$double_encrypted_session_key = $this->_rsa_crypt(
$double_encrypted_session_key,
array(
$host_key_public_exponent,
$host_key_public_modulus
)
);
} else {
$double_encrypted_session_key = $this->_rsa_crypt(
$double_encrypted_session_key,
array(
$host_key_public_exponent,
$host_key_public_modulus
)
);
$double_encrypted_session_key = $this->_rsa_crypt(
$double_encrypted_session_key,
array(
$server_key_public_exponent,
$server_key_public_modulus
)
);
}

$cipher = isset($this->supported_ciphers[$this->cipher]) ? $this->cipher : self::CIPHER_3DES;
$data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0);

if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_SESSION_KEY');
return false;
}

switch ($cipher) {

 
 
 case self::CIPHER_DES:
$this->crypto = new DES();
$this->crypto->disablePadding();
$this->crypto->enableContinuousBuffer();
$this->crypto->setKey(substr($session_key, 0, 8));
break;
case self::CIPHER_3DES:
$this->crypto = new TripleDES(TripleDES::MODE_3CBC);
$this->crypto->disablePadding();
$this->crypto->enableContinuousBuffer();
$this->crypto->setKey(substr($session_key, 0, 24));
break;

 
 
 
 
 }

$response = $this->_get_binary_packet();

if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
user_error('Expected SSH_SMSG_SUCCESS');
return false;
}

$this->bitmap = self::MASK_CONNECTED;

return true;
}









function login($username, $password = '')
{
if (!($this->bitmap & self::MASK_CONSTRUCTOR)) {
$this->bitmap |= self::MASK_CONSTRUCTOR;
if (!$this->_connect()) {
return false;
}
}

if (!($this->bitmap & self::MASK_CONNECTED)) {
return false;
}

$data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username);

if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_USER');
return false;
}

$response = $this->_get_binary_packet();

if ($response === true) {
return false;
}
if ($response[self::RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
$this->bitmap |= self::MASK_LOGIN;
return true;
} elseif ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) {
user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
return false;
}

$data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password);

if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_AUTH_PASSWORD');
return false;
}


 if (defined('NET_SSH1_LOGGING') && NET_SSH1_LOGGING == self::LOG_COMPLEX) {
$data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen('password'), 'password');
$this->message_log[count($this->message_log) - 1] = $data;
}

$response = $this->_get_binary_packet();

if ($response === true) {
return false;
}
if ($response[self::RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
$this->bitmap |= self::MASK_LOGIN;
return true;
} elseif ($response[self::RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) {
return false;
} else {
user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
return false;
}
}









function setTimeout($timeout)
{
$this->timeout = $this->curTimeout = $timeout;
}






















function exec($cmd, $block = true)
{
if (!($this->bitmap & self::MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
}

$data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd);

if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_EXEC_CMD');
return false;
}

if (!$block) {
return true;
}

$output = '';
$response = $this->_get_binary_packet();

if ($response !== false) {
do {
$output.= substr($response[self::RESPONSE_DATA], 4);
$response = $this->_get_binary_packet();
} while (is_array($response) && $response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_EXITSTATUS);
}

$data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);


 $this->_send_binary_packet($data);

fclose($this->fsock);


 $this->bitmap = 0;

return $output;
}









function _initShell()
{

 
 
 $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, self::TTY_OP_END);

if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_REQUEST_PTY');
return false;
}

$response = $this->_get_binary_packet();

if ($response === true) {
return false;
}
if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
user_error('Expected SSH_SMSG_SUCCESS');
return false;
}

$data = pack('C', NET_SSH1_CMSG_EXEC_SHELL);

if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_EXEC_SHELL');
return false;
}

$this->bitmap |= self::MASK_SHELL;



return true;
}









function write($cmd)
{
return $this->interactiveWrite($cmd);
}













function read($expect, $mode = self::READ_SIMPLE)
{
if (!($this->bitmap & self::MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
}

if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
}

$match = $expect;
while (true) {
if ($mode == self::READ_REGEX) {
preg_match($expect, $this->interactiveBuffer, $matches);
$match = isset($matches[0]) ? $matches[0] : '';
}
$pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false;
if ($pos !== false) {
return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match));
}
$response = $this->_get_binary_packet();

if ($response === true) {
return $this->_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer));
}
$this->interactiveBuffer.= substr($response[self::RESPONSE_DATA], 4);
}
}









function interactiveWrite($cmd)
{
if (!($this->bitmap & self::MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
}

if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
}

$data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd);

if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_STDIN');
return false;
}

return true;
}














function interactiveRead()
{
if (!($this->bitmap & self::MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
}

if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
}

$read = array($this->fsock);
$write = $except = null;
if (stream_select($read, $write, $except, 0)) {
$response = $this->_get_binary_packet();
return substr($response[self::RESPONSE_DATA], 4);
} else {
return '';
}
}






function disconnect()
{
$this->_disconnect();
}









function __destruct()
{
$this->_disconnect();
}







function _disconnect($msg = 'Client Quit')
{
if ($this->bitmap) {
$data = pack('C', NET_SSH1_CMSG_EOF);
$this->_send_binary_packet($data);













$data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);

$this->_send_binary_packet($data);
fclose($this->fsock);
$this->bitmap = 0;
}
}













function _get_binary_packet()
{
if (feof($this->fsock)) {

 return false;
}

if ($this->curTimeout) {
$read = array($this->fsock);
$write = $except = null;

$start = strtok(microtime(), ' ') + strtok(''); 
 $sec = floor($this->curTimeout);
$usec = 1000000 * ($this->curTimeout - $sec);

 if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {

 return true;
}
$elapsed = strtok(microtime(), ' ') + strtok('') - $start;
$this->curTimeout-= $elapsed;
}

$start = strtok(microtime(), ' ') + strtok(''); 
 $data = fread($this->fsock, 4);
if (strlen($data) < 4) {
return false;
}
$temp = unpack('Nlength', $data);

$padding_length = 8 - ($temp['length'] & 7);
$length = $temp['length'] + $padding_length;
$raw = '';

while ($length > 0) {
$temp = fread($this->fsock, $length);
if (strlen($temp) != $length) {
return false;
}
$raw.= $temp;
$length-= strlen($temp);
}
$stop = strtok(microtime(), ' ') + strtok('');

if (strlen($raw) && $this->crypto !== false) {
$raw = $this->crypto->decrypt($raw);
}

$padding = substr($raw, 0, $padding_length);
$type = $raw[$padding_length];
$data = substr($raw, $padding_length + 1, -4);

if (strlen($raw) < 4) {
return false;
}
$temp = unpack('Ncrc', substr($raw, -4));


 
 
 

$type = ord($type);

if (defined('NET_SSH1_LOGGING')) {
$temp = isset($this->protocol_flags[$type]) ? $this->protocol_flags[$type] : 'UNKNOWN';
$temp = '<- ' . $temp .
' (' . round($stop - $start, 4) . 's)';
$this->_append_log($temp, $data);
}

return array(
self::RESPONSE_TYPE => $type,
self::RESPONSE_DATA => $data
);
}











function _send_binary_packet($data)
{
if (feof($this->fsock)) {

 return false;
}

$length = strlen($data) + 4;

$padding = Random::string(8 - ($length & 7));

$orig = $data;
$data = $padding . $data;
$data.= pack('N', $this->_crc($data));

if ($this->crypto !== false) {
$data = $this->crypto->encrypt($data);
}

$packet = pack('Na*', $length, $data);

$start = strtok(microtime(), ' ') + strtok(''); 
 $result = strlen($packet) == fputs($this->fsock, $packet);
$stop = strtok(microtime(), ' ') + strtok('');

if (defined('NET_SSH1_LOGGING')) {
$temp = isset($this->protocol_flags[ord($orig[0])]) ? $this->protocol_flags[ord($orig[0])] : 'UNKNOWN';
$temp = '-> ' . $temp .
' (' . round($stop - $start, 4) . 's)';
$this->_append_log($temp, $orig);
}

return $result;
}














function _crc($data)
{
static $crc_lookup_table = array(
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
);


 
 $crc = 0x00000000;
$length = strlen($data);

for ($i=0; $i<$length; $i++) {

 
 
 
 $crc = (($crc >> 8) & 0x00FFFFFF) ^ $crc_lookup_table[($crc & 0xFF) ^ ord($data[$i])];
}


 
 return $crc;
}











function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}














function _rsa_crypt($m, $key)
{








 
 
 
 
 
 
 
 


 
 
 $modulus = $key[1]->toBytes();
$length = strlen($modulus) - strlen($m) - 3;
$random = '';
while (strlen($random) != $length) {
$block = Random::string($length - strlen($random));
$block = str_replace("\x00", '', $block);
$random.= $block;
}
$temp = chr(0) . chr(2) . $random . chr(0) . $m;

$m = new BigInteger($temp, 256);
$m = $m->modPow($key[0], $key[1]);

return $m->toBytes();
}










function _define_array()
{
$args = func_get_args();
foreach ($args as $arg) {
foreach ($arg as $key => $value) {
if (!defined($value)) {
define($value, $key);
} else {
break 2;
}
}
}
}









function getLog()
{
if (!defined('NET_SSH1_LOGGING')) {
return false;
}

switch (NET_SSH1_LOGGING) {
case self::LOG_SIMPLE:
return $this->message_number_log;
break;
case self::LOG_COMPLEX:
return $this->_format_log($this->message_log, $this->protocol_flags_log);
break;
default:
return false;
}
}









function _format_log($message_log, $message_number_log)
{
$output = '';
for ($i = 0; $i < count($message_log); $i++) {
$output.= $message_number_log[$i] . "\r\n";
$current_log = $message_log[$i];
$j = 0;
do {
if (strlen($current_log)) {
$output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0  ';
}
$fragment = $this->_string_shift($current_log, $this->log_short_width);
$hex = substr(preg_replace_callback('#.#s', array($this, '_format_log_helper'), $fragment), strlen($this->log_boundary));

 
 
 $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment);
$output.= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n";
$j++;
} while (strlen($current_log));
$output.= "\r\n";
}

return $output;
}










function _format_log_helper($matches)
{
return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT);
}











function getServerKeyPublicExponent($raw_output = false)
{
return $raw_output ? $this->server_key_public_exponent->toBytes() : $this->server_key_public_exponent->toString();
}











function getServerKeyPublicModulus($raw_output = false)
{
return $raw_output ? $this->server_key_public_modulus->toBytes() : $this->server_key_public_modulus->toString();
}











function getHostKeyPublicExponent($raw_output = false)
{
return $raw_output ? $this->host_key_public_exponent->toBytes() : $this->host_key_public_exponent->toString();
}











function getHostKeyPublicModulus($raw_output = false)
{
return $raw_output ? $this->host_key_public_modulus->toBytes() : $this->host_key_public_modulus->toString();
}












function getSupportedCiphers($raw_output = false)
{
return $raw_output ? array_keys($this->supported_ciphers) : array_values($this->supported_ciphers);
}












function getSupportedAuthentications($raw_output = false)
{
return $raw_output ? array_keys($this->supported_authentications) : array_values($this->supported_authentications);
}







function getServerIdentification()
{
return rtrim($this->server_identification);
}










function _append_log($protocol_flags, $message)
{
switch (NET_SSH1_LOGGING) {

 case self::LOG_SIMPLE:
$this->protocol_flags_log[] = $protocol_flags;
break;

 case self::LOG_COMPLEX:
$this->protocol_flags_log[] = $protocol_flags;
$this->_string_shift($message);
$this->log_size+= strlen($message);
$this->message_log[] = $message;
while ($this->log_size > self::LOG_MAX_SIZE) {
$this->log_size-= strlen(array_shift($this->message_log));
array_shift($this->protocol_flags_log);
}
break;

 
 
 case self::LOG_REALTIME:
echo "<pre>\r\n" . $this->_format_log(array($message), array($protocol_flags)) . "\r\n</pre>\r\n";
@flush();
@ob_flush();
break;

 
 
 
 case self::LOG_REALTIME_FILE:
if (!isset($this->realtime_log_file)) {

 $filename = self::LOG_REALTIME_FILE;
$fp = fopen($filename, 'w');
$this->realtime_log_file = $fp;
}
if (!is_resource($this->realtime_log_file)) {
break;
}
$entry = $this->_format_log(array($message), array($protocol_flags));
if ($this->realtime_log_wrap) {
$temp = "<<< START >>>\r\n";
$entry.= $temp;
fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp));
}
$this->realtime_log_size+= strlen($entry);
if ($this->realtime_log_size > self::LOG_MAX_SIZE) {
fseek($this->realtime_log_file, 0);
$this->realtime_log_size = strlen($entry);
$this->realtime_log_wrap = true;
}
fputs($this->realtime_log_file, $entry);
}
}
}
<?php
















































namespace phpseclib\Math;

use phpseclib\Crypt\Random;









class BigInteger
{










const MONTGOMERY = 0;



const BARRETT = 1;



const POWEROF2 = 2;



const CLASSIC = 3;



const NONE = 4;













const VALUE = 0;



const SIGN = 1;












const VARIABLE = 0;



const DATA = 1;











const MODE_INTERNAL = 1;





const MODE_BCMATH = 2;





const MODE_GMP = 3;









const KARATSUBA_CUTOFF = 25;






protected static $base;
protected static $baseFull;
protected static $maxDigit;
protected static $msb;





protected static $max10;





protected static $max10Len;
protected static $maxDigit2;








var $value;







var $is_negative = false;







var $precision = -1;







var $bitmask = false;













var $hex;





















function __construct($x = 0, $base = 10)
{
if (!defined('MATH_BIGINTEGER_MODE')) {
switch (true) {
case extension_loaded('gmp'):
define('MATH_BIGINTEGER_MODE', self::MODE_GMP);
break;
case extension_loaded('bcmath'):
define('MATH_BIGINTEGER_MODE', self::MODE_BCMATH);
break;
default:
define('MATH_BIGINTEGER_MODE', self::MODE_INTERNAL);
}
}

if (extension_loaded('openssl') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {

 $versions = array();


 if (strpos(ini_get('disable_functions'), 'phpinfo') === false) {
ob_start();
@phpinfo();
$content = ob_get_contents();
ob_end_clean();

preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);

if (!empty($matches[1])) {
for ($i = 0; $i < count($matches[1]); $i++) {
$fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));


 if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
$versions[$matches[1][$i]] = $fullVersion;
} else {
$versions[$matches[1][$i]] = $m[0];
}
}
}
}


 switch (true) {
case !isset($versions['Header']):
case !isset($versions['Library']):
case $versions['Header'] == $versions['Library']:
case version_compare($versions['Header'], '1.0.0') >= 0 && version_compare($versions['Library'], '1.0.0') >= 0:
define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
break;
default:
define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
}
}

if (!defined('PHP_INT_SIZE')) {
define('PHP_INT_SIZE', 4);
}

if (empty(self::$base) && MATH_BIGINTEGER_MODE == self::MODE_INTERNAL) {
switch (PHP_INT_SIZE) {
case 8: 
 self::$base = 31;
self::$baseFull = 0x80000000;
self::$maxDigit = 0x7FFFFFFF;
self::$msb = 0x40000000;
self::$max10 = 1000000000;
self::$max10Len = 9;
self::$maxDigit2 = pow(2, 62);
break;

 default:
self::$base = 26;
self::$baseFull = 0x4000000;
self::$maxDigit = 0x3FFFFFF;
self::$msb = 0x2000000;
self::$max10 = 10000000;
self::$max10Len = 7;
self::$maxDigit2 = pow(2, 52); 
 }
}

switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
switch (true) {
case is_resource($x) && get_resource_type($x) == 'GMP integer':

 case $x instanceof \GMP:
$this->value = $x;
return;
}
$this->value = gmp_init(0);
break;
case self::MODE_BCMATH:
$this->value = '0';
break;
default:
$this->value = array();
}


 
 if (empty($x) && (abs($base) != 256 || $x !== '0')) {
return;
}

switch ($base) {
case -256:
if (ord($x[0]) & 0x80) {
$x = ~$x;
$this->is_negative = true;
}
case 256:
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$this->value = function_exists('gmp_import') ?
gmp_import($x) :
gmp_init('0x' . bin2hex($x));
if ($this->is_negative) {
$this->value = gmp_neg($this->value);
}
break;
case self::MODE_BCMATH:

 $len = (strlen($x) + 3) & 0xFFFFFFFC;

$x = str_pad($x, $len, chr(0), STR_PAD_LEFT);

for ($i = 0; $i < $len; $i+= 4) {
$this->value = bcmul($this->value, '4294967296', 0); 
 $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0);
}

if ($this->is_negative) {
$this->value = '-' . $this->value;
}

break;

 default:
while (strlen($x)) {
$this->value[] = $this->_bytes2int($this->_base256_rshift($x, self::$base));
}
}

if ($this->is_negative) {
if (MATH_BIGINTEGER_MODE != self::MODE_INTERNAL) {
$this->is_negative = false;
}
$temp = $this->add(new static('-1'));
$this->value = $temp->value;
}
break;
case 16:
case -16:
if ($base > 0 && $x[0] == '-') {
$this->is_negative = true;
$x = substr($x, 1);
}

$x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);

$is_negative = false;
if ($base < 0 && hexdec($x[0]) >= 8) {
$this->is_negative = $is_negative = true;
$x = bin2hex(~pack('H*', $x));
}

switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$temp = $this->is_negative ? '-0x' . $x : '0x' . $x;
$this->value = gmp_init($temp);
$this->is_negative = false;
break;
case self::MODE_BCMATH:
$x = (strlen($x) & 1) ? '0' . $x : $x;
$temp = new static(pack('H*', $x), 256);
$this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
$this->is_negative = false;
break;
default:
$x = (strlen($x) & 1) ? '0' . $x : $x;
$temp = new static(pack('H*', $x), 256);
$this->value = $temp->value;
}

if ($is_negative) {
$temp = $this->add(new static('-1'));
$this->value = $temp->value;
}
break;
case 10:
case -10:

 
 
 $x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x);
if (!strlen($x) || $x == '-') {
$x = '0';
}

switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$this->value = gmp_init($x);
break;
case self::MODE_BCMATH:

 
 $this->value = $x === '-' ? '0' : (string) $x;
break;
default:
$temp = new static();

$multiplier = new static();
$multiplier->value = array(self::$max10);

if ($x[0] == '-') {
$this->is_negative = true;
$x = substr($x, 1);
}

$x = str_pad($x, strlen($x) + ((self::$max10Len - 1) * strlen($x)) % self::$max10Len, 0, STR_PAD_LEFT);
while (strlen($x)) {
$temp = $temp->multiply($multiplier);
$temp = $temp->add(new static($this->_int2bytes(substr($x, 0, self::$max10Len)), 256));
$x = substr($x, self::$max10Len);
}

$this->value = $temp->value;
}
break;
case 2: 
 case -2:
if ($base > 0 && $x[0] == '-') {
$this->is_negative = true;
$x = substr($x, 1);
}

$x = preg_replace('#^([01]*).*#', '$1', $x);
$x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);

$str = '0x';
while (strlen($x)) {
$part = substr($x, 0, 4);
$str.= dechex(bindec($part));
$x = substr($x, 4);
}

if ($this->is_negative) {
$str = '-' . $str;
}

$temp = new static($str, 8 * $base); 
 $this->value = $temp->value;
$this->is_negative = $temp->is_negative;

break;
default:

 }
}





















function toBytes($twos_compliment = false)
{
if ($twos_compliment) {
$comparison = $this->compare(new static());
if ($comparison == 0) {
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
}

$temp = $comparison < 0 ? $this->add(new static(1)) : $this->copy();
$bytes = $temp->toBytes();

if (!strlen($bytes)) { 
 $bytes = chr(0);
}

if ($this->precision <= 0 && (ord($bytes[0]) & 0x80)) {
$bytes = chr(0) . $bytes;
}

return $comparison < 0 ? ~$bytes : $bytes;
}

switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
if (gmp_cmp($this->value, gmp_init(0)) == 0) {
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
}

if (function_exists('gmp_export')) {
$temp = gmp_export($this->value);
} else {
$temp = gmp_strval(gmp_abs($this->value), 16);
$temp = (strlen($temp) & 1) ? '0' . $temp : $temp;
$temp = pack('H*', $temp);
}

return $this->precision > 0 ?
substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
ltrim($temp, chr(0));
case self::MODE_BCMATH:
if ($this->value === '0') {
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
}

$value = '';
$current = $this->value;

if ($current[0] == '-') {
$current = substr($current, 1);
}

while (bccomp($current, '0', 0) > 0) {
$temp = bcmod($current, '16777216');
$value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
$current = bcdiv($current, '16777216', 0);
}

return $this->precision > 0 ?
substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
ltrim($value, chr(0));
}

if (!count($this->value)) {
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
}
$result = $this->_int2bytes($this->value[count($this->value) - 1]);

$temp = $this->copy();

for ($i = count($temp->value) - 2; $i >= 0; --$i) {
$temp->_base256_lshift($result, self::$base);
$result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
}

return $this->precision > 0 ?
str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :
$result;
}





















function toHex($twos_compliment = false)
{
return bin2hex($this->toBytes($twos_compliment));
}





















function toBits($twos_compliment = false)
{
$hex = $this->toHex($twos_compliment);
$bits = '';
for ($i = strlen($hex) - 6, $start = strlen($hex) % 6; $i >= $start; $i-=6) {
$bits = str_pad(decbin(hexdec(substr($hex, $i, 6))), 24, '0', STR_PAD_LEFT) . $bits;
}
if ($start) { 
 $bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8 * $start, '0', STR_PAD_LEFT) . $bits;
}
$result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');

if ($twos_compliment && $this->compare(new static()) > 0 && $this->precision <= 0) {
return '0' . $result;
}

return $result;
}

















function toString()
{
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
return gmp_strval($this->value);
case self::MODE_BCMATH:
if ($this->value === '0') {
return '0';
}

return ltrim($this->value, '0');
}

if (!count($this->value)) {
return '0';
}

$temp = $this->copy();
$temp->bitmask = false;
$temp->is_negative = false;

$divisor = new static();
$divisor->value = array(self::$max10);
$result = '';
while (count($temp->value)) {
list($temp, $mod) = $temp->divide($divisor);
$result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', self::$max10Len, '0', STR_PAD_LEFT) . $result;
}
$result = ltrim($result, '0');
if (empty($result)) {
$result = '0';
}

if ($this->is_negative) {
$result = '-' . $result;
}

return $result;
}













function copy()
{
$temp = new static();
$temp->value = $this->value;
$temp->is_negative = $this->is_negative;
$temp->precision = $this->precision;
$temp->bitmask = $this->bitmask;
return $temp;
}










function __toString()
{
return $this->toString();
}













function __clone()
{
return $this->copy();
}









function __sleep()
{
$this->hex = $this->toHex(true);
$vars = array('hex');
if ($this->precision > 0) {
$vars[] = 'precision';
}
return $vars;
}









function __wakeup()
{
$temp = new static($this->hex, -16);
$this->value = $temp->value;
$this->is_negative = $temp->is_negative;
if ($this->precision > 0) {

 $this->setPrecision($this->precision);
}
}








function __debugInfo()
{
$opts = array();
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$engine = 'gmp';
break;
case self::MODE_BCMATH:
$engine = 'bcmath';
break;
case self::MODE_INTERNAL:
$engine = 'internal';
$opts[] = PHP_INT_SIZE == 8 ? '64-bit' : '32-bit';
}
if (MATH_BIGINTEGER_MODE != self::MODE_GMP && defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
$opts[] = 'OpenSSL';
}
if (!empty($opts)) {
$engine.= ' (' . implode('.', $opts) . ')';
}
return array(
'value' => '0x' . $this->toHex(true),
'engine' => $engine
);
}





















function add($y)
{
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$temp = new static();
$temp->value = gmp_add($this->value, $y->value);

return $this->_normalize($temp);
case self::MODE_BCMATH:
$temp = new static();
$temp->value = bcadd($this->value, $y->value, 0);

return $this->_normalize($temp);
}

$temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);

$result = new static();
$result->value = $temp[self::VALUE];
$result->is_negative = $temp[self::SIGN];

return $this->_normalize($result);
}











function _add($x_value, $x_negative, $y_value, $y_negative)
{
$x_size = count($x_value);
$y_size = count($y_value);

if ($x_size == 0) {
return array(
self::VALUE => $y_value,
self::SIGN => $y_negative
);
} elseif ($y_size == 0) {
return array(
self::VALUE => $x_value,
self::SIGN => $x_negative
);
}


 if ($x_negative != $y_negative) {
if ($x_value == $y_value) {
return array(
self::VALUE => array(),
self::SIGN => false
);
}

$temp = $this->_subtract($x_value, false, $y_value, false);
$temp[self::SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ?
$x_negative : $y_negative;

return $temp;
}

if ($x_size < $y_size) {
$size = $x_size;
$value = $y_value;
} else {
$size = $y_size;
$value = $x_value;
}

$value[count($value)] = 0; 

$carry = 0;
for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
$sum = $x_value[$j] * self::$baseFull + $x_value[$i] + $y_value[$j] * self::$baseFull + $y_value[$i] + $carry;
$carry = $sum >= self::$maxDigit2; 
 $sum = $carry ? $sum - self::$maxDigit2 : $sum;

$temp = self::$base === 26 ? intval($sum / 0x4000000) : ($sum >> 31);

$value[$i] = (int) ($sum - self::$baseFull * $temp); 
 $value[$j] = $temp;
}

if ($j == $size) { 
 $sum = $x_value[$i] + $y_value[$i] + $carry;
$carry = $sum >= self::$baseFull;
$value[$i] = $carry ? $sum - self::$baseFull : $sum;
++$i; 
 }

if ($carry) {
for (; $value[$i] == self::$maxDigit; ++$i) {
$value[$i] = 0;
}
++$value[$i];
}

return array(
self::VALUE => $this->_trim($value),
self::SIGN => $x_negative
);
}





















function subtract($y)
{
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$temp = new static();
$temp->value = gmp_sub($this->value, $y->value);

return $this->_normalize($temp);
case self::MODE_BCMATH:
$temp = new static();
$temp->value = bcsub($this->value, $y->value, 0);

return $this->_normalize($temp);
}

$temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);

$result = new static();
$result->value = $temp[self::VALUE];
$result->is_negative = $temp[self::SIGN];

return $this->_normalize($result);
}











function _subtract($x_value, $x_negative, $y_value, $y_negative)
{
$x_size = count($x_value);
$y_size = count($y_value);

if ($x_size == 0) {
return array(
self::VALUE => $y_value,
self::SIGN => !$y_negative
);
} elseif ($y_size == 0) {
return array(
self::VALUE => $x_value,
self::SIGN => $x_negative
);
}


 if ($x_negative != $y_negative) {
$temp = $this->_add($x_value, false, $y_value, false);
$temp[self::SIGN] = $x_negative;

return $temp;
}

$diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);

if (!$diff) {
return array(
self::VALUE => array(),
self::SIGN => false
);
}


 if ((!$x_negative && $diff < 0) || ($x_negative && $diff > 0)) {
$temp = $x_value;
$x_value = $y_value;
$y_value = $temp;

$x_negative = !$x_negative;

$x_size = count($x_value);
$y_size = count($y_value);
}



$carry = 0;
for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {
$sum = $x_value[$j] * self::$baseFull + $x_value[$i] - $y_value[$j] * self::$baseFull - $y_value[$i] - $carry;
$carry = $sum < 0; 
 $sum = $carry ? $sum + self::$maxDigit2 : $sum;

$temp = self::$base === 26 ? intval($sum / 0x4000000) : ($sum >> 31);

$x_value[$i] = (int) ($sum - self::$baseFull * $temp);
$x_value[$j] = $temp;
}

if ($j == $y_size) { 
 $sum = $x_value[$i] - $y_value[$i] - $carry;
$carry = $sum < 0;
$x_value[$i] = $carry ? $sum + self::$baseFull : $sum;
++$i;
}

if ($carry) {
for (; !$x_value[$i]; ++$i) {
$x_value[$i] = self::$maxDigit;
}
--$x_value[$i];
}

return array(
self::VALUE => $this->_trim($x_value),
self::SIGN => $x_negative
);
}




















function multiply($x)
{
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$temp = new static();
$temp->value = gmp_mul($this->value, $x->value);

return $this->_normalize($temp);
case self::MODE_BCMATH:
$temp = new static();
$temp->value = bcmul($this->value, $x->value, 0);

return $this->_normalize($temp);
}

$temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);

$product = new static();
$product->value = $temp[self::VALUE];
$product->is_negative = $temp[self::SIGN];

return $this->_normalize($product);
}











function _multiply($x_value, $x_negative, $y_value, $y_negative)
{

 
 
 
 
 

$x_length = count($x_value);
$y_length = count($y_value);

if (!$x_length || !$y_length) { 
 return array(
self::VALUE => array(),
self::SIGN => false
);
}

return array(
self::VALUE => min($x_length, $y_length) < 2 * self::KARATSUBA_CUTOFF ?
$this->_trim($this->_regularMultiply($x_value, $y_value)) :
$this->_trim($this->_karatsuba($x_value, $y_value)),
self::SIGN => $x_negative != $y_negative
);
}











function _regularMultiply($x_value, $y_value)
{
$x_length = count($x_value);
$y_length = count($y_value);

if (!$x_length || !$y_length) { 
 return array();
}

if ($x_length < $y_length) {
$temp = $x_value;
$x_value = $y_value;
$y_value = $temp;

$x_length = count($x_value);
$y_length = count($y_value);
}

$product_value = $this->_array_repeat(0, $x_length + $y_length);


 
 
 
 

$carry = 0;

for ($j = 0; $j < $x_length; ++$j) { 
 $temp = $x_value[$j] * $y_value[0] + $carry; 
 $carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$product_value[$j] = (int) ($temp - self::$baseFull * $carry);
}

$product_value[$j] = $carry;


 
 for ($i = 1; $i < $y_length; ++$i) {
$carry = 0;

for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
$carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$product_value[$k] = (int) ($temp - self::$baseFull * $carry);
}

$product_value[$k] = $carry;
}

return $product_value;
}












function _karatsuba($x_value, $y_value)
{
$m = min(count($x_value) >> 1, count($y_value) >> 1);

if ($m < self::KARATSUBA_CUTOFF) {
return $this->_regularMultiply($x_value, $y_value);
}

$x1 = array_slice($x_value, $m);
$x0 = array_slice($x_value, 0, $m);
$y1 = array_slice($y_value, $m);
$y0 = array_slice($y_value, 0, $m);

$z2 = $this->_karatsuba($x1, $y1);
$z0 = $this->_karatsuba($x0, $y0);

$z1 = $this->_add($x1, false, $x0, false);
$temp = $this->_add($y1, false, $y0, false);
$z1 = $this->_karatsuba($z1[self::VALUE], $temp[self::VALUE]);
$temp = $this->_add($z2, false, $z0, false);
$z1 = $this->_subtract($z1, false, $temp[self::VALUE], false);

$z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
$z1[self::VALUE] = array_merge(array_fill(0, $m, 0), $z1[self::VALUE]);

$xy = $this->_add($z2, false, $z1[self::VALUE], $z1[self::SIGN]);
$xy = $this->_add($xy[self::VALUE], $xy[self::SIGN], $z0, false);

return $xy[self::VALUE];
}








function _square($x = false)
{
return count($x) < 2 * self::KARATSUBA_CUTOFF ?
$this->_trim($this->_baseSquare($x)) :
$this->_trim($this->_karatsubaSquare($x));
}












function _baseSquare($value)
{
if (empty($value)) {
return array();
}
$square_value = $this->_array_repeat(0, 2 * count($value));

for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {
$i2 = $i << 1;

$temp = $square_value[$i2] + $value[$i] * $value[$i];
$carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$square_value[$i2] = (int) ($temp - self::$baseFull * $carry);


 for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
$temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
$carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$square_value[$k] = (int) ($temp - self::$baseFull * $carry);
}


 
 $square_value[$i + $max_index + 1] = $carry;
}

return $square_value;
}











function _karatsubaSquare($value)
{
$m = count($value) >> 1;

if ($m < self::KARATSUBA_CUTOFF) {
return $this->_baseSquare($value);
}

$x1 = array_slice($value, $m);
$x0 = array_slice($value, 0, $m);

$z2 = $this->_karatsubaSquare($x1);
$z0 = $this->_karatsubaSquare($x0);

$z1 = $this->_add($x1, false, $x0, false);
$z1 = $this->_karatsubaSquare($z1[self::VALUE]);
$temp = $this->_add($z2, false, $z0, false);
$z1 = $this->_subtract($z1, false, $temp[self::VALUE], false);

$z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
$z1[self::VALUE] = array_merge(array_fill(0, $m, 0), $z1[self::VALUE]);

$xx = $this->_add($z2, false, $z1[self::VALUE], $z1[self::SIGN]);
$xx = $this->_add($xx[self::VALUE], $xx[self::SIGN], $z0, false);

return $xx[self::VALUE];
}




























function divide($y)
{
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$quotient = new static();
$remainder = new static();

list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);

if (gmp_sign($remainder->value) < 0) {
$remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
}

return array($this->_normalize($quotient), $this->_normalize($remainder));
case self::MODE_BCMATH:
$quotient = new static();
$remainder = new static();

$quotient->value = bcdiv($this->value, $y->value, 0);
$remainder->value = bcmod($this->value, $y->value);

if ($remainder->value[0] == '-') {
$remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0);
}

return array($this->_normalize($quotient), $this->_normalize($remainder));
}

if (count($y->value) == 1) {
list($q, $r) = $this->_divide_digit($this->value, $y->value[0]);
$quotient = new static();
$remainder = new static();
$quotient->value = $q;
$remainder->value = array($r);
$quotient->is_negative = $this->is_negative != $y->is_negative;
return array($this->_normalize($quotient), $this->_normalize($remainder));
}

static $zero;
if (!isset($zero)) {
$zero = new static();
}

$x = $this->copy();
$y = $y->copy();

$x_sign = $x->is_negative;
$y_sign = $y->is_negative;

$x->is_negative = $y->is_negative = false;

$diff = $x->compare($y);

if (!$diff) {
$temp = new static();
$temp->value = array(1);
$temp->is_negative = $x_sign != $y_sign;
return array($this->_normalize($temp), $this->_normalize(new static()));
}

if ($diff < 0) {

 if ($x_sign) {
$x = $y->subtract($x);
}
return array($this->_normalize(new static()), $this->_normalize($x));
}


 $msb = $y->value[count($y->value) - 1];
for ($shift = 0; !($msb & self::$msb); ++$shift) {
$msb <<= 1;
}
$x->_lshift($shift);
$y->_lshift($shift);
$y_value = &$y->value;

$x_max = count($x->value) - 1;
$y_max = count($y->value) - 1;

$quotient = new static();
$quotient_value = &$quotient->value;
$quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1);

static $temp, $lhs, $rhs;
if (!isset($temp)) {
$temp = new static();
$lhs = new static();
$rhs = new static();
}
$temp_value = &$temp->value;
$rhs_value = &$rhs->value;


 $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value);

while ($x->compare($temp) >= 0) {

 ++$quotient_value[$x_max - $y_max];
$x = $x->subtract($temp);
$x_max = count($x->value) - 1;
}

for ($i = $x_max; $i >= $y_max + 1; --$i) {
$x_value = &$x->value;
$x_window = array(
isset($x_value[$i]) ? $x_value[$i] : 0,
isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0
);
$y_window = array(
$y_value[$y_max],
($y_max > 0) ? $y_value[$y_max - 1] : 0
);

$q_index = $i - $y_max - 1;
if ($x_window[0] == $y_window[0]) {
$quotient_value[$q_index] = self::$maxDigit;
} else {
$quotient_value[$q_index] = $this->_safe_divide(
$x_window[0] * self::$baseFull + $x_window[1],
$y_window[0]
);
}

$temp_value = array($y_window[1], $y_window[0]);

$lhs->value = array($quotient_value[$q_index]);
$lhs = $lhs->multiply($temp);

$rhs_value = array($x_window[2], $x_window[1], $x_window[0]);

while ($lhs->compare($rhs) > 0) {
--$quotient_value[$q_index];

$lhs->value = array($quotient_value[$q_index]);
$lhs = $lhs->multiply($temp);
}

$adjust = $this->_array_repeat(0, $q_index);
$temp_value = array($quotient_value[$q_index]);
$temp = $temp->multiply($y);
$temp_value = &$temp->value;
if (count($temp_value)) {
$temp_value = array_merge($adjust, $temp_value);
}

$x = $x->subtract($temp);

if ($x->compare($zero) < 0) {
$temp_value = array_merge($adjust, $y_value);
$x = $x->add($temp);

--$quotient_value[$q_index];
}

$x_max = count($x_value) - 1;
}


 $x->_rshift($shift);

$quotient->is_negative = $x_sign != $y_sign;


 if ($x_sign) {
$y->_rshift($shift);
$x = $y->subtract($x);
}

return array($this->_normalize($quotient), $this->_normalize($x));
}











function _divide_digit($dividend, $divisor)
{
$carry = 0;
$result = array();

for ($i = count($dividend) - 1; $i >= 0; --$i) {
$temp = self::$baseFull * $carry + $dividend[$i];
$result[$i] = $this->_safe_divide($temp, $divisor);
$carry = (int) ($temp - $divisor * $result[$i]);
}

return array($result, $carry);
}









































function modPow($e, $n)
{
$n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();

if ($e->compare(new static()) < 0) {
$e = $e->abs();

$temp = $this->modInverse($n);
if ($temp === false) {
return false;
}

return $this->_normalize($temp->modPow($e, $n));
}

if (MATH_BIGINTEGER_MODE == self::MODE_GMP) {
$temp = new static();
$temp->value = gmp_powm($this->value, $e->value, $n->value);

return $this->_normalize($temp);
}

if ($this->compare(new static()) < 0 || $this->compare($n) > 0) {
list(, $temp) = $this->divide($n);
return $temp->modPow($e, $n);
}

if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
$components = array(
'modulus' => $n->toBytes(true),
'publicExponent' => $e->toBytes(true)
);

$components = array(
'modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']),
'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent'])
);

$RSAPublicKey = pack(
'Ca*a*a*',
48,
$this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])),
$components['modulus'],
$components['publicExponent']
);

$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); 
 $RSAPublicKey = chr(0) . $RSAPublicKey;
$RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey;

$encapsulated = pack(
'Ca*a*',
48,
$this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)),
$rsaOID . $RSAPublicKey
);

$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
chunk_split(base64_encode($encapsulated)) .
'-----END PUBLIC KEY-----';

$plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT);

if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) {
return new static($result, 256);
}
}

if (MATH_BIGINTEGER_MODE == self::MODE_BCMATH) {
$temp = new static();
$temp->value = bcpowmod($this->value, $e->value, $n->value, 0);

return $this->_normalize($temp);
}

if (empty($e->value)) {
$temp = new static();
$temp->value = array(1);
return $this->_normalize($temp);
}

if ($e->value == array(1)) {
list(, $temp) = $this->divide($n);
return $this->_normalize($temp);
}

if ($e->value == array(2)) {
$temp = new static();
$temp->value = $this->_square($this->value);
list(, $temp) = $temp->divide($n);
return $this->_normalize($temp);
}

return $this->_normalize($this->_slidingWindow($e, $n, self::BARRETT));


 
 
 


 if ($n->value[0] & 1) {
return $this->_normalize($this->_slidingWindow($e, $n, self::MONTGOMERY));
}



 for ($i = 0; $i < count($n->value); ++$i) {
if ($n->value[$i]) {
$temp = decbin($n->value[$i]);
$j = strlen($temp) - strrpos($temp, '1') - 1;
$j+= 26 * $i;
break;
}
}


$mod1 = $n->copy();
$mod1->_rshift($j);
$mod2 = new static();
$mod2->value = array(1);
$mod2->_lshift($j);

$part1 = ($mod1->value != array(1)) ? $this->_slidingWindow($e, $mod1, self::MONTGOMERY) : new static();
$part2 = $this->_slidingWindow($e, $mod2, self::POWEROF2);

$y1 = $mod2->modInverse($mod1);
$y2 = $mod1->modInverse($mod2);

$result = $part1->multiply($mod2);
$result = $result->multiply($y1);

$temp = $part2->multiply($mod1);
$temp = $temp->multiply($y2);

$result = $result->add($temp);
list(, $result) = $result->divide($n);

return $this->_normalize($result);
}











function powMod($e, $n)
{
return $this->modPow($e, $n);
}















function _slidingWindow($e, $n, $mode)
{
static $window_ranges = array(7, 25, 81, 241, 673, 1793); 
 

$e_value = $e->value;
$e_length = count($e_value) - 1;
$e_bits = decbin($e_value[$e_length]);
for ($i = $e_length - 1; $i >= 0; --$i) {
$e_bits.= str_pad(decbin($e_value[$i]), self::$base, '0', STR_PAD_LEFT);
}

$e_length = strlen($e_bits);


 
 for ($i = 0, $window_size = 1; $i < count($window_ranges) && $e_length > $window_ranges[$i]; ++$window_size, ++$i) {
}

$n_value = $n->value;


 $powers = array();
$powers[1] = $this->_prepareReduce($this->value, $n_value, $mode);
$powers[2] = $this->_squareReduce($powers[1], $n_value, $mode);


 
 $temp = 1 << ($window_size - 1);
for ($i = 1; $i < $temp; ++$i) {
$i2 = $i << 1;
$powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode);
}

$result = array(1);
$result = $this->_prepareReduce($result, $n_value, $mode);

for ($i = 0; $i < $e_length;) {
if (!$e_bits[$i]) {
$result = $this->_squareReduce($result, $n_value, $mode);
++$i;
} else {
for ($j = $window_size - 1; $j > 0; --$j) {
if (!empty($e_bits[$i + $j])) {
break;
}
}


 for ($k = 0; $k <= $j; ++$k) {
$result = $this->_squareReduce($result, $n_value, $mode);
}

$result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode);

$i += $j + 1;
}
}

$temp = new static();
$temp->value = $this->_reduce($result, $n_value, $mode);

return $temp;
}













function _reduce($x, $n, $mode)
{
switch ($mode) {
case self::MONTGOMERY:
return $this->_montgomery($x, $n);
case self::BARRETT:
return $this->_barrett($x, $n);
case self::POWEROF2:
$lhs = new static();
$lhs->value = $x;
$rhs = new static();
$rhs->value = $n;
return $x->_mod2($n);
case self::CLASSIC:
$lhs = new static();
$lhs->value = $x;
$rhs = new static();
$rhs->value = $n;
list(, $temp) = $lhs->divide($rhs);
return $temp->value;
case self::NONE:
return $x;
default:

 }
}











function _prepareReduce($x, $n, $mode)
{
if ($mode == self::MONTGOMERY) {
return $this->_prepMontgomery($x, $n);
}
return $this->_reduce($x, $n, $mode);
}












function _multiplyReduce($x, $y, $n, $mode)
{
if ($mode == self::MONTGOMERY) {
return $this->_montgomeryMultiply($x, $y, $n);
}
$temp = $this->_multiply($x, false, $y, false);
return $this->_reduce($temp[self::VALUE], $n, $mode);
}











function _squareReduce($x, $n, $mode)
{
if ($mode == self::MONTGOMERY) {
return $this->_montgomeryMultiply($x, $x, $n);
}
return $this->_reduce($this->_square($x), $n, $mode);
}












function _mod2($n)
{
$temp = new static();
$temp->value = array(1);
return $this->bitwise_and($n->subtract($temp));
}

























function _barrett($n, $m)
{
static $cache = array(
self::VARIABLE => array(),
self::DATA => array()
);

$m_length = count($m);


 if (count($n) > 2 * $m_length) {
$lhs = new static();
$rhs = new static();
$lhs->value = $n;
$rhs->value = $m;
list(, $temp) = $lhs->divide($rhs);
return $temp->value;
}


 if ($m_length < 5) {
return $this->_regularBarrett($n, $m);
}



if (($key = array_search($m, $cache[self::VARIABLE])) === false) {
$key = count($cache[self::VARIABLE]);
$cache[self::VARIABLE][] = $m;

$lhs = new static();
$lhs_value = &$lhs->value;
$lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1));
$lhs_value[] = 1;
$rhs = new static();
$rhs->value = $m;

list($u, $m1) = $lhs->divide($rhs);
$u = $u->value;
$m1 = $m1->value;

$cache[self::DATA][] = array(
'u' => $u, 
 'm1'=> $m1 
 );
} else {
extract($cache[self::DATA][$key]);
}

$cutoff = $m_length + ($m_length >> 1);
$lsd = array_slice($n, 0, $cutoff); 
 $msd = array_slice($n, $cutoff); 
 $lsd = $this->_trim($lsd);
$temp = $this->_multiply($msd, false, $m1, false);
$n = $this->_add($lsd, false, $temp[self::VALUE], false); 

if ($m_length & 1) {
return $this->_regularBarrett($n[self::VALUE], $m);
}


 $temp = array_slice($n[self::VALUE], $m_length - 1);

 
 $temp = $this->_multiply($temp, false, $u, false);

 
 $temp = array_slice($temp[self::VALUE], ($m_length >> 1) + 1);

 
 $temp = $this->_multiply($temp, false, $m, false);


 
 

$result = $this->_subtract($n[self::VALUE], false, $temp[self::VALUE], false);

while ($this->_compare($result[self::VALUE], $result[self::SIGN], $m, false) >= 0) {
$result = $this->_subtract($result[self::VALUE], $result[self::SIGN], $m, false);
}

return $result[self::VALUE];
}













function _regularBarrett($x, $n)
{
static $cache = array(
self::VARIABLE => array(),
self::DATA => array()
);

$n_length = count($n);

if (count($x) > 2 * $n_length) {
$lhs = new static();
$rhs = new static();
$lhs->value = $x;
$rhs->value = $n;
list(, $temp) = $lhs->divide($rhs);
return $temp->value;
}

if (($key = array_search($n, $cache[self::VARIABLE])) === false) {
$key = count($cache[self::VARIABLE]);
$cache[self::VARIABLE][] = $n;
$lhs = new static();
$lhs_value = &$lhs->value;
$lhs_value = $this->_array_repeat(0, 2 * $n_length);
$lhs_value[] = 1;
$rhs = new static();
$rhs->value = $n;
list($temp, ) = $lhs->divide($rhs); 
 $cache[self::DATA][] = $temp->value;
}


 $temp = array_slice($x, $n_length - 1);

 $temp = $this->_multiply($temp, false, $cache[self::DATA][$key], false);

 $temp = array_slice($temp[self::VALUE], $n_length + 1);


 $result = array_slice($x, 0, $n_length + 1);

 $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1);


if ($this->_compare($result, false, $temp[self::VALUE], $temp[self::SIGN]) < 0) {
$corrector_value = $this->_array_repeat(0, $n_length + 1);
$corrector_value[count($corrector_value)] = 1;
$result = $this->_add($result, false, $corrector_value, false);
$result = $result[self::VALUE];
}


 $result = $this->_subtract($result, false, $temp[self::VALUE], $temp[self::SIGN]);
while ($this->_compare($result[self::VALUE], $result[self::SIGN], $n, false) > 0) {
$result = $this->_subtract($result[self::VALUE], $result[self::SIGN], $n, false);
}

return $result[self::VALUE];
}















function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop)
{
$x_length = count($x_value);
$y_length = count($y_value);

if (!$x_length || !$y_length) { 
 return array(
self::VALUE => array(),
self::SIGN => false
);
}

if ($x_length < $y_length) {
$temp = $x_value;
$x_value = $y_value;
$y_value = $temp;

$x_length = count($x_value);
$y_length = count($y_value);
}

$product_value = $this->_array_repeat(0, $x_length + $y_length);


 
 
 
 

$carry = 0;

for ($j = 0; $j < $x_length; ++$j) { 
 $temp = $x_value[$j] * $y_value[0] + $carry; 
 $carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$product_value[$j] = (int) ($temp - self::$baseFull * $carry);
}

if ($j < $stop) {
$product_value[$j] = $carry;
}


 

for ($i = 1; $i < $y_length; ++$i) {
$carry = 0;

for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
$carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$product_value[$k] = (int) ($temp - self::$baseFull * $carry);
}

if ($k < $stop) {
$product_value[$k] = $carry;
}
}

return array(
self::VALUE => $this->_trim($product_value),
self::SIGN => $x_negative != $y_negative
);
}
















function _montgomery($x, $n)
{
static $cache = array(
self::VARIABLE => array(),
self::DATA => array()
);

if (($key = array_search($n, $cache[self::VARIABLE])) === false) {
$key = count($cache[self::VARIABLE]);
$cache[self::VARIABLE][] = $x;
$cache[self::DATA][] = $this->_modInverse67108864($n);
}

$k = count($n);

$result = array(self::VALUE => $x);

for ($i = 0; $i < $k; ++$i) {
$temp = $result[self::VALUE][$i] * $cache[self::DATA][$key];
$temp = $temp - self::$baseFull * (self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
$temp = $this->_regularMultiply(array($temp), $n);
$temp = array_merge($this->_array_repeat(0, $i), $temp);
$result = $this->_add($result[self::VALUE], false, $temp, false);
}

$result[self::VALUE] = array_slice($result[self::VALUE], $k);

if ($this->_compare($result, false, $n, false) >= 0) {
$result = $this->_subtract($result[self::VALUE], false, $n, false);
}

return $result[self::VALUE];
}















function _montgomeryMultiply($x, $y, $m)
{
$temp = $this->_multiply($x, false, $y, false);
return $this->_montgomery($temp[self::VALUE], $m);


 
 
 

static $cache = array(
self::VARIABLE => array(),
self::DATA => array()
);

if (($key = array_search($m, $cache[self::VARIABLE])) === false) {
$key = count($cache[self::VARIABLE]);
$cache[self::VARIABLE][] = $m;
$cache[self::DATA][] = $this->_modInverse67108864($m);
}

$n = max(count($x), count($y), count($m));
$x = array_pad($x, $n, 0);
$y = array_pad($y, $n, 0);
$m = array_pad($m, $n, 0);
$a = array(self::VALUE => $this->_array_repeat(0, $n + 1));
for ($i = 0; $i < $n; ++$i) {
$temp = $a[self::VALUE][0] + $x[$i] * $y[0];
$temp = $temp - self::$baseFull * (self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
$temp = $temp * $cache[self::DATA][$key];
$temp = $temp - self::$baseFull * (self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
$temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);
$a = $this->_add($a[self::VALUE], false, $temp[self::VALUE], false);
$a[self::VALUE] = array_slice($a[self::VALUE], 1);
}
if ($this->_compare($a[self::VALUE], false, $m, false) >= 0) {
$a = $this->_subtract($a[self::VALUE], false, $m, false);
}
return $a[self::VALUE];
}











function _prepMontgomery($x, $n)
{
$lhs = new static();
$lhs->value = array_merge($this->_array_repeat(0, count($n)), $x);
$rhs = new static();
$rhs->value = $n;

list(, $temp) = $lhs->divide($rhs);
return $temp->value;
}



























function _modInverse67108864($x) 
 {
$x = -$x[0];
$result = $x & 0x3; 
 $result = ($result * (2 - $x * $result)) & 0xF; 
 $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; 
 $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; 
 $result = fmod($result * (2 - fmod($x * $result, self::$baseFull)), self::$baseFull); 
 return $result & self::$maxDigit;
}




























function modInverse($n)
{
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$temp = new static();
$temp->value = gmp_invert($this->value, $n->value);

return ($temp->value === false) ? false : $this->_normalize($temp);
}

static $zero, $one;
if (!isset($zero)) {
$zero = new static();
$one = new static(1);
}


 $n = $n->abs();

if ($this->compare($zero) < 0) {
$temp = $this->abs();
$temp = $temp->modInverse($n);
return $this->_normalize($n->subtract($temp));
}

extract($this->extendedGCD($n));

if (!$gcd->equals($one)) {
return false;
}

$x = $x->compare($zero) < 0 ? $x->add($n) : $x;

return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x);
}





























function extendedGCD($n)
{
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
extract(gmp_gcdext($this->value, $n->value));

return array(
'gcd' => $this->_normalize(new static($g)),
'x' => $this->_normalize(new static($s)),
'y' => $this->_normalize(new static($t))
);
case self::MODE_BCMATH:

 
 

$u = $this->value;
$v = $n->value;

$a = '1';
$b = '0';
$c = '0';
$d = '1';

while (bccomp($v, '0', 0) != 0) {
$q = bcdiv($u, $v, 0);

$temp = $u;
$u = $v;
$v = bcsub($temp, bcmul($v, $q, 0), 0);

$temp = $a;
$a = $c;
$c = bcsub($temp, bcmul($a, $q, 0), 0);

$temp = $b;
$b = $d;
$d = bcsub($temp, bcmul($b, $q, 0), 0);
}

return array(
'gcd' => $this->_normalize(new static($u)),
'x' => $this->_normalize(new static($a)),
'y' => $this->_normalize(new static($b))
);
}

$y = $n->copy();
$x = $this->copy();
$g = new static();
$g->value = array(1);

while (!(($x->value[0] & 1)|| ($y->value[0] & 1))) {
$x->_rshift(1);
$y->_rshift(1);
$g->_lshift(1);
}

$u = $x->copy();
$v = $y->copy();

$a = new static();
$b = new static();
$c = new static();
$d = new static();

$a->value = $d->value = $g->value = array(1);
$b->value = $c->value = array();

while (!empty($u->value)) {
while (!($u->value[0] & 1)) {
$u->_rshift(1);
if ((!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1))) {
$a = $a->add($y);
$b = $b->subtract($x);
}
$a->_rshift(1);
$b->_rshift(1);
}

while (!($v->value[0] & 1)) {
$v->_rshift(1);
if ((!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1))) {
$c = $c->add($y);
$d = $d->subtract($x);
}
$c->_rshift(1);
$d->_rshift(1);
}

if ($u->compare($v) >= 0) {
$u = $u->subtract($v);
$a = $a->subtract($c);
$b = $b->subtract($d);
} else {
$v = $v->subtract($u);
$c = $c->subtract($a);
$d = $d->subtract($b);
}
}

return array(
'gcd' => $this->_normalize($g->multiply($v)),
'x' => $this->_normalize($c),
'y' => $this->_normalize($d)
);
}






















function gcd($n)
{
extract($this->extendedGCD($n));
return $gcd;
}







function abs()
{
$temp = new static();

switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$temp->value = gmp_abs($this->value);
break;
case self::MODE_BCMATH:
$temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value;
break;
default:
$temp->value = $this->value;
}

return $temp;
}



















function compare($y)
{
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$r = gmp_cmp($this->value, $y->value);
if ($r < -1) {
$r = -1;
}
if ($r > 1) {
$r = 1;
}
return $r;
case self::MODE_BCMATH:
return bccomp($this->value, $y->value, 0);
}

return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative);
}












function _compare($x_value, $x_negative, $y_value, $y_negative)
{
if ($x_negative != $y_negative) {
return (!$x_negative && $y_negative) ? 1 : -1;
}

$result = $x_negative ? -1 : 1;

if (count($x_value) != count($y_value)) {
return (count($x_value) > count($y_value)) ? $result : -$result;
}
$size = max(count($x_value), count($y_value));

$x_value = array_pad($x_value, $size, 0);
$y_value = array_pad($y_value, $size, 0);

for ($i = count($x_value) - 1; $i >= 0; --$i) {
if ($x_value[$i] != $y_value[$i]) {
return ($x_value[$i] > $y_value[$i]) ? $result : -$result;
}
}

return 0;
}











function equals($x)
{
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
return gmp_cmp($this->value, $x->value) == 0;
default:
return $this->value === $x->value && $this->is_negative == $x->is_negative;
}
}










function setPrecision($bits)
{
$this->precision = $bits;
if (MATH_BIGINTEGER_MODE != self::MODE_BCMATH) {
$this->bitmask = new static(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256);
} else {
$this->bitmask = new static(bcpow('2', $bits, 0));
}

$temp = $this->_normalize($this);
$this->value = $temp->value;
}









function bitwise_and($x)
{
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$temp = new static();
$temp->value = gmp_and($this->value, $x->value);

return $this->_normalize($temp);
case self::MODE_BCMATH:
$left = $this->toBytes();
$right = $x->toBytes();

$length = max(strlen($left), strlen($right));

$left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
$right = str_pad($right, $length, chr(0), STR_PAD_LEFT);

return $this->_normalize(new static($left & $right, 256));
}

$result = $this->copy();

$length = min(count($x->value), count($this->value));

$result->value = array_slice($result->value, 0, $length);

for ($i = 0; $i < $length; ++$i) {
$result->value[$i]&= $x->value[$i];
}

return $this->_normalize($result);
}









function bitwise_or($x)
{
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$temp = new static();
$temp->value = gmp_or($this->value, $x->value);

return $this->_normalize($temp);
case self::MODE_BCMATH:
$left = $this->toBytes();
$right = $x->toBytes();

$length = max(strlen($left), strlen($right));

$left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
$right = str_pad($right, $length, chr(0), STR_PAD_LEFT);

return $this->_normalize(new static($left | $right, 256));
}

$length = max(count($this->value), count($x->value));
$result = $this->copy();
$result->value = array_pad($result->value, $length, 0);
$x->value = array_pad($x->value, $length, 0);

for ($i = 0; $i < $length; ++$i) {
$result->value[$i]|= $x->value[$i];
}

return $this->_normalize($result);
}









function bitwise_xor($x)
{
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$temp = new static();
$temp->value = gmp_xor(gmp_abs($this->value), gmp_abs($x->value));
return $this->_normalize($temp);
case self::MODE_BCMATH:
$left = $this->toBytes();
$right = $x->toBytes();

$length = max(strlen($left), strlen($right));

$left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
$right = str_pad($right, $length, chr(0), STR_PAD_LEFT);

return $this->_normalize(new static($left ^ $right, 256));
}

$length = max(count($this->value), count($x->value));
$result = $this->copy();
$result->is_negative = false;
$result->value = array_pad($result->value, $length, 0);
$x->value = array_pad($x->value, $length, 0);

for ($i = 0; $i < $length; ++$i) {
$result->value[$i]^= $x->value[$i];
}

return $this->_normalize($result);
}








function bitwise_not()
{

 
 $temp = $this->toBytes();
if ($temp == '') {
return $this->_normalize(new static());
}
$pre_msb = decbin(ord($temp[0]));
$temp = ~$temp;
$msb = decbin(ord($temp[0]));
if (strlen($msb) == 8) {
$msb = substr($msb, strpos($msb, '0'));
}
$temp[0] = chr(bindec($msb));


 $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;
$new_bits = $this->precision - $current_bits;
if ($new_bits <= 0) {
return $this->_normalize(new static($temp, 256));
}


 $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);
$this->_base256_lshift($leading_ones, $current_bits);

$temp = str_pad($temp, strlen($leading_ones), chr(0), STR_PAD_LEFT);

return $this->_normalize(new static($leading_ones | $temp, 256));
}











function bitwise_rightShift($shift)
{
$temp = new static();

switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
static $two;

if (!isset($two)) {
$two = gmp_init('2');
}

$temp->value = gmp_div_q($this->value, gmp_pow($two, $shift));

break;
case self::MODE_BCMATH:
$temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0);

break;
default: 
 
 $temp->value = $this->value;
$temp->_rshift($shift);
}

return $this->_normalize($temp);
}











function bitwise_leftShift($shift)
{
$temp = new static();

switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
static $two;

if (!isset($two)) {
$two = gmp_init('2');
}

$temp->value = gmp_mul($this->value, gmp_pow($two, $shift));

break;
case self::MODE_BCMATH:
$temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0);

break;
default: 
 
 $temp->value = $this->value;
$temp->_lshift($shift);
}

return $this->_normalize($temp);
}










function bitwise_leftRotate($shift)
{
$bits = $this->toBytes();

if ($this->precision > 0) {
$precision = $this->precision;
if (MATH_BIGINTEGER_MODE == self::MODE_BCMATH) {
$mask = $this->bitmask->subtract(new static(1));
$mask = $mask->toBytes();
} else {
$mask = $this->bitmask->toBytes();
}
} else {
$temp = ord($bits[0]);
for ($i = 0; $temp >> $i; ++$i) {
}
$precision = 8 * strlen($bits) - 8 + $i;
$mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);
}

if ($shift < 0) {
$shift+= $precision;
}
$shift%= $precision;

if (!$shift) {
return $this->copy();
}

$left = $this->bitwise_leftShift($shift);
$left = $left->bitwise_and(new static($mask, 256));
$right = $this->bitwise_rightShift($precision - $shift);
$result = MATH_BIGINTEGER_MODE != self::MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right);
return $this->_normalize($result);
}










function bitwise_rightRotate($shift)
{
return $this->bitwise_leftRotate(-$shift);
}










function _random_number_helper($size)
{
if (class_exists('\phpseclib\Crypt\Random')) {
$random = Random::string($size);
} else {
$random = '';

if ($size & 1) {
$random.= chr(mt_rand(0, 255));
}

$blocks = $size >> 1;
for ($i = 0; $i < $blocks; ++$i) {

 $random.= pack('n', mt_rand(0, 0xFFFF));
}
}

return new static($random, 256);
}

















function random($arg1, $arg2 = false)
{
if ($arg1 === false) {
return false;
}

if ($arg2 === false) {
$max = $arg1;
$min = $this;
} else {
$min = $arg1;
$max = $arg2;
}

$compare = $max->compare($min);

if (!$compare) {
return $this->_normalize($min);
} elseif ($compare < 0) {

 $temp = $max;
$max = $min;
$min = $temp;
}

static $one;
if (!isset($one)) {
$one = new static(1);
}

$max = $max->subtract($min->subtract($one));
$size = strlen(ltrim($max->toBytes(), chr(0)));
















$random_max = new static(chr(1) . str_repeat("\0", $size), 256);
$random = $this->_random_number_helper($size);

list($max_multiple) = $random_max->divide($max);
$max_multiple = $max_multiple->multiply($max);

while ($random->compare($max_multiple) >= 0) {
$random = $random->subtract($max_multiple);
$random_max = $random_max->subtract($max_multiple);
$random = $random->bitwise_leftShift(8);
$random = $random->add($this->_random_number_helper(1));
$random_max = $random_max->bitwise_leftShift(8);
list($max_multiple) = $random_max->divide($max);
$max_multiple = $max_multiple->multiply($max);
}
list(, $random) = $random->divide($max);

return $this->_normalize($random->add($min));
}














function randomPrime($arg1, $arg2 = false, $timeout = false)
{
if ($arg1 === false) {
return false;
}

if ($arg2 === false) {
$max = $arg1;
$min = $this;
} else {
$min = $arg1;
$max = $arg2;
}

$compare = $max->compare($min);

if (!$compare) {
return $min->isPrime() ? $min : false;
} elseif ($compare < 0) {

 $temp = $max;
$max = $min;
$min = $temp;
}

static $one, $two;
if (!isset($one)) {
$one = new static(1);
$two = new static(2);
}

$start = time();

$x = $this->random($min, $max);


 if (MATH_BIGINTEGER_MODE == self::MODE_GMP && extension_loaded('gmp')) {
$p = new static();
$p->value = gmp_nextprime($x->value);

if ($p->compare($max) <= 0) {
return $p;
}

if (!$min->equals($x)) {
$x = $x->subtract($one);
}

return $x->randomPrime($min, $x);
}

if ($x->equals($two)) {
return $x;
}

$x->_make_odd();
if ($x->compare($max) > 0) {

 if ($min->equals($max)) {
return false;
}
$x = $min->copy();
$x->_make_odd();
}

$initial_x = $x->copy();

while (true) {
if ($timeout !== false && time() - $start > $timeout) {
return false;
}

if ($x->isPrime()) {
return $x;
}

$x = $x->add($two);

if ($x->compare($max) > 0) {
$x = $min->copy();
if ($x->equals($two)) {
return $x;
}
$x->_make_odd();
}

if ($x->equals($initial_x)) {
return false;
}
}
}









function _make_odd()
{
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
gmp_setbit($this->value, 0);
break;
case self::MODE_BCMATH:
if ($this->value[strlen($this->value) - 1] % 2 == 0) {
$this->value = bcadd($this->value, '1');
}
break;
default:
$this->value[0] |= 1;
}
}















function isPrime($t = false)
{
$length = strlen($this->toBytes());

if (!$t) {

 
 if ($length >= 163) { $t = 2; } 
 else if ($length >= 106) { $t = 3; } 
 else if ($length >= 81 ) { $t = 4; } 
 else if ($length >= 68 ) { $t = 5; } 
 else if ($length >= 56 ) { $t = 6; } 
 else if ($length >= 50 ) { $t = 7; } 
 else if ($length >= 43 ) { $t = 8; } 
 else if ($length >= 37 ) { $t = 9; } 
 else if ($length >= 31 ) { $t = 12; } 
 else if ($length >= 25 ) { $t = 15; } 
 else if ($length >= 18 ) { $t = 18; } 
 else { $t = 27; }

 }


 
 switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
return gmp_prob_prime($this->value, $t) != 0;
case self::MODE_BCMATH:
if ($this->value === '2') {
return true;
}
if ($this->value[strlen($this->value) - 1] % 2 == 0) {
return false;
}
break;
default:
if ($this->value == array(2)) {
return true;
}
if (~$this->value[0] & 1) {
return false;
}
}

static $primes, $zero, $one, $two;

if (!isset($primes)) {
$primes = array(
3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
953, 967, 971, 977, 983, 991, 997
);

if (MATH_BIGINTEGER_MODE != self::MODE_INTERNAL) {
for ($i = 0; $i < count($primes); ++$i) {
$primes[$i] = new static($primes[$i]);
}
}

$zero = new static();
$one = new static(1);
$two = new static(2);
}

if ($this->equals($one)) {
return false;
}


 if (MATH_BIGINTEGER_MODE != self::MODE_INTERNAL) {
foreach ($primes as $prime) {
list(, $r) = $this->divide($prime);
if ($r->equals($zero)) {
return $this->equals($prime);
}
}
} else {
$value = $this->value;
foreach ($primes as $prime) {
list(, $r) = $this->_divide_digit($value, $prime);
if (!$r) {
return count($value) == 1 && $value[0] == $prime;
}
}
}

$n = $this->copy();
$n_1 = $n->subtract($one);
$n_2 = $n->subtract($two);

$r = $n_1->copy();
$r_value = $r->value;

 if (MATH_BIGINTEGER_MODE == self::MODE_BCMATH) {
$s = 0;

 while ($r->value[strlen($r->value) - 1] % 2 == 0) {
$r->value = bcdiv($r->value, '2', 0);
++$s;
}
} else {
for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {
$temp = ~$r_value[$i] & 0xFFFFFF;
for ($j = 1; ($temp >> $j) & 1; ++$j) {
}
if ($j != 25) {
break;
}
}
$s = 26 * $i + $j;
$r->_rshift($s);
}

for ($i = 0; $i < $t; ++$i) {
$a = $this->random($two, $n_2);
$y = $a->modPow($r, $n);

if (!$y->equals($one) && !$y->equals($n_1)) {
for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) {
$y = $y->modPow($two, $n);
if ($y->equals($one)) {
return false;
}
}

if (!$y->equals($n_1)) {
return false;
}
}
}
return true;
}









function _lshift($shift)
{
if ($shift == 0) {
return;
}

$num_digits = (int) ($shift / self::$base);
$shift %= self::$base;
$shift = 1 << $shift;

$carry = 0;

for ($i = 0; $i < count($this->value); ++$i) {
$temp = $this->value[$i] * $shift + $carry;
$carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$this->value[$i] = (int) ($temp - $carry * self::$baseFull);
}

if ($carry) {
$this->value[count($this->value)] = $carry;
}

while ($num_digits--) {
array_unshift($this->value, 0);
}
}









function _rshift($shift)
{
if ($shift == 0) {
return;
}

$num_digits = (int) ($shift / self::$base);
$shift %= self::$base;
$carry_shift = self::$base - $shift;
$carry_mask = (1 << $shift) - 1;

if ($num_digits) {
$this->value = array_slice($this->value, $num_digits);
}

$carry = 0;

for ($i = count($this->value) - 1; $i >= 0; --$i) {
$temp = $this->value[$i] >> $shift | $carry;
$carry = ($this->value[$i] & $carry_mask) << $carry_shift;
$this->value[$i] = $temp;
}

$this->value = $this->_trim($this->value);
}











function _normalize($result)
{
$result->precision = $this->precision;
$result->bitmask = $this->bitmask;

switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
if ($this->bitmask !== false) {
$flip = gmp_cmp($result->value, gmp_init(0)) < 0;
if ($flip) {
$result->value = gmp_neg($result->value);
}
$result->value = gmp_and($result->value, $result->bitmask->value);
if ($flip) {
$result->value = gmp_neg($result->value);
}
}

return $result;
case self::MODE_BCMATH:
if (!empty($result->bitmask->value)) {
$result->value = bcmod($result->value, $result->bitmask->value);
}

return $result;
}

$value = &$result->value;

if (!count($value)) {
$result->is_negative = false;
return $result;
}

$value = $this->_trim($value);

if (!empty($result->bitmask->value)) {
$length = min(count($value), count($this->bitmask->value));
$value = array_slice($value, 0, $length);

for ($i = 0; $i < $length; ++$i) {
$value[$i] = $value[$i] & $this->bitmask->value[$i];
}
}

return $result;
}










function _trim($value)
{
for ($i = count($value) - 1; $i >= 0; --$i) {
if ($value[$i]) {
break;
}
unset($value[$i]);
}

return $value;
}









function _array_repeat($input, $multiplier)
{
return ($multiplier) ? array_fill(0, $multiplier, $input) : array();
}











function _base256_lshift(&$x, $shift)
{
if ($shift == 0) {
return;
}

$num_bytes = $shift >> 3; 
 $shift &= 7; 

$carry = 0;
for ($i = strlen($x) - 1; $i >= 0; --$i) {
$temp = ord($x[$i]) << $shift | $carry;
$x[$i] = chr($temp);
$carry = $temp >> 8;
}
$carry = ($carry != 0) ? chr($carry) : '';
$x = $carry . $x . str_repeat(chr(0), $num_bytes);
}











function _base256_rshift(&$x, $shift)
{
if ($shift == 0) {
$x = ltrim($x, chr(0));
return '';
}

$num_bytes = $shift >> 3; 
 $shift &= 7; 

$remainder = '';
if ($num_bytes) {
$start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes;
$remainder = substr($x, $start);
$x = substr($x, 0, -$num_bytes);
}

$carry = 0;
$carry_shift = 8 - $shift;
for ($i = 0; $i < strlen($x); ++$i) {
$temp = (ord($x[$i]) >> $shift) | $carry;
$carry = (ord($x[$i]) << $carry_shift) & 0xFF;
$x[$i] = chr($temp);
}
$x = ltrim($x, chr(0));

$remainder = chr($carry >> $carry_shift) . $remainder;

return ltrim($remainder, chr(0));
}


 








function _int2bytes($x)
{
return ltrim(pack('N', $x), chr(0));
}








function _bytes2int($x)
{
$temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));
return $temp['int'];
}











function _encodeASN1Length($length)
{
if ($length <= 0x7F) {
return chr($length);
}

$temp = ltrim(pack('N', $length), chr(0));
return pack('Ca*', 0x80 | strlen($temp), $temp);
}














function _safe_divide($x, $y)
{
if (self::$base === 26) {
return (int) ($x / $y);
}


 return ($x - ($x % $y)) / $y;
}
}
<?php


































namespace phpseclib\Crypt;







class RC2 extends Base
{







var $block_size = 8;









var $key;











var $orig_key;








var $skip_key_adjustment = true;








var $key_length = 16; 








var $cipher_name_mcrypt = 'rc2';








var $cfb_init_len = 500;











var $default_key_length = 1024;










var $current_key_length;








var $keys;









var $pitable = array(
0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD,
0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD
);








var $invpitable = array(
0xD1, 0xDA, 0xB9, 0x6F, 0x9C, 0xC8, 0x78, 0x66,
0x80, 0x2C, 0xF8, 0x37, 0xEA, 0xE0, 0x62, 0xA4,
0xCB, 0x71, 0x50, 0x27, 0x4B, 0x95, 0xD9, 0x20,
0x9D, 0x04, 0x91, 0xE3, 0x47, 0x6A, 0x7E, 0x53,
0xFA, 0x3A, 0x3B, 0xB4, 0xA8, 0xBC, 0x5F, 0x68,
0x08, 0xCA, 0x8F, 0x14, 0xD7, 0xC0, 0xEF, 0x7B,
0x5B, 0xBF, 0x2F, 0xE5, 0xE2, 0x8C, 0xBA, 0x12,
0xE1, 0xAF, 0xB2, 0x54, 0x5D, 0x59, 0x76, 0xDB,
0x32, 0xA2, 0x58, 0x6E, 0x1C, 0x29, 0x64, 0xF3,
0xE9, 0x96, 0x0C, 0x98, 0x19, 0x8D, 0x3E, 0x26,
0xAB, 0xA5, 0x85, 0x16, 0x40, 0xBD, 0x49, 0x67,
0xDC, 0x22, 0x94, 0xBB, 0x3C, 0xC1, 0x9B, 0xEB,
0x45, 0x28, 0x18, 0xD8, 0x1A, 0x42, 0x7D, 0xCC,
0xFB, 0x65, 0x8E, 0x3D, 0xCD, 0x2A, 0xA3, 0x60,
0xAE, 0x93, 0x8A, 0x48, 0x97, 0x51, 0x15, 0xF7,
0x01, 0x0B, 0xB7, 0x36, 0xB1, 0x2E, 0x11, 0xFD,
0x84, 0x2D, 0x3F, 0x13, 0x88, 0xB3, 0x34, 0x24,
0x1B, 0xDE, 0xC5, 0x1D, 0x4D, 0x2B, 0x17, 0x31,
0x74, 0xA9, 0xC6, 0x43, 0x6D, 0x39, 0x90, 0xBE,
0xC3, 0xB0, 0x21, 0x6B, 0xF6, 0x0F, 0xD5, 0x99,
0x0D, 0xAC, 0x1F, 0x5C, 0x9E, 0xF5, 0xF9, 0x4C,
0xD6, 0xDF, 0x89, 0xE4, 0x8B, 0xFF, 0xC7, 0xAA,
0xE7, 0xED, 0x46, 0x25, 0xB6, 0x06, 0x5E, 0x35,
0xB5, 0xEC, 0xCE, 0xE8, 0x6C, 0x30, 0x55, 0x61,
0x4A, 0xFE, 0xA0, 0x79, 0x03, 0xF0, 0x10, 0x72,
0x7C, 0xCF, 0x52, 0xA6, 0xA7, 0xEE, 0x44, 0xD3,
0x9A, 0x57, 0x92, 0xD0, 0x5A, 0x7A, 0x41, 0x7F,
0x0E, 0x00, 0x63, 0xF2, 0x4F, 0x05, 0x83, 0xC9,
0xA1, 0xD4, 0xDD, 0xC4, 0x56, 0xF4, 0xD2, 0x77,
0x81, 0x09, 0x82, 0x33, 0x9F, 0x07, 0x86, 0x75,
0x38, 0x4E, 0x69, 0xF1, 0xAD, 0x23, 0x73, 0x87,
0x70, 0x02, 0xC2, 0x1E, 0xB8, 0x0A, 0xFC, 0xE6
);











function isValidEngine($engine)
{
switch ($engine) {
case self::ENGINE_OPENSSL:
if ($this->current_key_length != 128 || strlen($this->orig_key) < 16) {
return false;
}
$this->cipher_name_openssl_ecb = 'rc2-ecb';
$this->cipher_name_openssl = 'rc2-' . $this->_openssl_translate_mode();
}

return parent::isValidEngine($engine);
}











function setKeyLength($length)
{
if ($length < 8) {
$this->default_key_length = 1;
} elseif ($length > 1024) {
$this->default_key_length = 128;
} else {
$this->default_key_length = $length;
}
$this->current_key_length = $this->default_key_length;

parent::setKeyLength($length);
}







function getKeyLength()
{
return $this->current_key_length;
}

















function setKey($key, $t1 = 0)
{
$this->orig_key = $key;

if ($t1 <= 0) {
$t1 = $this->default_key_length;
} elseif ($t1 > 1024) {
$t1 = 1024;
}
$this->current_key_length = $t1;

 $key = strlen($key) ? substr($key, 0, 128) : "\x00";
$t = strlen($key);


 
 
 
 


 $l = array_values(unpack('C*', $key));
$t8 = ($t1 + 7) >> 3;
$tm = 0xFF >> (8 * $t8 - $t1);


 $pitable = $this->pitable;
for ($i = $t; $i < 128; $i++) {
$l[$i] = $pitable[$l[$i - 1] + $l[$i - $t]];
}
$i = 128 - $t8;
$l[$i] = $pitable[$l[$i] & $tm];
while ($i--) {
$l[$i] = $pitable[$l[$i + 1] ^ $l[$i + $t8]];
}


 $l[0] = $this->invpitable[$l[0]];
array_unshift($l, 'C*');

parent::setKey(call_user_func_array('pack', $l));
}











function encrypt($plaintext)
{
if ($this->engine == self::ENGINE_OPENSSL) {
$temp = $this->key;
$this->key = $this->orig_key;
$result = parent::encrypt($plaintext);
$this->key = $temp;
return $result;
}

return parent::encrypt($plaintext);
}











function decrypt($ciphertext)
{
if ($this->engine == self::ENGINE_OPENSSL) {
$temp = $this->key;
$this->key = $this->orig_key;
$result = parent::decrypt($ciphertext);
$this->key = $temp;
return $result;
}

return parent::decrypt($ciphertext);
}










function _encryptBlock($in)
{
list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
$keys = $this->keys;
$limit = 20;
$actions = array($limit => 44, 44 => 64);
$j = 0;

for (;;) {

 $r0 = (($r0 + $keys[$j++] + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
$r0 |= $r0 >> 16;
$r1 = (($r1 + $keys[$j++] + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
$r1 |= $r1 >> 16;
$r2 = (($r2 + $keys[$j++] + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
$r2 |= $r2 >> 16;
$r3 = (($r3 + $keys[$j++] + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
$r3 |= $r3 >> 16;

if ($j === $limit) {
if ($limit === 64) {
break;
}


 $r0 += $keys[$r3 & 0x3F];
$r1 += $keys[$r0 & 0x3F];
$r2 += $keys[$r1 & 0x3F];
$r3 += $keys[$r2 & 0x3F];
$limit = $actions[$limit];
}
}

return pack('vvvv', $r0, $r1, $r2, $r3);
}










function _decryptBlock($in)
{
list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
$keys = $this->keys;
$limit = 44;
$actions = array($limit => 20, 20 => 0);
$j = 64;

for (;;) {

 $r3 = ($r3 | ($r3 << 16)) >> 5;
$r3 = ($r3 - $keys[--$j] - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
$r2 = ($r2 | ($r2 << 16)) >> 3;
$r2 = ($r2 - $keys[--$j] - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
$r1 = ($r1 | ($r1 << 16)) >> 2;
$r1 = ($r1 - $keys[--$j] - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
$r0 = ($r0 | ($r0 << 16)) >> 1;
$r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;

if ($j === $limit) {
if ($limit === 0) {
break;
}


 $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
$r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
$r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
$r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;
$limit = $actions[$limit];
}
}

return pack('vvvv', $r0, $r1, $r2, $r3);
}







function _setupMcrypt()
{
if (!isset($this->key)) {
$this->setKey('');
}

parent::_setupMcrypt();
}







function _setupKey()
{
if (!isset($this->key)) {
$this->setKey('');
}


 
 $l = unpack('Ca/Cb/v*', $this->key);
array_unshift($l, $this->pitable[$l['a']] | ($l['b'] << 8));
unset($l['a']);
unset($l['b']);
$this->keys = $l;
}







function _setupInlineCrypt()
{
$lambda_functions =& self::_getLambdaFunctions();


 
 
 
 $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);


 $code_hash = "Crypt_RC2, {$this->mode}";
if ($gen_hi_opt_code) {
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}


 
 if (!isset($lambda_functions[$code_hash])) {

 $init_crypt = '$keys = $self->keys;';

switch (true) {
case $gen_hi_opt_code:
$keys = $this->keys;
default:
$keys = array();
foreach ($this->keys as $k => $v) {
$keys[$k] = '$keys[' . $k . ']';
}
}


 $encrypt_block = $decrypt_block = '
                $in = unpack("v4", $in);
                $r0 = $in[1];
                $r1 = $in[2];
                $r2 = $in[3];
                $r3 = $in[4];
            ';


 $limit = 20;
$actions = array($limit => 44, 44 => 64);
$j = 0;

for (;;) {

 $encrypt_block .= '
                    $r0 = (($r0 + ' . $keys[$j++] . ' +
                           ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
                    $r0 |= $r0 >> 16;
                    $r1 = (($r1 + ' . $keys[$j++] . ' +
                           ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
                    $r1 |= $r1 >> 16;
                    $r2 = (($r2 + ' . $keys[$j++] . ' +
                           ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
                    $r2 |= $r2 >> 16;
                    $r3 = (($r3 + ' . $keys[$j++] . ' +
                           ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
                    $r3 |= $r3 >> 16;';

if ($j === $limit) {
if ($limit === 64) {
break;
}


 $encrypt_block .= '
                        $r0 += $keys[$r3 & 0x3F];
                        $r1 += $keys[$r0 & 0x3F];
                        $r2 += $keys[$r1 & 0x3F];
                        $r3 += $keys[$r2 & 0x3F];';
$limit = $actions[$limit];
}
}

$encrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';


 $limit = 44;
$actions = array($limit => 20, 20 => 0);
$j = 64;

for (;;) {

 $decrypt_block .= '
                    $r3 = ($r3 | ($r3 << 16)) >> 5;
                    $r3 = ($r3 - ' . $keys[--$j] . ' -
                           ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
                    $r2 = ($r2 | ($r2 << 16)) >> 3;
                    $r2 = ($r2 - ' . $keys[--$j] . ' -
                           ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
                    $r1 = ($r1 | ($r1 << 16)) >> 2;
                    $r1 = ($r1 - ' . $keys[--$j] . ' -
                           ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
                    $r0 = ($r0 | ($r0 << 16)) >> 1;
                    $r0 = ($r0 - ' . $keys[--$j] . ' -
                           ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;';

if ($j === $limit) {
if ($limit === 0) {
break;
}


 $decrypt_block .= '
                        $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
                        $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
                        $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
                        $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;';
$limit = $actions[$limit];
}
}

$decrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';


 $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
array(
'init_crypt' => $init_crypt,
'encrypt_block' => $encrypt_block,
'decrypt_block' => $decrypt_block
)
);
}


 $this->inline_crypt = $lambda_functions[$code_hash];
}
}
<?php























namespace phpseclib\Crypt;








class Random
{










static function string($length)
{
if (!$length) {
return '';
}

if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
try {
return \random_bytes($length);
} catch (\Throwable $e) {

 
 
 
 
 
 }
}

if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {

 
 if (extension_loaded('mcrypt') && function_exists('class_alias')) {
return @mcrypt_create_iv($length);
}

 
 
 
 
 
 
 
 
 
 
 
 
 if (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
return openssl_random_pseudo_bytes($length);
}
} else {

 if (extension_loaded('openssl')) {
return openssl_random_pseudo_bytes($length);
}

 static $fp = true;
if ($fp === true) {

 
 $fp = @fopen('/dev/urandom', 'rb');
}
if ($fp !== true && $fp !== false) { 
 $temp = fread($fp, $length);
if (strlen($temp) == $length) {
return $temp;
}
}

 
 
 
 
 if (extension_loaded('mcrypt')) {
return @mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
}
}



 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 static $crypto = false, $v;
if ($crypto === false) {

 $old_session_id = session_id();
$old_use_cookies = ini_get('session.use_cookies');
$old_session_cache_limiter = session_cache_limiter();
$_OLD_SESSION = isset($_SESSION) ? $_SESSION : false;
if ($old_session_id != '') {
session_write_close();
}

session_id(1);
ini_set('session.use_cookies', 0);
session_cache_limiter('');
session_start();

$v = $seed = $_SESSION['seed'] = pack('H*', sha1(
(isset($_SERVER) ? phpseclib_safe_serialize($_SERVER) : '') .
(isset($_POST) ? phpseclib_safe_serialize($_POST) : '') .
(isset($_GET) ? phpseclib_safe_serialize($_GET) : '') .
(isset($_COOKIE) ? phpseclib_safe_serialize($_COOKIE) : '') .
phpseclib_safe_serialize($GLOBALS) .
phpseclib_safe_serialize($_SESSION) .
phpseclib_safe_serialize($_OLD_SESSION)
));
if (!isset($_SESSION['count'])) {
$_SESSION['count'] = 0;
}
$_SESSION['count']++;

session_write_close();


 if ($old_session_id != '') {
session_id($old_session_id);
session_start();
ini_set('session.use_cookies', $old_use_cookies);
session_cache_limiter($old_session_cache_limiter);
} else {
if ($_OLD_SESSION !== false) {
$_SESSION = $_OLD_SESSION;
unset($_OLD_SESSION);
} else {
unset($_SESSION);
}
}


 
 
 
 
 
 
 
 $key = pack('H*', sha1($seed . 'A'));
$iv = pack('H*', sha1($seed . 'C'));


 
 
 switch (true) {
case class_exists('\phpseclib\Crypt\AES'):
$crypto = new AES(Base::MODE_CTR);
break;
case class_exists('\phpseclib\Crypt\Twofish'):
$crypto = new Twofish(Base::MODE_CTR);
break;
case class_exists('\phpseclib\Crypt\Blowfish'):
$crypto = new Blowfish(Base::MODE_CTR);
break;
case class_exists('\phpseclib\Crypt\TripleDES'):
$crypto = new TripleDES(Base::MODE_CTR);
break;
case class_exists('\phpseclib\Crypt\DES'):
$crypto = new DES(Base::MODE_CTR);
break;
case class_exists('\phpseclib\Crypt\RC4'):
$crypto = new RC4();
break;
default:
user_error(__CLASS__ . ' requires at least one symmetric cipher be loaded');
return false;
}

$crypto->setKey($key);
$crypto->setIV($iv);
$crypto->enableContinuousBuffer();
}




 
 
 
 
 
 
 
 $result = '';
while (strlen($result) < $length) {
$i = $crypto->encrypt(microtime()); 
 $r = $crypto->encrypt($i ^ $v); 
 $v = $crypto->encrypt($r ^ $i); 
 $result.= $r;
}
return substr($result, 0, $length);
}
}

if (!function_exists('phpseclib_safe_serialize')) {









function phpseclib_safe_serialize(&$arr)
{
if (is_object($arr)) {
return '';
}
if (!is_array($arr)) {
return serialize($arr);
}

 if (isset($arr['__phpseclib_marker'])) {
return '';
}
$safearr = array();
$arr['__phpseclib_marker'] = true;
foreach (array_keys($arr) as $key) {

 if ($key !== '__phpseclib_marker') {
$safearr[$key] = phpseclib_safe_serialize($arr[$key]);
}
}
unset($arr['__phpseclib_marker']);
return serialize($safearr);
}
}
<?php





















































namespace phpseclib\Crypt;








class Rijndael extends Base
{














var $cipher_name_mcrypt = 'rijndael-128';









var $password_default_salt = 'phpseclib';








var $w;








var $dw;












var $Nb = 4;












var $key_length = 16;









var $Nk = 4;








var $Nr;







var $c;







var $kl;





















function setKeyLength($length)
{
switch (true) {
case $length <= 128:
$this->key_length = 16;
break;
case $length <= 160:
$this->key_length = 20;
break;
case $length <= 192:
$this->key_length = 24;
break;
case $length <= 224:
$this->key_length = 28;
break;
default:
$this->key_length = 32;
}

parent::setKeyLength($length);
}










function setBlockLength($length)
{
$length >>= 5;
if ($length > 8) {
$length = 8;
} elseif ($length < 4) {
$length = 4;
}
$this->Nb = $length;
$this->block_size = $length << 2;
$this->changed = true;
$this->_setEngine();
}











function isValidEngine($engine)
{
switch ($engine) {
case self::ENGINE_OPENSSL:
if ($this->block_size != 16) {
return false;
}
$this->cipher_name_openssl_ecb = 'aes-' . ($this->key_length << 3) . '-ecb';
$this->cipher_name_openssl = 'aes-' . ($this->key_length << 3) . '-' . $this->_openssl_translate_mode();
break;
case self::ENGINE_MCRYPT:
$this->cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3);
if ($this->key_length % 8) { 
 
 return false;
}
}

return parent::isValidEngine($engine);
}








function _encryptBlock($in)
{
static $tables;
if (empty($tables)) {
$tables = &$this->_getTables();
}
$t0 = $tables[0];
$t1 = $tables[1];
$t2 = $tables[2];
$t3 = $tables[3];
$sbox = $tables[4];

$state = array();
$words = unpack('N*', $in);

$c = $this->c;
$w = $this->w;
$Nb = $this->Nb;
$Nr = $this->Nr;


 $wc = $Nb - 1;
foreach ($words as $word) {
$state[] = $word ^ $w[++$wc];
}


 
 
 
 
 


 $temp = array();
for ($round = 1; $round < $Nr; ++$round) {
$i = 0; 
 $j = $c[1];
$k = $c[2];
$l = $c[3];

while ($i < $Nb) {
$temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^
$t1[$state[$j] >> 16 & 0x000000FF] ^
$t2[$state[$k] >> 8 & 0x000000FF] ^
$t3[$state[$l] & 0x000000FF] ^
$w[++$wc];
++$i;
$j = ($j + 1) % $Nb;
$k = ($k + 1) % $Nb;
$l = ($l + 1) % $Nb;
}
$state = $temp;
}


 for ($i = 0; $i < $Nb; ++$i) {
$state[$i] = $sbox[$state[$i] & 0x000000FF] |
($sbox[$state[$i] >> 8 & 0x000000FF] << 8) |
($sbox[$state[$i] >> 16 & 0x000000FF] << 16) |
($sbox[$state[$i] >> 24 & 0x000000FF] << 24);
}


 $i = 0; 
 $j = $c[1];
$k = $c[2];
$l = $c[3];
while ($i < $Nb) {
$temp[$i] = ($state[$i] & 0xFF000000) ^
($state[$j] & 0x00FF0000) ^
($state[$k] & 0x0000FF00) ^
($state[$l] & 0x000000FF) ^
$w[$i];
++$i;
$j = ($j + 1) % $Nb;
$k = ($k + 1) % $Nb;
$l = ($l + 1) % $Nb;
}

switch ($Nb) {
case 8:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
case 7:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
case 6:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
case 5:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
default:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
}
}








function _decryptBlock($in)
{
static $invtables;
if (empty($invtables)) {
$invtables = &$this->_getInvTables();
}
$dt0 = $invtables[0];
$dt1 = $invtables[1];
$dt2 = $invtables[2];
$dt3 = $invtables[3];
$isbox = $invtables[4];

$state = array();
$words = unpack('N*', $in);

$c = $this->c;
$dw = $this->dw;
$Nb = $this->Nb;
$Nr = $this->Nr;


 $wc = $Nb - 1;
foreach ($words as $word) {
$state[] = $word ^ $dw[++$wc];
}

$temp = array();
for ($round = $Nr - 1; $round > 0; --$round) {
$i = 0; 
 $j = $Nb - $c[1];
$k = $Nb - $c[2];
$l = $Nb - $c[3];

while ($i < $Nb) {
$temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^
$dt1[$state[$j] >> 16 & 0x000000FF] ^
$dt2[$state[$k] >> 8 & 0x000000FF] ^
$dt3[$state[$l] & 0x000000FF] ^
$dw[++$wc];
++$i;
$j = ($j + 1) % $Nb;
$k = ($k + 1) % $Nb;
$l = ($l + 1) % $Nb;
}
$state = $temp;
}


 $i = 0; 
 $j = $Nb - $c[1];
$k = $Nb - $c[2];
$l = $Nb - $c[3];

while ($i < $Nb) {
$word = ($state[$i] & 0xFF000000) |
($state[$j] & 0x00FF0000) |
($state[$k] & 0x0000FF00) |
($state[$l] & 0x000000FF);

$temp[$i] = $dw[$i] ^ ($isbox[$word & 0x000000FF] |
($isbox[$word >> 8 & 0x000000FF] << 8) |
($isbox[$word >> 16 & 0x000000FF] << 16) |
($isbox[$word >> 24 & 0x000000FF] << 24));
++$i;
$j = ($j + 1) % $Nb;
$k = ($k + 1) % $Nb;
$l = ($l + 1) % $Nb;
}

switch ($Nb) {
case 8:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
case 7:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
case 6:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
case 5:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
default:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
}
}







function _setupKey()
{

 
 static $rcon = array(0,
0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
);

if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_length === $this->kl['key_length'] && $this->block_size === $this->kl['block_size']) {

 return;
}
$this->kl = array('key' => $this->key, 'key_length' => $this->key_length, 'block_size' => $this->block_size);

$this->Nk = $this->key_length >> 2;

 $this->Nr = max($this->Nk, $this->Nb) + 6;


 
 
 
 switch ($this->Nb) {
case 4:
case 5:
case 6:
$this->c = array(0, 1, 2, 3);
break;
case 7:
$this->c = array(0, 1, 2, 4);
break;
case 8:
$this->c = array(0, 1, 3, 4);
}

$w = array_values(unpack('N*words', $this->key));

$length = $this->Nb * ($this->Nr + 1);
for ($i = $this->Nk; $i < $length; $i++) {
$temp = $w[$i - 1];
if ($i % $this->Nk == 0) {

 
 
 
 $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); 
 $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk];
} elseif ($this->Nk > 6 && $i % $this->Nk == 4) {
$temp = $this->_subWord($temp);
}
$w[$i] = $w[$i - $this->Nk] ^ $temp;
}


 
 
 
 
 
 
 list($dt0, $dt1, $dt2, $dt3) = $this->_getInvTables();
$temp = $this->w = $this->dw = array();
for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
if ($col == $this->Nb) {
if ($row == 0) {
$this->dw[0] = $this->w[0];
} else {

 $j = 0;
while ($j < $this->Nb) {
$dw = $this->_subWord($this->w[$row][$j]);
$temp[$j] = $dt0[$dw >> 24 & 0x000000FF] ^
$dt1[$dw >> 16 & 0x000000FF] ^
$dt2[$dw >> 8 & 0x000000FF] ^
$dt3[$dw & 0x000000FF];
$j++;
}
$this->dw[$row] = $temp;
}

$col = 0;
$row++;
}
$this->w[$row][$col] = $w[$i];
}

$this->dw[$row] = $this->w[$row];


 $this->dw = array_reverse($this->dw);
$w = array_pop($this->w);
$dw = array_pop($this->dw);
foreach ($this->w as $r => $wr) {
foreach ($wr as $c => $wc) {
$w[] = $wc;
$dw[] = $this->dw[$r][$c];
}
}
$this->w = $w;
$this->dw = $dw;
}







function _subWord($word)
{
static $sbox;
if (empty($sbox)) {
list(, , , , $sbox) = $this->_getTables();
}

return $sbox[$word & 0x000000FF] |
($sbox[$word >> 8 & 0x000000FF] << 8) |
($sbox[$word >> 16 & 0x000000FF] << 16) |
($sbox[$word >> 24 & 0x000000FF] << 24);
}










function &_getTables()
{
static $tables;
if (empty($tables)) {

 
 
 $t3 = array_map('intval', array(

 
 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
));

foreach ($t3 as $t3i) {
$t0[] = (($t3i << 24) & 0xFF000000) | (($t3i >> 8) & 0x00FFFFFF);
$t1[] = (($t3i << 16) & 0xFFFF0000) | (($t3i >> 16) & 0x0000FFFF);
$t2[] = (($t3i << 8) & 0xFFFFFF00) | (($t3i >> 24) & 0x000000FF);
}

$tables = array(

 $t0,
$t1,
$t2,
$t3,

 array(
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
)
);
}
return $tables;
}










function &_getInvTables()
{
static $tables;
if (empty($tables)) {
$dt3 = array_map('intval', array(
0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
));

foreach ($dt3 as $dt3i) {
$dt0[] = (($dt3i << 24) & 0xFF000000) | (($dt3i >> 8) & 0x00FFFFFF);
$dt1[] = (($dt3i << 16) & 0xFFFF0000) | (($dt3i >> 16) & 0x0000FFFF);
$dt2[] = (($dt3i << 8) & 0xFFFFFF00) | (($dt3i >> 24) & 0x000000FF);
};

$tables = array(

 $dt0,
$dt1,
$dt2,
$dt3,

 array(
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
)
);
}
return $tables;
}







function _setupInlineCrypt()
{

 
 

$lambda_functions =& self::_getLambdaFunctions();


 
 
 $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);


 $code_hash = "Crypt_Rijndael, {$this->mode}, {$this->Nr}, {$this->Nb}";
if ($gen_hi_opt_code) {
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}

if (!isset($lambda_functions[$code_hash])) {
switch (true) {
case $gen_hi_opt_code:

 $w = $this->w;
$dw = $this->dw;
$init_encrypt = '';
$init_decrypt = '';
break;
default:
for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) {
$w[] = '$w[' . $i . ']';
$dw[] = '$dw[' . $i . ']';
}
$init_encrypt = '$w  = $self->w;';
$init_decrypt = '$dw = $self->dw;';
}

$Nr = $this->Nr;
$Nb = $this->Nb;
$c = $this->c;


 $init_encrypt.= '
                static $tables;
                if (empty($tables)) {
                    $tables = &$self->_getTables();
                }
                $t0   = $tables[0];
                $t1   = $tables[1];
                $t2   = $tables[2];
                $t3   = $tables[3];
                $sbox = $tables[4];
            ';

$s = 'e';
$e = 's';
$wc = $Nb - 1;


 $encrypt_block = '$in = unpack("N*", $in);'."\n";
for ($i = 0; $i < $Nb; ++$i) {
$encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n";
}


 for ($round = 1; $round < $Nr; ++$round) {
list($s, $e) = array($e, $s);
for ($i = 0; $i < $Nb; ++$i) {
$encrypt_block.=
'$'.$e.$i.' =
                        $t0[($'.$s.$i .' >> 24) & 0xff] ^
                        $t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^
                        $t2[($'.$s.(($i + $c[2]) % $Nb).' >>  8) & 0xff] ^
                        $t3[ $'.$s.(($i + $c[3]) % $Nb).'        & 0xff] ^
                        '.$w[++$wc].";\n";
}
}


 for ($i = 0; $i < $Nb; ++$i) {
$encrypt_block.=
'$'.$e.$i.' =
                     $sbox[ $'.$e.$i.'        & 0xff]        |
                    ($sbox[($'.$e.$i.' >>  8) & 0xff] <<  8) |
                    ($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
                    ($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
}
$encrypt_block .= '$in = pack("N*"'."\n";
for ($i = 0; $i < $Nb; ++$i) {
$encrypt_block.= ',
                    ($'.$e.$i .' & '.((int)0xFF000000).') ^
                    ($'.$e.(($i + $c[1]) % $Nb).' &         0x00FF0000   ) ^
                    ($'.$e.(($i + $c[2]) % $Nb).' &         0x0000FF00   ) ^
                    ($'.$e.(($i + $c[3]) % $Nb).' &         0x000000FF   ) ^
                    '.$w[$i]."\n";
}
$encrypt_block .= ');';


 $init_decrypt.= '
                static $invtables;
                if (empty($invtables)) {
                    $invtables = &$self->_getInvTables();
                }
                $dt0   = $invtables[0];
                $dt1   = $invtables[1];
                $dt2   = $invtables[2];
                $dt3   = $invtables[3];
                $isbox = $invtables[4];
            ';

$s = 'e';
$e = 's';
$wc = $Nb - 1;


 $decrypt_block = '$in = unpack("N*", $in);'."\n";
for ($i = 0; $i < $Nb; ++$i) {
$decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n";
}


 for ($round = 1; $round < $Nr; ++$round) {
list($s, $e) = array($e, $s);
for ($i = 0; $i < $Nb; ++$i) {
$decrypt_block.=
'$'.$e.$i.' =
                        $dt0[($'.$s.$i .' >> 24) & 0xff] ^
                        $dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^
                        $dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >>  8) & 0xff] ^
                        $dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).'        & 0xff] ^
                        '.$dw[++$wc].";\n";
}
}


 for ($i = 0; $i < $Nb; ++$i) {
$decrypt_block.=
'$'.$e.$i.' =
                     $isbox[ $'.$e.$i.'        & 0xff]        |
                    ($isbox[($'.$e.$i.' >>  8) & 0xff] <<  8) |
                    ($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
                    ($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
}
$decrypt_block .= '$in = pack("N*"'."\n";
for ($i = 0; $i < $Nb; ++$i) {
$decrypt_block.= ',
                    ($'.$e.$i. ' & '.((int)0xFF000000).') ^
                    ($'.$e.(($Nb + $i - $c[1]) % $Nb).' &         0x00FF0000   ) ^
                    ($'.$e.(($Nb + $i - $c[2]) % $Nb).' &         0x0000FF00   ) ^
                    ($'.$e.(($Nb + $i - $c[3]) % $Nb).' &         0x000000FF   ) ^
                    '.$dw[$i]."\n";
}
$decrypt_block .= ');';

$lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
array(
'init_crypt' => '',
'init_encrypt' => $init_encrypt,
'init_decrypt' => $init_decrypt,
'encrypt_block' => $encrypt_block,
'decrypt_block' => $decrypt_block
)
);
}
$this->inline_crypt = $lambda_functions[$code_hash];
}
}
<?php




































namespace phpseclib\Crypt;









class Blowfish extends Base
{







var $block_size = 8;








var $cipher_name_mcrypt = 'blowfish';








var $cfb_init_len = 500;









var $sbox0 = array(
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
);







var $sbox1 = array(
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
);







var $sbox2 = array(
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
);







var $sbox3 = array(
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
);







var $parray = array(
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
);









var $bctx;







var $kl;












var $key_length = 16;









function setKeyLength($length)
{
if ($length < 32) {
$this->key_length = 4;
} elseif ($length > 448) {
$this->key_length = 56;
} else {
$this->key_length = $length >> 3;
}

parent::setKeyLength($length);
}











function isValidEngine($engine)
{
if ($engine == self::ENGINE_OPENSSL) {
if (version_compare(PHP_VERSION, '5.3.7') < 0 && $this->key_length != 16) {
return false;
}
if ($this->key_length < 16) {
return false;
}
$this->cipher_name_openssl_ecb = 'bf-ecb';
$this->cipher_name_openssl = 'bf-' . $this->_openssl_translate_mode();
}

return parent::isValidEngine($engine);
}







function _setupKey()
{
if (isset($this->kl['key']) && $this->key === $this->kl['key']) {

 return;
}
$this->kl = array('key' => $this->key);


$this->bctx = array(
'p' => array(),
'sb' => array(
$this->sbox0,
$this->sbox1,
$this->sbox2,
$this->sbox3
)
);


 $key = array_values(unpack('C*', $this->key));
$keyl = count($key);
for ($j = 0, $i = 0; $i < 18; ++$i) {

 for ($data = 0, $k = 0; $k < 4; ++$k) {
$data = ($data << 8) | $key[$j];
if (++$j >= $keyl) {
$j = 0;
}
}
$this->bctx['p'][] = $this->parray[$i] ^ $data;
}


 
 $data = "\0\0\0\0\0\0\0\0";
for ($i = 0; $i < 18; $i += 2) {
list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
$this->bctx['p'][$i ] = $l;
$this->bctx['p'][$i + 1] = $r;
}
for ($i = 0; $i < 4; ++$i) {
for ($j = 0; $j < 256; $j += 2) {
list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
$this->bctx['sb'][$i][$j ] = $l;
$this->bctx['sb'][$i][$j + 1] = $r;
}
}
}








function _encryptBlock($in)
{
$p = $this->bctx["p"];

 $sb_0 = $this->bctx["sb"][0];
$sb_1 = $this->bctx["sb"][1];
$sb_2 = $this->bctx["sb"][2];
$sb_3 = $this->bctx["sb"][3];

$in = unpack("N*", $in);
$l = $in[1];
$r = $in[2];

for ($i = 0; $i < 16; $i+= 2) {
$l^= $p[$i];
$r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
$sb_2[$l >> 8 & 0xff]) +
$sb_3[$l & 0xff]);

$r^= $p[$i + 1];
$l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
$sb_2[$r >> 8 & 0xff]) +
$sb_3[$r & 0xff]);
}
return pack("N*", $r ^ $p[17], $l ^ $p[16]);
}








function _decryptBlock($in)
{
$p = $this->bctx["p"];
$sb_0 = $this->bctx["sb"][0];
$sb_1 = $this->bctx["sb"][1];
$sb_2 = $this->bctx["sb"][2];
$sb_3 = $this->bctx["sb"][3];

$in = unpack("N*", $in);
$l = $in[1];
$r = $in[2];

for ($i = 17; $i > 2; $i-= 2) {
$l^= $p[$i];
$r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
$sb_2[$l >> 8 & 0xff]) +
$sb_3[$l & 0xff]);

$r^= $p[$i - 1];
$l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
$sb_2[$r >> 8 & 0xff]) +
$sb_3[$r & 0xff]);
}
return pack("N*", $r ^ $p[0], $l ^ $p[1]);
}







function _setupInlineCrypt()
{
$lambda_functions =& self::_getLambdaFunctions();


 
 
 $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);


 $code_hash = "Crypt_Blowfish, {$this->mode}";
if ($gen_hi_opt_code) {
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}

$safeint = $this->safe_intval_inline();

if (!isset($lambda_functions[$code_hash])) {
switch (true) {
case $gen_hi_opt_code:
$p = $this->bctx['p'];
$init_crypt = '
                        static $sb_0, $sb_1, $sb_2, $sb_3;
                        if (!$sb_0) {
                            $sb_0 = $self->bctx["sb"][0];
                            $sb_1 = $self->bctx["sb"][1];
                            $sb_2 = $self->bctx["sb"][2];
                            $sb_3 = $self->bctx["sb"][3];
                        }
                    ';
break;
default:
$p = array();
for ($i = 0; $i < 18; ++$i) {
$p[] = '$p_' . $i;
}
$init_crypt = '
                        list($sb_0, $sb_1, $sb_2, $sb_3) = $self->bctx["sb"];
                        list(' . implode(',', $p) . ') = $self->bctx["p"];

                    ';
}


 $encrypt_block = '
                $in = unpack("N*", $in);
                $l = $in[1];
                $r = $in[2];
            ';
for ($i = 0; $i < 16; $i+= 2) {
$encrypt_block.= '
                    $l^= ' . $p[$i] . ';
                    $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
                          $sb_2[$l >>  8 & 0xff]) +
                          $sb_3[$l       & 0xff]') . ';

                    $r^= ' . $p[$i + 1] . ';
                    $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . '  ^
                          $sb_2[$r >>  8 & 0xff]) +
                          $sb_3[$r       & 0xff]') . ';
                ';
}
$encrypt_block.= '
                $in = pack("N*",
                    $r ^ ' . $p[17] . ',
                    $l ^ ' . $p[16] . '
                );
            ';


 $decrypt_block = '
                $in = unpack("N*", $in);
                $l = $in[1];
                $r = $in[2];
            ';

for ($i = 17; $i > 2; $i-= 2) {
$decrypt_block.= '
                    $l^= ' . $p[$i] . ';
                    $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
                          $sb_2[$l >>  8 & 0xff]) +
                          $sb_3[$l       & 0xff]') . ';

                    $r^= ' . $p[$i - 1] . ';
                    $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
                          $sb_2[$r >>  8 & 0xff]) +
                          $sb_3[$r       & 0xff]') . ';
                ';
}

$decrypt_block.= '
                $in = pack("N*",
                    $r ^ ' . $p[0] . ',
                    $l ^ ' . $p[1] . '
                );
            ';

$lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
array(
'init_crypt' => $init_crypt,
'init_encrypt' => '',
'init_decrypt' => '',
'encrypt_block' => $encrypt_block,
'decrypt_block' => $decrypt_block
)
);
}
$this->inline_crypt = $lambda_functions[$code_hash];
}
}
<?php




































namespace phpseclib\Crypt;









class Twofish extends Base
{







var $cipher_name_mcrypt = 'twofish';








var $cfb_init_len = 800;







var $q0 = array(
0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76,
0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38,
0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48,
0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23,
0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C,
0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61,
0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1,
0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66,
0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA,
0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71,
0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7,
0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2,
0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB,
0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF,
0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64,
0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A,
0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02,
0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D,
0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8,
0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00,
0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0
);







var $q1 = array(
0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8,
0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B,
0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F,
0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D,
0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3,
0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51,
0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C,
0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70,
0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC,
0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2,
0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17,
0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3,
0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49,
0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9,
0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48,
0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19,
0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5,
0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69,
0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC,
0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB,
0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2,
0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91
);







var $m0 = array(
0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, 0xE2E22BFB, 0x9E9EFAC8,
0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B,
0x3C3C57D6, 0x93938A32, 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, 0xB0B0B306, 0x7575DE3F,
0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D,
0xAEAE2C6D, 0x7F7FABC1, 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, 0x3131272C, 0x808065A3,
0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51,
0x2A2A3638, 0xC4C49CB0, 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, 0x6767C027, 0xE9E9AF8C,
0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70,
0x29294CCA, 0xF0F035E3, 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, 0xC8C81DC3, 0x9999FFCC,
0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2,
0xB5B53D79, 0x09090F0C, 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, 0xEDEDD07A, 0x4343FC17,
0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3,
0x5656E70B, 0xE3E3DA72, 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, 0x8181942A, 0x91910149,
0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9,
0x7878AEC5, 0xC5C56D39, 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, 0x55559DF9, 0x7E7E5A48,
0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519,
0x0606F48D, 0x404086E5, 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, 0x2D2D333C, 0x3030D6A5,
0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969,
0xD9D97929, 0x8686912E, 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, 0xC1C112CF, 0x8585EBDC,
0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB,
0xABABA212, 0x6F6F3EA2, 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, 0x04047FF6, 0x272746C2,
0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91
);







var $m1 = array(
0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, 0xA3658080, 0x76DFE4E4,
0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A,
0x0D54E6E6, 0xC6432020, 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, 0x94B1FBFB, 0x485A7E7E,
0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060,
0x1945FDFD, 0x5BA33A3A, 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, 0x9B53AAAA, 0x7C635D5D,
0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7,
0xC0F09090, 0x8CAFE9E9, 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, 0xB499C3C3, 0xF1975B5B,
0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8,
0xCCFF9999, 0x95EA1414, 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, 0xBF7E9595, 0xBA207D7D,
0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB,
0x81FB0F0F, 0x793DB5B5, 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, 0x86135050, 0xE730F7F7,
0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B,
0x410B9F9F, 0x7B8B0202, 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, 0xB1C72B2B, 0xAB6F8E8E,
0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9,
0x91EF1313, 0x85FE0808, 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, 0x6929A9A9, 0x647D4F4F,
0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED,
0xAC87D1D1, 0x7F8E0505, 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, 0x4C5F7979, 0x02B6B7B7,
0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2,
0x57AC3333, 0xC718CFCF, 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, 0x99E51D1D, 0x34392323,
0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA,
0xC8FA9E9E, 0xA882D6D6, 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, 0x0FE25151, 0x00000000,
0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8
);







var $m2 = array(
0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, 0xE2FBE22B, 0x9EC89EFA,
0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7,
0x3CD63C57, 0x9332938A, 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, 0xB006B0B3, 0x753F75DE,
0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0,
0xAE6DAE2C, 0x7FC17FAB, 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, 0x312C3127, 0x80A38065,
0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F,
0x2A382A36, 0xC4B0C49C, 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, 0x672767C0, 0xE98CE9AF,
0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C,
0x29CA294C, 0xF0E3F035, 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, 0xC8C3C81D, 0x99CC99FF,
0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E,
0xB579B53D, 0x090C090F, 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, 0xED7AEDD0, 0x431743FC,
0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71,
0x560B56E7, 0xE372E3DA, 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, 0x812A8194, 0x91499101,
0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5,
0x78C578AE, 0xC539C56D, 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, 0x55F9559D, 0x7E487E5A,
0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45,
0x068D06F4, 0x40E54086, 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, 0x2D3C2D33, 0x30A530D6,
0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929,
0xD929D979, 0x862E8691, 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, 0xC1CFC112, 0x85DC85EB,
0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F,
0xAB12ABA2, 0x6FA26F3E, 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, 0x04F6047F, 0x27C22746,
0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF
);







var $m3 = array(
0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, 0x6580A365, 0xDFE476DF,
0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836,
0x54E60D54, 0x4320C643, 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, 0xB1FB94B1, 0x5A7E485A,
0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5,
0x45FD1945, 0xA33A5BA3, 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, 0x53AA9B53, 0x635D7C63,
0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123,
0xF090C0F0, 0xAFE98CAF, 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, 0x99C3B499, 0x975BF197,
0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB,
0xFF99CCFF, 0xEA1495EA, 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, 0x7E95BF7E, 0x207DBA20,
0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137,
0xFB0F81FB, 0x3DB5793D, 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, 0x13508613, 0x30F7E730,
0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252,
0x0B9F410B, 0x8B027B8B, 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, 0xC72BB1C7, 0x6F8EAB6F,
0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A,
0xEF1391EF, 0xFE0885FE, 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, 0x29A96929, 0x7D4F647D,
0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0,
0x87D1AC87, 0x8E057F8E, 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, 0x5F794C5F, 0xB6B702B6,
0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38,
0xAC3357AC, 0x18CFC718, 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, 0xE51D99E5, 0x39233439,
0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6,
0xFA9EC8FA, 0x82D6A882, 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, 0xE2510FE2, 0x00000000,
0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8
);







var $K = array();







var $S0 = array();







var $S1 = array();







var $S2 = array();







var $S3 = array();







var $kl;








var $key_length = 16;









function setKeyLength($length)
{
switch (true) {
case $length <= 128:
$this->key_length = 16;
break;
case $length <= 192:
$this->key_length = 24;
break;
default:
$this->key_length = 32;
}

parent::setKeyLength($length);
}







function _setupKey()
{
if (isset($this->kl['key']) && $this->key === $this->kl['key']) {

 return;
}
$this->kl = array('key' => $this->key);


$le_longs = unpack('V*', $this->key);
$key = unpack('C*', $this->key);
$m0 = $this->m0;
$m1 = $this->m1;
$m2 = $this->m2;
$m3 = $this->m3;
$q0 = $this->q0;
$q1 = $this->q1;

$K = $S0 = $S1 = $S2 = $S3 = array();

switch (strlen($this->key)) {
case 16:
list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[1], $le_longs[2]);
list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[3], $le_longs[4]);
for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
$A = $m0[$q0[$q0[$i] ^ $key[ 9]] ^ $key[1]] ^
$m1[$q0[$q1[$i] ^ $key[10]] ^ $key[2]] ^
$m2[$q1[$q0[$i] ^ $key[11]] ^ $key[3]] ^
$m3[$q1[$q1[$i] ^ $key[12]] ^ $key[4]];
$B = $m0[$q0[$q0[$j] ^ $key[13]] ^ $key[5]] ^
$m1[$q0[$q1[$j] ^ $key[14]] ^ $key[6]] ^
$m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^
$m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]];
$B = ($B << 8) | ($B >> 24 & 0xff);
$A = $this->safe_intval($A + $B);
$K[] = $A;
$A = $this->safe_intval($A + $B);
$K[] = ($A << 9 | $A >> 23 & 0x1ff);
}
for ($i = 0; $i < 256; ++$i) {
$S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0];
$S1[$i] = $m1[$q0[$q1[$i] ^ $s5] ^ $s1];
$S2[$i] = $m2[$q1[$q0[$i] ^ $s6] ^ $s2];
$S3[$i] = $m3[$q1[$q1[$i] ^ $s7] ^ $s3];
}
break;
case 24:
list($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[1], $le_longs[2]);
list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[3], $le_longs[4]);
list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[5], $le_longs[6]);
for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
$A = $m0[$q0[$q0[$q1[$i] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
$m1[$q0[$q1[$q1[$i] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
$m2[$q1[$q0[$q0[$i] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
$m3[$q1[$q1[$q0[$i] ^ $key[20]] ^ $key[12]] ^ $key[4]];
$B = $m0[$q0[$q0[$q1[$j] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
$m1[$q0[$q1[$q1[$j] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
$m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
$m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]];
$B = ($B << 8) | ($B >> 24 & 0xff);
$A = $this->safe_intval($A + $B);
$K[] = $A;
$A = $this->safe_intval($A + $B);
$K[] = ($A << 9 | $A >> 23 & 0x1ff);
}
for ($i = 0; $i < 256; ++$i) {
$S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0];
$S1[$i] = $m1[$q0[$q1[$q1[$i] ^ $s9] ^ $s5] ^ $s1];
$S2[$i] = $m2[$q1[$q0[$q0[$i] ^ $sa] ^ $s6] ^ $s2];
$S3[$i] = $m3[$q1[$q1[$q0[$i] ^ $sb] ^ $s7] ^ $s3];
}
break;
default: 
 list($sf, $se, $sd, $sc) = $this->_mdsrem($le_longs[1], $le_longs[2]);
list($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[3], $le_longs[4]);
list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[5], $le_longs[6]);
list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[7], $le_longs[8]);
for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
$A = $m0[$q0[$q0[$q1[$q1[$i] ^ $key[25]] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
$m1[$q0[$q1[$q1[$q0[$i] ^ $key[26]] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
$m2[$q1[$q0[$q0[$q0[$i] ^ $key[27]] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
$m3[$q1[$q1[$q0[$q1[$i] ^ $key[28]] ^ $key[20]] ^ $key[12]] ^ $key[4]];
$B = $m0[$q0[$q0[$q1[$q1[$j] ^ $key[29]] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
$m1[$q0[$q1[$q1[$q0[$j] ^ $key[30]] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
$m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
$m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]];
$B = ($B << 8) | ($B >> 24 & 0xff);
$A = $this->safe_intval($A + $B);
$K[] = $A;
$A = $this->safe_intval($A + $B);
$K[] = ($A << 9 | $A >> 23 & 0x1ff);
}
for ($i = 0; $i < 256; ++$i) {
$S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0];
$S1[$i] = $m1[$q0[$q1[$q1[$q0[$i] ^ $sd] ^ $s9] ^ $s5] ^ $s1];
$S2[$i] = $m2[$q1[$q0[$q0[$q0[$i] ^ $se] ^ $sa] ^ $s6] ^ $s2];
$S3[$i] = $m3[$q1[$q1[$q0[$q1[$i] ^ $sf] ^ $sb] ^ $s7] ^ $s3];
}
}

$this->K = $K;
$this->S0 = $S0;
$this->S1 = $S1;
$this->S2 = $S2;
$this->S3 = $S3;
}









function _mdsrem($A, $B)
{

 for ($i = 0; $i < 8; ++$i) {

 $t = 0xff & ($B >> 24);


 $B = ($B << 8) | (0xff & ($A >> 24));
$A<<= 8;

$u = $t << 1;


 if ($t & 0x80) {
$u^= 0x14d;
}


 $B ^= $t ^ ($u << 16);


 $u^= 0x7fffffff & ($t >> 1);


 if ($t & 0x01) {
$u^= 0xa6 ;
}


 $B^= ($u << 24) | ($u << 8);
}

return array(
0xff & $B >> 24,
0xff & $B >> 16,
0xff & $B >> 8,
0xff & $B);
}








function _encryptBlock($in)
{
$S0 = $this->S0;
$S1 = $this->S1;
$S2 = $this->S2;
$S3 = $this->S3;
$K = $this->K;

$in = unpack("V4", $in);
$R0 = $K[0] ^ $in[1];
$R1 = $K[1] ^ $in[2];
$R2 = $K[2] ^ $in[3];
$R3 = $K[3] ^ $in[4];

$ki = 7;
while ($ki < 39) {
$t0 = $S0[ $R0 & 0xff] ^
$S1[($R0 >> 8) & 0xff] ^
$S2[($R0 >> 16) & 0xff] ^
$S3[($R0 >> 24) & 0xff];
$t1 = $S0[($R1 >> 24) & 0xff] ^
$S1[ $R1 & 0xff] ^
$S2[($R1 >> 8) & 0xff] ^
$S3[($R1 >> 16) & 0xff];
$R2^= $this->safe_intval($t0 + $t1 + $K[++$ki]);
$R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
$R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ $this->safe_intval($t0 + ($t1 << 1) + $K[++$ki]);

$t0 = $S0[ $R2 & 0xff] ^
$S1[($R2 >> 8) & 0xff] ^
$S2[($R2 >> 16) & 0xff] ^
$S3[($R2 >> 24) & 0xff];
$t1 = $S0[($R3 >> 24) & 0xff] ^
$S1[ $R3 & 0xff] ^
$S2[($R3 >> 8) & 0xff] ^
$S3[($R3 >> 16) & 0xff];
$R0^= $this->safe_intval($t0 + $t1 + $K[++$ki]);
$R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
$R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ $this->safe_intval($t0 + ($t1 << 1) + $K[++$ki]);
}


 return pack("V4", $K[4] ^ $R2,
$K[5] ^ $R3,
$K[6] ^ $R0,
$K[7] ^ $R1);

 }








function _decryptBlock($in)
{
$S0 = $this->S0;
$S1 = $this->S1;
$S2 = $this->S2;
$S3 = $this->S3;
$K = $this->K;

$in = unpack("V4", $in);
$R0 = $K[4] ^ $in[1];
$R1 = $K[5] ^ $in[2];
$R2 = $K[6] ^ $in[3];
$R3 = $K[7] ^ $in[4];

$ki = 40;
while ($ki > 8) {
$t0 = $S0[$R0 & 0xff] ^
$S1[$R0 >> 8 & 0xff] ^
$S2[$R0 >> 16 & 0xff] ^
$S3[$R0 >> 24 & 0xff];
$t1 = $S0[$R1 >> 24 & 0xff] ^
$S1[$R1 & 0xff] ^
$S2[$R1 >> 8 & 0xff] ^
$S3[$R1 >> 16 & 0xff];
$R3^= $this->safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
$R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
$R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ $this->safe_intval($t0 + $t1 + $K[--$ki]);

$t0 = $S0[$R2 & 0xff] ^
$S1[$R2 >> 8 & 0xff] ^
$S2[$R2 >> 16 & 0xff] ^
$S3[$R2 >> 24 & 0xff];
$t1 = $S0[$R3 >> 24 & 0xff] ^
$S1[$R3 & 0xff] ^
$S2[$R3 >> 8 & 0xff] ^
$S3[$R3 >> 16 & 0xff];
$R1^= $this->safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
$R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
$R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ $this->safe_intval($t0 + $t1 + $K[--$ki]);
}


 return pack("V4", $K[0] ^ $R2,
$K[1] ^ $R3,
$K[2] ^ $R0,
$K[3] ^ $R1);

 }







function _setupInlineCrypt()
{
$lambda_functions =& self::_getLambdaFunctions();


 
 $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);


 $code_hash = "Crypt_Twofish, {$this->mode}";
if ($gen_hi_opt_code) {
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}

$safeint = $this->safe_intval_inline();

if (!isset($lambda_functions[$code_hash])) {
switch (true) {
case $gen_hi_opt_code:
$K = $this->K;
$init_crypt = '
                        static $S0, $S1, $S2, $S3;
                        if (!$S0) {
                            for ($i = 0; $i < 256; ++$i) {
                                $S0[] = (int)$self->S0[$i];
                                $S1[] = (int)$self->S1[$i];
                                $S2[] = (int)$self->S2[$i];
                                $S3[] = (int)$self->S3[$i];
                            }
                        }
                    ';
break;
default:
$K = array();
for ($i = 0; $i < 40; ++$i) {
$K[] = '$K_' . $i;
}
$init_crypt = '
                        $S0 = $self->S0;
                        $S1 = $self->S1;
                        $S2 = $self->S2;
                        $S3 = $self->S3;
                        list(' . implode(',', $K) . ') = $self->K;
                    ';
}


 $encrypt_block = '
                $in = unpack("V4", $in);
                $R0 = '.$K[0].' ^ $in[1];
                $R1 = '.$K[1].' ^ $in[2];
                $R2 = '.$K[2].' ^ $in[3];
                $R3 = '.$K[3].' ^ $in[4];
            ';
for ($ki = 7, $i = 0; $i < 8; ++$i) {
$encrypt_block.= '
                    $t0 = $S0[ $R0        & 0xff] ^
                          $S1[($R0 >>  8) & 0xff] ^
                          $S2[($R0 >> 16) & 0xff] ^
                          $S3[($R0 >> 24) & 0xff];
                    $t1 = $S0[($R1 >> 24) & 0xff] ^
                          $S1[ $R1        & 0xff] ^
                          $S2[($R1 >>  8) & 0xff] ^
                          $S3[($R1 >> 16) & 0xff];
                    $R2^= ' . sprintf($safeint, '$t0 + $t1 + ' . $K[++$ki]) . ';
                    $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
                    $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';

                    $t0 = $S0[ $R2        & 0xff] ^
                          $S1[($R2 >>  8) & 0xff] ^
                          $S2[($R2 >> 16) & 0xff] ^
                          $S3[($R2 >> 24) & 0xff];
                    $t1 = $S0[($R3 >> 24) & 0xff] ^
                          $S1[ $R3        & 0xff] ^
                          $S2[($R3 >>  8) & 0xff] ^
                          $S3[($R3 >> 16) & 0xff];
                    $R0^= ' . sprintf($safeint, '($t0 + $t1 + ' . $K[++$ki] . ')') . ';
                    $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
                    $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';
                ';
}
$encrypt_block.= '
                $in = pack("V4", ' . $K[4] . ' ^ $R2,
                                 ' . $K[5] . ' ^ $R3,
                                 ' . $K[6] . ' ^ $R0,
                                 ' . $K[7] . ' ^ $R1);
            ';


 $decrypt_block = '
                $in = unpack("V4", $in);
                $R0 = '.$K[4].' ^ $in[1];
                $R1 = '.$K[5].' ^ $in[2];
                $R2 = '.$K[6].' ^ $in[3];
                $R3 = '.$K[7].' ^ $in[4];
            ';
for ($ki = 40, $i = 0; $i < 8; ++$i) {
$decrypt_block.= '
                    $t0 = $S0[$R0       & 0xff] ^
                          $S1[$R0 >>  8 & 0xff] ^
                          $S2[$R0 >> 16 & 0xff] ^
                          $S3[$R0 >> 24 & 0xff];
                    $t1 = $S0[$R1 >> 24 & 0xff] ^
                          $S1[$R1       & 0xff] ^
                          $S2[$R1 >>  8 & 0xff] ^
                          $S3[$R1 >> 16 & 0xff];
                    $R3^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
                    $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
                    $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + '.$K[--$ki] . ')') . ';

                    $t0 = $S0[$R2       & 0xff] ^
                          $S1[$R2 >>  8 & 0xff] ^
                          $S2[$R2 >> 16 & 0xff] ^
                          $S3[$R2 >> 24 & 0xff];
                    $t1 = $S0[$R3 >> 24 & 0xff] ^
                          $S1[$R3       & 0xff] ^
                          $S2[$R3 >>  8 & 0xff] ^
                          $S3[$R3 >> 16 & 0xff];
                    $R1^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
                    $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
                    $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + '.$K[--$ki] . ')') . ';
                ';
}
$decrypt_block.= '
                $in = pack("V4", ' . $K[0] . ' ^ $R2,
                                 ' . $K[1] . ' ^ $R3,
                                 ' . $K[2] . ' ^ $R0,
                                 ' . $K[3] . ' ^ $R1);
            ';

$lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
array(
'init_crypt' => $init_crypt,
'init_encrypt' => '',
'init_decrypt' => '',
'encrypt_block' => $encrypt_block,
'decrypt_block' => $decrypt_block
)
);
}
$this->inline_crypt = $lambda_functions[$code_hash];
}
}
<?php
















































namespace phpseclib\Crypt;








class AES extends Rijndael
{









function setBlockLength($length)
{
return;
}











function setKeyLength($length)
{
switch ($length) {
case 160:
$length = 192;
break;
case 224:
$length = 256;
}
parent::setKeyLength($length);
}











function setKey($key)
{
parent::setKey($key);

if (!$this->explicit_key_length) {
$length = strlen($key);
switch (true) {
case $length <= 16:
$this->key_length = 16;
break;
case $length <= 24:
$this->key_length = 24;
break;
default:
$this->key_length = 32;
}
$this->_setEngine();
}
}
}
<?php



































namespace phpseclib\Crypt;








abstract class Base
{












const MODE_CTR = -1;





const MODE_ECB = 1;





const MODE_CBC = 2;





const MODE_CFB = 3;



const MODE_CFB8 = 38;





const MODE_OFB = 4;



const MODE_STREAM = 5;









static $WHIRLPOOL_AVAILABLE;








const ENGINE_INTERNAL = 1;



const ENGINE_MCRYPT = 2;



const ENGINE_OPENSSL = 3;









var $mode;







var $block_size = 16;








var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";








var $iv;









var $encryptIV;









var $decryptIV;








var $continuousBuffer = false;









var $enbuffer;









var $debuffer;











var $enmcrypt;











var $demcrypt;









var $enchanged = true;









var $dechanged = true;


















var $ecb;





















var $cfb_init_len = 600;










var $changed = true;








var $padding = true;








var $paddable = false;
















var $engine;









var $preferredEngine;












var $cipher_name_mcrypt;










var $cipher_name_openssl;











var $cipher_name_openssl_ecb;








var $password_default_salt = 'phpseclib/salt';














var $inline_crypt;










var $use_inline_crypt = true;








var $openssl_emulate_ctr = false;








var $openssl_options;








var $explicit_key_length = false;








var $skip_key_adjustment = false;























function __construct($mode = self::MODE_CBC)
{

 switch ($mode) {
case self::MODE_ECB:
$this->paddable = true;
$this->mode = self::MODE_ECB;
break;
case self::MODE_CTR:
case self::MODE_CFB:
case self::MODE_CFB8:
case self::MODE_OFB:
case self::MODE_STREAM:
$this->mode = $mode;
break;
case self::MODE_CBC:
default:
$this->paddable = true;
$this->mode = self::MODE_CBC;
}

$this->_setEngine();
}











function setIV($iv)
{
if ($this->mode == self::MODE_ECB) {
return;
}

$this->iv = $iv;
$this->changed = true;
}









function setKeyLength($length)
{
$this->explicit_key_length = true;
$this->changed = true;
$this->_setEngine();
}







function getKeyLength()
{
return $this->key_length << 3;
}







function getBlockLength()
{
return $this->block_size << 3;
}















function setKey($key)
{
if (!$this->explicit_key_length) {
$this->setKeyLength(strlen($key) << 3);
$this->explicit_key_length = false;
}

$this->key = $key;
$this->changed = true;
$this->_setEngine();
}

















function setPassword($password, $method = 'pbkdf2')
{
$key = '';

switch ($method) {
default: 
 $func_args = func_get_args();


 $hash = isset($func_args[2]) ? $func_args[2] : 'sha1';


 $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;


 
 $count = isset($func_args[4]) ? $func_args[4] : 1000;


 if (isset($func_args[5])) {
$dkLen = $func_args[5];
} else {
$dkLen = $method == 'pbkdf1' ? 2 * $this->key_length : $this->key_length;
}

switch (true) {
case $method == 'pbkdf1':
$hashObj = new Hash();
$hashObj->setHash($hash);
if ($dkLen > $hashObj->getLength()) {
user_error('Derived key too long');
return false;
}
$t = $password . $salt;
for ($i = 0; $i < $count; ++$i) {
$t = $hashObj->hash($t);
}
$key = substr($t, 0, $dkLen);

$this->setKey(substr($key, 0, $dkLen >> 1));
$this->setIV(substr($key, $dkLen >> 1));

return true;

 case !function_exists('hash_pbkdf2'):
case !function_exists('hash_algos'):
case !in_array($hash, hash_algos()):
$i = 1;
$hmac = new Hash();
$hmac->setHash($hash);
$hmac->setKey($password);
while (strlen($key) < $dkLen) {
$f = $u = $hmac->hash($salt . pack('N', $i++));
for ($j = 2; $j <= $count; ++$j) {
$u = $hmac->hash($u);
$f^= $u;
}
$key.= $f;
}
$key = substr($key, 0, $dkLen);
break;
default:
$key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
}
}

$this->setKey($key);

return true;
}





















function encrypt($plaintext)
{
if ($this->paddable) {
$plaintext = $this->_pad($plaintext);
}

if ($this->engine === self::ENGINE_OPENSSL) {
if ($this->changed) {
$this->_clearBuffers();
$this->changed = false;
}
switch ($this->mode) {
case self::MODE_STREAM:
return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
case self::MODE_ECB:
$result = @openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
case self::MODE_CBC:
$result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
if (!defined('OPENSSL_RAW_DATA')) {
$result = substr($result, 0, -$this->block_size);
}
if ($this->continuousBuffer) {
$this->encryptIV = substr($result, -$this->block_size);
}
return $result;
case self::MODE_CTR:
return $this->_openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer);
case self::MODE_CFB:

 
 $ciphertext = '';
if ($this->continuousBuffer) {
$iv = &$this->encryptIV;
$pos = &$this->enbuffer['pos'];
} else {
$iv = $this->encryptIV;
$pos = 0;
}
$len = strlen($plaintext);
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $this->block_size - $pos;
if ($len >= $max) {
$i = $max;
$len-= $max;
$pos = 0;
} else {
$i = $len;
$pos+= $len;
$len = 0;
}

 $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
$plaintext = substr($plaintext, $i);
}

$overflow = $len % $this->block_size;

if ($overflow) {
$ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
$iv = $this->_string_pop($ciphertext, $this->block_size);

$size = $len - $overflow;
$block = $iv ^ substr($plaintext, -$overflow);
$iv = substr_replace($iv, $block, 0, $overflow);
$ciphertext.= $block;
$pos = $overflow;
} elseif ($len) {
$ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
$iv = substr($ciphertext, -$this->block_size);
}

return $ciphertext;
case self::MODE_CFB8:
$ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
if ($this->continuousBuffer) {
if (($len = strlen($ciphertext)) >= $this->block_size) {
$this->encryptIV = substr($ciphertext, -$this->block_size);
} else {
$this->encryptIV = substr($this->encryptIV, $len - $this->block_size) . substr($ciphertext, -$len);
}
}
return $ciphertext;
case self::MODE_OFB:
return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
}
}

if ($this->engine === self::ENGINE_MCRYPT) {
set_error_handler(array($this, 'do_nothing'));

if ($this->changed) {
$this->_setupMcrypt();
$this->changed = false;
}
if ($this->enchanged) {
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
$this->enchanged = false;
}


 
 
 if ($this->mode == self::MODE_CFB && $this->continuousBuffer) {
$block_size = $this->block_size;
$iv = &$this->encryptIV;
$pos = &$this->enbuffer['pos'];
$len = strlen($plaintext);
$ciphertext = '';
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $block_size - $pos;
if ($len >= $max) {
$i = $max;
$len-= $max;
$pos = 0;
} else {
$i = $len;
$pos+= $len;
$len = 0;
}
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
$this->enbuffer['enmcrypt_init'] = true;
}
if ($len >= $block_size) {
if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) {
if ($this->enbuffer['enmcrypt_init'] === true) {
mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
$this->enbuffer['enmcrypt_init'] = false;
}
$ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
$iv = substr($ciphertext, -$block_size);
$len%= $block_size;
} else {
while ($len >= $block_size) {
$iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
$ciphertext.= $iv;
$len-= $block_size;
$i+= $block_size;
}
}
}

if ($len) {
$iv = mcrypt_generic($this->ecb, $iv);
$block = $iv ^ substr($plaintext, -$len);
$iv = substr_replace($iv, $block, 0, $len);
$ciphertext.= $block;
$pos = $len;
}

restore_error_handler();

return $ciphertext;
}

$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);

if (!$this->continuousBuffer) {
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
}

restore_error_handler();

return $ciphertext;
}

if ($this->changed) {
$this->_setup();
$this->changed = false;
}
if ($this->use_inline_crypt) {
$inline = $this->inline_crypt;
return $inline('encrypt', $this, $plaintext);
}

$buffer = &$this->enbuffer;
$block_size = $this->block_size;
$ciphertext = '';
switch ($this->mode) {
case self::MODE_ECB:
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
}
break;
case self::MODE_CBC:
$xor = $this->encryptIV;
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
$block = $this->_encryptBlock($block ^ $xor);
$xor = $block;
$ciphertext.= $block;
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
}
break;
case self::MODE_CTR:
$xor = $this->encryptIV;
if (strlen($buffer['ciphertext'])) {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
if (strlen($block) > strlen($buffer['ciphertext'])) {
$buffer['ciphertext'].= $this->_encryptBlock($xor);
}
$this->_increment_str($xor);
$key = $this->_string_shift($buffer['ciphertext'], $block_size);
$ciphertext.= $block ^ $key;
}
} else {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
$key = $this->_encryptBlock($xor);
$this->_increment_str($xor);
$ciphertext.= $block ^ $key;
}
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
if ($start = strlen($plaintext) % $block_size) {
$buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
}
}
break;
case self::MODE_CFB:

 
 if ($this->continuousBuffer) {
$iv = &$this->encryptIV;
$pos = &$buffer['pos'];
} else {
$iv = $this->encryptIV;
$pos = 0;
}
$len = strlen($plaintext);
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $block_size - $pos;
if ($len >= $max) {
$i = $max;
$len-= $max;
$pos = 0;
} else {
$i = $len;
$pos+= $len;
$len = 0;
}

 $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
}
while ($len >= $block_size) {
$iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
$ciphertext.= $iv;
$len-= $block_size;
$i+= $block_size;
}
if ($len) {
$iv = $this->_encryptBlock($iv);
$block = $iv ^ substr($plaintext, $i);
$iv = substr_replace($iv, $block, 0, $len);
$ciphertext.= $block;
$pos = $len;
}
break;
case self::MODE_CFB8:
$ciphertext = '';
$len = strlen($plaintext);
$iv = $this->encryptIV;

for ($i = 0; $i < $len; ++$i) {
$ciphertext .= ($c = $plaintext[$i] ^ $this->_encryptBlock($iv));
$iv = substr($iv, 1) . $c;
}

if ($this->continuousBuffer) {
if ($len >= $block_size) {
$this->encryptIV = substr($ciphertext, -$block_size);
} else {
$this->encryptIV = substr($this->encryptIV, $len - $block_size) . substr($ciphertext, -$len);
}
}
break;
case self::MODE_OFB:
$xor = $this->encryptIV;
if (strlen($buffer['xor'])) {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
if (strlen($block) > strlen($buffer['xor'])) {
$xor = $this->_encryptBlock($xor);
$buffer['xor'].= $xor;
}
$key = $this->_string_shift($buffer['xor'], $block_size);
$ciphertext.= $block ^ $key;
}
} else {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$xor = $this->_encryptBlock($xor);
$ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
}
$key = $xor;
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
if ($start = strlen($plaintext) % $block_size) {
$buffer['xor'] = substr($key, $start) . $buffer['xor'];
}
}
break;
case self::MODE_STREAM:
$ciphertext = $this->_encryptBlock($plaintext);
break;
}

return $ciphertext;
}













function decrypt($ciphertext)
{
if ($this->paddable) {

 
 $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
}

if ($this->engine === self::ENGINE_OPENSSL) {
if ($this->changed) {
$this->_clearBuffers();
$this->changed = false;
}
switch ($this->mode) {
case self::MODE_STREAM:
$plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
break;
case self::MODE_ECB:
if (!defined('OPENSSL_RAW_DATA')) {
$ciphertext.= @openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true);
}
$plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
break;
case self::MODE_CBC:
if (!defined('OPENSSL_RAW_DATA')) {
$padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size);
$ciphertext.= substr(@openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size);
$offset = 2 * $this->block_size;
} else {
$offset = $this->block_size;
}
$plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV);
if ($this->continuousBuffer) {
$this->decryptIV = substr($ciphertext, -$offset, $this->block_size);
}
break;
case self::MODE_CTR:
$plaintext = $this->_openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer);
break;
case self::MODE_CFB:

 
 $plaintext = '';
if ($this->continuousBuffer) {
$iv = &$this->decryptIV;
$pos = &$this->buffer['pos'];
} else {
$iv = $this->decryptIV;
$pos = 0;
}
$len = strlen($ciphertext);
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $this->block_size - $pos;
if ($len >= $max) {
$i = $max;
$len-= $max;
$pos = 0;
} else {
$i = $len;
$pos+= $len;
$len = 0;
}

 $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
$ciphertext = substr($ciphertext, $i);
}
$overflow = $len % $this->block_size;
if ($overflow) {
$plaintext.= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
if ($len - $overflow) {
$iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow);
}
$iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
$plaintext.= $iv ^ substr($ciphertext, -$overflow);
$iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow);
$pos = $overflow;
} elseif ($len) {
$plaintext.= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
$iv = substr($ciphertext, -$this->block_size);
}
break;
case self::MODE_CFB8:
$plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV);
if ($this->continuousBuffer) {
if (($len = strlen($ciphertext)) >= $this->block_size) {
$this->decryptIV = substr($ciphertext, -$this->block_size);
} else {
$this->decryptIV = substr($this->decryptIV, $len - $this->block_size) . substr($ciphertext, -$len);
}
}
break;
case self::MODE_OFB:
$plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
}

return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
}

if ($this->engine === self::ENGINE_MCRYPT) {
set_error_handler(array($this, 'do_nothing'));
$block_size = $this->block_size;
if ($this->changed) {
$this->_setupMcrypt();
$this->changed = false;
}
if ($this->dechanged) {
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
$this->dechanged = false;
}

if ($this->mode == self::MODE_CFB && $this->continuousBuffer) {
$iv = &$this->decryptIV;
$pos = &$this->debuffer['pos'];
$len = strlen($ciphertext);
$plaintext = '';
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $block_size - $pos;
if ($len >= $max) {
$i = $max;
$len-= $max;
$pos = 0;
} else {
$i = $len;
$pos+= $len;
$len = 0;
}

 $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
}
if ($len >= $block_size) {
$cb = substr($ciphertext, $i, $len - $len % $block_size);
$plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
$iv = substr($cb, -$block_size);
$len%= $block_size;
}
if ($len) {
$iv = mcrypt_generic($this->ecb, $iv);
$plaintext.= $iv ^ substr($ciphertext, -$len);
$iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
$pos = $len;
}

restore_error_handler();

return $plaintext;
}

$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);

if (!$this->continuousBuffer) {
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
}

restore_error_handler();

return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
}

if ($this->changed) {
$this->_setup();
$this->changed = false;
}
if ($this->use_inline_crypt) {
$inline = $this->inline_crypt;
return $inline('decrypt', $this, $ciphertext);
}

$block_size = $this->block_size;

$buffer = &$this->debuffer;
$plaintext = '';
switch ($this->mode) {
case self::MODE_ECB:
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
}
break;
case self::MODE_CBC:
$xor = $this->decryptIV;
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$block = substr($ciphertext, $i, $block_size);
$plaintext.= $this->_decryptBlock($block) ^ $xor;
$xor = $block;
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
}
break;
case self::MODE_CTR:
$xor = $this->decryptIV;
if (strlen($buffer['ciphertext'])) {
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$block = substr($ciphertext, $i, $block_size);
if (strlen($block) > strlen($buffer['ciphertext'])) {
$buffer['ciphertext'].= $this->_encryptBlock($xor);
$this->_increment_str($xor);
}
$key = $this->_string_shift($buffer['ciphertext'], $block_size);
$plaintext.= $block ^ $key;
}
} else {
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$block = substr($ciphertext, $i, $block_size);
$key = $this->_encryptBlock($xor);
$this->_increment_str($xor);
$plaintext.= $block ^ $key;
}
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
if ($start = strlen($ciphertext) % $block_size) {
$buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
}
}
break;
case self::MODE_CFB:
if ($this->continuousBuffer) {
$iv = &$this->decryptIV;
$pos = &$buffer['pos'];
} else {
$iv = $this->decryptIV;
$pos = 0;
}
$len = strlen($ciphertext);
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $block_size - $pos;
if ($len >= $max) {
$i = $max;
$len-= $max;
$pos = 0;
} else {
$i = $len;
$pos+= $len;
$len = 0;
}

 $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
}
while ($len >= $block_size) {
$iv = $this->_encryptBlock($iv);
$cb = substr($ciphertext, $i, $block_size);
$plaintext.= $iv ^ $cb;
$iv = $cb;
$len-= $block_size;
$i+= $block_size;
}
if ($len) {
$iv = $this->_encryptBlock($iv);
$plaintext.= $iv ^ substr($ciphertext, $i);
$iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
$pos = $len;
}
break;
case self::MODE_CFB8:
$plaintext = '';
$len = strlen($ciphertext);
$iv = $this->decryptIV;

for ($i = 0; $i < $len; ++$i) {
$plaintext .= $ciphertext[$i] ^ $this->_encryptBlock($iv);
$iv = substr($iv, 1) . $ciphertext[$i];
}

if ($this->continuousBuffer) {
if ($len >= $block_size) {
$this->decryptIV = substr($ciphertext, -$block_size);
} else {
$this->decryptIV = substr($this->decryptIV, $len - $block_size) . substr($ciphertext, -$len);
}
}
break;
case self::MODE_OFB:
$xor = $this->decryptIV;
if (strlen($buffer['xor'])) {
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$block = substr($ciphertext, $i, $block_size);
if (strlen($block) > strlen($buffer['xor'])) {
$xor = $this->_encryptBlock($xor);
$buffer['xor'].= $xor;
}
$key = $this->_string_shift($buffer['xor'], $block_size);
$plaintext.= $block ^ $key;
}
} else {
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$xor = $this->_encryptBlock($xor);
$plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
}
$key = $xor;
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
if ($start = strlen($ciphertext) % $block_size) {
$buffer['xor'] = substr($key, $start) . $buffer['xor'];
}
}
break;
case self::MODE_STREAM:
$plaintext = $this->_decryptBlock($ciphertext);
break;
}
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
}

















function _openssl_ctr_process($plaintext, &$encryptIV, &$buffer)
{
$ciphertext = '';

$block_size = $this->block_size;
$key = $this->key;

if ($this->openssl_emulate_ctr) {
$xor = $encryptIV;
if (strlen($buffer['ciphertext'])) {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
if (strlen($block) > strlen($buffer['ciphertext'])) {
$result = @openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
$result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
$buffer['ciphertext'].= $result;
}
$this->_increment_str($xor);
$otp = $this->_string_shift($buffer['ciphertext'], $block_size);
$ciphertext.= $block ^ $otp;
}
} else {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
$otp = @openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
$otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp;
$this->_increment_str($xor);
$ciphertext.= $block ^ $otp;
}
}
if ($this->continuousBuffer) {
$encryptIV = $xor;
if ($start = strlen($plaintext) % $block_size) {
$buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
}
}

return $ciphertext;
}

if (strlen($buffer['ciphertext'])) {
$ciphertext = $plaintext ^ $this->_string_shift($buffer['ciphertext'], strlen($plaintext));
$plaintext = substr($plaintext, strlen($ciphertext));

if (!strlen($plaintext)) {
return $ciphertext;
}
}

$overflow = strlen($plaintext) % $block_size;
if ($overflow) {
$plaintext2 = $this->_string_pop($plaintext, $overflow); 
 $encrypted = openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
$temp = $this->_string_pop($encrypted, $block_size);
$ciphertext.= $encrypted . ($plaintext2 ^ $temp);
if ($this->continuousBuffer) {
$buffer['ciphertext'] = substr($temp, $overflow);
$encryptIV = $temp;
}
} elseif (!strlen($buffer['ciphertext'])) {
$ciphertext.= openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
$temp = $this->_string_pop($ciphertext, $block_size);
if ($this->continuousBuffer) {
$encryptIV = $temp;
}
}
if ($this->continuousBuffer) {
if (!defined('OPENSSL_RAW_DATA')) {
$encryptIV.= @openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
}
$encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
if ($overflow) {
$this->_increment_str($encryptIV);
}
}

return $ciphertext;
}
















function _openssl_ofb_process($plaintext, &$encryptIV, &$buffer)
{
if (strlen($buffer['xor'])) {
$ciphertext = $plaintext ^ $buffer['xor'];
$buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
$plaintext = substr($plaintext, strlen($ciphertext));
} else {
$ciphertext = '';
}

$block_size = $this->block_size;

$len = strlen($plaintext);
$key = $this->key;
$overflow = $len % $block_size;

if (strlen($plaintext)) {
if ($overflow) {
$ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
$xor = $this->_string_pop($ciphertext, $block_size);
if ($this->continuousBuffer) {
$encryptIV = $xor;
}
$ciphertext.= $this->_string_shift($xor, $overflow) ^ substr($plaintext, -$overflow);
if ($this->continuousBuffer) {
$buffer['xor'] = $xor;
}
} else {
$ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
if ($this->continuousBuffer) {
$encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size);
}
}
}

return $ciphertext;
}









function _openssl_translate_mode()
{
switch ($this->mode) {
case self::MODE_ECB:
return 'ecb';
case self::MODE_CBC:
return 'cbc';
case self::MODE_CTR:
return 'ctr';
case self::MODE_CFB:
return 'cfb';
case self::MODE_CFB8:
return 'cfb8';
case self::MODE_OFB:
return 'ofb';
}
}
















function enablePadding()
{
$this->padding = true;
}







function disablePadding()
{
$this->padding = false;
}







































function enableContinuousBuffer()
{
if ($this->mode == self::MODE_ECB) {
return;
}

$this->continuousBuffer = true;

$this->_setEngine();
}










function disableContinuousBuffer()
{
if ($this->mode == self::MODE_ECB) {
return;
}
if (!$this->continuousBuffer) {
return;
}

$this->continuousBuffer = false;
$this->changed = true;

$this->_setEngine();
}









function isValidEngine($engine)
{
switch ($engine) {
case self::ENGINE_OPENSSL:
if ($this->mode == self::MODE_STREAM && $this->continuousBuffer) {
return false;
}
$this->openssl_emulate_ctr = false;
$result = $this->cipher_name_openssl &&
extension_loaded('openssl') &&

 version_compare(PHP_VERSION, '5.3.3', '>=');
if (!$result) {
return false;
}


 
 if (!defined('OPENSSL_RAW_DATA')) {
$this->openssl_options = true;
} else {
$this->openssl_options = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;
}

$methods = openssl_get_cipher_methods();
if (in_array($this->cipher_name_openssl, $methods)) {
return true;
}

 
 switch ($this->mode) {
case self::MODE_CTR:
if (in_array($this->cipher_name_openssl_ecb, $methods)) {
$this->openssl_emulate_ctr = true;
return true;
}
}
return false;
case self::ENGINE_MCRYPT:
set_error_handler(array($this, 'do_nothing'));
$result = $this->cipher_name_mcrypt &&
extension_loaded('mcrypt') &&
in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms());
restore_error_handler();
return $result;
case self::ENGINE_INTERNAL:
return true;
}

return false;
}


















function setPreferredEngine($engine)
{
switch ($engine) {

 case self::ENGINE_MCRYPT:
case self::ENGINE_INTERNAL:
$this->preferredEngine = $engine;
break;
default:
$this->preferredEngine = self::ENGINE_OPENSSL;
}

$this->_setEngine();
}







function getEngine()
{
return $this->engine;
}







function _setEngine()
{
$this->engine = null;

$candidateEngines = array(
$this->preferredEngine,
self::ENGINE_OPENSSL,
self::ENGINE_MCRYPT
);
foreach ($candidateEngines as $engine) {
if ($this->isValidEngine($engine)) {
$this->engine = $engine;
break;
}
}
if (!$this->engine) {
$this->engine = self::ENGINE_INTERNAL;
}

if ($this->engine != self::ENGINE_MCRYPT && $this->enmcrypt) {
set_error_handler(array($this, 'do_nothing'));

 
 mcrypt_module_close($this->enmcrypt);
mcrypt_module_close($this->demcrypt);
$this->enmcrypt = null;
$this->demcrypt = null;

if ($this->ecb) {
mcrypt_module_close($this->ecb);
$this->ecb = null;
}
restore_error_handler();
}

$this->changed = true;
}










abstract function _encryptBlock($in);










abstract function _decryptBlock($in);











abstract function _setupKey();

























function _setup()
{
$this->_clearBuffers();
$this->_setupKey();

if ($this->use_inline_crypt) {
$this->_setupInlineCrypt();
}
}
























function _setupMcrypt()
{
$this->_clearBuffers();
$this->enchanged = $this->dechanged = true;

if (!isset($this->enmcrypt)) {
static $mcrypt_modes = array(
self::MODE_CTR => 'ctr',
self::MODE_ECB => MCRYPT_MODE_ECB,
self::MODE_CBC => MCRYPT_MODE_CBC,
self::MODE_CFB => 'ncfb',
self::MODE_CFB8 => MCRYPT_MODE_CFB,
self::MODE_OFB => MCRYPT_MODE_NOFB,
self::MODE_STREAM => MCRYPT_MODE_STREAM,
);

$this->demcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
$this->enmcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');


 
 
 if ($this->mode == self::MODE_CFB) {
$this->ecb = mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
}
} 

if ($this->mode == self::MODE_CFB) {
mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
}
}
















function _pad($text)
{
$length = strlen($text);

if (!$this->padding) {
if ($length % $this->block_size == 0) {
return $text;
} else {
user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
$this->padding = true;
}
}

$pad = $this->block_size - ($length % $this->block_size);

return str_pad($text, $length + $pad, chr($pad));
}












function _unpad($text)
{
if (!$this->padding) {
return $text;
}

$length = ord($text[strlen($text) - 1]);

if (!$length || $length > $this->block_size) {
return false;
}

return substr($text, 0, -$length);
}











function _clearBuffers()
{
$this->enbuffer = $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);


 
 $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");

if (!$this->skip_key_adjustment) {
$this->key = str_pad(substr($this->key, 0, $this->key_length), $this->key_length, "\0");
}
}











function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}











function _string_pop(&$string, $index = 1)
{
$substr = substr($string, -$index);
$string = substr($string, 0, -$index);
return $substr;
}









function _increment_str(&$var)
{
for ($i = 4; $i <= strlen($var); $i+= 4) {
$temp = substr($var, -$i, 4);
switch ($temp) {
case "\xFF\xFF\xFF\xFF":
$var = substr_replace($var, "\x00\x00\x00\x00", -$i, 4);
break;
case "\x7F\xFF\xFF\xFF":
$var = substr_replace($var, "\x80\x00\x00\x00", -$i, 4);
return;
default:
$temp = unpack('Nnum', $temp);
$var = substr_replace($var, pack('N', $temp['num'] + 1), -$i, 4);
return;
}
}

$remainder = strlen($var) % 4;

if ($remainder == 0) {
return;
}

$temp = unpack('Nnum', str_pad(substr($var, 0, $remainder), 4, "\0", STR_PAD_LEFT));
$temp = substr(pack('N', $temp['num'] + 1), -$remainder);
$var = substr_replace($var, $temp, 0, $remainder);
}





























































function _setupInlineCrypt()
{

 
 
 
 

$this->use_inline_crypt = false;
}
















































































































function _createInlineCryptFunction($cipher_code)
{
$block_size = $this->block_size;


 $init_crypt = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : '';
$init_encrypt = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : '';
$init_decrypt = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : '';

 $encrypt_block = $cipher_code['encrypt_block'];
$decrypt_block = $cipher_code['decrypt_block'];


 
 
 switch ($this->mode) {
case self::MODE_ECB:
$encrypt = $init_encrypt . '
                    $_ciphertext = "";
                    $_plaintext_len = strlen($_text);

                    for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
                        $in = substr($_text, $_i, '.$block_size.');
                        '.$encrypt_block.'
                        $_ciphertext.= $in;
                    }

                    return $_ciphertext;
                    ';

$decrypt = $init_decrypt . '
                    $_plaintext = "";
                    $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
                    $_ciphertext_len = strlen($_text);

                    for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
                        $in = substr($_text, $_i, '.$block_size.');
                        '.$decrypt_block.'
                        $_plaintext.= $in;
                    }

                    return $self->_unpad($_plaintext);
                    ';
break;
case self::MODE_CTR:
$encrypt = $init_encrypt . '
                    $_ciphertext = "";
                    $_plaintext_len = strlen($_text);
                    $_xor = $self->encryptIV;
                    $_buffer = &$self->enbuffer;
                    if (strlen($_buffer["ciphertext"])) {
                        for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
                            $_block = substr($_text, $_i, '.$block_size.');
                            if (strlen($_block) > strlen($_buffer["ciphertext"])) {
                                $in = $_xor;
                                '.$encrypt_block.'
                                $self->_increment_str($_xor);
                                $_buffer["ciphertext"].= $in;
                            }
                            $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
                            $_ciphertext.= $_block ^ $_key;
                        }
                    } else {
                        for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
                            $_block = substr($_text, $_i, '.$block_size.');
                            $in = $_xor;
                            '.$encrypt_block.'
                            $self->_increment_str($_xor);
                            $_key = $in;
                            $_ciphertext.= $_block ^ $_key;
                        }
                    }
                    if ($self->continuousBuffer) {
                        $self->encryptIV = $_xor;
                        if ($_start = $_plaintext_len % '.$block_size.') {
                            $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
                        }
                    }

                    return $_ciphertext;
                ';

$decrypt = $init_encrypt . '
                    $_plaintext = "";
                    $_ciphertext_len = strlen($_text);
                    $_xor = $self->decryptIV;
                    $_buffer = &$self->debuffer;

                    if (strlen($_buffer["ciphertext"])) {
                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
                            $_block = substr($_text, $_i, '.$block_size.');
                            if (strlen($_block) > strlen($_buffer["ciphertext"])) {
                                $in = $_xor;
                                '.$encrypt_block.'
                                $self->_increment_str($_xor);
                                $_buffer["ciphertext"].= $in;
                            }
                            $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
                            $_plaintext.= $_block ^ $_key;
                        }
                    } else {
                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
                            $_block = substr($_text, $_i, '.$block_size.');
                            $in = $_xor;
                            '.$encrypt_block.'
                            $self->_increment_str($_xor);
                            $_key = $in;
                            $_plaintext.= $_block ^ $_key;
                        }
                    }
                    if ($self->continuousBuffer) {
                        $self->decryptIV = $_xor;
                        if ($_start = $_ciphertext_len % '.$block_size.') {
                            $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
                        }
                    }

                    return $_plaintext;
                    ';
break;
case self::MODE_CFB:
$encrypt = $init_encrypt . '
                    $_ciphertext = "";
                    $_buffer = &$self->enbuffer;

                    if ($self->continuousBuffer) {
                        $_iv = &$self->encryptIV;
                        $_pos = &$_buffer["pos"];
                    } else {
                        $_iv = $self->encryptIV;
                        $_pos = 0;
                    }
                    $_len = strlen($_text);
                    $_i = 0;
                    if ($_pos) {
                        $_orig_pos = $_pos;
                        $_max = '.$block_size.' - $_pos;
                        if ($_len >= $_max) {
                            $_i = $_max;
                            $_len-= $_max;
                            $_pos = 0;
                        } else {
                            $_i = $_len;
                            $_pos+= $_len;
                            $_len = 0;
                        }
                        $_ciphertext = substr($_iv, $_orig_pos) ^ $_text;
                        $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i);
                    }
                    while ($_len >= '.$block_size.') {
                        $in = $_iv;
                        '.$encrypt_block.';
                        $_iv = $in ^ substr($_text, $_i, '.$block_size.');
                        $_ciphertext.= $_iv;
                        $_len-= '.$block_size.';
                        $_i+= '.$block_size.';
                    }
                    if ($_len) {
                        $in = $_iv;
                        '.$encrypt_block.'
                        $_iv = $in;
                        $_block = $_iv ^ substr($_text, $_i);
                        $_iv = substr_replace($_iv, $_block, 0, $_len);
                        $_ciphertext.= $_block;
                        $_pos = $_len;
                    }
                    return $_ciphertext;
                ';

$decrypt = $init_encrypt . '
                    $_plaintext = "";
                    $_buffer = &$self->debuffer;

                    if ($self->continuousBuffer) {
                        $_iv = &$self->decryptIV;
                        $_pos = &$_buffer["pos"];
                    } else {
                        $_iv = $self->decryptIV;
                        $_pos = 0;
                    }
                    $_len = strlen($_text);
                    $_i = 0;
                    if ($_pos) {
                        $_orig_pos = $_pos;
                        $_max = '.$block_size.' - $_pos;
                        if ($_len >= $_max) {
                            $_i = $_max;
                            $_len-= $_max;
                            $_pos = 0;
                        } else {
                            $_i = $_len;
                            $_pos+= $_len;
                            $_len = 0;
                        }
                        $_plaintext = substr($_iv, $_orig_pos) ^ $_text;
                        $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i);
                    }
                    while ($_len >= '.$block_size.') {
                        $in = $_iv;
                        '.$encrypt_block.'
                        $_iv = $in;
                        $cb = substr($_text, $_i, '.$block_size.');
                        $_plaintext.= $_iv ^ $cb;
                        $_iv = $cb;
                        $_len-= '.$block_size.';
                        $_i+= '.$block_size.';
                    }
                    if ($_len) {
                        $in = $_iv;
                        '.$encrypt_block.'
                        $_iv = $in;
                        $_plaintext.= $_iv ^ substr($_text, $_i);
                        $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len);
                        $_pos = $_len;
                    }

                    return $_plaintext;
                    ';
break;
case self::MODE_CFB8:
$encrypt = $init_encrypt . '
                    $_ciphertext = "";
                    $_len = strlen($_text);
                    $_iv = $self->encryptIV;

                    for ($_i = 0; $_i < $_len; ++$_i) {
                        $in = $_iv;
                        '.$encrypt_block.'
                        $_ciphertext .= ($_c = $_text[$_i] ^ $in);
                        $_iv = substr($_iv, 1) . $_c;
                    }

                    if ($self->continuousBuffer) {
                        if ($_len >= '.$block_size.') {
                            $self->encryptIV = substr($_ciphertext, -'.$block_size.');
                        } else {
                            $self->encryptIV = substr($self->encryptIV, $_len - '.$block_size.') . substr($_ciphertext, -$_len);
                        }
                    }

                    return $_ciphertext;
                    ';
$decrypt = $init_encrypt . '
                    $_plaintext = "";
                    $_len = strlen($_text);
                    $_iv = $self->decryptIV;

                    for ($_i = 0; $_i < $_len; ++$_i) {
                        $in = $_iv;
                        '.$encrypt_block.'
                        $_plaintext .= $_text[$_i] ^ $in;
                        $_iv = substr($_iv, 1) . $_text[$_i];
                    }

                    if ($self->continuousBuffer) {
                        if ($_len >= '.$block_size.') {
                            $self->decryptIV = substr($_text, -'.$block_size.');
                        } else {
                            $self->decryptIV = substr($self->decryptIV, $_len - '.$block_size.') . substr($_text, -$_len);
                        }
                    }

                    return $_plaintext;
                    ';
break;
case self::MODE_OFB:
$encrypt = $init_encrypt . '
                    $_ciphertext = "";
                    $_plaintext_len = strlen($_text);
                    $_xor = $self->encryptIV;
                    $_buffer = &$self->enbuffer;

                    if (strlen($_buffer["xor"])) {
                        for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
                            $_block = substr($_text, $_i, '.$block_size.');
                            if (strlen($_block) > strlen($_buffer["xor"])) {
                                $in = $_xor;
                                '.$encrypt_block.'
                                $_xor = $in;
                                $_buffer["xor"].= $_xor;
                            }
                            $_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
                            $_ciphertext.= $_block ^ $_key;
                        }
                    } else {
                        for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
                            $in = $_xor;
                            '.$encrypt_block.'
                            $_xor = $in;
                            $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
                        }
                        $_key = $_xor;
                    }
                    if ($self->continuousBuffer) {
                        $self->encryptIV = $_xor;
                        if ($_start = $_plaintext_len % '.$block_size.') {
                             $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
                        }
                    }
                    return $_ciphertext;
                    ';

$decrypt = $init_encrypt . '
                    $_plaintext = "";
                    $_ciphertext_len = strlen($_text);
                    $_xor = $self->decryptIV;
                    $_buffer = &$self->debuffer;

                    if (strlen($_buffer["xor"])) {
                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
                            $_block = substr($_text, $_i, '.$block_size.');
                            if (strlen($_block) > strlen($_buffer["xor"])) {
                                $in = $_xor;
                                '.$encrypt_block.'
                                $_xor = $in;
                                $_buffer["xor"].= $_xor;
                            }
                            $_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
                            $_plaintext.= $_block ^ $_key;
                        }
                    } else {
                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
                            $in = $_xor;
                            '.$encrypt_block.'
                            $_xor = $in;
                            $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
                        }
                        $_key = $_xor;
                    }
                    if ($self->continuousBuffer) {
                        $self->decryptIV = $_xor;
                        if ($_start = $_ciphertext_len % '.$block_size.') {
                             $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
                        }
                    }
                    return $_plaintext;
                    ';
break;
case self::MODE_STREAM:
$encrypt = $init_encrypt . '
                    $_ciphertext = "";
                    '.$encrypt_block.'
                    return $_ciphertext;
                    ';
$decrypt = $init_decrypt . '
                    $_plaintext = "";
                    '.$decrypt_block.'
                    return $_plaintext;
                    ';
break;

 default:
$encrypt = $init_encrypt . '
                    $_ciphertext = "";
                    $_plaintext_len = strlen($_text);

                    $in = $self->encryptIV;

                    for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
                        $in = substr($_text, $_i, '.$block_size.') ^ $in;
                        '.$encrypt_block.'
                        $_ciphertext.= $in;
                    }

                    if ($self->continuousBuffer) {
                        $self->encryptIV = $in;
                    }

                    return $_ciphertext;
                    ';

$decrypt = $init_decrypt . '
                    $_plaintext = "";
                    $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
                    $_ciphertext_len = strlen($_text);

                    $_iv = $self->decryptIV;

                    for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
                        $in = $_block = substr($_text, $_i, '.$block_size.');
                        '.$decrypt_block.'
                        $_plaintext.= $in ^ $_iv;
                        $_iv = $_block;
                    }

                    if ($self->continuousBuffer) {
                        $self->decryptIV = $_iv;
                    }

                    return $self->_unpad($_plaintext);
                    ';
break;
}


 eval('$func = function ($_action, &$self, $_text) { ' . $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' } };');
return $func;
}
















function &_getLambdaFunctions()
{
static $functions = array();
return $functions;
}









function _hashInlineCryptFunction($bytes)
{
if (!isset(self::$WHIRLPOOL_AVAILABLE)) {
self::$WHIRLPOOL_AVAILABLE = extension_loaded('hash') && in_array('whirlpool', hash_algos());
}

$result = '';
$hash = $bytes;

switch (true) {
case self::$WHIRLPOOL_AVAILABLE:
foreach (str_split($bytes, 64) as $t) {
$hash = hash('whirlpool', $hash, true);
$result .= $t ^ $hash;
}
return $result . hash('whirlpool', $hash, true);
default:
$len = strlen($bytes);
for ($i = 0; $i < $len; $i+=20) {
$t = substr($bytes, $i, 20);
$hash = pack('H*', sha1($hash));
$result .= $t ^ $hash;
}
return $result . pack('H*', sha1($hash));
}
}










function safe_intval($x)
{
switch (true) {
case is_int($x):

 case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
return $x;
}
return (fmod($x, 0x80000000) & 0x7FFFFFFF) |
((fmod(floor($x / 0x80000000), 2) & 1) << 31);
}







function safe_intval_inline()
{
switch (true) {
case defined('PHP_INT_SIZE') && PHP_INT_SIZE == 8:
case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
return '%s';
break;
default:
$safeint = '(is_int($temp = %s) ? $temp : (fmod($temp, 0x80000000) & 0x7FFFFFFF) | ';
return $safeint . '((fmod(floor($temp / 0x80000000), 2) & 1) << 31))';
}
}






function do_nothing()
{
}
}
<?php



































namespace phpseclib\Crypt;








class TripleDES extends DES
{





const MODE_3CBC = -2;






const MODE_CBC3 = Base::MODE_CBC;








var $key_length = 24;









var $password_default_salt = 'phpseclib';









var $cipher_name_mcrypt = 'tripledes';








var $cfb_init_len = 750;









var $key_length_max = 24;







var $mode_3cbc;









var $des;



























function __construct($mode = Base::MODE_CBC)
{
switch ($mode) {

 
 case self::MODE_3CBC:
parent::__construct(Base::MODE_CBC);
$this->mode_3cbc = true;


 $this->des = array(
new DES(Base::MODE_CBC),
new DES(Base::MODE_CBC),
new DES(Base::MODE_CBC),
);


 $this->des[0]->disablePadding();
$this->des[1]->disablePadding();
$this->des[2]->disablePadding();
break;

 default:
parent::__construct($mode);
}
}











function isValidEngine($engine)
{
if ($engine == self::ENGINE_OPENSSL) {
$this->cipher_name_openssl_ecb = 'des-ede3';
$mode = $this->_openssl_translate_mode();
$this->cipher_name_openssl = $mode == 'ecb' ? 'des-ede3' : 'des-ede3-' . $mode;
}

return parent::isValidEngine($engine);
}











function setIV($iv)
{
parent::setIV($iv);
if ($this->mode_3cbc) {
$this->des[0]->setIV($iv);
$this->des[1]->setIV($iv);
$this->des[2]->setIV($iv);
}
}










function setKeyLength($length)
{
$length >>= 3;
switch (true) {
case $length <= 8:
$this->key_length = 8;
break;
case $length <= 16:
$this->key_length = 16;
break;
default:
$this->key_length = 24;
}

parent::setKeyLength($length);
}
















function setKey($key)
{
$length = $this->explicit_key_length ? $this->key_length : strlen($key);
if ($length > 8) {
$key = str_pad(substr($key, 0, 24), 24, chr(0));

 
 $key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
} else {
$key = str_pad($key, 8, chr(0));
}
parent::setKey($key);


 
 
 
 if ($this->mode_3cbc && $length > 8) {
$this->des[0]->setKey(substr($key, 0, 8));
$this->des[1]->setKey(substr($key, 8, 8));
$this->des[2]->setKey(substr($key, 16, 8));
}
}









function encrypt($plaintext)
{

 


 if ($this->mode_3cbc && strlen($this->key) > 8) {
return $this->des[2]->encrypt(
$this->des[1]->decrypt(
$this->des[0]->encrypt(
$this->_pad($plaintext)
)
)
);
}

return parent::encrypt($plaintext);
}









function decrypt($ciphertext)
{
if ($this->mode_3cbc && strlen($this->key) > 8) {
return $this->_unpad(
$this->des[0]->decrypt(
$this->des[1]->encrypt(
$this->des[2]->decrypt(
str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0")
)
)
)
);
}

return parent::decrypt($ciphertext);
}







































function enableContinuousBuffer()
{
parent::enableContinuousBuffer();
if ($this->mode_3cbc) {
$this->des[0]->enableContinuousBuffer();
$this->des[1]->enableContinuousBuffer();
$this->des[2]->enableContinuousBuffer();
}
}










function disableContinuousBuffer()
{
parent::disableContinuousBuffer();
if ($this->mode_3cbc) {
$this->des[0]->disableContinuousBuffer();
$this->des[1]->disableContinuousBuffer();
$this->des[2]->disableContinuousBuffer();
}
}








function _setupKey()
{
switch (true) {

 
 case strlen($this->key) <= 8:
$this->des_rounds = 1;
break;


 default:
$this->des_rounds = 3;


 if ($this->mode_3cbc) {
$this->des[0]->_setupKey();
$this->des[1]->_setupKey();
$this->des[2]->_setupKey();


 
 return;
}
}

 parent::_setupKey();
}










function setPreferredEngine($engine)
{
if ($this->mode_3cbc) {
$this->des[0]->setPreferredEngine($engine);
$this->des[1]->setPreferredEngine($engine);
$this->des[2]->setPreferredEngine($engine);
}

return parent::setPreferredEngine($engine);
}
}
<?php









































namespace phpseclib\Crypt;








class DES extends Base
{








const ENCRYPT = 0;



const DECRYPT = 1;









var $block_size = 8;








var $key_length = 8;








var $cipher_name_mcrypt = 'des';








var $openssl_mode_names = array(
self::MODE_ECB => 'des-ecb',
self::MODE_CBC => 'des-cbc',
self::MODE_CFB => 'des-cfb',
self::MODE_OFB => 'des-ofb'

 );








var $cfb_init_len = 500;











var $des_rounds = 1;








var $key_length_max = 8;








var $keys;













var $shuffle = array(
"\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\xFF",
"\x00\x00\x00\x00\x00\x00\xFF\x00", "\x00\x00\x00\x00\x00\x00\xFF\xFF",
"\x00\x00\x00\x00\x00\xFF\x00\x00", "\x00\x00\x00\x00\x00\xFF\x00\xFF",
"\x00\x00\x00\x00\x00\xFF\xFF\x00", "\x00\x00\x00\x00\x00\xFF\xFF\xFF",
"\x00\x00\x00\x00\xFF\x00\x00\x00", "\x00\x00\x00\x00\xFF\x00\x00\xFF",
"\x00\x00\x00\x00\xFF\x00\xFF\x00", "\x00\x00\x00\x00\xFF\x00\xFF\xFF",
"\x00\x00\x00\x00\xFF\xFF\x00\x00", "\x00\x00\x00\x00\xFF\xFF\x00\xFF",
"\x00\x00\x00\x00\xFF\xFF\xFF\x00", "\x00\x00\x00\x00\xFF\xFF\xFF\xFF",
"\x00\x00\x00\xFF\x00\x00\x00\x00", "\x00\x00\x00\xFF\x00\x00\x00\xFF",
"\x00\x00\x00\xFF\x00\x00\xFF\x00", "\x00\x00\x00\xFF\x00\x00\xFF\xFF",
"\x00\x00\x00\xFF\x00\xFF\x00\x00", "\x00\x00\x00\xFF\x00\xFF\x00\xFF",
"\x00\x00\x00\xFF\x00\xFF\xFF\x00", "\x00\x00\x00\xFF\x00\xFF\xFF\xFF",
"\x00\x00\x00\xFF\xFF\x00\x00\x00", "\x00\x00\x00\xFF\xFF\x00\x00\xFF",
"\x00\x00\x00\xFF\xFF\x00\xFF\x00", "\x00\x00\x00\xFF\xFF\x00\xFF\xFF",
"\x00\x00\x00\xFF\xFF\xFF\x00\x00", "\x00\x00\x00\xFF\xFF\xFF\x00\xFF",
"\x00\x00\x00\xFF\xFF\xFF\xFF\x00", "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF",
"\x00\x00\xFF\x00\x00\x00\x00\x00", "\x00\x00\xFF\x00\x00\x00\x00\xFF",
"\x00\x00\xFF\x00\x00\x00\xFF\x00", "\x00\x00\xFF\x00\x00\x00\xFF\xFF",
"\x00\x00\xFF\x00\x00\xFF\x00\x00", "\x00\x00\xFF\x00\x00\xFF\x00\xFF",
"\x00\x00\xFF\x00\x00\xFF\xFF\x00", "\x00\x00\xFF\x00\x00\xFF\xFF\xFF",
"\x00\x00\xFF\x00\xFF\x00\x00\x00", "\x00\x00\xFF\x00\xFF\x00\x00\xFF",
"\x00\x00\xFF\x00\xFF\x00\xFF\x00", "\x00\x00\xFF\x00\xFF\x00\xFF\xFF",
"\x00\x00\xFF\x00\xFF\xFF\x00\x00", "\x00\x00\xFF\x00\xFF\xFF\x00\xFF",
"\x00\x00\xFF\x00\xFF\xFF\xFF\x00", "\x00\x00\xFF\x00\xFF\xFF\xFF\xFF",
"\x00\x00\xFF\xFF\x00\x00\x00\x00", "\x00\x00\xFF\xFF\x00\x00\x00\xFF",
"\x00\x00\xFF\xFF\x00\x00\xFF\x00", "\x00\x00\xFF\xFF\x00\x00\xFF\xFF",
"\x00\x00\xFF\xFF\x00\xFF\x00\x00", "\x00\x00\xFF\xFF\x00\xFF\x00\xFF",
"\x00\x00\xFF\xFF\x00\xFF\xFF\x00", "\x00\x00\xFF\xFF\x00\xFF\xFF\xFF",
"\x00\x00\xFF\xFF\xFF\x00\x00\x00", "\x00\x00\xFF\xFF\xFF\x00\x00\xFF",
"\x00\x00\xFF\xFF\xFF\x00\xFF\x00", "\x00\x00\xFF\xFF\xFF\x00\xFF\xFF",
"\x00\x00\xFF\xFF\xFF\xFF\x00\x00", "\x00\x00\xFF\xFF\xFF\xFF\x00\xFF",
"\x00\x00\xFF\xFF\xFF\xFF\xFF\x00", "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF",
"\x00\xFF\x00\x00\x00\x00\x00\x00", "\x00\xFF\x00\x00\x00\x00\x00\xFF",
"\x00\xFF\x00\x00\x00\x00\xFF\x00", "\x00\xFF\x00\x00\x00\x00\xFF\xFF",
"\x00\xFF\x00\x00\x00\xFF\x00\x00", "\x00\xFF\x00\x00\x00\xFF\x00\xFF",
"\x00\xFF\x00\x00\x00\xFF\xFF\x00", "\x00\xFF\x00\x00\x00\xFF\xFF\xFF",
"\x00\xFF\x00\x00\xFF\x00\x00\x00", "\x00\xFF\x00\x00\xFF\x00\x00\xFF",
"\x00\xFF\x00\x00\xFF\x00\xFF\x00", "\x00\xFF\x00\x00\xFF\x00\xFF\xFF",
"\x00\xFF\x00\x00\xFF\xFF\x00\x00", "\x00\xFF\x00\x00\xFF\xFF\x00\xFF",
"\x00\xFF\x00\x00\xFF\xFF\xFF\x00", "\x00\xFF\x00\x00\xFF\xFF\xFF\xFF",
"\x00\xFF\x00\xFF\x00\x00\x00\x00", "\x00\xFF\x00\xFF\x00\x00\x00\xFF",
"\x00\xFF\x00\xFF\x00\x00\xFF\x00", "\x00\xFF\x00\xFF\x00\x00\xFF\xFF",
"\x00\xFF\x00\xFF\x00\xFF\x00\x00", "\x00\xFF\x00\xFF\x00\xFF\x00\xFF",
"\x00\xFF\x00\xFF\x00\xFF\xFF\x00", "\x00\xFF\x00\xFF\x00\xFF\xFF\xFF",
"\x00\xFF\x00\xFF\xFF\x00\x00\x00", "\x00\xFF\x00\xFF\xFF\x00\x00\xFF",
"\x00\xFF\x00\xFF\xFF\x00\xFF\x00", "\x00\xFF\x00\xFF\xFF\x00\xFF\xFF",
"\x00\xFF\x00\xFF\xFF\xFF\x00\x00", "\x00\xFF\x00\xFF\xFF\xFF\x00\xFF",
"\x00\xFF\x00\xFF\xFF\xFF\xFF\x00", "\x00\xFF\x00\xFF\xFF\xFF\xFF\xFF",
"\x00\xFF\xFF\x00\x00\x00\x00\x00", "\x00\xFF\xFF\x00\x00\x00\x00\xFF",
"\x00\xFF\xFF\x00\x00\x00\xFF\x00", "\x00\xFF\xFF\x00\x00\x00\xFF\xFF",
"\x00\xFF\xFF\x00\x00\xFF\x00\x00", "\x00\xFF\xFF\x00\x00\xFF\x00\xFF",
"\x00\xFF\xFF\x00\x00\xFF\xFF\x00", "\x00\xFF\xFF\x00\x00\xFF\xFF\xFF",
"\x00\xFF\xFF\x00\xFF\x00\x00\x00", "\x00\xFF\xFF\x00\xFF\x00\x00\xFF",
"\x00\xFF\xFF\x00\xFF\x00\xFF\x00", "\x00\xFF\xFF\x00\xFF\x00\xFF\xFF",
"\x00\xFF\xFF\x00\xFF\xFF\x00\x00", "\x00\xFF\xFF\x00\xFF\xFF\x00\xFF",
"\x00\xFF\xFF\x00\xFF\xFF\xFF\x00", "\x00\xFF\xFF\x00\xFF\xFF\xFF\xFF",
"\x00\xFF\xFF\xFF\x00\x00\x00\x00", "\x00\xFF\xFF\xFF\x00\x00\x00\xFF",
"\x00\xFF\xFF\xFF\x00\x00\xFF\x00", "\x00\xFF\xFF\xFF\x00\x00\xFF\xFF",
"\x00\xFF\xFF\xFF\x00\xFF\x00\x00", "\x00\xFF\xFF\xFF\x00\xFF\x00\xFF",
"\x00\xFF\xFF\xFF\x00\xFF\xFF\x00", "\x00\xFF\xFF\xFF\x00\xFF\xFF\xFF",
"\x00\xFF\xFF\xFF\xFF\x00\x00\x00", "\x00\xFF\xFF\xFF\xFF\x00\x00\xFF",
"\x00\xFF\xFF\xFF\xFF\x00\xFF\x00", "\x00\xFF\xFF\xFF\xFF\x00\xFF\xFF",
"\x00\xFF\xFF\xFF\xFF\xFF\x00\x00", "\x00\xFF\xFF\xFF\xFF\xFF\x00\xFF",
"\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
"\xFF\x00\x00\x00\x00\x00\x00\x00", "\xFF\x00\x00\x00\x00\x00\x00\xFF",
"\xFF\x00\x00\x00\x00\x00\xFF\x00", "\xFF\x00\x00\x00\x00\x00\xFF\xFF",
"\xFF\x00\x00\x00\x00\xFF\x00\x00", "\xFF\x00\x00\x00\x00\xFF\x00\xFF",
"\xFF\x00\x00\x00\x00\xFF\xFF\x00", "\xFF\x00\x00\x00\x00\xFF\xFF\xFF",
"\xFF\x00\x00\x00\xFF\x00\x00\x00", "\xFF\x00\x00\x00\xFF\x00\x00\xFF",
"\xFF\x00\x00\x00\xFF\x00\xFF\x00", "\xFF\x00\x00\x00\xFF\x00\xFF\xFF",
"\xFF\x00\x00\x00\xFF\xFF\x00\x00", "\xFF\x00\x00\x00\xFF\xFF\x00\xFF",
"\xFF\x00\x00\x00\xFF\xFF\xFF\x00", "\xFF\x00\x00\x00\xFF\xFF\xFF\xFF",
"\xFF\x00\x00\xFF\x00\x00\x00\x00", "\xFF\x00\x00\xFF\x00\x00\x00\xFF",
"\xFF\x00\x00\xFF\x00\x00\xFF\x00", "\xFF\x00\x00\xFF\x00\x00\xFF\xFF",
"\xFF\x00\x00\xFF\x00\xFF\x00\x00", "\xFF\x00\x00\xFF\x00\xFF\x00\xFF",
"\xFF\x00\x00\xFF\x00\xFF\xFF\x00", "\xFF\x00\x00\xFF\x00\xFF\xFF\xFF",
"\xFF\x00\x00\xFF\xFF\x00\x00\x00", "\xFF\x00\x00\xFF\xFF\x00\x00\xFF",
"\xFF\x00\x00\xFF\xFF\x00\xFF\x00", "\xFF\x00\x00\xFF\xFF\x00\xFF\xFF",
"\xFF\x00\x00\xFF\xFF\xFF\x00\x00", "\xFF\x00\x00\xFF\xFF\xFF\x00\xFF",
"\xFF\x00\x00\xFF\xFF\xFF\xFF\x00", "\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF",
"\xFF\x00\xFF\x00\x00\x00\x00\x00", "\xFF\x00\xFF\x00\x00\x00\x00\xFF",
"\xFF\x00\xFF\x00\x00\x00\xFF\x00", "\xFF\x00\xFF\x00\x00\x00\xFF\xFF",
"\xFF\x00\xFF\x00\x00\xFF\x00\x00", "\xFF\x00\xFF\x00\x00\xFF\x00\xFF",
"\xFF\x00\xFF\x00\x00\xFF\xFF\x00", "\xFF\x00\xFF\x00\x00\xFF\xFF\xFF",
"\xFF\x00\xFF\x00\xFF\x00\x00\x00", "\xFF\x00\xFF\x00\xFF\x00\x00\xFF",
"\xFF\x00\xFF\x00\xFF\x00\xFF\x00", "\xFF\x00\xFF\x00\xFF\x00\xFF\xFF",
"\xFF\x00\xFF\x00\xFF\xFF\x00\x00", "\xFF\x00\xFF\x00\xFF\xFF\x00\xFF",
"\xFF\x00\xFF\x00\xFF\xFF\xFF\x00", "\xFF\x00\xFF\x00\xFF\xFF\xFF\xFF",
"\xFF\x00\xFF\xFF\x00\x00\x00\x00", "\xFF\x00\xFF\xFF\x00\x00\x00\xFF",
"\xFF\x00\xFF\xFF\x00\x00\xFF\x00", "\xFF\x00\xFF\xFF\x00\x00\xFF\xFF",
"\xFF\x00\xFF\xFF\x00\xFF\x00\x00", "\xFF\x00\xFF\xFF\x00\xFF\x00\xFF",
"\xFF\x00\xFF\xFF\x00\xFF\xFF\x00", "\xFF\x00\xFF\xFF\x00\xFF\xFF\xFF",
"\xFF\x00\xFF\xFF\xFF\x00\x00\x00", "\xFF\x00\xFF\xFF\xFF\x00\x00\xFF",
"\xFF\x00\xFF\xFF\xFF\x00\xFF\x00", "\xFF\x00\xFF\xFF\xFF\x00\xFF\xFF",
"\xFF\x00\xFF\xFF\xFF\xFF\x00\x00", "\xFF\x00\xFF\xFF\xFF\xFF\x00\xFF",
"\xFF\x00\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF",
"\xFF\xFF\x00\x00\x00\x00\x00\x00", "\xFF\xFF\x00\x00\x00\x00\x00\xFF",
"\xFF\xFF\x00\x00\x00\x00\xFF\x00", "\xFF\xFF\x00\x00\x00\x00\xFF\xFF",
"\xFF\xFF\x00\x00\x00\xFF\x00\x00", "\xFF\xFF\x00\x00\x00\xFF\x00\xFF",
"\xFF\xFF\x00\x00\x00\xFF\xFF\x00", "\xFF\xFF\x00\x00\x00\xFF\xFF\xFF",
"\xFF\xFF\x00\x00\xFF\x00\x00\x00", "\xFF\xFF\x00\x00\xFF\x00\x00\xFF",
"\xFF\xFF\x00\x00\xFF\x00\xFF\x00", "\xFF\xFF\x00\x00\xFF\x00\xFF\xFF",
"\xFF\xFF\x00\x00\xFF\xFF\x00\x00", "\xFF\xFF\x00\x00\xFF\xFF\x00\xFF",
"\xFF\xFF\x00\x00\xFF\xFF\xFF\x00", "\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF",
"\xFF\xFF\x00\xFF\x00\x00\x00\x00", "\xFF\xFF\x00\xFF\x00\x00\x00\xFF",
"\xFF\xFF\x00\xFF\x00\x00\xFF\x00", "\xFF\xFF\x00\xFF\x00\x00\xFF\xFF",
"\xFF\xFF\x00\xFF\x00\xFF\x00\x00", "\xFF\xFF\x00\xFF\x00\xFF\x00\xFF",
"\xFF\xFF\x00\xFF\x00\xFF\xFF\x00", "\xFF\xFF\x00\xFF\x00\xFF\xFF\xFF",
"\xFF\xFF\x00\xFF\xFF\x00\x00\x00", "\xFF\xFF\x00\xFF\xFF\x00\x00\xFF",
"\xFF\xFF\x00\xFF\xFF\x00\xFF\x00", "\xFF\xFF\x00\xFF\xFF\x00\xFF\xFF",
"\xFF\xFF\x00\xFF\xFF\xFF\x00\x00", "\xFF\xFF\x00\xFF\xFF\xFF\x00\xFF",
"\xFF\xFF\x00\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF",
"\xFF\xFF\xFF\x00\x00\x00\x00\x00", "\xFF\xFF\xFF\x00\x00\x00\x00\xFF",
"\xFF\xFF\xFF\x00\x00\x00\xFF\x00", "\xFF\xFF\xFF\x00\x00\x00\xFF\xFF",
"\xFF\xFF\xFF\x00\x00\xFF\x00\x00", "\xFF\xFF\xFF\x00\x00\xFF\x00\xFF",
"\xFF\xFF\xFF\x00\x00\xFF\xFF\x00", "\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF",
"\xFF\xFF\xFF\x00\xFF\x00\x00\x00", "\xFF\xFF\xFF\x00\xFF\x00\x00\xFF",
"\xFF\xFF\xFF\x00\xFF\x00\xFF\x00", "\xFF\xFF\xFF\x00\xFF\x00\xFF\xFF",
"\xFF\xFF\xFF\x00\xFF\xFF\x00\x00", "\xFF\xFF\xFF\x00\xFF\xFF\x00\xFF",
"\xFF\xFF\xFF\x00\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF",
"\xFF\xFF\xFF\xFF\x00\x00\x00\x00", "\xFF\xFF\xFF\xFF\x00\x00\x00\xFF",
"\xFF\xFF\xFF\xFF\x00\x00\xFF\x00", "\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF",
"\xFF\xFF\xFF\xFF\x00\xFF\x00\x00", "\xFF\xFF\xFF\xFF\x00\xFF\x00\xFF",
"\xFF\xFF\xFF\xFF\x00\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF",
"\xFF\xFF\xFF\xFF\xFF\x00\x00\x00", "\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF",
"\xFF\xFF\xFF\xFF\xFF\x00\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF",
"\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF",
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
);









var $ipmap = array(
0x00, 0x10, 0x01, 0x11, 0x20, 0x30, 0x21, 0x31,
0x02, 0x12, 0x03, 0x13, 0x22, 0x32, 0x23, 0x33,
0x40, 0x50, 0x41, 0x51, 0x60, 0x70, 0x61, 0x71,
0x42, 0x52, 0x43, 0x53, 0x62, 0x72, 0x63, 0x73,
0x04, 0x14, 0x05, 0x15, 0x24, 0x34, 0x25, 0x35,
0x06, 0x16, 0x07, 0x17, 0x26, 0x36, 0x27, 0x37,
0x44, 0x54, 0x45, 0x55, 0x64, 0x74, 0x65, 0x75,
0x46, 0x56, 0x47, 0x57, 0x66, 0x76, 0x67, 0x77,
0x80, 0x90, 0x81, 0x91, 0xA0, 0xB0, 0xA1, 0xB1,
0x82, 0x92, 0x83, 0x93, 0xA2, 0xB2, 0xA3, 0xB3,
0xC0, 0xD0, 0xC1, 0xD1, 0xE0, 0xF0, 0xE1, 0xF1,
0xC2, 0xD2, 0xC3, 0xD3, 0xE2, 0xF2, 0xE3, 0xF3,
0x84, 0x94, 0x85, 0x95, 0xA4, 0xB4, 0xA5, 0xB5,
0x86, 0x96, 0x87, 0x97, 0xA6, 0xB6, 0xA7, 0xB7,
0xC4, 0xD4, 0xC5, 0xD5, 0xE4, 0xF4, 0xE5, 0xF5,
0xC6, 0xD6, 0xC7, 0xD7, 0xE6, 0xF6, 0xE7, 0xF7,
0x08, 0x18, 0x09, 0x19, 0x28, 0x38, 0x29, 0x39,
0x0A, 0x1A, 0x0B, 0x1B, 0x2A, 0x3A, 0x2B, 0x3B,
0x48, 0x58, 0x49, 0x59, 0x68, 0x78, 0x69, 0x79,
0x4A, 0x5A, 0x4B, 0x5B, 0x6A, 0x7A, 0x6B, 0x7B,
0x0C, 0x1C, 0x0D, 0x1D, 0x2C, 0x3C, 0x2D, 0x3D,
0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
0x4C, 0x5C, 0x4D, 0x5D, 0x6C, 0x7C, 0x6D, 0x7D,
0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
0x88, 0x98, 0x89, 0x99, 0xA8, 0xB8, 0xA9, 0xB9,
0x8A, 0x9A, 0x8B, 0x9B, 0xAA, 0xBA, 0xAB, 0xBB,
0xC8, 0xD8, 0xC9, 0xD9, 0xE8, 0xF8, 0xE9, 0xF9,
0xCA, 0xDA, 0xCB, 0xDB, 0xEA, 0xFA, 0xEB, 0xFB,
0x8C, 0x9C, 0x8D, 0x9D, 0xAC, 0xBC, 0xAD, 0xBD,
0x8E, 0x9E, 0x8F, 0x9F, 0xAE, 0xBE, 0xAF, 0xBF,
0xCC, 0xDC, 0xCD, 0xDD, 0xEC, 0xFC, 0xED, 0xFD,
0xCE, 0xDE, 0xCF, 0xDF, 0xEE, 0xFE, 0xEF, 0xFF
);








var $invipmap = array(
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
);










var $sbox1 = array(
0x00808200, 0x00000000, 0x00008000, 0x00808202,
0x00808002, 0x00008202, 0x00000002, 0x00008000,
0x00000200, 0x00808200, 0x00808202, 0x00000200,
0x00800202, 0x00808002, 0x00800000, 0x00000002,
0x00000202, 0x00800200, 0x00800200, 0x00008200,
0x00008200, 0x00808000, 0x00808000, 0x00800202,
0x00008002, 0x00800002, 0x00800002, 0x00008002,
0x00000000, 0x00000202, 0x00008202, 0x00800000,
0x00008000, 0x00808202, 0x00000002, 0x00808000,
0x00808200, 0x00800000, 0x00800000, 0x00000200,
0x00808002, 0x00008000, 0x00008200, 0x00800002,
0x00000200, 0x00000002, 0x00800202, 0x00008202,
0x00808202, 0x00008002, 0x00808000, 0x00800202,
0x00800002, 0x00000202, 0x00008202, 0x00808200,
0x00000202, 0x00800200, 0x00800200, 0x00000000,
0x00008002, 0x00008200, 0x00000000, 0x00808002
);







var $sbox2 = array(
0x40084010, 0x40004000, 0x00004000, 0x00084010,
0x00080000, 0x00000010, 0x40080010, 0x40004010,
0x40000010, 0x40084010, 0x40084000, 0x40000000,
0x40004000, 0x00080000, 0x00000010, 0x40080010,
0x00084000, 0x00080010, 0x40004010, 0x00000000,
0x40000000, 0x00004000, 0x00084010, 0x40080000,
0x00080010, 0x40000010, 0x00000000, 0x00084000,
0x00004010, 0x40084000, 0x40080000, 0x00004010,
0x00000000, 0x00084010, 0x40080010, 0x00080000,
0x40004010, 0x40080000, 0x40084000, 0x00004000,
0x40080000, 0x40004000, 0x00000010, 0x40084010,
0x00084010, 0x00000010, 0x00004000, 0x40000000,
0x00004010, 0x40084000, 0x00080000, 0x40000010,
0x00080010, 0x40004010, 0x40000010, 0x00080010,
0x00084000, 0x00000000, 0x40004000, 0x00004010,
0x40000000, 0x40080010, 0x40084010, 0x00084000
);







var $sbox3 = array(
0x00000104, 0x04010100, 0x00000000, 0x04010004,
0x04000100, 0x00000000, 0x00010104, 0x04000100,
0x00010004, 0x04000004, 0x04000004, 0x00010000,
0x04010104, 0x00010004, 0x04010000, 0x00000104,
0x04000000, 0x00000004, 0x04010100, 0x00000100,
0x00010100, 0x04010000, 0x04010004, 0x00010104,
0x04000104, 0x00010100, 0x00010000, 0x04000104,
0x00000004, 0x04010104, 0x00000100, 0x04000000,
0x04010100, 0x04000000, 0x00010004, 0x00000104,
0x00010000, 0x04010100, 0x04000100, 0x00000000,
0x00000100, 0x00010004, 0x04010104, 0x04000100,
0x04000004, 0x00000100, 0x00000000, 0x04010004,
0x04000104, 0x00010000, 0x04000000, 0x04010104,
0x00000004, 0x00010104, 0x00010100, 0x04000004,
0x04010000, 0x04000104, 0x00000104, 0x04010000,
0x00010104, 0x00000004, 0x04010004, 0x00010100
);







var $sbox4 = array(
0x80401000, 0x80001040, 0x80001040, 0x00000040,
0x00401040, 0x80400040, 0x80400000, 0x80001000,
0x00000000, 0x00401000, 0x00401000, 0x80401040,
0x80000040, 0x00000000, 0x00400040, 0x80400000,
0x80000000, 0x00001000, 0x00400000, 0x80401000,
0x00000040, 0x00400000, 0x80001000, 0x00001040,
0x80400040, 0x80000000, 0x00001040, 0x00400040,
0x00001000, 0x00401040, 0x80401040, 0x80000040,
0x00400040, 0x80400000, 0x00401000, 0x80401040,
0x80000040, 0x00000000, 0x00000000, 0x00401000,
0x00001040, 0x00400040, 0x80400040, 0x80000000,
0x80401000, 0x80001040, 0x80001040, 0x00000040,
0x80401040, 0x80000040, 0x80000000, 0x00001000,
0x80400000, 0x80001000, 0x00401040, 0x80400040,
0x80001000, 0x00001040, 0x00400000, 0x80401000,
0x00000040, 0x00400000, 0x00001000, 0x00401040
);







var $sbox5 = array(
0x00000080, 0x01040080, 0x01040000, 0x21000080,
0x00040000, 0x00000080, 0x20000000, 0x01040000,
0x20040080, 0x00040000, 0x01000080, 0x20040080,
0x21000080, 0x21040000, 0x00040080, 0x20000000,
0x01000000, 0x20040000, 0x20040000, 0x00000000,
0x20000080, 0x21040080, 0x21040080, 0x01000080,
0x21040000, 0x20000080, 0x00000000, 0x21000000,
0x01040080, 0x01000000, 0x21000000, 0x00040080,
0x00040000, 0x21000080, 0x00000080, 0x01000000,
0x20000000, 0x01040000, 0x21000080, 0x20040080,
0x01000080, 0x20000000, 0x21040000, 0x01040080,
0x20040080, 0x00000080, 0x01000000, 0x21040000,
0x21040080, 0x00040080, 0x21000000, 0x21040080,
0x01040000, 0x00000000, 0x20040000, 0x21000000,
0x00040080, 0x01000080, 0x20000080, 0x00040000,
0x00000000, 0x20040000, 0x01040080, 0x20000080
);







var $sbox6 = array(
0x10000008, 0x10200000, 0x00002000, 0x10202008,
0x10200000, 0x00000008, 0x10202008, 0x00200000,
0x10002000, 0x00202008, 0x00200000, 0x10000008,
0x00200008, 0x10002000, 0x10000000, 0x00002008,
0x00000000, 0x00200008, 0x10002008, 0x00002000,
0x00202000, 0x10002008, 0x00000008, 0x10200008,
0x10200008, 0x00000000, 0x00202008, 0x10202000,
0x00002008, 0x00202000, 0x10202000, 0x10000000,
0x10002000, 0x00000008, 0x10200008, 0x00202000,
0x10202008, 0x00200000, 0x00002008, 0x10000008,
0x00200000, 0x10002000, 0x10000000, 0x00002008,
0x10000008, 0x10202008, 0x00202000, 0x10200000,
0x00202008, 0x10202000, 0x00000000, 0x10200008,
0x00000008, 0x00002000, 0x10200000, 0x00202008,
0x00002000, 0x00200008, 0x10002008, 0x00000000,
0x10202000, 0x10000000, 0x00200008, 0x10002008
);







var $sbox7 = array(
0x00100000, 0x02100001, 0x02000401, 0x00000000,
0x00000400, 0x02000401, 0x00100401, 0x02100400,
0x02100401, 0x00100000, 0x00000000, 0x02000001,
0x00000001, 0x02000000, 0x02100001, 0x00000401,
0x02000400, 0x00100401, 0x00100001, 0x02000400,
0x02000001, 0x02100000, 0x02100400, 0x00100001,
0x02100000, 0x00000400, 0x00000401, 0x02100401,
0x00100400, 0x00000001, 0x02000000, 0x00100400,
0x02000000, 0x00100400, 0x00100000, 0x02000401,
0x02000401, 0x02100001, 0x02100001, 0x00000001,
0x00100001, 0x02000000, 0x02000400, 0x00100000,
0x02100400, 0x00000401, 0x00100401, 0x02100400,
0x00000401, 0x02000001, 0x02100401, 0x02100000,
0x00100400, 0x00000000, 0x00000001, 0x02100401,
0x00000000, 0x00100401, 0x02100000, 0x00000400,
0x02000001, 0x02000400, 0x00000400, 0x00100001
);







var $sbox8 = array(
0x08000820, 0x00000800, 0x00020000, 0x08020820,
0x08000000, 0x08000820, 0x00000020, 0x08000000,
0x00020020, 0x08020000, 0x08020820, 0x00020800,
0x08020800, 0x00020820, 0x00000800, 0x00000020,
0x08020000, 0x08000020, 0x08000800, 0x00000820,
0x00020800, 0x00020020, 0x08020020, 0x08020800,
0x00000820, 0x00000000, 0x00000000, 0x08020020,
0x08000020, 0x08000800, 0x00020820, 0x00020000,
0x00020820, 0x00020000, 0x08020800, 0x00000800,
0x00000020, 0x08020020, 0x00000800, 0x00020820,
0x08000800, 0x00000020, 0x08000020, 0x08020000,
0x08020020, 0x08000000, 0x00020000, 0x08000820,
0x00000000, 0x08020820, 0x00020020, 0x08000020,
0x08020000, 0x08000800, 0x08000820, 0x00000000,
0x08020820, 0x00020800, 0x00020800, 0x00000820,
0x00000820, 0x00020020, 0x08000000, 0x08020800
);











function isValidEngine($engine)
{
if ($this->key_length_max == 8) {
if ($engine == self::ENGINE_OPENSSL) {
$this->cipher_name_openssl_ecb = 'des-ecb';
$this->cipher_name_openssl = 'des-' . $this->_openssl_translate_mode();
}
}

return parent::isValidEngine($engine);
}
















function setKey($key)
{

 
 if (strlen($key) > $this->key_length_max) {
$key = substr($key, 0, $this->key_length_max);
}


 parent::setKey($key);
}











function _encryptBlock($in)
{
return $this->_processBlock($in, self::ENCRYPT);
}











function _decryptBlock($in)
{
return $this->_processBlock($in, self::DECRYPT);
}















function _processBlock($block, $mode)
{
static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
if (!$sbox1) {
$sbox1 = array_map("intval", $this->sbox1);
$sbox2 = array_map("intval", $this->sbox2);
$sbox3 = array_map("intval", $this->sbox3);
$sbox4 = array_map("intval", $this->sbox4);
$sbox5 = array_map("intval", $this->sbox5);
$sbox6 = array_map("intval", $this->sbox6);
$sbox7 = array_map("intval", $this->sbox7);
$sbox8 = array_map("intval", $this->sbox8);

for ($i = 0; $i < 256; ++$i) {
$shuffleip[] = $this->shuffle[$this->ipmap[$i]];
$shuffleinvip[] = $this->shuffle[$this->invipmap[$i]];
}
}

$keys = $this->keys[$mode];
$ki = -1;


 $t = unpack('Nl/Nr', $block);
list($l, $r) = array($t['l'], $t['r']);
$block = ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");


 $t = unpack('Nl/Nr', $block);
list($l, $r) = array($t['l'], $t['r']);

for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {

 for ($i = 0; $i < 16; $i++) {

 
 
 $b1 = (($r >> 3) & 0x1FFFFFFF) ^ ($r << 29) ^ $keys[++$ki];
$b2 = (($r >> 31) & 0x00000001) ^ ($r << 1) ^ $keys[++$ki];


 $t = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
$sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
$sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
$sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $l;


$l = $r;
$r = $t;
}


 $t = $l;
$l = $r;
$r = $t;
}


 return ($shuffleinvip[($r >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
($shuffleinvip[($l >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
($shuffleinvip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
($shuffleinvip[($l >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
($shuffleinvip[($r >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
($shuffleinvip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
($shuffleinvip[ $r & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
($shuffleinvip[ $l & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
}







function _setupKey()
{
if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->des_rounds === $this->kl['des_rounds']) {

 return;
}
$this->kl = array('key' => $this->key, 'des_rounds' => $this->des_rounds);

static $shifts = array( 
 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
);

static $pc1map = array(
0x00, 0x00, 0x08, 0x08, 0x04, 0x04, 0x0C, 0x0C,
0x02, 0x02, 0x0A, 0x0A, 0x06, 0x06, 0x0E, 0x0E,
0x10, 0x10, 0x18, 0x18, 0x14, 0x14, 0x1C, 0x1C,
0x12, 0x12, 0x1A, 0x1A, 0x16, 0x16, 0x1E, 0x1E,
0x20, 0x20, 0x28, 0x28, 0x24, 0x24, 0x2C, 0x2C,
0x22, 0x22, 0x2A, 0x2A, 0x26, 0x26, 0x2E, 0x2E,
0x30, 0x30, 0x38, 0x38, 0x34, 0x34, 0x3C, 0x3C,
0x32, 0x32, 0x3A, 0x3A, 0x36, 0x36, 0x3E, 0x3E,
0x40, 0x40, 0x48, 0x48, 0x44, 0x44, 0x4C, 0x4C,
0x42, 0x42, 0x4A, 0x4A, 0x46, 0x46, 0x4E, 0x4E,
0x50, 0x50, 0x58, 0x58, 0x54, 0x54, 0x5C, 0x5C,
0x52, 0x52, 0x5A, 0x5A, 0x56, 0x56, 0x5E, 0x5E,
0x60, 0x60, 0x68, 0x68, 0x64, 0x64, 0x6C, 0x6C,
0x62, 0x62, 0x6A, 0x6A, 0x66, 0x66, 0x6E, 0x6E,
0x70, 0x70, 0x78, 0x78, 0x74, 0x74, 0x7C, 0x7C,
0x72, 0x72, 0x7A, 0x7A, 0x76, 0x76, 0x7E, 0x7E,
0x80, 0x80, 0x88, 0x88, 0x84, 0x84, 0x8C, 0x8C,
0x82, 0x82, 0x8A, 0x8A, 0x86, 0x86, 0x8E, 0x8E,
0x90, 0x90, 0x98, 0x98, 0x94, 0x94, 0x9C, 0x9C,
0x92, 0x92, 0x9A, 0x9A, 0x96, 0x96, 0x9E, 0x9E,
0xA0, 0xA0, 0xA8, 0xA8, 0xA4, 0xA4, 0xAC, 0xAC,
0xA2, 0xA2, 0xAA, 0xAA, 0xA6, 0xA6, 0xAE, 0xAE,
0xB0, 0xB0, 0xB8, 0xB8, 0xB4, 0xB4, 0xBC, 0xBC,
0xB2, 0xB2, 0xBA, 0xBA, 0xB6, 0xB6, 0xBE, 0xBE,
0xC0, 0xC0, 0xC8, 0xC8, 0xC4, 0xC4, 0xCC, 0xCC,
0xC2, 0xC2, 0xCA, 0xCA, 0xC6, 0xC6, 0xCE, 0xCE,
0xD0, 0xD0, 0xD8, 0xD8, 0xD4, 0xD4, 0xDC, 0xDC,
0xD2, 0xD2, 0xDA, 0xDA, 0xD6, 0xD6, 0xDE, 0xDE,
0xE0, 0xE0, 0xE8, 0xE8, 0xE4, 0xE4, 0xEC, 0xEC,
0xE2, 0xE2, 0xEA, 0xEA, 0xE6, 0xE6, 0xEE, 0xEE,
0xF0, 0xF0, 0xF8, 0xF8, 0xF4, 0xF4, 0xFC, 0xFC,
0xF2, 0xF2, 0xFA, 0xFA, 0xF6, 0xF6, 0xFE, 0xFE
);


 static $pc2mapc1 = array(
0x00000000, 0x00000400, 0x00200000, 0x00200400,
0x00000001, 0x00000401, 0x00200001, 0x00200401,
0x02000000, 0x02000400, 0x02200000, 0x02200400,
0x02000001, 0x02000401, 0x02200001, 0x02200401
);
static $pc2mapc2 = array(
0x00000000, 0x00000800, 0x08000000, 0x08000800,
0x00010000, 0x00010800, 0x08010000, 0x08010800,
0x00000000, 0x00000800, 0x08000000, 0x08000800,
0x00010000, 0x00010800, 0x08010000, 0x08010800,
0x00000100, 0x00000900, 0x08000100, 0x08000900,
0x00010100, 0x00010900, 0x08010100, 0x08010900,
0x00000100, 0x00000900, 0x08000100, 0x08000900,
0x00010100, 0x00010900, 0x08010100, 0x08010900,
0x00000010, 0x00000810, 0x08000010, 0x08000810,
0x00010010, 0x00010810, 0x08010010, 0x08010810,
0x00000010, 0x00000810, 0x08000010, 0x08000810,
0x00010010, 0x00010810, 0x08010010, 0x08010810,
0x00000110, 0x00000910, 0x08000110, 0x08000910,
0x00010110, 0x00010910, 0x08010110, 0x08010910,
0x00000110, 0x00000910, 0x08000110, 0x08000910,
0x00010110, 0x00010910, 0x08010110, 0x08010910,
0x00040000, 0x00040800, 0x08040000, 0x08040800,
0x00050000, 0x00050800, 0x08050000, 0x08050800,
0x00040000, 0x00040800, 0x08040000, 0x08040800,
0x00050000, 0x00050800, 0x08050000, 0x08050800,
0x00040100, 0x00040900, 0x08040100, 0x08040900,
0x00050100, 0x00050900, 0x08050100, 0x08050900,
0x00040100, 0x00040900, 0x08040100, 0x08040900,
0x00050100, 0x00050900, 0x08050100, 0x08050900,
0x00040010, 0x00040810, 0x08040010, 0x08040810,
0x00050010, 0x00050810, 0x08050010, 0x08050810,
0x00040010, 0x00040810, 0x08040010, 0x08040810,
0x00050010, 0x00050810, 0x08050010, 0x08050810,
0x00040110, 0x00040910, 0x08040110, 0x08040910,
0x00050110, 0x00050910, 0x08050110, 0x08050910,
0x00040110, 0x00040910, 0x08040110, 0x08040910,
0x00050110, 0x00050910, 0x08050110, 0x08050910,
0x01000000, 0x01000800, 0x09000000, 0x09000800,
0x01010000, 0x01010800, 0x09010000, 0x09010800,
0x01000000, 0x01000800, 0x09000000, 0x09000800,
0x01010000, 0x01010800, 0x09010000, 0x09010800,
0x01000100, 0x01000900, 0x09000100, 0x09000900,
0x01010100, 0x01010900, 0x09010100, 0x09010900,
0x01000100, 0x01000900, 0x09000100, 0x09000900,
0x01010100, 0x01010900, 0x09010100, 0x09010900,
0x01000010, 0x01000810, 0x09000010, 0x09000810,
0x01010010, 0x01010810, 0x09010010, 0x09010810,
0x01000010, 0x01000810, 0x09000010, 0x09000810,
0x01010010, 0x01010810, 0x09010010, 0x09010810,
0x01000110, 0x01000910, 0x09000110, 0x09000910,
0x01010110, 0x01010910, 0x09010110, 0x09010910,
0x01000110, 0x01000910, 0x09000110, 0x09000910,
0x01010110, 0x01010910, 0x09010110, 0x09010910,
0x01040000, 0x01040800, 0x09040000, 0x09040800,
0x01050000, 0x01050800, 0x09050000, 0x09050800,
0x01040000, 0x01040800, 0x09040000, 0x09040800,
0x01050000, 0x01050800, 0x09050000, 0x09050800,
0x01040100, 0x01040900, 0x09040100, 0x09040900,
0x01050100, 0x01050900, 0x09050100, 0x09050900,
0x01040100, 0x01040900, 0x09040100, 0x09040900,
0x01050100, 0x01050900, 0x09050100, 0x09050900,
0x01040010, 0x01040810, 0x09040010, 0x09040810,
0x01050010, 0x01050810, 0x09050010, 0x09050810,
0x01040010, 0x01040810, 0x09040010, 0x09040810,
0x01050010, 0x01050810, 0x09050010, 0x09050810,
0x01040110, 0x01040910, 0x09040110, 0x09040910,
0x01050110, 0x01050910, 0x09050110, 0x09050910,
0x01040110, 0x01040910, 0x09040110, 0x09040910,
0x01050110, 0x01050910, 0x09050110, 0x09050910
);
static $pc2mapc3 = array(
0x00000000, 0x00000004, 0x00001000, 0x00001004,
0x00000000, 0x00000004, 0x00001000, 0x00001004,
0x10000000, 0x10000004, 0x10001000, 0x10001004,
0x10000000, 0x10000004, 0x10001000, 0x10001004,
0x00000020, 0x00000024, 0x00001020, 0x00001024,
0x00000020, 0x00000024, 0x00001020, 0x00001024,
0x10000020, 0x10000024, 0x10001020, 0x10001024,
0x10000020, 0x10000024, 0x10001020, 0x10001024,
0x00080000, 0x00080004, 0x00081000, 0x00081004,
0x00080000, 0x00080004, 0x00081000, 0x00081004,
0x10080000, 0x10080004, 0x10081000, 0x10081004,
0x10080000, 0x10080004, 0x10081000, 0x10081004,
0x00080020, 0x00080024, 0x00081020, 0x00081024,
0x00080020, 0x00080024, 0x00081020, 0x00081024,
0x10080020, 0x10080024, 0x10081020, 0x10081024,
0x10080020, 0x10080024, 0x10081020, 0x10081024,
0x20000000, 0x20000004, 0x20001000, 0x20001004,
0x20000000, 0x20000004, 0x20001000, 0x20001004,
0x30000000, 0x30000004, 0x30001000, 0x30001004,
0x30000000, 0x30000004, 0x30001000, 0x30001004,
0x20000020, 0x20000024, 0x20001020, 0x20001024,
0x20000020, 0x20000024, 0x20001020, 0x20001024,
0x30000020, 0x30000024, 0x30001020, 0x30001024,
0x30000020, 0x30000024, 0x30001020, 0x30001024,
0x20080000, 0x20080004, 0x20081000, 0x20081004,
0x20080000, 0x20080004, 0x20081000, 0x20081004,
0x30080000, 0x30080004, 0x30081000, 0x30081004,
0x30080000, 0x30080004, 0x30081000, 0x30081004,
0x20080020, 0x20080024, 0x20081020, 0x20081024,
0x20080020, 0x20080024, 0x20081020, 0x20081024,
0x30080020, 0x30080024, 0x30081020, 0x30081024,
0x30080020, 0x30080024, 0x30081020, 0x30081024,
0x00000002, 0x00000006, 0x00001002, 0x00001006,
0x00000002, 0x00000006, 0x00001002, 0x00001006,
0x10000002, 0x10000006, 0x10001002, 0x10001006,
0x10000002, 0x10000006, 0x10001002, 0x10001006,
0x00000022, 0x00000026, 0x00001022, 0x00001026,
0x00000022, 0x00000026, 0x00001022, 0x00001026,
0x10000022, 0x10000026, 0x10001022, 0x10001026,
0x10000022, 0x10000026, 0x10001022, 0x10001026,
0x00080002, 0x00080006, 0x00081002, 0x00081006,
0x00080002, 0x00080006, 0x00081002, 0x00081006,
0x10080002, 0x10080006, 0x10081002, 0x10081006,
0x10080002, 0x10080006, 0x10081002, 0x10081006,
0x00080022, 0x00080026, 0x00081022, 0x00081026,
0x00080022, 0x00080026, 0x00081022, 0x00081026,
0x10080022, 0x10080026, 0x10081022, 0x10081026,
0x10080022, 0x10080026, 0x10081022, 0x10081026,
0x20000002, 0x20000006, 0x20001002, 0x20001006,
0x20000002, 0x20000006, 0x20001002, 0x20001006,
0x30000002, 0x30000006, 0x30001002, 0x30001006,
0x30000002, 0x30000006, 0x30001002, 0x30001006,
0x20000022, 0x20000026, 0x20001022, 0x20001026,
0x20000022, 0x20000026, 0x20001022, 0x20001026,
0x30000022, 0x30000026, 0x30001022, 0x30001026,
0x30000022, 0x30000026, 0x30001022, 0x30001026,
0x20080002, 0x20080006, 0x20081002, 0x20081006,
0x20080002, 0x20080006, 0x20081002, 0x20081006,
0x30080002, 0x30080006, 0x30081002, 0x30081006,
0x30080002, 0x30080006, 0x30081002, 0x30081006,
0x20080022, 0x20080026, 0x20081022, 0x20081026,
0x20080022, 0x20080026, 0x20081022, 0x20081026,
0x30080022, 0x30080026, 0x30081022, 0x30081026,
0x30080022, 0x30080026, 0x30081022, 0x30081026
);
static $pc2mapc4 = array(
0x00000000, 0x00100000, 0x00000008, 0x00100008,
0x00000200, 0x00100200, 0x00000208, 0x00100208,
0x00000000, 0x00100000, 0x00000008, 0x00100008,
0x00000200, 0x00100200, 0x00000208, 0x00100208,
0x04000000, 0x04100000, 0x04000008, 0x04100008,
0x04000200, 0x04100200, 0x04000208, 0x04100208,
0x04000000, 0x04100000, 0x04000008, 0x04100008,
0x04000200, 0x04100200, 0x04000208, 0x04100208,
0x00002000, 0x00102000, 0x00002008, 0x00102008,
0x00002200, 0x00102200, 0x00002208, 0x00102208,
0x00002000, 0x00102000, 0x00002008, 0x00102008,
0x00002200, 0x00102200, 0x00002208, 0x00102208,
0x04002000, 0x04102000, 0x04002008, 0x04102008,
0x04002200, 0x04102200, 0x04002208, 0x04102208,
0x04002000, 0x04102000, 0x04002008, 0x04102008,
0x04002200, 0x04102200, 0x04002208, 0x04102208,
0x00000000, 0x00100000, 0x00000008, 0x00100008,
0x00000200, 0x00100200, 0x00000208, 0x00100208,
0x00000000, 0x00100000, 0x00000008, 0x00100008,
0x00000200, 0x00100200, 0x00000208, 0x00100208,
0x04000000, 0x04100000, 0x04000008, 0x04100008,
0x04000200, 0x04100200, 0x04000208, 0x04100208,
0x04000000, 0x04100000, 0x04000008, 0x04100008,
0x04000200, 0x04100200, 0x04000208, 0x04100208,
0x00002000, 0x00102000, 0x00002008, 0x00102008,
0x00002200, 0x00102200, 0x00002208, 0x00102208,
0x00002000, 0x00102000, 0x00002008, 0x00102008,
0x00002200, 0x00102200, 0x00002208, 0x00102208,
0x04002000, 0x04102000, 0x04002008, 0x04102008,
0x04002200, 0x04102200, 0x04002208, 0x04102208,
0x04002000, 0x04102000, 0x04002008, 0x04102008,
0x04002200, 0x04102200, 0x04002208, 0x04102208,
0x00020000, 0x00120000, 0x00020008, 0x00120008,
0x00020200, 0x00120200, 0x00020208, 0x00120208,
0x00020000, 0x00120000, 0x00020008, 0x00120008,
0x00020200, 0x00120200, 0x00020208, 0x00120208,
0x04020000, 0x04120000, 0x04020008, 0x04120008,
0x04020200, 0x04120200, 0x04020208, 0x04120208,
0x04020000, 0x04120000, 0x04020008, 0x04120008,
0x04020200, 0x04120200, 0x04020208, 0x04120208,
0x00022000, 0x00122000, 0x00022008, 0x00122008,
0x00022200, 0x00122200, 0x00022208, 0x00122208,
0x00022000, 0x00122000, 0x00022008, 0x00122008,
0x00022200, 0x00122200, 0x00022208, 0x00122208,
0x04022000, 0x04122000, 0x04022008, 0x04122008,
0x04022200, 0x04122200, 0x04022208, 0x04122208,
0x04022000, 0x04122000, 0x04022008, 0x04122008,
0x04022200, 0x04122200, 0x04022208, 0x04122208,
0x00020000, 0x00120000, 0x00020008, 0x00120008,
0x00020200, 0x00120200, 0x00020208, 0x00120208,
0x00020000, 0x00120000, 0x00020008, 0x00120008,
0x00020200, 0x00120200, 0x00020208, 0x00120208,
0x04020000, 0x04120000, 0x04020008, 0x04120008,
0x04020200, 0x04120200, 0x04020208, 0x04120208,
0x04020000, 0x04120000, 0x04020008, 0x04120008,
0x04020200, 0x04120200, 0x04020208, 0x04120208,
0x00022000, 0x00122000, 0x00022008, 0x00122008,
0x00022200, 0x00122200, 0x00022208, 0x00122208,
0x00022000, 0x00122000, 0x00022008, 0x00122008,
0x00022200, 0x00122200, 0x00022208, 0x00122208,
0x04022000, 0x04122000, 0x04022008, 0x04122008,
0x04022200, 0x04122200, 0x04022208, 0x04122208,
0x04022000, 0x04122000, 0x04022008, 0x04122008,
0x04022200, 0x04122200, 0x04022208, 0x04122208
);
static $pc2mapd1 = array(
0x00000000, 0x00000001, 0x08000000, 0x08000001,
0x00200000, 0x00200001, 0x08200000, 0x08200001,
0x00000002, 0x00000003, 0x08000002, 0x08000003,
0x00200002, 0x00200003, 0x08200002, 0x08200003
);
static $pc2mapd2 = array(
0x00000000, 0x00100000, 0x00000800, 0x00100800,
0x00000000, 0x00100000, 0x00000800, 0x00100800,
0x04000000, 0x04100000, 0x04000800, 0x04100800,
0x04000000, 0x04100000, 0x04000800, 0x04100800,
0x00000004, 0x00100004, 0x00000804, 0x00100804,
0x00000004, 0x00100004, 0x00000804, 0x00100804,
0x04000004, 0x04100004, 0x04000804, 0x04100804,
0x04000004, 0x04100004, 0x04000804, 0x04100804,
0x00000000, 0x00100000, 0x00000800, 0x00100800,
0x00000000, 0x00100000, 0x00000800, 0x00100800,
0x04000000, 0x04100000, 0x04000800, 0x04100800,
0x04000000, 0x04100000, 0x04000800, 0x04100800,
0x00000004, 0x00100004, 0x00000804, 0x00100804,
0x00000004, 0x00100004, 0x00000804, 0x00100804,
0x04000004, 0x04100004, 0x04000804, 0x04100804,
0x04000004, 0x04100004, 0x04000804, 0x04100804,
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
0x00020000, 0x00120000, 0x00020800, 0x00120800,
0x00020000, 0x00120000, 0x00020800, 0x00120800,
0x04020000, 0x04120000, 0x04020800, 0x04120800,
0x04020000, 0x04120000, 0x04020800, 0x04120800,
0x00020004, 0x00120004, 0x00020804, 0x00120804,
0x00020004, 0x00120004, 0x00020804, 0x00120804,
0x04020004, 0x04120004, 0x04020804, 0x04120804,
0x04020004, 0x04120004, 0x04020804, 0x04120804,
0x00020000, 0x00120000, 0x00020800, 0x00120800,
0x00020000, 0x00120000, 0x00020800, 0x00120800,
0x04020000, 0x04120000, 0x04020800, 0x04120800,
0x04020000, 0x04120000, 0x04020800, 0x04120800,
0x00020004, 0x00120004, 0x00020804, 0x00120804,
0x00020004, 0x00120004, 0x00020804, 0x00120804,
0x04020004, 0x04120004, 0x04020804, 0x04120804,
0x04020004, 0x04120004, 0x04020804, 0x04120804,
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
0x04020204, 0x04120204, 0x04020A04, 0x04120A04
);
static $pc2mapd3 = array(
0x00000000, 0x00010000, 0x02000000, 0x02010000,
0x00000020, 0x00010020, 0x02000020, 0x02010020,
0x00040000, 0x00050000, 0x02040000, 0x02050000,
0x00040020, 0x00050020, 0x02040020, 0x02050020,
0x00002000, 0x00012000, 0x02002000, 0x02012000,
0x00002020, 0x00012020, 0x02002020, 0x02012020,
0x00042000, 0x00052000, 0x02042000, 0x02052000,
0x00042020, 0x00052020, 0x02042020, 0x02052020,
0x00000000, 0x00010000, 0x02000000, 0x02010000,
0x00000020, 0x00010020, 0x02000020, 0x02010020,
0x00040000, 0x00050000, 0x02040000, 0x02050000,
0x00040020, 0x00050020, 0x02040020, 0x02050020,
0x00002000, 0x00012000, 0x02002000, 0x02012000,
0x00002020, 0x00012020, 0x02002020, 0x02012020,
0x00042000, 0x00052000, 0x02042000, 0x02052000,
0x00042020, 0x00052020, 0x02042020, 0x02052020,
0x00000010, 0x00010010, 0x02000010, 0x02010010,
0x00000030, 0x00010030, 0x02000030, 0x02010030,
0x00040010, 0x00050010, 0x02040010, 0x02050010,
0x00040030, 0x00050030, 0x02040030, 0x02050030,
0x00002010, 0x00012010, 0x02002010, 0x02012010,
0x00002030, 0x00012030, 0x02002030, 0x02012030,
0x00042010, 0x00052010, 0x02042010, 0x02052010,
0x00042030, 0x00052030, 0x02042030, 0x02052030,
0x00000010, 0x00010010, 0x02000010, 0x02010010,
0x00000030, 0x00010030, 0x02000030, 0x02010030,
0x00040010, 0x00050010, 0x02040010, 0x02050010,
0x00040030, 0x00050030, 0x02040030, 0x02050030,
0x00002010, 0x00012010, 0x02002010, 0x02012010,
0x00002030, 0x00012030, 0x02002030, 0x02012030,
0x00042010, 0x00052010, 0x02042010, 0x02052010,
0x00042030, 0x00052030, 0x02042030, 0x02052030,
0x20000000, 0x20010000, 0x22000000, 0x22010000,
0x20000020, 0x20010020, 0x22000020, 0x22010020,
0x20040000, 0x20050000, 0x22040000, 0x22050000,
0x20040020, 0x20050020, 0x22040020, 0x22050020,
0x20002000, 0x20012000, 0x22002000, 0x22012000,
0x20002020, 0x20012020, 0x22002020, 0x22012020,
0x20042000, 0x20052000, 0x22042000, 0x22052000,
0x20042020, 0x20052020, 0x22042020, 0x22052020,
0x20000000, 0x20010000, 0x22000000, 0x22010000,
0x20000020, 0x20010020, 0x22000020, 0x22010020,
0x20040000, 0x20050000, 0x22040000, 0x22050000,
0x20040020, 0x20050020, 0x22040020, 0x22050020,
0x20002000, 0x20012000, 0x22002000, 0x22012000,
0x20002020, 0x20012020, 0x22002020, 0x22012020,
0x20042000, 0x20052000, 0x22042000, 0x22052000,
0x20042020, 0x20052020, 0x22042020, 0x22052020,
0x20000010, 0x20010010, 0x22000010, 0x22010010,
0x20000030, 0x20010030, 0x22000030, 0x22010030,
0x20040010, 0x20050010, 0x22040010, 0x22050010,
0x20040030, 0x20050030, 0x22040030, 0x22050030,
0x20002010, 0x20012010, 0x22002010, 0x22012010,
0x20002030, 0x20012030, 0x22002030, 0x22012030,
0x20042010, 0x20052010, 0x22042010, 0x22052010,
0x20042030, 0x20052030, 0x22042030, 0x22052030,
0x20000010, 0x20010010, 0x22000010, 0x22010010,
0x20000030, 0x20010030, 0x22000030, 0x22010030,
0x20040010, 0x20050010, 0x22040010, 0x22050010,
0x20040030, 0x20050030, 0x22040030, 0x22050030,
0x20002010, 0x20012010, 0x22002010, 0x22012010,
0x20002030, 0x20012030, 0x22002030, 0x22012030,
0x20042010, 0x20052010, 0x22042010, 0x22052010,
0x20042030, 0x20052030, 0x22042030, 0x22052030
);
static $pc2mapd4 = array(
0x00000000, 0x00000400, 0x01000000, 0x01000400,
0x00000000, 0x00000400, 0x01000000, 0x01000400,
0x00000100, 0x00000500, 0x01000100, 0x01000500,
0x00000100, 0x00000500, 0x01000100, 0x01000500,
0x10000000, 0x10000400, 0x11000000, 0x11000400,
0x10000000, 0x10000400, 0x11000000, 0x11000400,
0x10000100, 0x10000500, 0x11000100, 0x11000500,
0x10000100, 0x10000500, 0x11000100, 0x11000500,
0x00080000, 0x00080400, 0x01080000, 0x01080400,
0x00080000, 0x00080400, 0x01080000, 0x01080400,
0x00080100, 0x00080500, 0x01080100, 0x01080500,
0x00080100, 0x00080500, 0x01080100, 0x01080500,
0x10080000, 0x10080400, 0x11080000, 0x11080400,
0x10080000, 0x10080400, 0x11080000, 0x11080400,
0x10080100, 0x10080500, 0x11080100, 0x11080500,
0x10080100, 0x10080500, 0x11080100, 0x11080500,
0x00000008, 0x00000408, 0x01000008, 0x01000408,
0x00000008, 0x00000408, 0x01000008, 0x01000408,
0x00000108, 0x00000508, 0x01000108, 0x01000508,
0x00000108, 0x00000508, 0x01000108, 0x01000508,
0x10000008, 0x10000408, 0x11000008, 0x11000408,
0x10000008, 0x10000408, 0x11000008, 0x11000408,
0x10000108, 0x10000508, 0x11000108, 0x11000508,
0x10000108, 0x10000508, 0x11000108, 0x11000508,
0x00080008, 0x00080408, 0x01080008, 0x01080408,
0x00080008, 0x00080408, 0x01080008, 0x01080408,
0x00080108, 0x00080508, 0x01080108, 0x01080508,
0x00080108, 0x00080508, 0x01080108, 0x01080508,
0x10080008, 0x10080408, 0x11080008, 0x11080408,
0x10080008, 0x10080408, 0x11080008, 0x11080408,
0x10080108, 0x10080508, 0x11080108, 0x11080508,
0x10080108, 0x10080508, 0x11080108, 0x11080508,
0x00001000, 0x00001400, 0x01001000, 0x01001400,
0x00001000, 0x00001400, 0x01001000, 0x01001400,
0x00001100, 0x00001500, 0x01001100, 0x01001500,
0x00001100, 0x00001500, 0x01001100, 0x01001500,
0x10001000, 0x10001400, 0x11001000, 0x11001400,
0x10001000, 0x10001400, 0x11001000, 0x11001400,
0x10001100, 0x10001500, 0x11001100, 0x11001500,
0x10001100, 0x10001500, 0x11001100, 0x11001500,
0x00081000, 0x00081400, 0x01081000, 0x01081400,
0x00081000, 0x00081400, 0x01081000, 0x01081400,
0x00081100, 0x00081500, 0x01081100, 0x01081500,
0x00081100, 0x00081500, 0x01081100, 0x01081500,
0x10081000, 0x10081400, 0x11081000, 0x11081400,
0x10081000, 0x10081400, 0x11081000, 0x11081400,
0x10081100, 0x10081500, 0x11081100, 0x11081500,
0x10081100, 0x10081500, 0x11081100, 0x11081500,
0x00001008, 0x00001408, 0x01001008, 0x01001408,
0x00001008, 0x00001408, 0x01001008, 0x01001408,
0x00001108, 0x00001508, 0x01001108, 0x01001508,
0x00001108, 0x00001508, 0x01001108, 0x01001508,
0x10001008, 0x10001408, 0x11001008, 0x11001408,
0x10001008, 0x10001408, 0x11001008, 0x11001408,
0x10001108, 0x10001508, 0x11001108, 0x11001508,
0x10001108, 0x10001508, 0x11001108, 0x11001508,
0x00081008, 0x00081408, 0x01081008, 0x01081408,
0x00081008, 0x00081408, 0x01081008, 0x01081408,
0x00081108, 0x00081508, 0x01081108, 0x01081508,
0x00081108, 0x00081508, 0x01081108, 0x01081508,
0x10081008, 0x10081408, 0x11081008, 0x11081408,
0x10081008, 0x10081408, 0x11081008, 0x11081408,
0x10081108, 0x10081508, 0x11081108, 0x11081508,
0x10081108, 0x10081508, 0x11081108, 0x11081508
);

$keys = array();
for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {

 $key = str_pad(substr($this->key, $des_round * 8, 8), 8, "\0");


 $t = unpack('Nl/Nr', $key);
list($l, $r) = array($t['l'], $t['r']);
$key = ($this->shuffle[$pc1map[ $r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x00") |
($this->shuffle[$pc1map[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x00") |
($this->shuffle[$pc1map[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x00") |
($this->shuffle[$pc1map[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x00") |
($this->shuffle[$pc1map[ $l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x00") |
($this->shuffle[$pc1map[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x00") |
($this->shuffle[$pc1map[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x00") |
($this->shuffle[$pc1map[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x00");
$key = unpack('Nc/Nd', $key);
$c = ( $key['c'] >> 4) & 0x0FFFFFFF;
$d = (($key['d'] >> 4) & 0x0FFFFFF0) | ($key['c'] & 0x0F);

$keys[$des_round] = array(
self::ENCRYPT => array(),
self::DECRYPT => array_fill(0, 32, 0)
);
for ($i = 0, $ki = 31; $i < 16; ++$i, $ki-= 2) {
$c <<= $shifts[$i];
$c = ($c | ($c >> 28)) & 0x0FFFFFFF;
$d <<= $shifts[$i];
$d = ($d | ($d >> 28)) & 0x0FFFFFFF;


 $cp = $pc2mapc1[ $c >> 24 ] | $pc2mapc2[($c >> 16) & 0xFF] |
$pc2mapc3[($c >> 8) & 0xFF] | $pc2mapc4[ $c & 0xFF];
$dp = $pc2mapd1[ $d >> 24 ] | $pc2mapd2[($d >> 16) & 0xFF] |
$pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[ $d & 0xFF];


 $val1 = ( $cp & 0xFF000000) | (($cp << 8) & 0x00FF0000) |
(($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF);
$val2 = (($cp << 8) & 0xFF000000) | (($cp << 16) & 0x00FF0000) |
(($dp >> 8) & 0x0000FF00) | ( $dp & 0x000000FF);
$keys[$des_round][self::ENCRYPT][ ] = $val1;
$keys[$des_round][self::DECRYPT][$ki - 1] = $val1;
$keys[$des_round][self::ENCRYPT][ ] = $val2;
$keys[$des_round][self::DECRYPT][$ki ] = $val2;
}
}

switch ($this->des_rounds) {
case 3: 
 $this->keys = array(
self::ENCRYPT => array_merge(
$keys[0][self::ENCRYPT],
$keys[1][self::DECRYPT],
$keys[2][self::ENCRYPT]
),
self::DECRYPT => array_merge(
$keys[2][self::DECRYPT],
$keys[1][self::ENCRYPT],
$keys[0][self::DECRYPT]
)
);
break;

 default:
$this->keys = array(
self::ENCRYPT => $keys[0][self::ENCRYPT],
self::DECRYPT => $keys[0][self::DECRYPT]
);
}
}







function _setupInlineCrypt()
{
$lambda_functions =& self::_getLambdaFunctions();


 
 
 $des_rounds = $this->des_rounds;


 
 
 
 $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 );


 $code_hash = "Crypt_DES, $des_rounds, {$this->mode}";
if ($gen_hi_opt_code) {

 
 
 
 
 $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}


 if (!isset($lambda_functions[$code_hash])) {

 $init_crypt = 'static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
                if (!$sbox1) {
                    $sbox1 = array_map("intval", $self->sbox1);
                    $sbox2 = array_map("intval", $self->sbox2);
                    $sbox3 = array_map("intval", $self->sbox3);
                    $sbox4 = array_map("intval", $self->sbox4);
                    $sbox5 = array_map("intval", $self->sbox5);
                    $sbox6 = array_map("intval", $self->sbox6);
                    $sbox7 = array_map("intval", $self->sbox7);
                    $sbox8 = array_map("intval", $self->sbox8);'
 . '
                    for ($i = 0; $i < 256; ++$i) {
                        $shuffleip[]    =  $self->shuffle[$self->ipmap[$i]];
                        $shuffleinvip[] =  $self->shuffle[$self->invipmap[$i]];
                    }
                }
            ';

switch (true) {
case $gen_hi_opt_code:

 
 
 $k = array(
self::ENCRYPT => $this->keys[self::ENCRYPT],
self::DECRYPT => $this->keys[self::DECRYPT]
);
$init_encrypt = '';
$init_decrypt = '';
break;
default:

 
 $k = array(
self::ENCRYPT => array(),
self::DECRYPT => array()
);
for ($i = 0, $c = count($this->keys[self::ENCRYPT]); $i < $c; ++$i) {
$k[self::ENCRYPT][$i] = '$ke[' . $i . ']';
$k[self::DECRYPT][$i] = '$kd[' . $i . ']';
}
$init_encrypt = '$ke = $self->keys[$self::ENCRYPT];';
$init_decrypt = '$kd = $self->keys[$self::DECRYPT];';
break;
}


 $crypt_block = array();
foreach (array(self::ENCRYPT, self::DECRYPT) as $c) {

$crypt_block[$c] = '
                    $in = unpack("N*", $in);
                    $l  = $in[1];
                    $r  = $in[2];
                    $in = unpack("N*",
                        ($shuffleip[ $r        & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
                        ($shuffleip[($r >>  8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
                        ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
                        ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
                        ($shuffleip[ $l        & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
                        ($shuffleip[($l >>  8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
                        ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
                        ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01")
                    );
                    ' .  '
                    $l = $in[1];
                    $r = $in[2];
                ';

$l = '$l';
$r = '$r';


 for ($ki = -1, $des_round = 0; $des_round < $des_rounds; ++$des_round) {

 for ($i = 0; $i < 16; ++$i) {

 
 
 $crypt_block[$c].= '
                            $b1 = ((' . $r . ' >>  3) & 0x1FFFFFFF)  ^ (' . $r . ' << 29) ^ ' . $k[$c][++$ki] . ';
                            $b2 = ((' . $r . ' >> 31) & 0x00000001)  ^ (' . $r . ' <<  1) ^ ' . $k[$c][++$ki] . ';' .

$l . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
                                     $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
                                     $sbox5[($b1 >>  8) & 0x3F] ^ $sbox6[($b2 >>  8) & 0x3F] ^
                                     $sbox7[ $b1        & 0x3F] ^ $sbox8[ $b2        & 0x3F] ^ ' . $l . ';
                        ';



 list($l, $r) = array($r, $l);
}
list($l, $r) = array($r, $l);
}


 $crypt_block[$c].= '$in =
                    ($shuffleinvip[($l >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
                    ($shuffleinvip[($r >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
                    ($shuffleinvip[($l >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
                    ($shuffleinvip[($r >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
                    ($shuffleinvip[($l >>  8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
                    ($shuffleinvip[($r >>  8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
                    ($shuffleinvip[ $l        & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
                    ($shuffleinvip[ $r        & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
                ';
}


 $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
array(
'init_crypt' => $init_crypt,
'init_encrypt' => $init_encrypt,
'init_decrypt' => $init_decrypt,
'encrypt_block' => $crypt_block[self::ENCRYPT],
'decrypt_block' => $crypt_block[self::DECRYPT]
)
);
}


 $this->inline_crypt = $lambda_functions[$code_hash];
}
}
<?php


















































namespace phpseclib\Crypt;

use phpseclib\Math\BigInteger;








class RSA
{














const ENCRYPTION_OAEP = 1;






const ENCRYPTION_PKCS1 = 2;






const ENCRYPTION_NONE = 3;
















const SIGNATURE_PSS = 1;






const SIGNATURE_PKCS1 = 2;









const ASN1_INTEGER = 2;



const ASN1_BITSTRING = 3;



const ASN1_OCTETSTRING = 4;



const ASN1_OBJECT = 6;



const ASN1_SEQUENCE = 48;









const MODE_INTERNAL = 1;





const MODE_OPENSSL = 2;












const PRIVATE_FORMAT_PKCS1 = 0;



const PRIVATE_FORMAT_PUTTY = 1;



const PRIVATE_FORMAT_XML = 2;



const PRIVATE_FORMAT_PKCS8 = 8;



const PRIVATE_FORMAT_OPENSSH = 9;




















const PUBLIC_FORMAT_RAW = 3;











const PUBLIC_FORMAT_PKCS1 = 4;
const PUBLIC_FORMAT_PKCS1_RAW = 4;



const PUBLIC_FORMAT_XML = 5;





const PUBLIC_FORMAT_OPENSSH = 6;













const PUBLIC_FORMAT_PKCS8 = 7;








var $zero;







var $one;







var $privateKeyFormat = self::PRIVATE_FORMAT_PKCS1;







var $publicKeyFormat = self::PUBLIC_FORMAT_PKCS8;







var $modulus;







var $k;







var $exponent;







var $primes;







var $exponents;







var $coefficients;







var $hashName;







var $hash;







var $hLen;







var $sLen;







var $mgfHash;







var $mgfHLen;







var $encryptionMode = self::ENCRYPTION_OAEP;







var $signatureMode = self::SIGNATURE_PSS;







var $publicExponent = false;







var $password = false;











var $components = array();











var $current;









var $configFile;







var $comment = 'phpseclib-generated-key';











function __construct()
{
$this->configFile = dirname(__FILE__) . '/../openssl.cnf';

if (!defined('CRYPT_RSA_MODE')) {
switch (true) {

 
 
 case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'):
define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
break;
case extension_loaded('openssl') && file_exists($this->configFile):

 $versions = array();


 if (strpos(ini_get('disable_functions'), 'phpinfo') === false) {
ob_start();
@phpinfo();
$content = ob_get_contents();
ob_end_clean();

preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);

if (!empty($matches[1])) {
for ($i = 0; $i < count($matches[1]); $i++) {
$fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));


 if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
$versions[$matches[1][$i]] = $fullVersion;
} else {
$versions[$matches[1][$i]] = $m[0];
}
}
}
}


 switch (true) {
case !isset($versions['Header']):
case !isset($versions['Library']):
case $versions['Header'] == $versions['Library']:
case version_compare($versions['Header'], '1.0.0') >= 0 && version_compare($versions['Library'], '1.0.0') >= 0:
define('CRYPT_RSA_MODE', self::MODE_OPENSSL);
break;
default:
define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
}
break;
default:
define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
}
}

$this->zero = new BigInteger();
$this->one = new BigInteger(1);

$this->hash = new Hash('sha1');
$this->hLen = $this->hash->getLength();
$this->hashName = 'sha1';
$this->mgfHash = new Hash('sha1');
$this->mgfHLen = $this->mgfHash->getLength();
}















function createKey($bits = 1024, $timeout = false, $partial = array())
{
if (!defined('CRYPT_RSA_EXPONENT')) {

 define('CRYPT_RSA_EXPONENT', '65537');
}

 
 
 
 
 
 if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
define('CRYPT_RSA_SMALLEST_PRIME', 4096);
}


 if (CRYPT_RSA_MODE == self::MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
$config = array();
if (isset($this->configFile)) {
$config['config'] = $this->configFile;
}
$rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config);
openssl_pkey_export($rsa, $privatekey, null, $config);
$publickey = openssl_pkey_get_details($rsa);
$publickey = $publickey['key'];

$privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, self::PRIVATE_FORMAT_PKCS1)));
$publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, self::PUBLIC_FORMAT_PKCS1)));


 while (openssl_error_string() !== false) {
}

return array(
'privatekey' => $privatekey,
'publickey' => $publickey,
'partialkey' => false
);
}

static $e;
if (!isset($e)) {
$e = new BigInteger(CRYPT_RSA_EXPONENT);
}

extract($this->_generateMinMax($bits));
$absoluteMin = $min;
$temp = $bits >> 1; 
 if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
$num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
$temp = CRYPT_RSA_SMALLEST_PRIME;
} else {
$num_primes = 2;
}
extract($this->_generateMinMax($temp + $bits % $temp));
$finalMax = $max;
extract($this->_generateMinMax($temp));

$generator = new BigInteger();

$n = $this->one->copy();
if (!empty($partial)) {
extract(unserialize($partial));
} else {
$exponents = $coefficients = $primes = array();
$lcm = array(
'top' => $this->one->copy(),
'bottom' => false
);
}

$start = time();
$i0 = count($primes) + 1;

do {
for ($i = $i0; $i <= $num_primes; $i++) {
if ($timeout !== false) {
$timeout-= time() - $start;
$start = time();
if ($timeout <= 0) {
return array(
'privatekey' => '',
'publickey' => '',
'partialkey' => serialize(array(
'primes' => $primes,
'coefficients' => $coefficients,
'lcm' => $lcm,
'exponents' => $exponents
))
);
}
}

if ($i == $num_primes) {
list($min, $temp) = $absoluteMin->divide($n);
if (!$temp->equals($this->zero)) {
$min = $min->add($this->one); 
 }
$primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
} else {
$primes[$i] = $generator->randomPrime($min, $max, $timeout);
}

if ($primes[$i] === false) { 
 if (count($primes) > 1) {
$partialkey = '';
} else {
array_pop($primes);
$partialkey = serialize(array(
'primes' => $primes,
'coefficients' => $coefficients,
'lcm' => $lcm,
'exponents' => $exponents
));
}

return array(
'privatekey' => '',
'publickey' => '',
'partialkey' => $partialkey
);
}


 
 if ($i > 2) {
$coefficients[$i] = $n->modInverse($primes[$i]);
}

$n = $n->multiply($primes[$i]);

$temp = $primes[$i]->subtract($this->one);


 
 $lcm['top'] = $lcm['top']->multiply($temp);
$lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);

$exponents[$i] = $e->modInverse($temp);
}

list($temp) = $lcm['top']->divide($lcm['bottom']);
$gcd = $temp->gcd($e);
$i0 = 1;
} while (!$gcd->equals($this->one));

$d = $e->modInverse($temp);

$coefficients[2] = $primes[2]->modInverse($primes[1]);


 
 
 
 
 
 
 
 
 
 
 
 

return array(
'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
'publickey' => $this->_convertPublicKey($n, $e),
'partialkey' => false
);
}














function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
{
$signed = $this->privateKeyFormat != self::PRIVATE_FORMAT_XML;
$num_primes = count($primes);
$raw = array(
'version' => $num_primes == 2 ? chr(0) : chr(1), 
 'modulus' => $n->toBytes($signed),
'publicExponent' => $e->toBytes($signed),
'privateExponent' => $d->toBytes($signed),
'prime1' => $primes[1]->toBytes($signed),
'prime2' => $primes[2]->toBytes($signed),
'exponent1' => $exponents[1]->toBytes($signed),
'exponent2' => $exponents[2]->toBytes($signed),
'coefficient' => $coefficients[2]->toBytes($signed)
);


 
 switch ($this->privateKeyFormat) {
case self::PRIVATE_FORMAT_XML:
if ($num_primes != 2) {
return false;
}
return "<RSAKeyValue>\r\n" .
'  <Modulus>' . base64_encode($raw['modulus']) . "</Modulus>\r\n" .
'  <Exponent>' . base64_encode($raw['publicExponent']) . "</Exponent>\r\n" .
'  <P>' . base64_encode($raw['prime1']) . "</P>\r\n" .
'  <Q>' . base64_encode($raw['prime2']) . "</Q>\r\n" .
'  <DP>' . base64_encode($raw['exponent1']) . "</DP>\r\n" .
'  <DQ>' . base64_encode($raw['exponent2']) . "</DQ>\r\n" .
'  <InverseQ>' . base64_encode($raw['coefficient']) . "</InverseQ>\r\n" .
'  <D>' . base64_encode($raw['privateExponent']) . "</D>\r\n" .
'</RSAKeyValue>';
break;
case self::PRIVATE_FORMAT_PUTTY:
if ($num_primes != 2) {
return false;
}
$key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
$encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
$key.= $encryption;
$key.= "\r\nComment: " . $this->comment . "\r\n";
$public = pack(
'Na*Na*Na*',
strlen('ssh-rsa'),
'ssh-rsa',
strlen($raw['publicExponent']),
$raw['publicExponent'],
strlen($raw['modulus']),
$raw['modulus']
);
$source = pack(
'Na*Na*Na*Na*',
strlen('ssh-rsa'),
'ssh-rsa',
strlen($encryption),
$encryption,
strlen($this->comment),
$this->comment,
strlen($public),
$public
);
$public = base64_encode($public);
$key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";
$key.= chunk_split($public, 64);
$private = pack(
'Na*Na*Na*Na*',
strlen($raw['privateExponent']),
$raw['privateExponent'],
strlen($raw['prime1']),
$raw['prime1'],
strlen($raw['prime2']),
$raw['prime2'],
strlen($raw['coefficient']),
$raw['coefficient']
);
if (empty($this->password) && !is_string($this->password)) {
$source.= pack('Na*', strlen($private), $private);
$hashkey = 'putty-private-key-file-mac-key';
} else {
$private.= Random::string(16 - (strlen($private) & 15));
$source.= pack('Na*', strlen($private), $private);
$sequence = 0;
$symkey = '';
while (strlen($symkey) < 32) {
$temp = pack('Na*', $sequence++, $this->password);
$symkey.= pack('H*', sha1($temp));
}
$symkey = substr($symkey, 0, 32);
$crypto = new AES();

$crypto->setKey($symkey);
$crypto->disablePadding();
$private = $crypto->encrypt($private);
$hashkey = 'putty-private-key-file-mac-key' . $this->password;
}

$private = base64_encode($private);
$key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n";
$key.= chunk_split($private, 64);
$hash = new Hash('sha1');
$hash->setKey(pack('H*', sha1($hashkey)));
$key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";

return $key;
case self::PRIVATE_FORMAT_OPENSSH:
if ($num_primes != 2) {
return false;
}
$publicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus']);
$privateKey = pack(
'Na*Na*Na*Na*Na*Na*Na*',
strlen('ssh-rsa'),
'ssh-rsa',
strlen($raw['modulus']),
$raw['modulus'],
strlen($raw['publicExponent']),
$raw['publicExponent'],
strlen($raw['privateExponent']),
$raw['privateExponent'],
strlen($raw['coefficient']),
$raw['coefficient'],
strlen($raw['prime1']),
$raw['prime1'],
strlen($raw['prime2']),
$raw['prime2']
);
$checkint = Random::string(4);
$paddedKey = pack(
'a*Na*',
$checkint . $checkint . $privateKey,
strlen($this->comment),
$this->comment
);
$paddingLength = (7 * strlen($paddedKey)) % 8;
for ($i = 1; $i <= $paddingLength; $i++) {
$paddedKey.= chr($i);
}
$key = pack(
'Na*Na*Na*NNa*Na*',
strlen('none'),
'none',
strlen('none'),
'none',
0,
'',
1,
strlen($publicKey),
$publicKey,
strlen($paddedKey),
$paddedKey
);
$key = "openssh-key-v1\0$key";

return "-----BEGIN OPENSSH PRIVATE KEY-----\n" .
chunk_split(base64_encode($key), 70, "\n") .
"-----END OPENSSH PRIVATE KEY-----\n";
default: 
 $components = array();
foreach ($raw as $name => $value) {
$components[$name] = pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
}

$RSAPrivateKey = implode('', $components);

if ($num_primes > 2) {
$OtherPrimeInfos = '';
for ($i = 3; $i <= $num_primes; $i++) {

 
 
 
 
 
 
 $OtherPrimeInfo = pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
$OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
}
$RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
}

$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);

if ($this->privateKeyFormat == self::PRIVATE_FORMAT_PKCS8) {
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); 
 $RSAPrivateKey = pack(
'Ca*a*Ca*a*',
self::ASN1_INTEGER,
"\01\00",
$rsaOID,
4,
$this->_encodeLength(strlen($RSAPrivateKey)),
$RSAPrivateKey
);
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
if (!empty($this->password) || is_string($this->password)) {
$salt = Random::string(8);
$iterationCount = 2048;

$crypto = new DES();
$crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
$RSAPrivateKey = $crypto->encrypt($RSAPrivateKey);

$parameters = pack(
'Ca*a*Ca*N',
self::ASN1_OCTETSTRING,
$this->_encodeLength(strlen($salt)),
$salt,
self::ASN1_INTEGER,
$this->_encodeLength(4),
$iterationCount
);
$pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03";

$encryptionAlgorithm = pack(
'Ca*a*Ca*a*',
self::ASN1_OBJECT,
$this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)),
$pbeWithMD5AndDES_CBC,
self::ASN1_SEQUENCE,
$this->_encodeLength(strlen($parameters)),
$parameters
);

$RSAPrivateKey = pack(
'Ca*a*Ca*a*',
self::ASN1_SEQUENCE,
$this->_encodeLength(strlen($encryptionAlgorithm)),
$encryptionAlgorithm,
self::ASN1_OCTETSTRING,
$this->_encodeLength(strlen($RSAPrivateKey)),
$RSAPrivateKey
);

$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);

$RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" .
chunk_split(base64_encode($RSAPrivateKey), 64) .
'-----END ENCRYPTED PRIVATE KEY-----';
} else {
$RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" .
chunk_split(base64_encode($RSAPrivateKey), 64) .
'-----END PRIVATE KEY-----';
}
return $RSAPrivateKey;
}

if (!empty($this->password) || is_string($this->password)) {
$iv = Random::string(8);
$symkey = pack('H*', md5($this->password . $iv)); 
 $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
$des = new TripleDES();
$des->setKey($symkey);
$des->setIV($iv);
$iv = strtoupper(bin2hex($iv));
$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
"Proc-Type: 4,ENCRYPTED\r\n" .
"DEK-Info: DES-EDE3-CBC,$iv\r\n" .
"\r\n" .
chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) .
'-----END RSA PRIVATE KEY-----';
} else {
$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
chunk_split(base64_encode($RSAPrivateKey), 64) .
'-----END RSA PRIVATE KEY-----';
}

return $RSAPrivateKey;
}
}










function _convertPublicKey($n, $e)
{
$signed = $this->publicKeyFormat != self::PUBLIC_FORMAT_XML;

$modulus = $n->toBytes($signed);
$publicExponent = $e->toBytes($signed);

switch ($this->publicKeyFormat) {
case self::PUBLIC_FORMAT_RAW:
return array('e' => $e->copy(), 'n' => $n->copy());
case self::PUBLIC_FORMAT_XML:
return "<RSAKeyValue>\r\n" .
'  <Modulus>' . base64_encode($modulus) . "</Modulus>\r\n" .
'  <Exponent>' . base64_encode($publicExponent) . "</Exponent>\r\n" .
'</RSAKeyValue>';
break;
case self::PUBLIC_FORMAT_OPENSSH:

 
 
 
 $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
$RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $this->comment;

return $RSAPublicKey;
default: 
 
 
 
 
 
 $components = array(
'modulus' => pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
);

$RSAPublicKey = pack(
'Ca*a*a*',
self::ASN1_SEQUENCE,
$this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
$components['modulus'],
$components['publicExponent']
);

if ($this->publicKeyFormat == self::PUBLIC_FORMAT_PKCS1_RAW) {
$RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" .
chunk_split(base64_encode($RSAPublicKey), 64) .
'-----END RSA PUBLIC KEY-----';
} else {

 $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); 
 $RSAPublicKey = chr(0) . $RSAPublicKey;
$RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;

$RSAPublicKey = pack(
'Ca*a*',
self::ASN1_SEQUENCE,
$this->_encodeLength(strlen($rsaOID . $RSAPublicKey)),
$rsaOID . $RSAPublicKey
);

$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
chunk_split(base64_encode($RSAPublicKey), 64) .
'-----END PUBLIC KEY-----';
}

return $RSAPublicKey;
}
}











function _parseKey($key, $type)
{
if ($type != self::PUBLIC_FORMAT_RAW && !is_string($key)) {
return false;
}

switch ($type) {
case self::PUBLIC_FORMAT_RAW:
if (!is_array($key)) {
return false;
}
$components = array();
switch (true) {
case isset($key['e']):
$components['publicExponent'] = $key['e']->copy();
break;
case isset($key['exponent']):
$components['publicExponent'] = $key['exponent']->copy();
break;
case isset($key['publicExponent']):
$components['publicExponent'] = $key['publicExponent']->copy();
break;
case isset($key[0]):
$components['publicExponent'] = $key[0]->copy();
}
switch (true) {
case isset($key['n']):
$components['modulus'] = $key['n']->copy();
break;
case isset($key['modulo']):
$components['modulus'] = $key['modulo']->copy();
break;
case isset($key['modulus']):
$components['modulus'] = $key['modulus']->copy();
break;
case isset($key[1]):
$components['modulus'] = $key[1]->copy();
}
return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
case self::PRIVATE_FORMAT_PKCS1:
case self::PRIVATE_FORMAT_PKCS8:
case self::PUBLIC_FORMAT_PKCS1:















if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
$iv = pack('H*', trim($matches[2]));
$symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); 
 $symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8)));

 $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
$ciphertext = $this->_extractBER($key);
if ($ciphertext === false) {
$ciphertext = $key;
}
switch ($matches[1]) {
case 'AES-256-CBC':
$crypto = new AES();
break;
case 'AES-128-CBC':
$symkey = substr($symkey, 0, 16);
$crypto = new AES();
break;
case 'DES-EDE3-CFB':
$crypto = new TripleDES(Base::MODE_CFB);
break;
case 'DES-EDE3-CBC':
$symkey = substr($symkey, 0, 24);
$crypto = new TripleDES();
break;
case 'DES-CBC':
$crypto = new DES();
break;
default:
return false;
}
$crypto->setKey($symkey);
$crypto->setIV($iv);
$decoded = $crypto->decrypt($ciphertext);
} else {
$decoded = $this->_extractBER($key);
}

if ($decoded !== false) {
$key = $decoded;
}

$components = array();

if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
return false;
}
if ($this->_decodeLength($key) != strlen($key)) {
return false;
}

$tag = ord($this->_string_shift($key));











if ($tag == self::ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
$this->_string_shift($key, 3);
$tag = self::ASN1_SEQUENCE;
}

if ($tag == self::ASN1_SEQUENCE) {
$temp = $this->_string_shift($key, $this->_decodeLength($key));
if (ord($this->_string_shift($temp)) != self::ASN1_OBJECT) {
return false;
}
$length = $this->_decodeLength($temp);
switch ($this->_string_shift($temp, $length)) {
case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": 
 case "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0A": 
 break;
case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": 
 




if (ord($this->_string_shift($temp)) != self::ASN1_SEQUENCE) {
return false;
}
if ($this->_decodeLength($temp) != strlen($temp)) {
return false;
}
$this->_string_shift($temp); 
 $salt = $this->_string_shift($temp, $this->_decodeLength($temp));
if (ord($this->_string_shift($temp)) != self::ASN1_INTEGER) {
return false;
}
$this->_decodeLength($temp);
list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
$this->_string_shift($key); 
 $length = $this->_decodeLength($key);
if (strlen($key) != $length) {
return false;
}

$crypto = new DES();
$crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
$key = $crypto->decrypt($key);
if ($key === false) {
return false;
}
return $this->_parseKey($key, self::PRIVATE_FORMAT_PKCS1);
default:
return false;
}







$tag = ord($this->_string_shift($key)); 
 $this->_decodeLength($key); 
 
 
 
 if ($tag == self::ASN1_BITSTRING) {
$this->_string_shift($key);
}
if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
return false;
}
if ($this->_decodeLength($key) != strlen($key)) {
return false;
}
$tag = ord($this->_string_shift($key));
}
if ($tag != self::ASN1_INTEGER) {
return false;
}

$length = $this->_decodeLength($key);
$temp = $this->_string_shift($key, $length);
if (strlen($temp) != 1 || ord($temp) > 2) {
$components['modulus'] = new BigInteger($temp, 256);
$this->_string_shift($key); 
 $length = $this->_decodeLength($key);
$components[$type == self::PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new BigInteger($this->_string_shift($key, $length), 256);

return $components;
}
if (ord($this->_string_shift($key)) != self::ASN1_INTEGER) {
return false;
}
$length = $this->_decodeLength($key);
$components['modulus'] = new BigInteger($this->_string_shift($key, $length), 256);
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['publicExponent'] = new BigInteger($this->_string_shift($key, $length), 256);
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['privateExponent'] = new BigInteger($this->_string_shift($key, $length), 256);
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['primes'] = array(1 => new BigInteger($this->_string_shift($key, $length), 256));
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['primes'][] = new BigInteger($this->_string_shift($key, $length), 256);
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['exponents'] = array(1 => new BigInteger($this->_string_shift($key, $length), 256));
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['exponents'][] = new BigInteger($this->_string_shift($key, $length), 256);
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['coefficients'] = array(2 => new BigInteger($this->_string_shift($key, $length), 256));

if (!empty($key)) {
if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
return false;
}
$this->_decodeLength($key);
while (!empty($key)) {
if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
return false;
}
$this->_decodeLength($key);
$key = substr($key, 1);
$length = $this->_decodeLength($key);
$components['primes'][] = new BigInteger($this->_string_shift($key, $length), 256);
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['exponents'][] = new BigInteger($this->_string_shift($key, $length), 256);
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['coefficients'][] = new BigInteger($this->_string_shift($key, $length), 256);
}
}

return $components;
case self::PUBLIC_FORMAT_OPENSSH:
$parts = explode(' ', $key, 3);

$key = isset($parts[1]) ? base64_decode($parts[1]) : false;
if ($key === false) {
return false;
}

$comment = isset($parts[2]) ? $parts[2] : false;

$cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";

if (strlen($key) <= 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($key, 4)));
$publicExponent = new BigInteger($this->_string_shift($key, $length), -256);
if (strlen($key) <= 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($key, 4)));
$modulus = new BigInteger($this->_string_shift($key, $length), -256);

if ($cleanup && strlen($key)) {
if (strlen($key) <= 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($key, 4)));
$realModulus = new BigInteger($this->_string_shift($key, $length), -256);
return strlen($key) ? false : array(
'modulus' => $realModulus,
'publicExponent' => $modulus,
'comment' => $comment
);
} else {
return strlen($key) ? false : array(
'modulus' => $modulus,
'publicExponent' => $publicExponent,
'comment' => $comment
);
}

 
 case self::PRIVATE_FORMAT_XML:
case self::PUBLIC_FORMAT_XML:
$this->components = array();

$xml = xml_parser_create('UTF-8');
xml_set_object($xml, $this);
xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
xml_set_character_data_handler($xml, '_data_handler');

 if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
xml_parser_free($xml);
unset($xml);
return false;
}

xml_parser_free($xml);
unset($xml);

return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;

 case self::PRIVATE_FORMAT_PUTTY:
$components = array();
$key = preg_split('#\r\n|\r|\n#', $key);
$type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
if ($type != 'ssh-rsa') {
return false;
}
$encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
$comment = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));

$publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
$public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
$public = substr($public, 11);
extract(unpack('Nlength', $this->_string_shift($public, 4)));
$components['publicExponent'] = new BigInteger($this->_string_shift($public, $length), -256);
extract(unpack('Nlength', $this->_string_shift($public, 4)));
$components['modulus'] = new BigInteger($this->_string_shift($public, $length), -256);

$privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
$private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));

switch ($encryption) {
case 'aes256-cbc':
$symkey = '';
$sequence = 0;
while (strlen($symkey) < 32) {
$temp = pack('Na*', $sequence++, $this->password);
$symkey.= pack('H*', sha1($temp));
}
$symkey = substr($symkey, 0, 32);
$crypto = new AES();
}

if ($encryption != 'none') {
$crypto->setKey($symkey);
$crypto->disablePadding();
$private = $crypto->decrypt($private);
if ($private === false) {
return false;
}
}

extract(unpack('Nlength', $this->_string_shift($private, 4)));
if (strlen($private) < $length) {
return false;
}
$components['privateExponent'] = new BigInteger($this->_string_shift($private, $length), -256);
extract(unpack('Nlength', $this->_string_shift($private, 4)));
if (strlen($private) < $length) {
return false;
}
$components['primes'] = array(1 => new BigInteger($this->_string_shift($private, $length), -256));
extract(unpack('Nlength', $this->_string_shift($private, 4)));
if (strlen($private) < $length) {
return false;
}
$components['primes'][] = new BigInteger($this->_string_shift($private, $length), -256);

$temp = $components['primes'][1]->subtract($this->one);
$components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
$temp = $components['primes'][2]->subtract($this->one);
$components['exponents'][] = $components['publicExponent']->modInverse($temp);

extract(unpack('Nlength', $this->_string_shift($private, 4)));
if (strlen($private) < $length) {
return false;
}
$components['coefficients'] = array(2 => new BigInteger($this->_string_shift($private, $length), -256));

return $components;
case self::PRIVATE_FORMAT_OPENSSH:
$components = array();
$decoded = $this->_extractBER($key);
$magic = $this->_string_shift($decoded, 15);
if ($magic !== "openssh-key-v1\0") {
return false;
}
$options = $this->_string_shift($decoded, 24);

 
 
 
 if ($options != "\0\0\0\4none\0\0\0\4none\0\0\0\0\0\0\0\1") {
return false;
}
extract(unpack('Nlength', $this->_string_shift($decoded, 4)));
if (strlen($decoded) < $length) {
return false;
}
$publicKey = $this->_string_shift($decoded, $length);
extract(unpack('Nlength', $this->_string_shift($decoded, 4)));
if (strlen($decoded) < $length) {
return false;
}
$paddedKey = $this->_string_shift($decoded, $length);

if ($this->_string_shift($publicKey, 11) !== "\0\0\0\7ssh-rsa") {
return false;
}

$checkint1 = $this->_string_shift($paddedKey, 4);
$checkint2 = $this->_string_shift($paddedKey, 4);
if (strlen($checkint1) != 4 || $checkint1 !== $checkint2) {
return false;
}

if ($this->_string_shift($paddedKey, 11) !== "\0\0\0\7ssh-rsa") {
return false;
}

$values = array(
&$components['modulus'],
&$components['publicExponent'],
&$components['privateExponent'],
&$components['coefficients'][2],
&$components['primes'][1],
&$components['primes'][2]
);

foreach ($values as &$value) {
extract(unpack('Nlength', $this->_string_shift($paddedKey, 4)));
if (strlen($paddedKey) < $length) {
return false;
}
$value = new BigInteger($this->_string_shift($paddedKey, $length), -256);
}

extract(unpack('Nlength', $this->_string_shift($paddedKey, 4)));
if (strlen($paddedKey) < $length) {
return false;
}
$components['comment'] = $this->_string_shift($decoded, $length);

$temp = $components['primes'][1]->subtract($this->one);
$components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
$temp = $components['primes'][2]->subtract($this->one);
$components['exponents'][] = $components['publicExponent']->modInverse($temp);

return $components;
}

return false;
}









function getSize()
{
return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits());
}











function _start_element_handler($parser, $name, $attribs)
{

 switch ($name) {
case 'MODULUS':
$this->current = &$this->components['modulus'];
break;
case 'EXPONENT':
$this->current = &$this->components['publicExponent'];
break;
case 'P':
$this->current = &$this->components['primes'][1];
break;
case 'Q':
$this->current = &$this->components['primes'][2];
break;
case 'DP':
$this->current = &$this->components['exponents'][1];
break;
case 'DQ':
$this->current = &$this->components['exponents'][2];
break;
case 'INVERSEQ':
$this->current = &$this->components['coefficients'][2];
break;
case 'D':
$this->current = &$this->components['privateExponent'];
}
$this->current = '';
}










function _stop_element_handler($parser, $name)
{
if (isset($this->current)) {
$this->current = new BigInteger(base64_decode($this->current), 256);
unset($this->current);
}
}










function _data_handler($parser, $data)
{
if (!isset($this->current) || is_object($this->current)) {
return;
}
$this->current.= trim($data);
}











function loadKey($key, $type = false)
{
if ($key instanceof RSA) {
$this->privateKeyFormat = $key->privateKeyFormat;
$this->publicKeyFormat = $key->publicKeyFormat;
$this->k = $key->k;
$this->hLen = $key->hLen;
$this->sLen = $key->sLen;
$this->mgfHLen = $key->mgfHLen;
$this->encryptionMode = $key->encryptionMode;
$this->signatureMode = $key->signatureMode;
$this->password = $key->password;
$this->configFile = $key->configFile;
$this->comment = $key->comment;

if (is_object($key->hash)) {
$this->hash = new Hash($key->hash->getHash());
}
if (is_object($key->mgfHash)) {
$this->mgfHash = new Hash($key->mgfHash->getHash());
}

if (is_object($key->modulus)) {
$this->modulus = $key->modulus->copy();
}
if (is_object($key->exponent)) {
$this->exponent = $key->exponent->copy();
}
if (is_object($key->publicExponent)) {
$this->publicExponent = $key->publicExponent->copy();
}

$this->primes = array();
$this->exponents = array();
$this->coefficients = array();

foreach ($this->primes as $prime) {
$this->primes[] = $prime->copy();
}
foreach ($this->exponents as $exponent) {
$this->exponents[] = $exponent->copy();
}
foreach ($this->coefficients as $coefficient) {
$this->coefficients[] = $coefficient->copy();
}

return true;
}

if ($type === false) {
$types = array(
self::PUBLIC_FORMAT_RAW,
self::PRIVATE_FORMAT_PKCS1,
self::PRIVATE_FORMAT_XML,
self::PRIVATE_FORMAT_PUTTY,
self::PUBLIC_FORMAT_OPENSSH,
self::PRIVATE_FORMAT_OPENSSH
);
foreach ($types as $type) {
$components = $this->_parseKey($key, $type);
if ($components !== false) {
break;
}
}
} else {
$components = $this->_parseKey($key, $type);
}

if ($components === false) {
$this->comment = null;
$this->modulus = null;
$this->k = null;
$this->exponent = null;
$this->primes = null;
$this->exponents = null;
$this->coefficients = null;
$this->publicExponent = null;

return false;
}

if (isset($components['comment']) && $components['comment'] !== false) {
$this->comment = $components['comment'];
}
$this->modulus = $components['modulus'];
$this->k = strlen($this->modulus->toBytes());
$this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
if (isset($components['primes'])) {
$this->primes = $components['primes'];
$this->exponents = $components['exponents'];
$this->coefficients = $components['coefficients'];
$this->publicExponent = $components['publicExponent'];
} else {
$this->primes = array();
$this->exponents = array();
$this->coefficients = array();
$this->publicExponent = false;
}

switch ($type) {
case self::PUBLIC_FORMAT_OPENSSH:
case self::PUBLIC_FORMAT_RAW:
$this->setPublicKey();
break;
case self::PRIVATE_FORMAT_PKCS1:
switch (true) {
case strpos($key, '-BEGIN PUBLIC KEY-') !== false:
case strpos($key, '-BEGIN RSA PUBLIC KEY-') !== false:
$this->setPublicKey();
}
}

return true;
}












function setPassword($password = false)
{
$this->password = $password;
}






















function setPublicKey($key = false, $type = false)
{

 if (!empty($this->publicExponent)) {
return false;
}

if ($key === false && !empty($this->modulus)) {
$this->publicExponent = $this->exponent;
return true;
}

if ($type === false) {
$types = array(
self::PUBLIC_FORMAT_RAW,
self::PUBLIC_FORMAT_PKCS1,
self::PUBLIC_FORMAT_XML,
self::PUBLIC_FORMAT_OPENSSH
);
foreach ($types as $type) {
$components = $this->_parseKey($key, $type);
if ($components !== false) {
break;
}
}
} else {
$components = $this->_parseKey($key, $type);
}

if ($components === false) {
return false;
}

if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
$this->modulus = $components['modulus'];
$this->exponent = $this->publicExponent = $components['publicExponent'];
return true;
}

$this->publicExponent = $components['publicExponent'];

return true;
}

















function setPrivateKey($key = false, $type = false)
{
if ($key === false && !empty($this->publicExponent)) {
$this->publicExponent = false;
return true;
}

$rsa = new RSA();
if (!$rsa->loadKey($key, $type)) {
return false;
}
$rsa->publicExponent = false;


 $this->loadKey($rsa);
return true;
}












function getPublicKey($type = self::PUBLIC_FORMAT_PKCS8)
{
if (empty($this->modulus) || empty($this->publicExponent)) {
return false;
}

$oldFormat = $this->publicKeyFormat;
$this->publicKeyFormat = $type;
$temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
$this->publicKeyFormat = $oldFormat;
return $temp;
}













function getPublicKeyFingerprint($algorithm = 'md5')
{
if (empty($this->modulus) || empty($this->publicExponent)) {
return false;
}

$modulus = $this->modulus->toBytes(true);
$publicExponent = $this->publicExponent->toBytes(true);

$RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);

switch ($algorithm) {
case 'sha256':
$hash = new Hash('sha256');
$base = base64_encode($hash->hash($RSAPublicKey));
return substr($base, 0, strlen($base) - 1);
case 'md5':
return substr(chunk_split(md5($RSAPublicKey), 2, ':'), 0, -1);
default:
return false;
}
}











function getPrivateKey($type = self::PUBLIC_FORMAT_PKCS1)
{
if (empty($this->primes)) {
return false;
}

$oldFormat = $this->privateKeyFormat;
$this->privateKeyFormat = $type;
$temp = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients);
$this->privateKeyFormat = $oldFormat;
return $temp;
}











function _getPrivatePublicKey($mode = self::PUBLIC_FORMAT_PKCS8)
{
if (empty($this->modulus) || empty($this->exponent)) {
return false;
}

$oldFormat = $this->publicKeyFormat;
$this->publicKeyFormat = $mode;
$temp = $this->_convertPublicKey($this->modulus, $this->exponent);
$this->publicKeyFormat = $oldFormat;
return $temp;
}







function __toString()
{
$key = $this->getPrivateKey($this->privateKeyFormat);
if ($key !== false) {
return $key;
}
$key = $this->_getPrivatePublicKey($this->publicKeyFormat);
return $key !== false ? $key : '';
}







function __clone()
{
$key = new RSA();
$key->loadKey($this);
return $key;
}








function _generateMinMax($bits)
{
$bytes = $bits >> 3;
$min = str_repeat(chr(0), $bytes);
$max = str_repeat(chr(0xFF), $bytes);
$msb = $bits & 7;
if ($msb) {
$min = chr(1 << ($msb - 1)) . $min;
$max = chr((1 << $msb) - 1) . $max;
} else {
$min[0] = chr(0x80);
}

return array(
'min' => new BigInteger($min, 256),
'max' => new BigInteger($max, 256)
);
}











function _decodeLength(&$string)
{
$length = ord($this->_string_shift($string));
if ($length & 0x80) { 
 $length&= 0x7F;
$temp = $this->_string_shift($string, $length);
list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
}
return $length;
}











function _encodeLength($length)
{
if ($length <= 0x7F) {
return chr($length);
}

$temp = ltrim(pack('N', $length), chr(0));
return pack('Ca*', 0x80 | strlen($temp), $temp);
}











function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}








function setPrivateKeyFormat($format)
{
$this->privateKeyFormat = $format;
}








function setPublicKeyFormat($format)
{
$this->publicKeyFormat = $format;
}










function setHash($hash)
{

 switch ($hash) {
case 'md2':
case 'md5':
case 'sha1':
case 'sha256':
case 'sha384':
case 'sha512':
$this->hash = new Hash($hash);
$this->hashName = $hash;
break;
default:
$this->hash = new Hash('sha1');
$this->hashName = 'sha1';
}
$this->hLen = $this->hash->getLength();
}










function setMGFHash($hash)
{

 switch ($hash) {
case 'md2':
case 'md5':
case 'sha1':
case 'sha256':
case 'sha384':
case 'sha512':
$this->mgfHash = new Hash($hash);
break;
default:
$this->mgfHash = new Hash('sha1');
}
$this->mgfHLen = $this->mgfHash->getLength();
}












function setSaltLength($sLen)
{
$this->sLen = $sLen;
}











function _i2osp($x, $xLen)
{
$x = $x->toBytes();
if (strlen($x) > $xLen) {
user_error('Integer too large');
return false;
}
return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
}










function _os2ip($x)
{
return new BigInteger($x, 256);
}










function _exponentiate($x)
{
switch (true) {
case empty($this->primes):
case $this->primes[1]->equals($this->zero):
case empty($this->coefficients):
case $this->coefficients[2]->equals($this->zero):
case empty($this->exponents):
case $this->exponents[1]->equals($this->zero):
return $x->modPow($this->exponent, $this->modulus);
}

$num_primes = count($this->primes);

if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
$m_i = array(
1 => $x->modPow($this->exponents[1], $this->primes[1]),
2 => $x->modPow($this->exponents[2], $this->primes[2])
);
$h = $m_i[1]->subtract($m_i[2]);
$h = $h->multiply($this->coefficients[2]);
list(, $h) = $h->divide($this->primes[1]);
$m = $m_i[2]->add($h->multiply($this->primes[2]));

$r = $this->primes[1];
for ($i = 3; $i <= $num_primes; $i++) {
$m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);

$r = $r->multiply($this->primes[$i - 1]);

$h = $m_i->subtract($m);
$h = $h->multiply($this->coefficients[$i]);
list(, $h) = $h->divide($this->primes[$i]);

$m = $m->add($r->multiply($h));
}
} else {
$smallest = $this->primes[1];
for ($i = 2; $i <= $num_primes; $i++) {
if ($smallest->compare($this->primes[$i]) > 0) {
$smallest = $this->primes[$i];
}
}

$one = new BigInteger(1);

$r = $one->random($one, $smallest->subtract($one));

$m_i = array(
1 => $this->_blind($x, $r, 1),
2 => $this->_blind($x, $r, 2)
);
$h = $m_i[1]->subtract($m_i[2]);
$h = $h->multiply($this->coefficients[2]);
list(, $h) = $h->divide($this->primes[1]);
$m = $m_i[2]->add($h->multiply($this->primes[2]));

$r = $this->primes[1];
for ($i = 3; $i <= $num_primes; $i++) {
$m_i = $this->_blind($x, $r, $i);

$r = $r->multiply($this->primes[$i - 1]);

$h = $m_i->subtract($m);
$h = $h->multiply($this->coefficients[$i]);
list(, $h) = $h->divide($this->primes[$i]);

$m = $m->add($r->multiply($h));
}
}

return $m;
}













function _blind($x, $r, $i)
{
$x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
$x = $x->modPow($this->exponents[$i], $this->primes[$i]);

$r = $r->modInverse($this->primes[$i]);
$x = $x->multiply($r);
list(, $x) = $x->divide($this->primes[$i]);

return $x;
}















function _equals($x, $y)
{
if (function_exists('hash_equals')) {
return hash_equals($x, $y);
}

if (strlen($x) != strlen($y)) {
return false;
}

$result = "\0";
$x^= $y;
for ($i = 0; $i < strlen($x); $i++) {
$result|= $x[$i];
}

return $result === "\0";
}










function _rsaep($m)
{
if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
user_error('Message representative out of range');
return false;
}
return $this->_exponentiate($m);
}










function _rsadp($c)
{
if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
user_error('Ciphertext representative out of range');
return false;
}
return $this->_exponentiate($c);
}










function _rsasp1($m)
{
if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
user_error('Message representative out of range');
return false;
}
return $this->_exponentiate($m);
}










function _rsavp1($s)
{
if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
user_error('Signature representative out of range');
return false;
}
return $this->_exponentiate($s);
}











function _mgf1($mgfSeed, $maskLen)
{


$t = '';
$count = ceil($maskLen / $this->mgfHLen);
for ($i = 0; $i < $count; $i++) {
$c = pack('N', $i);
$t.= $this->mgfHash->hash($mgfSeed . $c);
}

return substr($t, 0, $maskLen);
}












function _rsaes_oaep_encrypt($m, $l = '')
{
$mLen = strlen($m);




 

if ($mLen > $this->k - 2 * $this->hLen - 2) {
user_error('Message too long');
return false;
}



$lHash = $this->hash->hash($l);
$ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
$db = $lHash . $ps . chr(1) . $m;
$seed = Random::string($this->hLen);
$dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
$maskedDB = $db ^ $dbMask;
$seedMask = $this->_mgf1($maskedDB, $this->hLen);
$maskedSeed = $seed ^ $seedMask;
$em = chr(0) . $maskedSeed . $maskedDB;



$m = $this->_os2ip($em);
$c = $this->_rsaep($m);
$c = $this->_i2osp($c, $this->k);



return $c;
}



























function _rsaes_oaep_decrypt($c, $l = '')
{



 

if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
user_error('Decryption error');
return false;
}



$c = $this->_os2ip($c);
$m = $this->_rsadp($c);
if ($m === false) {
user_error('Decryption error');
return false;
}
$em = $this->_i2osp($m, $this->k);



$lHash = $this->hash->hash($l);
$y = ord($em[0]);
$maskedSeed = substr($em, 1, $this->hLen);
$maskedDB = substr($em, $this->hLen + 1);
$seedMask = $this->_mgf1($maskedDB, $this->hLen);
$seed = $maskedSeed ^ $seedMask;
$dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
$db = $maskedDB ^ $dbMask;
$lHash2 = substr($db, 0, $this->hLen);
$m = substr($db, $this->hLen);
$hashesMatch = $this->_equals($lHash, $lHash2);
$leadingZeros = 1;
$patternMatch = 0;
$offset = 0;
for ($i = 0; $i < strlen($m); $i++) {
$patternMatch|= $leadingZeros & ($m[$i] === "\1");
$leadingZeros&= $m[$i] === "\0";
$offset+= $patternMatch ? 0 : 1;
}


 
 if (!$hashesMatch | !$patternMatch) {
user_error('Decryption error');
return false;
}



return substr($m, $offset + 1);
}










function _raw_encrypt($m)
{
$temp = $this->_os2ip($m);
$temp = $this->_rsaep($temp);
return $this->_i2osp($temp, $this->k);
}










function _rsaes_pkcs1_v1_5_encrypt($m)
{
$mLen = strlen($m);



if ($mLen > $this->k - 11) {
user_error('Message too long');
return false;
}



$psLen = $this->k - $mLen - 3;
$ps = '';
while (strlen($ps) != $psLen) {
$temp = Random::string($psLen - strlen($ps));
$temp = str_replace("\x00", '', $temp);
$ps.= $temp;
}
$type = 2;

 if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) {
$type = 1;

 $ps = str_repeat("\xFF", $psLen);
}
$em = chr(0) . chr($type) . $ps . chr(0) . $m;


 $m = $this->_os2ip($em);
$c = $this->_rsaep($m);
$c = $this->_i2osp($c, $this->k);



return $c;
}





















function _rsaes_pkcs1_v1_5_decrypt($c)
{


if (strlen($c) != $this->k) { 
 user_error('Decryption error');
return false;
}



$c = $this->_os2ip($c);
$m = $this->_rsadp($c);

if ($m === false) {
user_error('Decryption error');
return false;
}
$em = $this->_i2osp($m, $this->k);



if (ord($em[0]) != 0 || ord($em[1]) > 2) {
user_error('Decryption error');
return false;
}

$ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
$m = substr($em, strlen($ps) + 3);

if (strlen($ps) < 8) {
user_error('Decryption error');
return false;
}



return $m;
}










function _emsa_pss_encode($m, $emBits)
{

 

$emLen = ($emBits + 1) >> 3; 
 $sLen = $this->sLen !== null ? $this->sLen : $this->hLen;

$mHash = $this->hash->hash($m);
if ($emLen < $this->hLen + $sLen + 2) {
user_error('Encoding error');
return false;
}

$salt = Random::string($sLen);
$m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
$h = $this->hash->hash($m2);
$ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
$db = $ps . chr(1) . $salt;
$dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
$maskedDB = $db ^ $dbMask;
$maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
$em = $maskedDB . $h . chr(0xBC);

return $em;
}












function _emsa_pss_verify($m, $em, $emBits)
{

 

$emLen = ($emBits + 7) >> 3; 
 $sLen = $this->sLen !== null ? $this->sLen : $this->hLen;

$mHash = $this->hash->hash($m);
if ($emLen < $this->hLen + $sLen + 2) {
return false;
}

if ($em[strlen($em) - 1] != chr(0xBC)) {
return false;
}

$maskedDB = substr($em, 0, -$this->hLen - 1);
$h = substr($em, -$this->hLen - 1, $this->hLen);
$temp = chr(0xFF << ($emBits & 7));
if ((~$maskedDB[0] & $temp) != $temp) {
return false;
}
$dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
$db = $maskedDB ^ $dbMask;
$db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
$temp = $emLen - $this->hLen - $sLen - 2;
if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
return false;
}
$salt = substr($db, $temp + 1); 
 $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
$h2 = $this->hash->hash($m2);
return $this->_equals($h, $h2);
}










function _rsassa_pss_sign($m)
{


$em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);



$m = $this->_os2ip($em);
$s = $this->_rsasp1($m);
$s = $this->_i2osp($s, $this->k);



return $s;
}











function _rsassa_pss_verify($m, $s)
{


if (strlen($s) != $this->k) {
user_error('Invalid signature');
return false;
}



$modBits = strlen($this->modulus->toBits());

$s2 = $this->_os2ip($s);
$m2 = $this->_rsavp1($s2);
if ($m2 === false) {
user_error('Invalid signature');
return false;
}
$em = $this->_i2osp($m2, $this->k);
if ($em === false) {
user_error('Invalid signature');
return false;
}



return $this->_emsa_pss_verify($m, $em, $modBits - 1);
}











function _emsa_pkcs1_v1_5_encode($m, $emLen)
{
$h = $this->hash->hash($m);
if ($h === false) {
return false;
}


 switch ($this->hashName) {
case 'md2':
$t = pack('H*', '3020300c06082a864886f70d020205000410');
break;
case 'md5':
$t = pack('H*', '3020300c06082a864886f70d020505000410');
break;
case 'sha1':
$t = pack('H*', '3021300906052b0e03021a05000414');
break;
case 'sha256':
$t = pack('H*', '3031300d060960864801650304020105000420');
break;
case 'sha384':
$t = pack('H*', '3041300d060960864801650304020205000430');
break;
case 'sha512':
$t = pack('H*', '3051300d060960864801650304020305000440');
}
$t.= $h;
$tLen = strlen($t);

if ($emLen < $tLen + 11) {
user_error('Intended encoded message length too short');
return false;
}

$ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);

$em = "\0\1$ps\0$t";

return $em;
}
















function _emsa_pkcs1_v1_5_encode_without_null($m, $emLen)
{
$h = $this->hash->hash($m);
if ($h === false) {
return false;
}

switch ($this->hashName) {
case 'sha1':
$t = pack('H*', '301f300706052b0e03021a0414');
break;
case 'sha256':
$t = pack('H*', '302f300b06096086480165030402010420');
break;
case 'sha384':
$t = pack('H*', '303f300b06096086480165030402020430');
break;
case 'sha512':
$t = pack('H*', '304f300b06096086480165030402030440');
break;
default:
return false;
}
$t.= $h;
$tLen = strlen($t);

if ($emLen < $tLen + 11) {
user_error('Intended encoded message length too short');
return false;
}

$ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);

$em = "\0\1$ps\0$t";

return $em;
}










function _rsassa_pkcs1_v1_5_sign($m)
{


$em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
if ($em === false) {
user_error('RSA modulus too short');
return false;
}



$m = $this->_os2ip($em);
$s = $this->_rsasp1($m);
$s = $this->_i2osp($s, $this->k);



return $s;
}











function _rsassa_pkcs1_v1_5_verify($m, $s)
{


if (strlen($s) != $this->k) {
user_error('Invalid signature');
return false;
}



$s = $this->_os2ip($s);
$m2 = $this->_rsavp1($s);
if ($m2 === false) {
user_error('Invalid signature');
return false;
}
$em = $this->_i2osp($m2, $this->k);
if ($em === false) {
user_error('Invalid signature');
return false;
}



$em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
$em3 = $this->_emsa_pkcs1_v1_5_encode_without_null($m, $this->k);

if ($em2 === false && $em3 === false) {
user_error('RSA modulus too short');
return false;
}



return ($em2 !== false && $this->_equals($em, $em2)) ||
($em3 !== false && $this->_equals($em, $em3));
}









function setEncryptionMode($mode)
{
$this->encryptionMode = $mode;
}









function setSignatureMode($mode)
{
$this->signatureMode = $mode;
}







function setComment($comment)
{
$this->comment = $comment;
}







function getComment()
{
return $this->comment;
}













function encrypt($plaintext)
{
switch ($this->encryptionMode) {
case self::ENCRYPTION_NONE:
$plaintext = str_split($plaintext, $this->k);
$ciphertext = '';
foreach ($plaintext as $m) {
$ciphertext.= $this->_raw_encrypt($m);
}
return $ciphertext;
case self::ENCRYPTION_PKCS1:
$length = $this->k - 11;
if ($length <= 0) {
return false;
}

$plaintext = str_split($plaintext, $length);
$ciphertext = '';
foreach ($plaintext as $m) {
$ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m);
}
return $ciphertext;

 default:
$length = $this->k - 2 * $this->hLen - 2;
if ($length <= 0) {
return false;
}

$plaintext = str_split($plaintext, $length);
$ciphertext = '';
foreach ($plaintext as $m) {
$ciphertext.= $this->_rsaes_oaep_encrypt($m);
}
return $ciphertext;
}
}









function decrypt($ciphertext)
{
if ($this->k <= 0) {
return false;
}

$ciphertext = str_split($ciphertext, $this->k);
$ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);

$plaintext = '';

switch ($this->encryptionMode) {
case self::ENCRYPTION_NONE:
$decrypt = '_raw_encrypt';
break;
case self::ENCRYPTION_PKCS1:
$decrypt = '_rsaes_pkcs1_v1_5_decrypt';
break;

 default:
$decrypt = '_rsaes_oaep_decrypt';
}

foreach ($ciphertext as $c) {
$temp = $this->$decrypt($c);
if ($temp === false) {
return false;
}
$plaintext.= $temp;
}

return $plaintext;
}









function sign($message)
{
if (empty($this->modulus) || empty($this->exponent)) {
return false;
}

switch ($this->signatureMode) {
case self::SIGNATURE_PKCS1:
return $this->_rsassa_pkcs1_v1_5_sign($message);

 default:
return $this->_rsassa_pss_sign($message);
}
}










function verify($message, $signature)
{
if (empty($this->modulus) || empty($this->exponent)) {
return false;
}

switch ($this->signatureMode) {
case self::SIGNATURE_PKCS1:
return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);

 default:
return $this->_rsassa_pss_verify($message, $signature);
}
}








function _extractBER($str)
{









$temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);

 $temp = preg_replace('#-+[^-]+-+#', '', $temp);

 $temp = str_replace(array("\r", "\n", ' '), '', $temp);
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
return $temp != false ? $temp : $str;
}
}
<?php











































namespace phpseclib\Crypt;








class RC4 extends Base
{




const ENCRYPT = 0;
const DECRYPT = 1;












var $block_size = 0;








var $key_length = 128; 








var $cipher_name_mcrypt = 'arcfour';








var $use_inline_crypt = false; 








var $key;








var $stream;










function __construct()
{
parent::__construct(Base::MODE_STREAM);
}











function isValidEngine($engine)
{
if ($engine == Base::ENGINE_OPENSSL) {
if (version_compare(PHP_VERSION, '5.3.7') >= 0) {
$this->cipher_name_openssl = 'rc4-40';
} else {
switch (strlen($this->key)) {
case 5:
$this->cipher_name_openssl = 'rc4-40';
break;
case 8:
$this->cipher_name_openssl = 'rc4-64';
break;
case 16:
$this->cipher_name_openssl = 'rc4';
break;
default:
return false;
}
}
}

return parent::isValidEngine($engine);
}




















function setIV($iv)
{
}









function setKeyLength($length)
{
if ($length < 8) {
$this->key_length = 1;
} elseif ($length > 2048) {
$this->key_length = 256;
} else {
$this->key_length = $length >> 3;
}

parent::setKeyLength($length);
}










function encrypt($plaintext)
{
if ($this->engine != Base::ENGINE_INTERNAL) {
return parent::encrypt($plaintext);
}
return $this->_crypt($plaintext, self::ENCRYPT);
}













function decrypt($ciphertext)
{
if ($this->engine != Base::ENGINE_INTERNAL) {
return parent::decrypt($ciphertext);
}
return $this->_crypt($ciphertext, self::DECRYPT);
}







function _encryptBlock($in)
{

 }







function _decryptBlock($in)
{

 }







function _setupKey()
{
$key = $this->key;
$keyLength = strlen($key);
$keyStream = range(0, 255);
$j = 0;
for ($i = 0; $i < 256; $i++) {
$j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
$temp = $keyStream[$i];
$keyStream[$i] = $keyStream[$j];
$keyStream[$j] = $temp;
}

$this->stream = array();
$this->stream[self::DECRYPT] = $this->stream[self::ENCRYPT] = array(
0, 
 0, 
 $keyStream
);
}











function _crypt($text, $mode)
{
if ($this->changed) {
$this->_setup();
$this->changed = false;
}

$stream = &$this->stream[$mode];
if ($this->continuousBuffer) {
$i = &$stream[0];
$j = &$stream[1];
$keyStream = &$stream[2];
} else {
$i = $stream[0];
$j = $stream[1];
$keyStream = $stream[2];
}

$len = strlen($text);
for ($k = 0; $k < $len; ++$k) {
$i = ($i + 1) & 255;
$ksi = $keyStream[$i];
$j = ($j + $ksi) & 255;
$ksj = $keyStream[$j];

$keyStream[$i] = $ksj;
$keyStream[$j] = $ksi;
$text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
}

return $text;
}
}
<?php





































namespace phpseclib\Crypt;

use phpseclib\Math\BigInteger;








class Hash
{







const MODE_INTERNAL = 1;



const MODE_MHASH = 2;



const MODE_HASH = 3;









var $hashParam;








var $b;








var $l = false;








var $hash;








var $key = false;








var $computedKey = false;








var $opad;








var $ipad;








var $engine;








function __construct($hash = 'sha1')
{
if (!defined('CRYPT_HASH_MODE')) {
switch (true) {
case extension_loaded('hash'):
define('CRYPT_HASH_MODE', self::MODE_HASH);
break;
case extension_loaded('mhash'):
define('CRYPT_HASH_MODE', self::MODE_MHASH);
break;
default:
define('CRYPT_HASH_MODE', self::MODE_INTERNAL);
}
}

$this->setHash($hash);
}









function setKey($key = false)
{
$this->key = $key;
$this->_computeKey();
}













function _computeKey()
{
if ($this->key === false) {
$this->computedKey = false;
return;
}

if (strlen($this->key) <= $this->b) {
$this->computedKey = $this->key;
return;
}

switch ($this->engine) {
case self::MODE_MHASH:
$this->computedKey = mhash($this->hash, $this->key);
break;
case self::MODE_HASH:
$this->computedKey = hash($this->hash, $this->key, true);
break;
case self::MODE_INTERNAL:
$this->computedKey = call_user_func($this->hash, $this->key);
}
}









function getHash()
{
return $this->hashParam;
}







function setHash($hash)
{
$this->hashParam = $hash = strtolower($hash);
switch ($hash) {
case 'md5-96':
case 'sha1-96':
case 'sha256-96':
case 'sha512-96':
$hash = substr($hash, 0, -3);
$this->l = 12; 
 break;
case 'md2':
case 'md5':
$this->l = 16;
break;
case 'sha1':
$this->l = 20;
break;
case 'sha256':
$this->l = 32;
break;
case 'sha384':
$this->l = 48;
break;
case 'sha512':
$this->l = 64;
}

switch ($hash) {
case 'md2-96':
case 'md2':
$this->b = 16;
case 'md5-96':
case 'sha1-96':
case 'sha224-96':
case 'sha256-96':
case 'md2':
case 'md5':
case 'sha1':
case 'sha224':
case 'sha256':
$this->b = 64;
break;
default:
$this->b = 128;
}

switch ($hash) {
case 'md2':
$this->engine = CRYPT_HASH_MODE == self::MODE_HASH && in_array('md2', hash_algos()) ?
self::MODE_HASH : self::MODE_INTERNAL;
break;
case 'sha384':
case 'sha512':
$this->engine = CRYPT_HASH_MODE == self::MODE_MHASH ? self::MODE_INTERNAL : CRYPT_HASH_MODE;
break;
default:
$this->engine = CRYPT_HASH_MODE;
}

switch ($this->engine) {
case self::MODE_MHASH:
switch ($hash) {
case 'md5':
$this->hash = MHASH_MD5;
break;
case 'sha256':
$this->hash = MHASH_SHA256;
break;
case 'sha1':
default:
$this->hash = MHASH_SHA1;
}
$this->_computeKey(self::MODE_MHASH);
return;
case self::MODE_HASH:
switch ($hash) {
case 'md5':
$this->hash = 'md5';
return;
case 'md2':
case 'sha256':
case 'sha384':
case 'sha512':
$this->hash = $hash;
return;
case 'sha1':
default:
$this->hash = 'sha1';
}
$this->_computeKey(self::MODE_HASH);
return;
}

switch ($hash) {
case 'md2':
$this->hash = array($this, '_md2');
break;
case 'md5':
$this->hash = array($this, '_md5');
break;
case 'sha256':
$this->hash = array($this, '_sha256');
break;
case 'sha384':
case 'sha512':
$this->hash = array($this, '_sha512');
break;
case 'sha1':
default:
$this->hash = array($this, '_sha1');
}

$this->ipad = str_repeat(chr(0x36), $this->b);
$this->opad = str_repeat(chr(0x5C), $this->b);

$this->_computeKey(self::MODE_INTERNAL);
}








function hash($text)
{
if (!empty($this->key) || is_string($this->key)) {
switch ($this->engine) {
case self::MODE_MHASH:
$output = mhash($this->hash, $text, $this->computedKey);
break;
case self::MODE_HASH:
$output = hash_hmac($this->hash, $text, $this->computedKey, true);
break;
case self::MODE_INTERNAL:
$key = str_pad($this->computedKey, $this->b, chr(0)); 
 $temp = $this->ipad ^ $key; 
 $temp .= $text; 
 $temp = call_user_func($this->hash, $temp); 
 $output = $this->opad ^ $key; 
 $output.= $temp; 
 $output = call_user_func($this->hash, $output); 
 }
} else {
switch ($this->engine) {
case self::MODE_MHASH:
$output = mhash($this->hash, $text);
break;
case self::MODE_HASH:
$output = hash($this->hash, $text, true);
break;
case self::MODE_INTERNAL:
$output = call_user_func($this->hash, $text);
}
}

return substr($output, 0, $this->l);
}







function getLength()
{
return $this->l;
}







function _md5($m)
{
return pack('H*', md5($m));
}







function _sha1($m)
{
return pack('H*', sha1($m));
}









function _md2($m)
{
static $s = array(
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
31, 26, 219, 153, 141, 51, 159, 17, 131, 20
);


 $pad = 16 - (strlen($m) & 0xF);
$m.= str_repeat(chr($pad), $pad);

$length = strlen($m);


 $c = str_repeat(chr(0), 16);
$l = chr(0);
for ($i = 0; $i < $length; $i+= 16) {
for ($j = 0; $j < 16; $j++) {

 
 
 $c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j]));
$l = $c[$j];
}
}
$m.= $c;

$length+= 16;


 $x = str_repeat(chr(0), 48);


 for ($i = 0; $i < $length; $i+= 16) {
for ($j = 0; $j < 16; $j++) {
$x[$j + 16] = $m[$i + $j];
$x[$j + 32] = $x[$j + 16] ^ $x[$j];
}
$t = chr(0);
for ($j = 0; $j < 18; $j++) {
for ($k = 0; $k < 48; $k++) {
$x[$k] = $t = $x[$k] ^ chr($s[ord($t)]);

 }
$t = chr(ord($t) + $j);
}
}


 return substr($x, 0, 16);
}









function _sha256($m)
{
if (extension_loaded('suhosin')) {
return pack('H*', sha256($m));
}


 $hash = array(
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
);

 
 static $k = array(
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
);


 $length = strlen($m);

 $m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F));
$m[$length] = chr(0x80);

 $m.= pack('N2', 0, $length << 3);


 $chunks = str_split($m, 64);
foreach ($chunks as $chunk) {
$w = array();
for ($i = 0; $i < 16; $i++) {
extract(unpack('Ntemp', $this->_string_shift($chunk, 4)));
$w[] = $temp;
}


 for ($i = 16; $i < 64; $i++) {

 $s0 = $this->_rightRotate($w[$i - 15], 7) ^
$this->_rightRotate($w[$i - 15], 18) ^
$this->_rightShift( $w[$i - 15], 3);
$s1 = $this->_rightRotate($w[$i - 2], 17) ^
$this->_rightRotate($w[$i - 2], 19) ^
$this->_rightShift( $w[$i - 2], 10);

 $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
}


 list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;


 for ($i = 0; $i < 64; $i++) {
$s0 = $this->_rightRotate($a, 2) ^
$this->_rightRotate($a, 13) ^
$this->_rightRotate($a, 22);
$maj = ($a & $b) ^
($a & $c) ^
($b & $c);
$t2 = $this->_add($s0, $maj);

$s1 = $this->_rightRotate($e, 6) ^
$this->_rightRotate($e, 11) ^
$this->_rightRotate($e, 25);
$ch = ($e & $f) ^
($this->_not($e) & $g);
$t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]);

$h = $g;
$g = $f;
$f = $e;
$e = $this->_add($d, $t1);
$d = $c;
$c = $b;
$b = $a;
$a = $this->_add($t1, $t2);
}


 $hash = array(
$this->_add($hash[0], $a),
$this->_add($hash[1], $b),
$this->_add($hash[2], $c),
$this->_add($hash[3], $d),
$this->_add($hash[4], $e),
$this->_add($hash[5], $f),
$this->_add($hash[6], $g),
$this->_add($hash[7], $h)
);
}


 return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]);
}







function _sha512($m)
{
static $init384, $init512, $k;

if (!isset($k)) {

 $init384 = array( 
 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
'67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
);
$init512 = array( 
 '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
'510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
);

for ($i = 0; $i < 8; $i++) {
$init384[$i] = new BigInteger($init384[$i], 16);
$init384[$i]->setPrecision(64);
$init512[$i] = new BigInteger($init512[$i], 16);
$init512[$i]->setPrecision(64);
}


 
 $k = array(
'428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
'3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
'72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
'2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
'983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
'27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
'650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
'19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
'391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
'748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
'90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
'06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
'28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
'4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817'
);

for ($i = 0; $i < 80; $i++) {
$k[$i] = new BigInteger($k[$i], 16);
}
}

$hash = $this->l == 48 ? $init384 : $init512;


 $length = strlen($m);

 $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
$m[$length] = chr(0x80);

 $m.= pack('N4', 0, 0, 0, $length << 3);


 $chunks = str_split($m, 128);
foreach ($chunks as $chunk) {
$w = array();
for ($i = 0; $i < 16; $i++) {
$temp = new BigInteger($this->_string_shift($chunk, 8), 256);
$temp->setPrecision(64);
$w[] = $temp;
}


 for ($i = 16; $i < 80; $i++) {
$temp = array(
$w[$i - 15]->bitwise_rightRotate(1),
$w[$i - 15]->bitwise_rightRotate(8),
$w[$i - 15]->bitwise_rightShift(7)
);
$s0 = $temp[0]->bitwise_xor($temp[1]);
$s0 = $s0->bitwise_xor($temp[2]);
$temp = array(
$w[$i - 2]->bitwise_rightRotate(19),
$w[$i - 2]->bitwise_rightRotate(61),
$w[$i - 2]->bitwise_rightShift(6)
);
$s1 = $temp[0]->bitwise_xor($temp[1]);
$s1 = $s1->bitwise_xor($temp[2]);
$w[$i] = $w[$i - 16]->copy();
$w[$i] = $w[$i]->add($s0);
$w[$i] = $w[$i]->add($w[$i - 7]);
$w[$i] = $w[$i]->add($s1);
}


 $a = $hash[0]->copy();
$b = $hash[1]->copy();
$c = $hash[2]->copy();
$d = $hash[3]->copy();
$e = $hash[4]->copy();
$f = $hash[5]->copy();
$g = $hash[6]->copy();
$h = $hash[7]->copy();


 for ($i = 0; $i < 80; $i++) {
$temp = array(
$a->bitwise_rightRotate(28),
$a->bitwise_rightRotate(34),
$a->bitwise_rightRotate(39)
);
$s0 = $temp[0]->bitwise_xor($temp[1]);
$s0 = $s0->bitwise_xor($temp[2]);
$temp = array(
$a->bitwise_and($b),
$a->bitwise_and($c),
$b->bitwise_and($c)
);
$maj = $temp[0]->bitwise_xor($temp[1]);
$maj = $maj->bitwise_xor($temp[2]);
$t2 = $s0->add($maj);

$temp = array(
$e->bitwise_rightRotate(14),
$e->bitwise_rightRotate(18),
$e->bitwise_rightRotate(41)
);
$s1 = $temp[0]->bitwise_xor($temp[1]);
$s1 = $s1->bitwise_xor($temp[2]);
$temp = array(
$e->bitwise_and($f),
$g->bitwise_and($e->bitwise_not())
);
$ch = $temp[0]->bitwise_xor($temp[1]);
$t1 = $h->add($s1);
$t1 = $t1->add($ch);
$t1 = $t1->add($k[$i]);
$t1 = $t1->add($w[$i]);

$h = $g->copy();
$g = $f->copy();
$f = $e->copy();
$e = $d->add($t1);
$d = $c->copy();
$c = $b->copy();
$b = $a->copy();
$a = $t1->add($t2);
}


 $hash = array(
$hash[0]->add($a),
$hash[1]->add($b),
$hash[2]->add($c),
$hash[3]->add($d),
$hash[4]->add($e),
$hash[5]->add($f),
$hash[6]->add($g),
$hash[7]->add($h)
);
}


 
 $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() .
$hash[4]->toBytes() . $hash[5]->toBytes();
if ($this->l != 48) {
$temp.= $hash[6]->toBytes() . $hash[7]->toBytes();
}

return $temp;
}










function _rightRotate($int, $amt)
{
$invamt = 32 - $amt;
$mask = (1 << $invamt) - 1;
return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
}










function _rightShift($int, $amt)
{
$mask = (1 << (32 - $amt)) - 1;
return ($int >> $amt) & $mask;
}









function _not($int)
{
return ~$int & 0xFFFFFFFF;
}











function _add()
{
static $mod;
if (!isset($mod)) {
$mod = pow(2, 32);
}

$result = 0;
$arguments = func_get_args();
foreach ($arguments as $argument) {
$result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
}

if ((php_uname('m') & "\xDF\xDF\xDF") != 'ARM') {
return fmod($result, $mod);
}

return (fmod($result, 0x80000000) & 0x7FFFFFFF) |
((fmod(floor($result / 0x80000000), 2) & 1) << 31);
}











function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
}
<?php

























namespace phpseclib\File;

use phpseclib\Crypt\Hash;
use phpseclib\Crypt\Random;
use phpseclib\Crypt\RSA;
use phpseclib\File\ASN1\Element;
use phpseclib\Math\BigInteger;
use DateTime;
use DateTimeZone;








class X509
{







const VALIDATE_SIGNATURE_BY_CA = 1;








const DN_ARRAY = 0;



const DN_STRING = 1;



const DN_ASN1 = 2;



const DN_OPENSSL = 3;



const DN_CANON = 4;



const DN_HASH = 5;













const FORMAT_PEM = 0;



const FORMAT_DER = 1;





const FORMAT_SPKAC = 2;





const FORMAT_AUTO_DETECT = 3;






const ATTR_ALL = -1; 
 const ATTR_APPEND = -2; 
 const ATTR_REPLACE = -3; 







var $Certificate;






var $DirectoryString;
var $PKCS9String;
var $AttributeValue;
var $Extensions;
var $KeyUsage;
var $ExtKeyUsageSyntax;
var $BasicConstraints;
var $KeyIdentifier;
var $CRLDistributionPoints;
var $AuthorityKeyIdentifier;
var $CertificatePolicies;
var $AuthorityInfoAccessSyntax;
var $SubjectAltName;
var $SubjectDirectoryAttributes;
var $PrivateKeyUsagePeriod;
var $IssuerAltName;
var $PolicyMappings;
var $NameConstraints;

var $CPSuri;
var $UserNotice;

var $netscape_cert_type;
var $netscape_comment;
var $netscape_ca_policy_url;

var $Name;
var $RelativeDistinguishedName;
var $CRLNumber;
var $CRLReason;
var $IssuingDistributionPoint;
var $InvalidityDate;
var $CertificateIssuer;
var $HoldInstructionCode;
var $SignedPublicKeyAndChallenge;







var $PostalAddress;








var $CertificationRequest;







var $CertificateList;







var $dn;







var $publicKey;







var $privateKey;








var $oids;







var $CAs;







var $currentCert;










var $signatureSubject;







var $startDate;







var $endDate;







var $serialNumber;










var $currentKeyIdentifier;







var $caFlag = false;







var $challenge;







static $recur_limit = 5;







static $disable_url_fetch = false;







function __construct()
{

 

$this->DirectoryString = array(
'type' => ASN1::TYPE_CHOICE,
'children' => array(
'teletexString' => array('type' => ASN1::TYPE_TELETEX_STRING),
'printableString' => array('type' => ASN1::TYPE_PRINTABLE_STRING),
'universalString' => array('type' => ASN1::TYPE_UNIVERSAL_STRING),
'utf8String' => array('type' => ASN1::TYPE_UTF8_STRING),
'bmpString' => array('type' => ASN1::TYPE_BMP_STRING)
)
);

$this->PKCS9String = array(
'type' => ASN1::TYPE_CHOICE,
'children' => array(
'ia5String' => array('type' => ASN1::TYPE_IA5_STRING),
'directoryString' => $this->DirectoryString
)
);

$this->AttributeValue = array('type' => ASN1::TYPE_ANY);

$AttributeType = array('type' => ASN1::TYPE_OBJECT_IDENTIFIER);

$AttributeTypeAndValue = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'type' => $AttributeType,
'value'=> $this->AttributeValue
)
);








$this->RelativeDistinguishedName = array(
'type' => ASN1::TYPE_SET,
'min' => 1,
'max' => -1,
'children' => $AttributeTypeAndValue
);


 $RDNSequence = array(
'type' => ASN1::TYPE_SEQUENCE,

 'min' => 0,
'max' => -1,
'children' => $this->RelativeDistinguishedName
);

$this->Name = array(
'type' => ASN1::TYPE_CHOICE,
'children' => array(
'rdnSequence' => $RDNSequence
)
);


 $AlgorithmIdentifier = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'algorithm' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER),
'parameters' => array(
'type' => ASN1::TYPE_ANY,
'optional' => true
)
)
);








$Extension = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'extnId' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER),
'critical' => array(
'type' => ASN1::TYPE_BOOLEAN,
'optional' => true,
'default' => false
),
'extnValue' => array('type' => ASN1::TYPE_OCTET_STRING)
)
);

$this->Extensions = array(
'type' => ASN1::TYPE_SEQUENCE,
'min' => 1,

 'max' => -1,

 'children' => $Extension
);

$SubjectPublicKeyInfo = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'algorithm' => $AlgorithmIdentifier,
'subjectPublicKey' => array('type' => ASN1::TYPE_BIT_STRING)
)
);

$UniqueIdentifier = array('type' => ASN1::TYPE_BIT_STRING);

$Time = array(
'type' => ASN1::TYPE_CHOICE,
'children' => array(
'utcTime' => array('type' => ASN1::TYPE_UTC_TIME),
'generalTime' => array('type' => ASN1::TYPE_GENERALIZED_TIME)
)
);


 $Validity = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'notBefore' => $Time,
'notAfter' => $Time
)
);

$CertificateSerialNumber = array('type' => ASN1::TYPE_INTEGER);

$Version = array(
'type' => ASN1::TYPE_INTEGER,
'mapping' => array('v1', 'v2', 'v3')
);


 $TBSCertificate = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(

 
 'version' => array(
'constant' => 0,
'optional' => true,
'explicit' => true,
'default' => 'v1'
) + $Version,
'serialNumber' => $CertificateSerialNumber,
'signature' => $AlgorithmIdentifier,
'issuer' => $this->Name,
'validity' => $Validity,
'subject' => $this->Name,
'subjectPublicKeyInfo' => $SubjectPublicKeyInfo,

 'issuerUniqueID' => array(
'constant' => 1,
'optional' => true,
'implicit' => true
) + $UniqueIdentifier,
'subjectUniqueID' => array(
'constant' => 2,
'optional' => true,
'implicit' => true
) + $UniqueIdentifier,

 
 'extensions' => array(
'constant' => 3,
'optional' => true,
'explicit' => true
) + $this->Extensions
)
);

$this->Certificate = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'tbsCertificate' => $TBSCertificate,
'signatureAlgorithm' => $AlgorithmIdentifier,
'signature' => array('type' => ASN1::TYPE_BIT_STRING)
)
);

$this->KeyUsage = array(
'type' => ASN1::TYPE_BIT_STRING,
'mapping' => array(
'digitalSignature',
'nonRepudiation',
'keyEncipherment',
'dataEncipherment',
'keyAgreement',
'keyCertSign',
'cRLSign',
'encipherOnly',
'decipherOnly'
)
);

$this->BasicConstraints = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'cA' => array(
'type' => ASN1::TYPE_BOOLEAN,
'optional' => true,
'default' => false
),
'pathLenConstraint' => array(
'type' => ASN1::TYPE_INTEGER,
'optional' => true
)
)
);

$this->KeyIdentifier = array('type' => ASN1::TYPE_OCTET_STRING);

$OrganizationalUnitNames = array(
'type' => ASN1::TYPE_SEQUENCE,
'min' => 1,
'max' => 4, 
 'children' => array('type' => ASN1::TYPE_PRINTABLE_STRING)
);

$PersonalName = array(
'type' => ASN1::TYPE_SET,
'children' => array(
'surname' => array(
'type' => ASN1::TYPE_PRINTABLE_STRING,
'constant' => 0,
'optional' => true,
'implicit' => true
),
'given-name' => array(
'type' => ASN1::TYPE_PRINTABLE_STRING,
'constant' => 1,
'optional' => true,
'implicit' => true
),
'initials' => array(
'type' => ASN1::TYPE_PRINTABLE_STRING,
'constant' => 2,
'optional' => true,
'implicit' => true
),
'generation-qualifier' => array(
'type' => ASN1::TYPE_PRINTABLE_STRING,
'constant' => 3,
'optional' => true,
'implicit' => true
)
)
);

$NumericUserIdentifier = array('type' => ASN1::TYPE_NUMERIC_STRING);

$OrganizationName = array('type' => ASN1::TYPE_PRINTABLE_STRING);

$PrivateDomainName = array(
'type' => ASN1::TYPE_CHOICE,
'children' => array(
'numeric' => array('type' => ASN1::TYPE_NUMERIC_STRING),
'printable' => array('type' => ASN1::TYPE_PRINTABLE_STRING)
)
);

$TerminalIdentifier = array('type' => ASN1::TYPE_PRINTABLE_STRING);

$NetworkAddress = array('type' => ASN1::TYPE_NUMERIC_STRING);

$AdministrationDomainName = array(
'type' => ASN1::TYPE_CHOICE,

 
 'class' => ASN1::CLASS_APPLICATION,
'cast' => 2,
'children' => array(
'numeric' => array('type' => ASN1::TYPE_NUMERIC_STRING),
'printable' => array('type' => ASN1::TYPE_PRINTABLE_STRING)
)
);

$CountryName = array(
'type' => ASN1::TYPE_CHOICE,

 
 'class' => ASN1::CLASS_APPLICATION,
'cast' => 1,
'children' => array(
'x121-dcc-code' => array('type' => ASN1::TYPE_NUMERIC_STRING),
'iso-3166-alpha2-code' => array('type' => ASN1::TYPE_PRINTABLE_STRING)
)
);

$AnotherName = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'type-id' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER),
'value' => array(
'type' => ASN1::TYPE_ANY,
'constant' => 0,
'optional' => true,
'explicit' => true
)
)
);

$ExtensionAttribute = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'extension-attribute-type' => array(
'type' => ASN1::TYPE_PRINTABLE_STRING,
'constant' => 0,
'optional' => true,
'implicit' => true
),
'extension-attribute-value' => array(
'type' => ASN1::TYPE_ANY,
'constant' => 1,
'optional' => true,
'explicit' => true
)
)
);

$ExtensionAttributes = array(
'type' => ASN1::TYPE_SET,
'min' => 1,
'max' => 256, 
 'children' => $ExtensionAttribute
);

$BuiltInDomainDefinedAttribute = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'type' => array('type' => ASN1::TYPE_PRINTABLE_STRING),
'value' => array('type' => ASN1::TYPE_PRINTABLE_STRING)
)
);

$BuiltInDomainDefinedAttributes = array(
'type' => ASN1::TYPE_SEQUENCE,
'min' => 1,
'max' => 4, 
 'children' => $BuiltInDomainDefinedAttribute
);

$BuiltInStandardAttributes = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'country-name' => array('optional' => true) + $CountryName,
'administration-domain-name' => array('optional' => true) + $AdministrationDomainName,
'network-address' => array(
'constant' => 0,
'optional' => true,
'implicit' => true
) + $NetworkAddress,
'terminal-identifier' => array(
'constant' => 1,
'optional' => true,
'implicit' => true
) + $TerminalIdentifier,
'private-domain-name' => array(
'constant' => 2,
'optional' => true,
'explicit' => true
) + $PrivateDomainName,
'organization-name' => array(
'constant' => 3,
'optional' => true,
'implicit' => true
) + $OrganizationName,
'numeric-user-identifier' => array(
'constant' => 4,
'optional' => true,
'implicit' => true
) + $NumericUserIdentifier,
'personal-name' => array(
'constant' => 5,
'optional' => true,
'implicit' => true
) + $PersonalName,
'organizational-unit-names' => array(
'constant' => 6,
'optional' => true,
'implicit' => true
) + $OrganizationalUnitNames
)
);

$ORAddress = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'built-in-standard-attributes' => $BuiltInStandardAttributes,
'built-in-domain-defined-attributes' => array('optional' => true) + $BuiltInDomainDefinedAttributes,
'extension-attributes' => array('optional' => true) + $ExtensionAttributes
)
);

$EDIPartyName = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'nameAssigner' => array(
'constant' => 0,
'optional' => true,
'implicit' => true
) + $this->DirectoryString,

 
 'partyName' => array(
'constant' => 1,
'optional' => true,
'implicit' => true
) + $this->DirectoryString
)
);

$GeneralName = array(
'type' => ASN1::TYPE_CHOICE,
'children' => array(
'otherName' => array(
'constant' => 0,
'optional' => true,
'implicit' => true
) + $AnotherName,
'rfc822Name' => array(
'type' => ASN1::TYPE_IA5_STRING,
'constant' => 1,
'optional' => true,
'implicit' => true
),
'dNSName' => array(
'type' => ASN1::TYPE_IA5_STRING,
'constant' => 2,
'optional' => true,
'implicit' => true
),
'x400Address' => array(
'constant' => 3,
'optional' => true,
'implicit' => true
) + $ORAddress,
'directoryName' => array(
'constant' => 4,
'optional' => true,
'explicit' => true
) + $this->Name,
'ediPartyName' => array(
'constant' => 5,
'optional' => true,
'implicit' => true
) + $EDIPartyName,
'uniformResourceIdentifier' => array(
'type' => ASN1::TYPE_IA5_STRING,
'constant' => 6,
'optional' => true,
'implicit' => true
),
'iPAddress' => array(
'type' => ASN1::TYPE_OCTET_STRING,
'constant' => 7,
'optional' => true,
'implicit' => true
),
'registeredID' => array(
'type' => ASN1::TYPE_OBJECT_IDENTIFIER,
'constant' => 8,
'optional' => true,
'implicit' => true
)
)
);

$GeneralNames = array(
'type' => ASN1::TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => $GeneralName
);

$this->IssuerAltName = $GeneralNames;

$ReasonFlags = array(
'type' => ASN1::TYPE_BIT_STRING,
'mapping' => array(
'unused',
'keyCompromise',
'cACompromise',
'affiliationChanged',
'superseded',
'cessationOfOperation',
'certificateHold',
'privilegeWithdrawn',
'aACompromise'
)
);

$DistributionPointName = array(
'type' => ASN1::TYPE_CHOICE,
'children' => array(
'fullName' => array(
'constant' => 0,
'optional' => true,
'implicit' => true
) + $GeneralNames,
'nameRelativeToCRLIssuer' => array(
'constant' => 1,
'optional' => true,
'implicit' => true
) + $this->RelativeDistinguishedName
)
);

$DistributionPoint = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'distributionPoint' => array(
'constant' => 0,
'optional' => true,
'explicit' => true
) + $DistributionPointName,
'reasons' => array(
'constant' => 1,
'optional' => true,
'implicit' => true
) + $ReasonFlags,
'cRLIssuer' => array(
'constant' => 2,
'optional' => true,
'implicit' => true
) + $GeneralNames
)
);

$this->CRLDistributionPoints = array(
'type' => ASN1::TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => $DistributionPoint
);

$this->AuthorityKeyIdentifier = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'keyIdentifier' => array(
'constant' => 0,
'optional' => true,
'implicit' => true
) + $this->KeyIdentifier,
'authorityCertIssuer' => array(
'constant' => 1,
'optional' => true,
'implicit' => true
) + $GeneralNames,
'authorityCertSerialNumber' => array(
'constant' => 2,
'optional' => true,
'implicit' => true
) + $CertificateSerialNumber
)
);

$PolicyQualifierId = array('type' => ASN1::TYPE_OBJECT_IDENTIFIER);

$PolicyQualifierInfo = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'policyQualifierId' => $PolicyQualifierId,
'qualifier' => array('type' => ASN1::TYPE_ANY)
)
);

$CertPolicyId = array('type' => ASN1::TYPE_OBJECT_IDENTIFIER);

$PolicyInformation = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'policyIdentifier' => $CertPolicyId,
'policyQualifiers' => array(
'type' => ASN1::TYPE_SEQUENCE,
'min' => 0,
'max' => -1,
'optional' => true,
'children' => $PolicyQualifierInfo
)
)
);

$this->CertificatePolicies = array(
'type' => ASN1::TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => $PolicyInformation
);

$this->PolicyMappings = array(
'type' => ASN1::TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'issuerDomainPolicy' => $CertPolicyId,
'subjectDomainPolicy' => $CertPolicyId
)
)
);

$KeyPurposeId = array('type' => ASN1::TYPE_OBJECT_IDENTIFIER);

$this->ExtKeyUsageSyntax = array(
'type' => ASN1::TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => $KeyPurposeId
);

$AccessDescription = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'accessMethod' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER),
'accessLocation' => $GeneralName
)
);

$this->AuthorityInfoAccessSyntax = array(
'type' => ASN1::TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => $AccessDescription
);

$this->SubjectInfoAccessSyntax = array(
'type' => ASN1::TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => $AccessDescription
);

$this->SubjectAltName = $GeneralNames;

$this->PrivateKeyUsagePeriod = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'notBefore' => array(
'constant' => 0,
'optional' => true,
'implicit' => true,
'type' => ASN1::TYPE_GENERALIZED_TIME),
'notAfter' => array(
'constant' => 1,
'optional' => true,
'implicit' => true,
'type' => ASN1::TYPE_GENERALIZED_TIME)
)
);

$BaseDistance = array('type' => ASN1::TYPE_INTEGER);

$GeneralSubtree = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'base' => $GeneralName,
'minimum' => array(
'constant' => 0,
'optional' => true,
'implicit' => true,
'default' => new BigInteger(0)
) + $BaseDistance,
'maximum' => array(
'constant' => 1,
'optional' => true,
'implicit' => true,
) + $BaseDistance
)
);

$GeneralSubtrees = array(
'type' => ASN1::TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => $GeneralSubtree
);

$this->NameConstraints = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'permittedSubtrees' => array(
'constant' => 0,
'optional' => true,
'implicit' => true
) + $GeneralSubtrees,
'excludedSubtrees' => array(
'constant' => 1,
'optional' => true,
'implicit' => true
) + $GeneralSubtrees
)
);

$this->CPSuri = array('type' => ASN1::TYPE_IA5_STRING);

$DisplayText = array(
'type' => ASN1::TYPE_CHOICE,
'children' => array(
'ia5String' => array('type' => ASN1::TYPE_IA5_STRING),
'visibleString' => array('type' => ASN1::TYPE_VISIBLE_STRING),
'bmpString' => array('type' => ASN1::TYPE_BMP_STRING),
'utf8String' => array('type' => ASN1::TYPE_UTF8_STRING)
)
);

$NoticeReference = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'organization' => $DisplayText,
'noticeNumbers' => array(
'type' => ASN1::TYPE_SEQUENCE,
'min' => 1,
'max' => 200,
'children' => array('type' => ASN1::TYPE_INTEGER)
)
)
);

$this->UserNotice = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'noticeRef' => array(
'optional' => true,
'implicit' => true
) + $NoticeReference,
'explicitText' => array(
'optional' => true,
'implicit' => true
) + $DisplayText
)
);


 $this->netscape_cert_type = array(
'type' => ASN1::TYPE_BIT_STRING,
'mapping' => array(
'SSLClient',
'SSLServer',
'Email',
'ObjectSigning',
'Reserved',
'SSLCA',
'EmailCA',
'ObjectSigningCA'
)
);

$this->netscape_comment = array('type' => ASN1::TYPE_IA5_STRING);
$this->netscape_ca_policy_url = array('type' => ASN1::TYPE_IA5_STRING);



$Attribute = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'type' => $AttributeType,
'value'=> array(
'type' => ASN1::TYPE_SET,
'min' => 1,
'max' => -1,
'children' => $this->AttributeValue
)
)
);

$this->SubjectDirectoryAttributes = array(
'type' => ASN1::TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => $Attribute
);



$Attributes = array(
'type' => ASN1::TYPE_SET,
'min' => 1,
'max' => -1,
'children' => $Attribute
);

$CertificationRequestInfo = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'version' => array(
'type' => ASN1::TYPE_INTEGER,
'mapping' => array('v1')
),
'subject' => $this->Name,
'subjectPKInfo' => $SubjectPublicKeyInfo,
'attributes' => array(
'constant' => 0,
'optional' => true,
'implicit' => true
) + $Attributes,
)
);

$this->CertificationRequest = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'certificationRequestInfo' => $CertificationRequestInfo,
'signatureAlgorithm' => $AlgorithmIdentifier,
'signature' => array('type' => ASN1::TYPE_BIT_STRING)
)
);

$RevokedCertificate = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'userCertificate' => $CertificateSerialNumber,
'revocationDate' => $Time,
'crlEntryExtensions' => array(
'optional' => true
) + $this->Extensions
)
);

$TBSCertList = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'version' => array(
'optional' => true,
'default' => 'v1'
) + $Version,
'signature' => $AlgorithmIdentifier,
'issuer' => $this->Name,
'thisUpdate' => $Time,
'nextUpdate' => array(
'optional' => true
) + $Time,
'revokedCertificates' => array(
'type' => ASN1::TYPE_SEQUENCE,
'optional' => true,
'min' => 0,
'max' => -1,
'children' => $RevokedCertificate
),
'crlExtensions' => array(
'constant' => 0,
'optional' => true,
'explicit' => true
) + $this->Extensions
)
);

$this->CertificateList = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'tbsCertList' => $TBSCertList,
'signatureAlgorithm' => $AlgorithmIdentifier,
'signature' => array('type' => ASN1::TYPE_BIT_STRING)
)
);

$this->CRLNumber = array('type' => ASN1::TYPE_INTEGER);

$this->CRLReason = array('type' => ASN1::TYPE_ENUMERATED,
'mapping' => array(
'unspecified',
'keyCompromise',
'cACompromise',
'affiliationChanged',
'superseded',
'cessationOfOperation',
'certificateHold',

 8 => 'removeFromCRL',
'privilegeWithdrawn',
'aACompromise'
)
);

$this->IssuingDistributionPoint = array('type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'distributionPoint' => array(
'constant' => 0,
'optional' => true,
'explicit' => true
) + $DistributionPointName,
'onlyContainsUserCerts' => array(
'type' => ASN1::TYPE_BOOLEAN,
'constant' => 1,
'optional' => true,
'default' => false,
'implicit' => true
),
'onlyContainsCACerts' => array(
'type' => ASN1::TYPE_BOOLEAN,
'constant' => 2,
'optional' => true,
'default' => false,
'implicit' => true
),
'onlySomeReasons' => array(
'constant' => 3,
'optional' => true,
'implicit' => true
) + $ReasonFlags,
'indirectCRL' => array(
'type' => ASN1::TYPE_BOOLEAN,
'constant' => 4,
'optional' => true,
'default' => false,
'implicit' => true
),
'onlyContainsAttributeCerts' => array(
'type' => ASN1::TYPE_BOOLEAN,
'constant' => 5,
'optional' => true,
'default' => false,
'implicit' => true
)
)
);

$this->InvalidityDate = array('type' => ASN1::TYPE_GENERALIZED_TIME);

$this->CertificateIssuer = $GeneralNames;

$this->HoldInstructionCode = array('type' => ASN1::TYPE_OBJECT_IDENTIFIER);

$PublicKeyAndChallenge = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'spki' => $SubjectPublicKeyInfo,
'challenge' => array('type' => ASN1::TYPE_IA5_STRING)
)
);

$this->SignedPublicKeyAndChallenge = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'publicKeyAndChallenge' => $PublicKeyAndChallenge,
'signatureAlgorithm' => $AlgorithmIdentifier,
'signature' => array('type' => ASN1::TYPE_BIT_STRING)
)
);

$this->PostalAddress = array(
'type' => ASN1::TYPE_SEQUENCE,
'optional' => true,
'min' => 1,
'max' => -1,
'children' => $this->DirectoryString
);


 $this->oids = array(
'1.3.6.1.5.5.7' => 'id-pkix',
'1.3.6.1.5.5.7.1' => 'id-pe',
'1.3.6.1.5.5.7.2' => 'id-qt',
'1.3.6.1.5.5.7.3' => 'id-kp',
'1.3.6.1.5.5.7.48' => 'id-ad',
'1.3.6.1.5.5.7.2.1' => 'id-qt-cps',
'1.3.6.1.5.5.7.2.2' => 'id-qt-unotice',
'1.3.6.1.5.5.7.48.1' =>'id-ad-ocsp',
'1.3.6.1.5.5.7.48.2' => 'id-ad-caIssuers',
'1.3.6.1.5.5.7.48.3' => 'id-ad-timeStamping',
'1.3.6.1.5.5.7.48.5' => 'id-ad-caRepository',
'2.5.4' => 'id-at',
'2.5.4.41' => 'id-at-name',
'2.5.4.4' => 'id-at-surname',
'2.5.4.42' => 'id-at-givenName',
'2.5.4.43' => 'id-at-initials',
'2.5.4.44' => 'id-at-generationQualifier',
'2.5.4.3' => 'id-at-commonName',
'2.5.4.7' => 'id-at-localityName',
'2.5.4.8' => 'id-at-stateOrProvinceName',
'2.5.4.10' => 'id-at-organizationName',
'2.5.4.11' => 'id-at-organizationalUnitName',
'2.5.4.12' => 'id-at-title',
'2.5.4.13' => 'id-at-description',
'2.5.4.46' => 'id-at-dnQualifier',
'2.5.4.6' => 'id-at-countryName',
'2.5.4.5' => 'id-at-serialNumber',
'2.5.4.65' => 'id-at-pseudonym',
'2.5.4.17' => 'id-at-postalCode',
'2.5.4.9' => 'id-at-streetAddress',
'2.5.4.45' => 'id-at-uniqueIdentifier',
'2.5.4.72' => 'id-at-role',
'2.5.4.16' => 'id-at-postalAddress',

'0.9.2342.19200300.100.1.25' => 'id-domainComponent',
'1.2.840.113549.1.9' => 'pkcs-9',
'1.2.840.113549.1.9.1' => 'pkcs-9-at-emailAddress',
'2.5.29' => 'id-ce',
'2.5.29.35' => 'id-ce-authorityKeyIdentifier',
'2.5.29.14' => 'id-ce-subjectKeyIdentifier',
'2.5.29.15' => 'id-ce-keyUsage',
'2.5.29.16' => 'id-ce-privateKeyUsagePeriod',
'2.5.29.32' => 'id-ce-certificatePolicies',
'2.5.29.32.0' => 'anyPolicy',

'2.5.29.33' => 'id-ce-policyMappings',
'2.5.29.17' => 'id-ce-subjectAltName',
'2.5.29.18' => 'id-ce-issuerAltName',
'2.5.29.9' => 'id-ce-subjectDirectoryAttributes',
'2.5.29.19' => 'id-ce-basicConstraints',
'2.5.29.30' => 'id-ce-nameConstraints',
'2.5.29.36' => 'id-ce-policyConstraints',
'2.5.29.31' => 'id-ce-cRLDistributionPoints',
'2.5.29.37' => 'id-ce-extKeyUsage',
'2.5.29.37.0' => 'anyExtendedKeyUsage',
'1.3.6.1.5.5.7.3.1' => 'id-kp-serverAuth',
'1.3.6.1.5.5.7.3.2' => 'id-kp-clientAuth',
'1.3.6.1.5.5.7.3.3' => 'id-kp-codeSigning',
'1.3.6.1.5.5.7.3.4' => 'id-kp-emailProtection',
'1.3.6.1.5.5.7.3.8' => 'id-kp-timeStamping',
'1.3.6.1.5.5.7.3.9' => 'id-kp-OCSPSigning',
'2.5.29.54' => 'id-ce-inhibitAnyPolicy',
'2.5.29.46' => 'id-ce-freshestCRL',
'1.3.6.1.5.5.7.1.1' => 'id-pe-authorityInfoAccess',
'1.3.6.1.5.5.7.1.11' => 'id-pe-subjectInfoAccess',
'2.5.29.20' => 'id-ce-cRLNumber',
'2.5.29.28' => 'id-ce-issuingDistributionPoint',
'2.5.29.27' => 'id-ce-deltaCRLIndicator',
'2.5.29.21' => 'id-ce-cRLReasons',
'2.5.29.29' => 'id-ce-certificateIssuer',
'2.5.29.23' => 'id-ce-holdInstructionCode',
'1.2.840.10040.2' => 'holdInstruction',
'1.2.840.10040.2.1' => 'id-holdinstruction-none',
'1.2.840.10040.2.2' => 'id-holdinstruction-callissuer',
'1.2.840.10040.2.3' => 'id-holdinstruction-reject',
'2.5.29.24' => 'id-ce-invalidityDate',

'1.2.840.113549.2.2' => 'md2',
'1.2.840.113549.2.5' => 'md5',
'1.3.14.3.2.26' => 'id-sha1',
'1.2.840.10040.4.1' => 'id-dsa',
'1.2.840.10040.4.3' => 'id-dsa-with-sha1',
'1.2.840.113549.1.1' => 'pkcs-1',
'1.2.840.113549.1.1.1' => 'rsaEncryption',
'1.2.840.113549.1.1.2' => 'md2WithRSAEncryption',
'1.2.840.113549.1.1.4' => 'md5WithRSAEncryption',
'1.2.840.113549.1.1.5' => 'sha1WithRSAEncryption',
'1.2.840.10046.2.1' => 'dhpublicnumber',
'2.16.840.1.101.2.1.1.22' => 'id-keyExchangeAlgorithm',
'1.2.840.10045' => 'ansi-X9-62',
'1.2.840.10045.4' => 'id-ecSigType',
'1.2.840.10045.4.1' => 'ecdsa-with-SHA1',
'1.2.840.10045.1' => 'id-fieldType',
'1.2.840.10045.1.1' => 'prime-field',
'1.2.840.10045.1.2' => 'characteristic-two-field',
'1.2.840.10045.1.2.3' => 'id-characteristic-two-basis',
'1.2.840.10045.1.2.3.1' => 'gnBasis',
'1.2.840.10045.1.2.3.2' => 'tpBasis',
'1.2.840.10045.1.2.3.3' => 'ppBasis',
'1.2.840.10045.2' => 'id-publicKeyType',
'1.2.840.10045.2.1' => 'id-ecPublicKey',
'1.2.840.10045.3' => 'ellipticCurve',
'1.2.840.10045.3.0' => 'c-TwoCurve',
'1.2.840.10045.3.0.1' => 'c2pnb163v1',
'1.2.840.10045.3.0.2' => 'c2pnb163v2',
'1.2.840.10045.3.0.3' => 'c2pnb163v3',
'1.2.840.10045.3.0.4' => 'c2pnb176w1',
'1.2.840.10045.3.0.5' => 'c2pnb191v1',
'1.2.840.10045.3.0.6' => 'c2pnb191v2',
'1.2.840.10045.3.0.7' => 'c2pnb191v3',
'1.2.840.10045.3.0.8' => 'c2pnb191v4',
'1.2.840.10045.3.0.9' => 'c2pnb191v5',
'1.2.840.10045.3.0.10' => 'c2pnb208w1',
'1.2.840.10045.3.0.11' => 'c2pnb239v1',
'1.2.840.10045.3.0.12' => 'c2pnb239v2',
'1.2.840.10045.3.0.13' => 'c2pnb239v3',
'1.2.840.10045.3.0.14' => 'c2pnb239v4',
'1.2.840.10045.3.0.15' => 'c2pnb239v5',
'1.2.840.10045.3.0.16' => 'c2pnb272w1',
'1.2.840.10045.3.0.17' => 'c2pnb304w1',
'1.2.840.10045.3.0.18' => 'c2pnb359v1',
'1.2.840.10045.3.0.19' => 'c2pnb368w1',
'1.2.840.10045.3.0.20' => 'c2pnb431r1',
'1.2.840.10045.3.1' => 'primeCurve',
'1.2.840.10045.3.1.1' => 'prime192v1',
'1.2.840.10045.3.1.2' => 'prime192v2',
'1.2.840.10045.3.1.3' => 'prime192v3',
'1.2.840.10045.3.1.4' => 'prime239v1',
'1.2.840.10045.3.1.5' => 'prime239v2',
'1.2.840.10045.3.1.6' => 'prime239v3',
'1.2.840.10045.3.1.7' => 'prime256v1',
'1.2.840.113549.1.1.7' => 'id-RSAES-OAEP',
'1.2.840.113549.1.1.9' => 'id-pSpecified',
'1.2.840.113549.1.1.10' => 'id-RSASSA-PSS',
'1.2.840.113549.1.1.8' => 'id-mgf1',
'1.2.840.113549.1.1.14' => 'sha224WithRSAEncryption',
'1.2.840.113549.1.1.11' => 'sha256WithRSAEncryption',
'1.2.840.113549.1.1.12' => 'sha384WithRSAEncryption',
'1.2.840.113549.1.1.13' => 'sha512WithRSAEncryption',
'2.16.840.1.101.3.4.2.4' => 'id-sha224',
'2.16.840.1.101.3.4.2.1' => 'id-sha256',
'2.16.840.1.101.3.4.2.2' => 'id-sha384',
'2.16.840.1.101.3.4.2.3' => 'id-sha512',
'1.2.643.2.2.4' => 'id-GostR3411-94-with-GostR3410-94',
'1.2.643.2.2.3' => 'id-GostR3411-94-with-GostR3410-2001',
'1.2.643.2.2.20' => 'id-GostR3410-2001',
'1.2.643.2.2.19' => 'id-GostR3410-94',

 '2.16.840.1.113730' => 'netscape',
'2.16.840.1.113730.1' => 'netscape-cert-extension',
'2.16.840.1.113730.1.1' => 'netscape-cert-type',
'2.16.840.1.113730.1.13' => 'netscape-comment',
'2.16.840.1.113730.1.8' => 'netscape-ca-policy-url',

 '1.3.6.1.5.5.7.1.12' => 'id-pe-logotype',
'1.2.840.113533.7.65.0' => 'entrustVersInfo',
'2.16.840.1.113733.1.6.9' => 'verisignPrivate',

 
 '1.2.840.113549.1.9.2' => 'pkcs-9-at-unstructuredName', 
 '1.2.840.113549.1.9.7' => 'pkcs-9-at-challengePassword', 
 '1.2.840.113549.1.9.14' => 'pkcs-9-at-extensionRequest' 
 );
}











function loadX509($cert, $mode = self::FORMAT_AUTO_DETECT)
{
if (is_array($cert) && isset($cert['tbsCertificate'])) {
unset($this->currentCert);
unset($this->currentKeyIdentifier);
$this->dn = $cert['tbsCertificate']['subject'];
if (!isset($this->dn)) {
return false;
}
$this->currentCert = $cert;

$currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
$this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null;

unset($this->signatureSubject);

return $cert;
}

$asn1 = new ASN1();

if ($mode != self::FORMAT_DER) {
$newcert = $this->_extractBER($cert);
if ($mode == self::FORMAT_PEM && $cert == $newcert) {
return false;
}
$cert = $newcert;
}

if ($cert === false) {
$this->currentCert = false;
return false;
}

$asn1->loadOIDs($this->oids);
$decoded = $asn1->decodeBER($cert);

if (!empty($decoded)) {
$x509 = $asn1->asn1map($decoded[0], $this->Certificate);
}
if (!isset($x509) || $x509 === false) {
$this->currentCert = false;
return false;
}

$this->signatureSubject = substr($cert, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);

if ($this->_isSubArrayValid($x509, 'tbsCertificate/extensions')) {
$this->_mapInExtensions($x509, 'tbsCertificate/extensions', $asn1);
}
$this->_mapInDNs($x509, 'tbsCertificate/issuer/rdnSequence', $asn1);
$this->_mapInDNs($x509, 'tbsCertificate/subject/rdnSequence', $asn1);

$key = &$x509['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'];
$key = $this->_reformatKey($x509['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $key);

$this->currentCert = $x509;
$this->dn = $x509['tbsCertificate']['subject'];

$currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
$this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null;

return $x509;
}









function saveX509($cert, $format = self::FORMAT_PEM)
{
if (!is_array($cert) || !isset($cert['tbsCertificate'])) {
return false;
}

switch (true) {

 case !($algorithm = $this->_subArray($cert, 'tbsCertificate/subjectPublicKeyInfo/algorithm/algorithm')):
case is_object($cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
break;
default:
switch ($algorithm) {
case 'rsaEncryption':
$cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']
= base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'])));






$cert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = null;

 $cert['signatureAlgorithm']['parameters'] = null;
$cert['tbsCertificate']['signature']['parameters'] = null;
}
}

$asn1 = new ASN1();
$asn1->loadOIDs($this->oids);

$filters = array();
$type_utf8_string = array('type' => ASN1::TYPE_UTF8_STRING);
$filters['tbsCertificate']['signature']['parameters'] = $type_utf8_string;
$filters['tbsCertificate']['signature']['issuer']['rdnSequence']['value'] = $type_utf8_string;
$filters['tbsCertificate']['issuer']['rdnSequence']['value'] = $type_utf8_string;
$filters['tbsCertificate']['subject']['rdnSequence']['value'] = $type_utf8_string;
$filters['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = $type_utf8_string;
$filters['signatureAlgorithm']['parameters'] = $type_utf8_string;
$filters['authorityCertIssuer']['directoryName']['rdnSequence']['value'] = $type_utf8_string;

 $filters['distributionPoint']['fullName']['directoryName']['rdnSequence']['value'] = $type_utf8_string;
$filters['directoryName']['rdnSequence']['value'] = $type_utf8_string;





$filters['policyQualifiers']['qualifier']
= array('type' => ASN1::TYPE_IA5_STRING);

$asn1->loadFilters($filters);

$this->_mapOutExtensions($cert, 'tbsCertificate/extensions', $asn1);
$this->_mapOutDNs($cert, 'tbsCertificate/issuer/rdnSequence', $asn1);
$this->_mapOutDNs($cert, 'tbsCertificate/subject/rdnSequence', $asn1);

$cert = $asn1->encodeDER($cert, $this->Certificate);

switch ($format) {
case self::FORMAT_DER:
return $cert;

 default:
return "-----BEGIN CERTIFICATE-----\r\n" . chunk_split(base64_encode($cert), 64) . '-----END CERTIFICATE-----';
}
}










function _mapInExtensions(&$root, $path, $asn1)
{
$extensions = &$this->_subArrayUnchecked($root, $path);

if ($extensions) {
for ($i = 0; $i < count($extensions); $i++) {
$id = $extensions[$i]['extnId'];
$value = &$extensions[$i]['extnValue'];
$value = base64_decode($value);


$map = $this->_getMapping($id);
if (!is_bool($map)) {
$decoder = $id == 'id-ce-nameConstraints' ?
array($this, '_decodeNameConstraintIP') :
array($this, '_decodeIP');
$decoded = $asn1->decodeBER($value);
$mapped = $asn1->asn1map($decoded[0], $map, array('iPAddress' => $decoder));
$value = $mapped === false ? $decoded[0] : $mapped;

if ($id == 'id-ce-certificatePolicies') {
for ($j = 0; $j < count($value); $j++) {
if (!isset($value[$j]['policyQualifiers'])) {
continue;
}
for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
$subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
$map = $this->_getMapping($subid);
$subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
if ($map !== false) {
$decoded = $asn1->decodeBER($subvalue);
$mapped = $asn1->asn1map($decoded[0], $map);
$subvalue = $mapped === false ? $decoded[0] : $mapped;
}
}
}
}
} else {
$value = base64_encode($value);
}
}
}
}










function _mapOutExtensions(&$root, $path, $asn1)
{
$extensions = &$this->_subArray($root, $path);

if (is_array($extensions)) {
$size = count($extensions);
for ($i = 0; $i < $size; $i++) {
if ($extensions[$i] instanceof Element) {
continue;
}

$id = $extensions[$i]['extnId'];
$value = &$extensions[$i]['extnValue'];

switch ($id) {
case 'id-ce-certificatePolicies':
for ($j = 0; $j < count($value); $j++) {
if (!isset($value[$j]['policyQualifiers'])) {
continue;
}
for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
$subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
$map = $this->_getMapping($subid);
$subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
if ($map !== false) {

 
 $subvalue = new Element($asn1->encodeDER($subvalue, $map));
}
}
}
break;
case 'id-ce-authorityKeyIdentifier': 
 if (isset($value['authorityCertSerialNumber'])) {
if ($value['authorityCertSerialNumber']->toBytes() == '') {
$temp = chr((ASN1::CLASS_CONTEXT_SPECIFIC << 6) | 2) . "\1\0";
$value['authorityCertSerialNumber'] = new Element($temp);
}
}
}



$map = $this->_getMapping($id);
if (is_bool($map)) {
if (!$map) {
user_error($id . ' is not a currently supported extension');
unset($extensions[$i]);
}
} else {
$temp = $asn1->encodeDER($value, $map, array('iPAddress' => array($this, '_encodeIP')));
$value = base64_encode($temp);
}
}
}
}










function _mapInAttributes(&$root, $path, $asn1)
{
$attributes = &$this->_subArray($root, $path);

if (is_array($attributes)) {
for ($i = 0; $i < count($attributes); $i++) {
$id = $attributes[$i]['type'];


$map = $this->_getMapping($id);
if (is_array($attributes[$i]['value'])) {
$values = &$attributes[$i]['value'];
for ($j = 0; $j < count($values); $j++) {
$value = $asn1->encodeDER($values[$j], $this->AttributeValue);
$decoded = $asn1->decodeBER($value);
if (!is_bool($map)) {
$mapped = $asn1->asn1map($decoded[0], $map);
if ($mapped !== false) {
$values[$j] = $mapped;
}
if ($id == 'pkcs-9-at-extensionRequest' && $this->_isSubArrayValid($values, $j)) {
$this->_mapInExtensions($values, $j, $asn1);
}
} elseif ($map) {
$values[$j] = base64_encode($value);
}
}
}
}
}
}










function _mapOutAttributes(&$root, $path, $asn1)
{
$attributes = &$this->_subArray($root, $path);

if (is_array($attributes)) {
$size = count($attributes);
for ($i = 0; $i < $size; $i++) {


$id = $attributes[$i]['type'];
$map = $this->_getMapping($id);
if ($map === false) {
user_error($id . ' is not a currently supported attribute', E_USER_NOTICE);
unset($attributes[$i]);
} elseif (is_array($attributes[$i]['value'])) {
$values = &$attributes[$i]['value'];
for ($j = 0; $j < count($values); $j++) {
switch ($id) {
case 'pkcs-9-at-extensionRequest':
$this->_mapOutExtensions($values, $j, $asn1);
break;
}

if (!is_bool($map)) {
$temp = $asn1->encodeDER($values[$j], $map);
$decoded = $asn1->decodeBER($temp);
$values[$j] = $asn1->asn1map($decoded[0], $this->AttributeValue);
}
}
}
}
}
}










function _mapInDNs(&$root, $path, $asn1)
{
$dns = &$this->_subArray($root, $path);

if (is_array($dns)) {
for ($i = 0; $i < count($dns); $i++) {
for ($j = 0; $j < count($dns[$i]); $j++) {
$type = $dns[$i][$j]['type'];
$value = &$dns[$i][$j]['value'];
if (is_object($value) && $value instanceof Element) {
$map = $this->_getMapping($type);
if (!is_bool($map)) {
$decoded = $asn1->decodeBER($value);
$value = $asn1->asn1map($decoded[0], $map);
}
}
}
}
}
}










function _mapOutDNs(&$root, $path, $asn1)
{
$dns = &$this->_subArray($root, $path);

if (is_array($dns)) {
$size = count($dns);
for ($i = 0; $i < $size; $i++) {
for ($j = 0; $j < count($dns[$i]); $j++) {
$type = $dns[$i][$j]['type'];
$value = &$dns[$i][$j]['value'];
if (is_object($value) && $value instanceof Element) {
continue;
}

$map = $this->_getMapping($type);
if (!is_bool($map)) {
$value = new Element($asn1->encodeDER($value, $map));
}
}
}
}
}








function _getMapping($extnId)
{
if (!is_string($extnId)) { 
 return true;
}

switch ($extnId) {
case 'id-ce-keyUsage':
return $this->KeyUsage;
case 'id-ce-basicConstraints':
return $this->BasicConstraints;
case 'id-ce-subjectKeyIdentifier':
return $this->KeyIdentifier;
case 'id-ce-cRLDistributionPoints':
return $this->CRLDistributionPoints;
case 'id-ce-authorityKeyIdentifier':
return $this->AuthorityKeyIdentifier;
case 'id-ce-certificatePolicies':
return $this->CertificatePolicies;
case 'id-ce-extKeyUsage':
return $this->ExtKeyUsageSyntax;
case 'id-pe-authorityInfoAccess':
return $this->AuthorityInfoAccessSyntax;
case 'id-pe-subjectInfoAccess':
return $this->SubjectInfoAccessSyntax;
case 'id-ce-subjectAltName':
return $this->SubjectAltName;
case 'id-ce-subjectDirectoryAttributes':
return $this->SubjectDirectoryAttributes;
case 'id-ce-privateKeyUsagePeriod':
return $this->PrivateKeyUsagePeriod;
case 'id-ce-issuerAltName':
return $this->IssuerAltName;
case 'id-ce-policyMappings':
return $this->PolicyMappings;
case 'id-ce-nameConstraints':
return $this->NameConstraints;

case 'netscape-cert-type':
return $this->netscape_cert_type;
case 'netscape-comment':
return $this->netscape_comment;
case 'netscape-ca-policy-url':
return $this->netscape_ca_policy_url;


 
 
 
 case 'id-qt-unotice':
return $this->UserNotice;


 case 'id-pe-logotype': 
 case 'entrustVersInfo':

 case '1.3.6.1.4.1.311.20.2': 
 case '1.3.6.1.4.1.311.21.1': 
 
 
 case '2.23.42.7.0': 
 
 
 case '1.3.6.1.4.1.11129.2.4.2':

 
 case '1.3.6.1.5.5.7.1.3':
return true;


 case 'pkcs-9-at-unstructuredName':
return $this->PKCS9String;
case 'pkcs-9-at-challengePassword':
return $this->DirectoryString;
case 'pkcs-9-at-extensionRequest':
return $this->Extensions;


 case 'id-ce-cRLNumber':
return $this->CRLNumber;
case 'id-ce-deltaCRLIndicator':
return $this->CRLNumber;
case 'id-ce-issuingDistributionPoint':
return $this->IssuingDistributionPoint;
case 'id-ce-freshestCRL':
return $this->CRLDistributionPoints;
case 'id-ce-cRLReasons':
return $this->CRLReason;
case 'id-ce-invalidityDate':
return $this->InvalidityDate;
case 'id-ce-certificateIssuer':
return $this->CertificateIssuer;
case 'id-ce-holdInstructionCode':
return $this->HoldInstructionCode;
case 'id-at-postalAddress':
return $this->PostalAddress;
}

return false;
}








function loadCA($cert)
{
$olddn = $this->dn;
$oldcert = $this->currentCert;
$oldsigsubj = $this->signatureSubject;
$oldkeyid = $this->currentKeyIdentifier;

$cert = $this->loadX509($cert);
if (!$cert) {
$this->dn = $olddn;
$this->currentCert = $oldcert;
$this->signatureSubject = $oldsigsubj;
$this->currentKeyIdentifier = $oldkeyid;

return false;
}







 
 
 











 
 
 

$this->CAs[] = $cert;

$this->dn = $olddn;
$this->currentCert = $oldcert;
$this->signatureSubject = $oldsigsubj;

return true;
}


















function validateURL($url)
{
if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
return false;
}

$components = parse_url($url);
if (!isset($components['host'])) {
return false;
}

if ($names = $this->getExtension('id-ce-subjectAltName')) {
foreach ($names as $name) {
foreach ($name as $key => $value) {
$value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value);
switch ($key) {
case 'dNSName':







if (preg_match('#^' . $value . '$#', $components['host'])) {
return true;
}
break;
case 'iPAddress':





if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) {
return true;
}
}
}
}
return false;
}

if ($value = $this->getDNProp('id-at-commonName')) {
$value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value[0]);
return preg_match('#^' . $value . '$#', $components['host']);
}

return false;
}









function validateDate($date = null)
{
if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
return false;
}

if (!isset($date)) {
$date = new DateTime(null, new DateTimeZone(@date_default_timezone_get()));
}

$notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore'];
$notBefore = isset($notBefore['generalTime']) ? $notBefore['generalTime'] : $notBefore['utcTime'];

$notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter'];
$notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime'];

if (is_string($date)) {
$date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
}

$notBefore = new DateTime($notBefore, new DateTimeZone(@date_default_timezone_get()));
$notAfter = new DateTime($notAfter, new DateTimeZone(@date_default_timezone_get()));

switch (true) {
case $date < $notBefore:
case $date > $notAfter:
return false;
}

return true;
}








static function _fetchURL($url)
{
if (self::$disable_url_fetch) {
return false;
}

$parts = parse_url($url);
$data = '';
switch ($parts['scheme']) {
case 'http':
$fsock = @fsockopen($parts['host'], isset($parts['port']) ? $parts['port'] : 80);
if (!$fsock) {
return false;
}
fputs($fsock, "GET $parts[path] HTTP/1.0\r\n");
fputs($fsock, "Host: $parts[host]\r\n\r\n");
$line = fgets($fsock, 1024);
if (strlen($line) < 3) {
return false;
}
preg_match('#HTTP/1.\d (\d{3})#', $line, $temp);
if ($temp[1] != '200') {
return false;
}


 while (!feof($fsock) && fgets($fsock, 1024) != "\r\n") {
}

while (!feof($fsock)) {
$temp = fread($fsock, 1024);
if ($temp === false) {
return false;
}
$data.= $temp;
}

break;

 
 
 }

return $data;
}











function _testForIntermediate($caonly, $count)
{
$opts = $this->getExtension('id-pe-authorityInfoAccess');
if (!is_array($opts)) {
return false;
}
foreach ($opts as $opt) {
if ($opt['accessMethod'] == 'id-ad-caIssuers') {

 
 
 if (isset($opt['accessLocation']['uniformResourceIdentifier'])) {
$url = $opt['accessLocation']['uniformResourceIdentifier'];
break;
}
}
}

if (!isset($url)) {
return false;
}

$cert = static::_fetchURL($url);
if (!is_string($cert)) {
return false;
}

$parent = new static();
$parent->CAs = $this->CAs;









if (!is_array($parent->loadX509($cert))) {
return false;
}

if (!$parent->_validateSignatureCountable($caonly, ++$count)) {
return false;
}

$this->CAs[] = $parent->currentCert;


return true;
}
















function validateSignature($caonly = true)
{
return $this->_validateSignatureCountable($caonly, 0);
}











function _validateSignatureCountable($caonly, $count)
{
if (!is_array($this->currentCert) || !isset($this->signatureSubject)) {
return null;
}

if ($count == self::$recur_limit) {
return false;
}







switch (true) {
case isset($this->currentCert['tbsCertificate']):

 switch (true) {
case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $this->currentCert['tbsCertificate']['subject']:
case defined('FILE_X509_IGNORE_TYPE') && $this->getIssuerDN(self::DN_STRING) === $this->getDN(self::DN_STRING):
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier');
switch (true) {
case !is_array($authorityKey):
case !$subjectKeyID:
case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
$signingCert = $this->currentCert; 
 }
}

if (!empty($this->CAs)) {
for ($i = 0; $i < count($this->CAs); $i++) {

 
 $ca = $this->CAs[$i];
switch (true) {
case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']:
case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(self::DN_STRING, $this->currentCert['tbsCertificate']['issuer']) === $this->getDN(self::DN_STRING, $ca['tbsCertificate']['subject']):
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
switch (true) {
case !is_array($authorityKey):
case !$subjectKeyID:
case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
if (is_array($authorityKey) && isset($authorityKey['authorityCertSerialNumber']) && !$authorityKey['authorityCertSerialNumber']->equals($ca['tbsCertificate']['serialNumber'])) {
break 2; 
 }
$signingCert = $ca; 
 break 3;
}
}
}
if (count($this->CAs) == $i && $caonly) {
return $this->_testForIntermediate($caonly, $count) && $this->validateSignature($caonly);
}
} elseif (!isset($signingCert) || $caonly) {
return $this->_testForIntermediate($caonly, $count) && $this->validateSignature($caonly);
}
return $this->_validateSignature(
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
$this->currentCert['signatureAlgorithm']['algorithm'],
substr(base64_decode($this->currentCert['signature']), 1),
$this->signatureSubject
);
case isset($this->currentCert['certificationRequestInfo']):
return $this->_validateSignature(
$this->currentCert['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'],
$this->currentCert['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'],
$this->currentCert['signatureAlgorithm']['algorithm'],
substr(base64_decode($this->currentCert['signature']), 1),
$this->signatureSubject
);
case isset($this->currentCert['publicKeyAndChallenge']):
return $this->_validateSignature(
$this->currentCert['publicKeyAndChallenge']['spki']['algorithm']['algorithm'],
$this->currentCert['publicKeyAndChallenge']['spki']['subjectPublicKey'],
$this->currentCert['signatureAlgorithm']['algorithm'],
substr(base64_decode($this->currentCert['signature']), 1),
$this->signatureSubject
);
case isset($this->currentCert['tbsCertList']):
if (!empty($this->CAs)) {
for ($i = 0; $i < count($this->CAs); $i++) {
$ca = $this->CAs[$i];
switch (true) {
case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertList']['issuer'] === $ca['tbsCertificate']['subject']:
case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(self::DN_STRING, $this->currentCert['tbsCertList']['issuer']) === $this->getDN(self::DN_STRING, $ca['tbsCertificate']['subject']):
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
switch (true) {
case !is_array($authorityKey):
case !$subjectKeyID:
case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
if (is_array($authorityKey) && isset($authorityKey['authorityCertSerialNumber']) && !$authorityKey['authorityCertSerialNumber']->equals($ca['tbsCertificate']['serialNumber'])) {
break 2; 
 }
$signingCert = $ca; 
 break 3;
}
}
}
}
if (!isset($signingCert)) {
return false;
}
return $this->_validateSignature(
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
$this->currentCert['signatureAlgorithm']['algorithm'],
substr(base64_decode($this->currentCert['signature']), 1),
$this->signatureSubject
);
default:
return false;
}
}














function _validateSignature($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject)
{
switch ($publicKeyAlgorithm) {
case 'rsaEncryption':
$rsa = new RSA();
$rsa->loadKey($publicKey);

switch ($signatureAlgorithm) {
case 'md2WithRSAEncryption':
case 'md5WithRSAEncryption':
case 'sha1WithRSAEncryption':
case 'sha224WithRSAEncryption':
case 'sha256WithRSAEncryption':
case 'sha384WithRSAEncryption':
case 'sha512WithRSAEncryption':
$rsa->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
$rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
if (!@$rsa->verify($signatureSubject, $signature)) {
return false;
}
break;
default:
return null;
}
break;
default:
return null;
}

return true;
}











static function setRecurLimit($count)
{
self::$recur_limit = $count;
}






static function disableURLFetch()
{
self::$disable_url_fetch = true;
}






static function enableURLFetch()
{
self::$disable_url_fetch = false;
}











function _reformatKey($algorithm, $key)
{
switch ($algorithm) {
case 'rsaEncryption':
return
"-----BEGIN RSA PUBLIC KEY-----\r\n" .

 
 
 chunk_split(base64_encode(substr(base64_decode($key), 1)), 64) .
'-----END RSA PUBLIC KEY-----';
default:
return $key;
}
}










function _decodeIP($ip)
{
return inet_ntop(base64_decode($ip));
}










function _decodeNameConstraintIP($ip)
{
$ip = base64_decode($ip);
$size = strlen($ip) >> 1;
$mask = substr($ip, $size);
$ip = substr($ip, 0, $size);
return array(inet_ntop($ip), inet_ntop($mask));
}










function _encodeIP($ip)
{
return is_string($ip) ?
base64_encode(inet_pton($ip)) :
base64_encode(inet_pton($ip[0]) . inet_pton($ip[1]));
}








function _translateDNProp($propName)
{
switch (strtolower($propName)) {
case 'id-at-countryname':
case 'countryname':
case 'c':
return 'id-at-countryName';
case 'id-at-organizationname':
case 'organizationname':
case 'o':
return 'id-at-organizationName';
case 'id-at-dnqualifier':
case 'dnqualifier':
return 'id-at-dnQualifier';
case 'id-at-commonname':
case 'commonname':
case 'cn':
return 'id-at-commonName';
case 'id-at-stateorprovincename':
case 'stateorprovincename':
case 'state':
case 'province':
case 'provincename':
case 'st':
return 'id-at-stateOrProvinceName';
case 'id-at-localityname':
case 'localityname':
case 'l':
return 'id-at-localityName';
case 'id-emailaddress':
case 'emailaddress':
return 'pkcs-9-at-emailAddress';
case 'id-at-serialnumber':
case 'serialnumber':
return 'id-at-serialNumber';
case 'id-at-postalcode':
case 'postalcode':
return 'id-at-postalCode';
case 'id-at-streetaddress':
case 'streetaddress':
return 'id-at-streetAddress';
case 'id-at-name':
case 'name':
return 'id-at-name';
case 'id-at-givenname':
case 'givenname':
return 'id-at-givenName';
case 'id-at-surname':
case 'surname':
case 'sn':
return 'id-at-surname';
case 'id-at-initials':
case 'initials':
return 'id-at-initials';
case 'id-at-generationqualifier':
case 'generationqualifier':
return 'id-at-generationQualifier';
case 'id-at-organizationalunitname':
case 'organizationalunitname':
case 'ou':
return 'id-at-organizationalUnitName';
case 'id-at-pseudonym':
case 'pseudonym':
return 'id-at-pseudonym';
case 'id-at-title':
case 'title':
return 'id-at-title';
case 'id-at-description':
case 'description':
return 'id-at-description';
case 'id-at-role':
case 'role':
return 'id-at-role';
case 'id-at-uniqueidentifier':
case 'uniqueidentifier':
case 'x500uniqueidentifier':
return 'id-at-uniqueIdentifier';
case 'postaladdress':
case 'id-at-postaladdress':
return 'id-at-postalAddress';
default:
return false;
}
}










function setDNProp($propName, $propValue, $type = 'utf8String')
{
if (empty($this->dn)) {
$this->dn = array('rdnSequence' => array());
}

if (($propName = $this->_translateDNProp($propName)) === false) {
return false;
}

foreach ((array) $propValue as $v) {
if (!is_array($v) && isset($type)) {
$v = array($type => $v);
}
$this->dn['rdnSequence'][] = array(
array(
'type' => $propName,
'value'=> $v
)
);
}

return true;
}







function removeDNProp($propName)
{
if (empty($this->dn)) {
return;
}

if (($propName = $this->_translateDNProp($propName)) === false) {
return;
}

$dn = &$this->dn['rdnSequence'];
$size = count($dn);
for ($i = 0; $i < $size; $i++) {
if ($dn[$i][0]['type'] == $propName) {
unset($dn[$i]);
}
}

$dn = array_values($dn);

 if (!isset($dn[0])) {
$dn = array_splice($dn, 0, 0);
}
}










function getDNProp($propName, $dn = null, $withType = false)
{
if (!isset($dn)) {
$dn = $this->dn;
}

if (empty($dn)) {
return false;
}

if (($propName = $this->_translateDNProp($propName)) === false) {
return false;
}

$asn1 = new ASN1();
$asn1->loadOIDs($this->oids);
$filters = array();
$filters['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
$asn1->loadFilters($filters);
$this->_mapOutDNs($dn, 'rdnSequence', $asn1);
$dn = $dn['rdnSequence'];
$result = array();
for ($i = 0; $i < count($dn); $i++) {
if ($dn[$i][0]['type'] == $propName) {
$v = $dn[$i][0]['value'];
if (!$withType) {
if (is_array($v)) {
foreach ($v as $type => $s) {
$type = array_search($type, $asn1->ANYmap, true);
if ($type !== false && isset($asn1->stringTypeSize[$type])) {
$s = $asn1->convert($s, $type);
if ($s !== false) {
$v = $s;
break;
}
}
}
if (is_array($v)) {
$v = array_pop($v); 
 }
} elseif (is_object($v) && $v instanceof Element) {
$map = $this->_getMapping($propName);
if (!is_bool($map)) {
$decoded = $asn1->decodeBER($v);
$v = $asn1->asn1map($decoded[0], $map);
}
}
}
$result[] = $v;
}
}

return $result;
}










function setDN($dn, $merge = false, $type = 'utf8String')
{
if (!$merge) {
$this->dn = null;
}

if (is_array($dn)) {
if (isset($dn['rdnSequence'])) {
$this->dn = $dn; 
 return true;
}


 foreach ($dn as $prop => $value) {
if (!$this->setDNProp($prop, $value, $type)) {
return false;
}
}
return true;
}


 $results = preg_split('#((?:^|, *|/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=|postalAddress=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
for ($i = 1; $i < count($results); $i+=2) {
$prop = trim($results[$i], ', =/');
$value = $results[$i + 1];
if (!$this->setDNProp($prop, $value, $type)) {
return false;
}
}

return true;
}









function getDN($format = self::DN_ARRAY, $dn = null)
{
if (!isset($dn)) {
$dn = isset($this->currentCert['tbsCertList']) ? $this->currentCert['tbsCertList']['issuer'] : $this->dn;
}

switch ((int) $format) {
case self::DN_ARRAY:
return $dn;
case self::DN_ASN1:
$asn1 = new ASN1();
$asn1->loadOIDs($this->oids);
$filters = array();
$filters['rdnSequence']['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
$asn1->loadFilters($filters);
$this->_mapOutDNs($dn, 'rdnSequence', $asn1);
return $asn1->encodeDER($dn, $this->Name);
case self::DN_CANON:

 
 
 $asn1 = new ASN1();
$asn1->loadOIDs($this->oids);
$filters = array();
$filters['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
$asn1->loadFilters($filters);
$result = '';
$this->_mapOutDNs($dn, 'rdnSequence', $asn1);
foreach ($dn['rdnSequence'] as $rdn) {
foreach ($rdn as $i => $attr) {
$attr = &$rdn[$i];
if (is_array($attr['value'])) {
foreach ($attr['value'] as $type => $v) {
$type = array_search($type, $asn1->ANYmap, true);
if ($type !== false && isset($asn1->stringTypeSize[$type])) {
$v = $asn1->convert($v, $type);
if ($v !== false) {
$v = preg_replace('/\s+/', ' ', $v);
$attr['value'] = strtolower(trim($v));
break;
}
}
}
}
}
$result .= $asn1->encodeDER($rdn, $this->RelativeDistinguishedName);
}
return $result;
case self::DN_HASH:
$dn = $this->getDN(self::DN_CANON, $dn);
$hash = new Hash('sha1');
$hash = $hash->hash($dn);
extract(unpack('Vhash', $hash));
return strtolower(bin2hex(pack('N', $hash)));
}


 $start = true;
$output = '';

$result = array();
$asn1 = new ASN1();
$asn1->loadOIDs($this->oids);
$filters = array();
$filters['rdnSequence']['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
$asn1->loadFilters($filters);
$this->_mapOutDNs($dn, 'rdnSequence', $asn1);

foreach ($dn['rdnSequence'] as $field) {
$prop = $field[0]['type'];
$value = $field[0]['value'];

$delim = ', ';
switch ($prop) {
case 'id-at-countryName':
$desc = 'C';
break;
case 'id-at-stateOrProvinceName':
$desc = 'ST';
break;
case 'id-at-organizationName':
$desc = 'O';
break;
case 'id-at-organizationalUnitName':
$desc = 'OU';
break;
case 'id-at-commonName':
$desc = 'CN';
break;
case 'id-at-localityName':
$desc = 'L';
break;
case 'id-at-surname':
$desc = 'SN';
break;
case 'id-at-uniqueIdentifier':
$delim = '/';
$desc = 'x500UniqueIdentifier';
break;
case 'id-at-postalAddress':
$delim = '/';
$desc = 'postalAddress';
break;
default:
$delim = '/';
$desc = preg_replace('#.+-([^-]+)$#', '$1', $prop);
}

if (!$start) {
$output.= $delim;
}
if (is_array($value)) {
foreach ($value as $type => $v) {
$type = array_search($type, $asn1->ANYmap, true);
if ($type !== false && isset($asn1->stringTypeSize[$type])) {
$v = $asn1->convert($v, $type);
if ($v !== false) {
$value = $v;
break;
}
}
}
if (is_array($value)) {
$value = array_pop($value); 
 }
} elseif (is_object($value) && $value instanceof Element) {
$callback = function ($x) {
return "\x" . bin2hex($x[0]);
};
$value = strtoupper(preg_replace_callback('#[^\x20-\x7E]#', $callback, $value->element));
}
$output.= $desc . '=' . $value;
$result[$desc] = isset($result[$desc]) ?
array_merge((array) $result[$desc], array($value)) :
$value;
$start = false;
}

return $format == self::DN_OPENSSL ? $result : $output;
}








function getIssuerDN($format = self::DN_ARRAY)
{
switch (true) {
case !isset($this->currentCert) || !is_array($this->currentCert):
break;
case isset($this->currentCert['tbsCertificate']):
return $this->getDN($format, $this->currentCert['tbsCertificate']['issuer']);
case isset($this->currentCert['tbsCertList']):
return $this->getDN($format, $this->currentCert['tbsCertList']['issuer']);
}

return false;
}









function getSubjectDN($format = self::DN_ARRAY)
{
switch (true) {
case !empty($this->dn):
return $this->getDN($format);
case !isset($this->currentCert) || !is_array($this->currentCert):
break;
case isset($this->currentCert['tbsCertificate']):
return $this->getDN($format, $this->currentCert['tbsCertificate']['subject']);
case isset($this->currentCert['certificationRequestInfo']):
return $this->getDN($format, $this->currentCert['certificationRequestInfo']['subject']);
}

return false;
}









function getIssuerDNProp($propName, $withType = false)
{
switch (true) {
case !isset($this->currentCert) || !is_array($this->currentCert):
break;
case isset($this->currentCert['tbsCertificate']):
return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['issuer'], $withType);
case isset($this->currentCert['tbsCertList']):
return $this->getDNProp($propName, $this->currentCert['tbsCertList']['issuer'], $withType);
}

return false;
}









function getSubjectDNProp($propName, $withType = false)
{
switch (true) {
case !empty($this->dn):
return $this->getDNProp($propName, null, $withType);
case !isset($this->currentCert) || !is_array($this->currentCert):
break;
case isset($this->currentCert['tbsCertificate']):
return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['subject'], $withType);
case isset($this->currentCert['certificationRequestInfo']):
return $this->getDNProp($propName, $this->currentCert['certificationRequestInfo']['subject'], $withType);
}

return false;
}







function getChain()
{
$chain = array($this->currentCert);

if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
return false;
}
if (empty($this->CAs)) {
return $chain;
}
while (true) {
$currentCert = $chain[count($chain) - 1];
for ($i = 0; $i < count($this->CAs); $i++) {
$ca = $this->CAs[$i];
if ($currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) {
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier', $currentCert);
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
switch (true) {
case !is_array($authorityKey):
case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
if ($currentCert === $ca) {
break 3;
}
$chain[] = $ca;
break 2;
}
}
}
if ($i == count($this->CAs)) {
break;
}
}
foreach ($chain as $key => $value) {
$chain[$key] = new X509();
$chain[$key]->loadX509($value);
}
return $chain;
}










function setPublicKey($key)
{
$key->setPublicKey();
$this->publicKey = $key;
}









function setPrivateKey($key)
{
$this->privateKey = $key;
}









function setChallenge($challenge)
{
$this->challenge = $challenge;
}









function getPublicKey()
{
if (isset($this->publicKey)) {
return $this->publicKey;
}

if (isset($this->currentCert) && is_array($this->currentCert)) {
foreach (array('tbsCertificate/subjectPublicKeyInfo', 'certificationRequestInfo/subjectPKInfo') as $path) {
$keyinfo = $this->_subArray($this->currentCert, $path);
if (!empty($keyinfo)) {
break;
}
}
}
if (empty($keyinfo)) {
return false;
}

$key = $keyinfo['subjectPublicKey'];

switch ($keyinfo['algorithm']['algorithm']) {
case 'rsaEncryption':
$publicKey = new RSA();
$publicKey->loadKey($key);
$publicKey->setPublicKey();
break;
default:
return false;
}

return $publicKey;
}









function loadCSR($csr, $mode = self::FORMAT_AUTO_DETECT)
{
if (is_array($csr) && isset($csr['certificationRequestInfo'])) {
unset($this->currentCert);
unset($this->currentKeyIdentifier);
unset($this->signatureSubject);
$this->dn = $csr['certificationRequestInfo']['subject'];
if (!isset($this->dn)) {
return false;
}

$this->currentCert = $csr;
return $csr;
}



$asn1 = new ASN1();

if ($mode != self::FORMAT_DER) {
$newcsr = $this->_extractBER($csr);
if ($mode == self::FORMAT_PEM && $csr == $newcsr) {
return false;
}
$csr = $newcsr;
}
$orig = $csr;

if ($csr === false) {
$this->currentCert = false;
return false;
}

$asn1->loadOIDs($this->oids);
$decoded = $asn1->decodeBER($csr);

if (empty($decoded)) {
$this->currentCert = false;
return false;
}

$csr = $asn1->asn1map($decoded[0], $this->CertificationRequest);
if (!isset($csr) || $csr === false) {
$this->currentCert = false;
return false;
}

$this->_mapInAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
$this->_mapInDNs($csr, 'certificationRequestInfo/subject/rdnSequence', $asn1);

$this->dn = $csr['certificationRequestInfo']['subject'];

$this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);

$algorithm = &$csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'];
$key = &$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'];
$key = $this->_reformatKey($algorithm, $key);

switch ($algorithm) {
case 'rsaEncryption':
$this->publicKey = new RSA();
$this->publicKey->loadKey($key);
$this->publicKey->setPublicKey();
break;
default:
$this->publicKey = null;
}

$this->currentKeyIdentifier = null;
$this->currentCert = $csr;

return $csr;
}









function saveCSR($csr, $format = self::FORMAT_PEM)
{
if (!is_array($csr) || !isset($csr['certificationRequestInfo'])) {
return false;
}

switch (true) {
case !($algorithm = $this->_subArray($csr, 'certificationRequestInfo/subjectPKInfo/algorithm/algorithm')):
case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
break;
default:
switch ($algorithm) {
case 'rsaEncryption':
$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']
= base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'])));
$csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['parameters'] = null;
$csr['signatureAlgorithm']['parameters'] = null;
$csr['certificationRequestInfo']['signature']['parameters'] = null;
}
}

$asn1 = new ASN1();

$asn1->loadOIDs($this->oids);

$filters = array();
$filters['certificationRequestInfo']['subject']['rdnSequence']['value']
= array('type' => ASN1::TYPE_UTF8_STRING);

$asn1->loadFilters($filters);

$this->_mapOutDNs($csr, 'certificationRequestInfo/subject/rdnSequence', $asn1);
$this->_mapOutAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
$csr = $asn1->encodeDER($csr, $this->CertificationRequest);

switch ($format) {
case self::FORMAT_DER:
return $csr;

 default:
return "-----BEGIN CERTIFICATE REQUEST-----\r\n" . chunk_split(base64_encode($csr), 64) . '-----END CERTIFICATE REQUEST-----';
}
}












function loadSPKAC($spkac)
{
if (is_array($spkac) && isset($spkac['publicKeyAndChallenge'])) {
unset($this->currentCert);
unset($this->currentKeyIdentifier);
unset($this->signatureSubject);
$this->currentCert = $spkac;
return $spkac;
}



$asn1 = new ASN1();


 $temp = preg_replace('#(?:SPKAC=)|[ \r\n\\\]#', '', $spkac);
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
if ($temp != false) {
$spkac = $temp;
}
$orig = $spkac;

if ($spkac === false) {
$this->currentCert = false;
return false;
}

$asn1->loadOIDs($this->oids);
$decoded = $asn1->decodeBER($spkac);

if (empty($decoded)) {
$this->currentCert = false;
return false;
}

$spkac = $asn1->asn1map($decoded[0], $this->SignedPublicKeyAndChallenge);

if (!isset($spkac) || $spkac === false) {
$this->currentCert = false;
return false;
}

$this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);

$algorithm = &$spkac['publicKeyAndChallenge']['spki']['algorithm']['algorithm'];
$key = &$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'];
$key = $this->_reformatKey($algorithm, $key);

switch ($algorithm) {
case 'rsaEncryption':
$this->publicKey = new RSA();
$this->publicKey->loadKey($key);
$this->publicKey->setPublicKey();
break;
default:
$this->publicKey = null;
}

$this->currentKeyIdentifier = null;
$this->currentCert = $spkac;

return $spkac;
}









function saveSPKAC($spkac, $format = self::FORMAT_PEM)
{
if (!is_array($spkac) || !isset($spkac['publicKeyAndChallenge'])) {
return false;
}

$algorithm = $this->_subArray($spkac, 'publicKeyAndChallenge/spki/algorithm/algorithm');
switch (true) {
case !$algorithm:
case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']):
break;
default:
switch ($algorithm) {
case 'rsaEncryption':
$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']
= base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'])));
}
}

$asn1 = new ASN1();

$asn1->loadOIDs($this->oids);
$spkac = $asn1->encodeDER($spkac, $this->SignedPublicKeyAndChallenge);

switch ($format) {
case self::FORMAT_DER:
return $spkac;

 default:

 
 return 'SPKAC=' . base64_encode($spkac);
}
}









function loadCRL($crl, $mode = self::FORMAT_AUTO_DETECT)
{
if (is_array($crl) && isset($crl['tbsCertList'])) {
$this->currentCert = $crl;
unset($this->signatureSubject);
return $crl;
}

$asn1 = new ASN1();

if ($mode != self::FORMAT_DER) {
$newcrl = $this->_extractBER($crl);
if ($mode == self::FORMAT_PEM && $crl == $newcrl) {
return false;
}
$crl = $newcrl;
}
$orig = $crl;

if ($crl === false) {
$this->currentCert = false;
return false;
}

$asn1->loadOIDs($this->oids);
$decoded = $asn1->decodeBER($crl);

if (empty($decoded)) {
$this->currentCert = false;
return false;
}

$crl = $asn1->asn1map($decoded[0], $this->CertificateList);
if (!isset($crl) || $crl === false) {
$this->currentCert = false;
return false;
}

$this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);

$this->_mapInDNs($crl, 'tbsCertList/issuer/rdnSequence', $asn1);
if ($this->_isSubArrayValid($crl, 'tbsCertList/crlExtensions')) {
$this->_mapInExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
}
if ($this->_isSubArrayValid($crl, 'tbsCertList/revokedCertificates')) {
$rclist_ref = &$this->_subArrayUnchecked($crl, 'tbsCertList/revokedCertificates');
if ($rclist_ref) {
$rclist = $crl['tbsCertList']['revokedCertificates'];
foreach ($rclist as $i => $extension) {
if ($this->_isSubArrayValid($rclist, "$i/crlEntryExtensions", $asn1)) {
$this->_mapInExtensions($rclist_ref, "$i/crlEntryExtensions", $asn1);
}
}
}
}

$this->currentKeyIdentifier = null;
$this->currentCert = $crl;

return $crl;
}









function saveCRL($crl, $format = self::FORMAT_PEM)
{
if (!is_array($crl) || !isset($crl['tbsCertList'])) {
return false;
}

$asn1 = new ASN1();

$asn1->loadOIDs($this->oids);

$filters = array();
$filters['tbsCertList']['issuer']['rdnSequence']['value']
= array('type' => ASN1::TYPE_UTF8_STRING);
$filters['tbsCertList']['signature']['parameters']
= array('type' => ASN1::TYPE_UTF8_STRING);
$filters['signatureAlgorithm']['parameters']
= array('type' => ASN1::TYPE_UTF8_STRING);

if (empty($crl['tbsCertList']['signature']['parameters'])) {
$filters['tbsCertList']['signature']['parameters']
= array('type' => ASN1::TYPE_NULL);
}

if (empty($crl['signatureAlgorithm']['parameters'])) {
$filters['signatureAlgorithm']['parameters']
= array('type' => ASN1::TYPE_NULL);
}

$asn1->loadFilters($filters);

$this->_mapOutDNs($crl, 'tbsCertList/issuer/rdnSequence', $asn1);
$this->_mapOutExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
$rclist = &$this->_subArray($crl, 'tbsCertList/revokedCertificates');
if (is_array($rclist)) {
foreach ($rclist as $i => $extension) {
$this->_mapOutExtensions($rclist, "$i/crlEntryExtensions", $asn1);
}
}

$crl = $asn1->encodeDER($crl, $this->CertificateList);

switch ($format) {
case self::FORMAT_DER:
return $crl;

 default:
return "-----BEGIN X509 CRL-----\r\n" . chunk_split(base64_encode($crl), 64) . '-----END X509 CRL-----';
}
}













function _timeField($date)
{
if ($date instanceof Element) {
return $date;
}
$dateObj = new DateTime($date, new DateTimeZone('GMT'));
$year = $dateObj->format('Y'); 
 if ($year < 2050) {
return array('utcTime' => $date);
} else {
return array('generalTime' => $date);
}
}














function sign($issuer, $subject, $signatureAlgorithm = 'sha1WithRSAEncryption')
{
if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
return false;
}

if (isset($subject->publicKey) && !($subjectPublicKey = $subject->_formatSubjectPublicKey())) {
return false;
}

$currentCert = isset($this->currentCert) ? $this->currentCert : null;
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;

if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertificate'])) {
$this->currentCert = $subject->currentCert;
$this->currentCert['tbsCertificate']['signature']['algorithm'] = $signatureAlgorithm;
$this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;

if (!empty($this->startDate)) {
$this->currentCert['tbsCertificate']['validity']['notBefore'] = $this->_timeField($this->startDate);
}
if (!empty($this->endDate)) {
$this->currentCert['tbsCertificate']['validity']['notAfter'] = $this->_timeField($this->endDate);
}
if (!empty($this->serialNumber)) {
$this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber;
}
if (!empty($subject->dn)) {
$this->currentCert['tbsCertificate']['subject'] = $subject->dn;
}
if (!empty($subject->publicKey)) {
$this->currentCert['tbsCertificate']['subjectPublicKeyInfo'] = $subjectPublicKey;
}
$this->removeExtension('id-ce-authorityKeyIdentifier');
if (isset($subject->domains)) {
$this->removeExtension('id-ce-subjectAltName');
}
} elseif (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertList'])) {
return false;
} else {
if (!isset($subject->publicKey)) {
return false;
}

$startDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
$startDate = !empty($this->startDate) ? $this->startDate : $startDate->format('D, d M Y H:i:s O');

$endDate = new DateTime('+1 year', new DateTimeZone(@date_default_timezone_get()));
$endDate = !empty($this->endDate) ? $this->endDate : $endDate->format('D, d M Y H:i:s O');








$serialNumber = !empty($this->serialNumber) ?
$this->serialNumber :
new BigInteger(Random::string(20) & ("\x7F" . str_repeat("\xFF", 19)), 256);

$this->currentCert = array(
'tbsCertificate' =>
array(
'version' => 'v3',
'serialNumber' => $serialNumber, 
 'signature' => array('algorithm' => $signatureAlgorithm),
'issuer' => false, 
 'validity' => array(
'notBefore' => $this->_timeField($startDate), 
 'notAfter' => $this->_timeField($endDate) 
 ),
'subject' => $subject->dn,
'subjectPublicKeyInfo' => $subjectPublicKey
),
'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
'signature' => false 
 );


 $csrexts = $subject->getAttribute('pkcs-9-at-extensionRequest', 0);

if (!empty($csrexts)) {
$this->currentCert['tbsCertificate']['extensions'] = $csrexts;
}
}

$this->currentCert['tbsCertificate']['issuer'] = $issuer->dn;

if (isset($issuer->currentKeyIdentifier)) {
$this->setExtension('id-ce-authorityKeyIdentifier', array(

 
 
 
 
 'keyIdentifier' => $issuer->currentKeyIdentifier
));

 
 
 
 
 }

if (isset($subject->currentKeyIdentifier)) {
$this->setExtension('id-ce-subjectKeyIdentifier', $subject->currentKeyIdentifier);
}

$altName = array();

if (isset($subject->domains) && count($subject->domains)) {
$altName = array_map(array('\phpseclib\File\X509', '_dnsName'), $subject->domains);
}

if (isset($subject->ipAddresses) && count($subject->ipAddresses)) {

 
 $ipAddresses = array();
foreach ($subject->ipAddresses as $ipAddress) {
$encoded = $subject->_ipAddress($ipAddress);
if ($encoded !== false) {
$ipAddresses[] = $encoded;
}
}
if (count($ipAddresses)) {
$altName = array_merge($altName, $ipAddresses);
}
}

if (!empty($altName)) {
$this->setExtension('id-ce-subjectAltName', $altName);
}

if ($this->caFlag) {
$keyUsage = $this->getExtension('id-ce-keyUsage');
if (!$keyUsage) {
$keyUsage = array();
}

$this->setExtension(
'id-ce-keyUsage',
array_values(array_unique(array_merge($keyUsage, array('cRLSign', 'keyCertSign'))))
);

$basicConstraints = $this->getExtension('id-ce-basicConstraints');
if (!$basicConstraints) {
$basicConstraints = array();
}

$this->setExtension(
'id-ce-basicConstraints',
array_unique(array_merge(array('cA' => true), $basicConstraints)),
true
);

if (!isset($subject->currentKeyIdentifier)) {
$this->setExtension('id-ce-subjectKeyIdentifier', base64_encode($this->computeKeyIdentifier($this->currentCert)), false, false);
}
}


 
 $tbsCertificate = $this->currentCert['tbsCertificate'];
$this->loadX509($this->saveX509($this->currentCert));

$result = $this->_sign($issuer->privateKey, $signatureAlgorithm);
$result['tbsCertificate'] = $tbsCertificate;

$this->currentCert = $currentCert;
$this->signatureSubject = $signatureSubject;

return $result;
}







function signCSR($signatureAlgorithm = 'sha1WithRSAEncryption')
{
if (!is_object($this->privateKey) || empty($this->dn)) {
return false;
}

$origPublicKey = $this->publicKey;
$class = get_class($this->privateKey);
$this->publicKey = new $class();
$this->publicKey->loadKey($this->privateKey->getPublicKey());
$this->publicKey->setPublicKey();
if (!($publicKey = $this->_formatSubjectPublicKey())) {
return false;
}
$this->publicKey = $origPublicKey;

$currentCert = isset($this->currentCert) ? $this->currentCert : null;
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;

if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['certificationRequestInfo'])) {
$this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
if (!empty($this->dn)) {
$this->currentCert['certificationRequestInfo']['subject'] = $this->dn;
}
$this->currentCert['certificationRequestInfo']['subjectPKInfo'] = $publicKey;
} else {
$this->currentCert = array(
'certificationRequestInfo' =>
array(
'version' => 'v1',
'subject' => $this->dn,
'subjectPKInfo' => $publicKey
),
'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
'signature' => false 
 );
}


 
 $certificationRequestInfo = $this->currentCert['certificationRequestInfo'];
$this->loadCSR($this->saveCSR($this->currentCert));

$result = $this->_sign($this->privateKey, $signatureAlgorithm);
$result['certificationRequestInfo'] = $certificationRequestInfo;

$this->currentCert = $currentCert;
$this->signatureSubject = $signatureSubject;

return $result;
}







function signSPKAC($signatureAlgorithm = 'sha1WithRSAEncryption')
{
if (!is_object($this->privateKey)) {
return false;
}

$origPublicKey = $this->publicKey;
$class = get_class($this->privateKey);
$this->publicKey = new $class();
$this->publicKey->loadKey($this->privateKey->getPublicKey());
$this->publicKey->setPublicKey();
$publicKey = $this->_formatSubjectPublicKey();
if (!$publicKey) {
return false;
}
$this->publicKey = $origPublicKey;

$currentCert = isset($this->currentCert) ? $this->currentCert : null;
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;


 if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['publicKeyAndChallenge'])) {
$this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
$this->currentCert['publicKeyAndChallenge']['spki'] = $publicKey;
if (!empty($this->challenge)) {

 $this->currentCert['publicKeyAndChallenge']['challenge'] = $this->challenge & str_repeat("\x7F", strlen($this->challenge));
}
} else {
$this->currentCert = array(
'publicKeyAndChallenge' =>
array(
'spki' => $publicKey,

 
 
 
 
 'challenge' => !empty($this->challenge) ? $this->challenge : ''
),
'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
'signature' => false 
 );
}


 
 $publicKeyAndChallenge = $this->currentCert['publicKeyAndChallenge'];
$this->loadSPKAC($this->saveSPKAC($this->currentCert));

$result = $this->_sign($this->privateKey, $signatureAlgorithm);
$result['publicKeyAndChallenge'] = $publicKeyAndChallenge;

$this->currentCert = $currentCert;
$this->signatureSubject = $signatureSubject;

return $result;
}












function signCRL($issuer, $crl, $signatureAlgorithm = 'sha1WithRSAEncryption')
{
if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
return false;
}

$currentCert = isset($this->currentCert) ? $this->currentCert : null;
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;

$thisUpdate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
$thisUpdate = !empty($this->startDate) ? $this->startDate : $thisUpdate->format('D, d M Y H:i:s O');

if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) {
$this->currentCert = $crl->currentCert;
$this->currentCert['tbsCertList']['signature']['algorithm'] = $signatureAlgorithm;
$this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
} else {
$this->currentCert = array(
'tbsCertList' =>
array(
'version' => 'v2',
'signature' => array('algorithm' => $signatureAlgorithm),
'issuer' => false, 
 'thisUpdate' => $this->_timeField($thisUpdate) 
 ),
'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
'signature' => false 
 );
}

$tbsCertList = &$this->currentCert['tbsCertList'];
$tbsCertList['issuer'] = $issuer->dn;
$tbsCertList['thisUpdate'] = $this->_timeField($thisUpdate);

if (!empty($this->endDate)) {
$tbsCertList['nextUpdate'] = $this->_timeField($this->endDate); 
 } else {
unset($tbsCertList['nextUpdate']);
}

if (!empty($this->serialNumber)) {
$crlNumber = $this->serialNumber;
} else {
$crlNumber = $this->getExtension('id-ce-cRLNumber');

 
 
 
 
 $crlNumber = $crlNumber !== false ? $crlNumber->add(new BigInteger(1)) : null;
}

$this->removeExtension('id-ce-authorityKeyIdentifier');
$this->removeExtension('id-ce-issuerAltName');


 $version = isset($tbsCertList['version']) ? $tbsCertList['version'] : 0;
if (!$version) {
if (!empty($tbsCertList['crlExtensions'])) {
$version = 1; 
 } elseif (!empty($tbsCertList['revokedCertificates'])) {
foreach ($tbsCertList['revokedCertificates'] as $cert) {
if (!empty($cert['crlEntryExtensions'])) {
$version = 1; 
 }
}
}

if ($version) {
$tbsCertList['version'] = $version;
}
}


 if (!empty($tbsCertList['version'])) { 
 if (!empty($crlNumber)) {
$this->setExtension('id-ce-cRLNumber', $crlNumber);
}

if (isset($issuer->currentKeyIdentifier)) {
$this->setExtension('id-ce-authorityKeyIdentifier', array(

 
 
 
 
 'keyIdentifier' => $issuer->currentKeyIdentifier
));

 
 
 
 
 }

$issuerAltName = $this->getExtension('id-ce-subjectAltName', $issuer->currentCert);

if ($issuerAltName !== false) {
$this->setExtension('id-ce-issuerAltName', $issuerAltName);
}
}

if (empty($tbsCertList['revokedCertificates'])) {
unset($tbsCertList['revokedCertificates']);
}

unset($tbsCertList);


 
 $tbsCertList = $this->currentCert['tbsCertList'];
$this->loadCRL($this->saveCRL($this->currentCert));

$result = $this->_sign($issuer->privateKey, $signatureAlgorithm);
$result['tbsCertList'] = $tbsCertList;

$this->currentCert = $currentCert;
$this->signatureSubject = $signatureSubject;

return $result;
}









function _sign($key, $signatureAlgorithm)
{
if ($key instanceof RSA) {
switch ($signatureAlgorithm) {
case 'md2WithRSAEncryption':
case 'md5WithRSAEncryption':
case 'sha1WithRSAEncryption':
case 'sha224WithRSAEncryption':
case 'sha256WithRSAEncryption':
case 'sha384WithRSAEncryption':
case 'sha512WithRSAEncryption':
$key->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
$key->setSignatureMode(RSA::SIGNATURE_PKCS1);

$this->currentCert['signature'] = base64_encode("\0" . $key->sign($this->signatureSubject));
return $this->currentCert;
}
}

return false;
}







function setStartDate($date)
{
if (!is_object($date) || !is_a($date, 'DateTime')) {
$date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
}

$this->startDate = $date->format('D, d M Y H:i:s O');
}







function setEndDate($date)
{







if (strtolower($date) == 'lifetime') {
$temp = '99991231235959Z';
$asn1 = new ASN1();
$temp = chr(ASN1::TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp;
$this->endDate = new Element($temp);
} else {
if (!is_object($date) || !is_a($date, 'DateTime')) {
$date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
}

$this->endDate = $date->format('D, d M Y H:i:s O');
}
}








function setSerialNumber($serial, $base = -256)
{
$this->serialNumber = new BigInteger($serial, $base);
}






function makeCA()
{
$this->caFlag = true;
}













function _isSubArrayValid($root, $path)
{
if (!is_array($root)) {
return false;
}

foreach (explode('/', $path) as $i) {
if (!is_array($root)) {
return false;
}

if (!isset($root[$i])) {
return true;
}

$root = $root[$i];
}

return true;
}

















function &_subArrayUnchecked(&$root, $path, $create = false)
{
$false = false;

foreach (explode('/', $path) as $i) {
if (!isset($root[$i])) {
if (!$create) {
return $false;
}

$root[$i] = array();
}

$root = &$root[$i];
}

return $root;
}










function &_subArray(&$root, $path, $create = false)
{
$false = false;

if (!is_array($root)) {
return $false;
}

foreach (explode('/', $path) as $i) {
if (!is_array($root)) {
return $false;
}

if (!isset($root[$i])) {
if (!$create) {
return $false;
}

$root[$i] = array();
}

$root = &$root[$i];
}

return $root;
}










function &_extensions(&$root, $path = null, $create = false)
{
if (!isset($root)) {
$root = $this->currentCert;
}

switch (true) {
case !empty($path):
case !is_array($root):
break;
case isset($root['tbsCertificate']):
$path = 'tbsCertificate/extensions';
break;
case isset($root['tbsCertList']):
$path = 'tbsCertList/crlExtensions';
break;
case isset($root['certificationRequestInfo']):
$pth = 'certificationRequestInfo/attributes';
$attributes = &$this->_subArray($root, $pth, $create);

if (is_array($attributes)) {
foreach ($attributes as $key => $value) {
if ($value['type'] == 'pkcs-9-at-extensionRequest') {
$path = "$pth/$key/value/0";
break 2;
}
}
if ($create) {
$key = count($attributes);
$attributes[] = array('type' => 'pkcs-9-at-extensionRequest', 'value' => array());
$path = "$pth/$key/value/0";
}
}
break;
}

$extensions = &$this->_subArray($root, $path, $create);

if (!is_array($extensions)) {
$false = false;
return $false;
}

return $extensions;
}









function _removeExtension($id, $path = null)
{
$extensions = &$this->_extensions($this->currentCert, $path);

if (!is_array($extensions)) {
return false;
}

$result = false;
foreach ($extensions as $key => $value) {
if ($value['extnId'] == $id) {
unset($extensions[$key]);
$result = true;
}
}

$extensions = array_values($extensions);

 if (!isset($extensions[0])) {
$extensions = array_splice($extensions, 0, 0);
}
return $result;
}












function _getExtension($id, $cert = null, $path = null)
{
$extensions = $this->_extensions($cert, $path);

if (!is_array($extensions)) {
return false;
}

foreach ($extensions as $key => $value) {
if ($value['extnId'] == $id) {
return $value['extnValue'];
}
}

return false;
}









function _getExtensions($cert = null, $path = null)
{
$exts = $this->_extensions($cert, $path);
$extensions = array();

if (is_array($exts)) {
foreach ($exts as $extension) {
$extensions[] = $extension['extnId'];
}
}

return $extensions;
}












function _setExtension($id, $value, $critical = false, $replace = true, $path = null)
{
$extensions = &$this->_extensions($this->currentCert, $path, true);

if (!is_array($extensions)) {
return false;
}

$newext = array('extnId' => $id, 'critical' => $critical, 'extnValue' => $value);

foreach ($extensions as $key => $value) {
if ($value['extnId'] == $id) {
if (!$replace) {
return false;
}

$extensions[$key] = $newext;
return true;
}
}

$extensions[] = $newext;
return true;
}








function removeExtension($id)
{
return $this->_removeExtension($id);
}











function getExtension($id, $cert = null)
{
return $this->_getExtension($id, $cert);
}








function getExtensions($cert = null)
{
return $this->_getExtensions($cert);
}











function setExtension($id, $value, $critical = false, $replace = true)
{
return $this->_setExtension($id, $value, $critical, $replace);
}









function removeAttribute($id, $disposition = self::ATTR_ALL)
{
$attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes');

if (!is_array($attributes)) {
return false;
}

$result = false;
foreach ($attributes as $key => $attribute) {
if ($attribute['type'] == $id) {
$n = count($attribute['value']);
switch (true) {
case $disposition == self::ATTR_APPEND:
case $disposition == self::ATTR_REPLACE:
return false;
case $disposition >= $n:
$disposition -= $n;
break;
case $disposition == self::ATTR_ALL:
case $n == 1:
unset($attributes[$key]);
$result = true;
break;
default:
unset($attributes[$key]['value'][$disposition]);
$attributes[$key]['value'] = array_values($attributes[$key]['value']);
$result = true;
break;
}
if ($result && $disposition != self::ATTR_ALL) {
break;
}
}
}

$attributes = array_values($attributes);
return $result;
}












function getAttribute($id, $disposition = self::ATTR_ALL, $csr = null)
{
if (empty($csr)) {
$csr = $this->currentCert;
}

$attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes');

if (!is_array($attributes)) {
return false;
}

foreach ($attributes as $key => $attribute) {
if ($attribute['type'] == $id) {
$n = count($attribute['value']);
switch (true) {
case $disposition == self::ATTR_APPEND:
case $disposition == self::ATTR_REPLACE:
return false;
case $disposition == self::ATTR_ALL:
return $attribute['value'];
case $disposition >= $n:
$disposition -= $n;
break;
default:
return $attribute['value'][$disposition];
}
}
}

return false;
}








function getAttributes($csr = null)
{
if (empty($csr)) {
$csr = $this->currentCert;
}

$attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes');
$attrs = array();

if (is_array($attributes)) {
foreach ($attributes as $attribute) {
$attrs[] = $attribute['type'];
}
}

return $attrs;
}










function setAttribute($id, $value, $disposition = self::ATTR_ALL)
{
$attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes', true);

if (!is_array($attributes)) {
return false;
}

switch ($disposition) {
case self::ATTR_REPLACE:
$disposition = self::ATTR_APPEND;
case self::ATTR_ALL:
$this->removeAttribute($id);
break;
}

foreach ($attributes as $key => $attribute) {
if ($attribute['type'] == $id) {
$n = count($attribute['value']);
switch (true) {
case $disposition == self::ATTR_APPEND:
$last = $key;
break;
case $disposition >= $n:
$disposition -= $n;
break;
default:
$attributes[$key]['value'][$disposition] = $value;
return true;
}
}
}

switch (true) {
case $disposition >= 0:
return false;
case isset($last):
$attributes[$last]['value'][] = $value;
break;
default:
$attributes[] = array('type' => $id, 'value' => $disposition == self::ATTR_ALL ? $value: array($value));
break;
}

return true;
}









function setKeyIdentifier($value)
{
if (empty($value)) {
unset($this->currentKeyIdentifier);
} else {
$this->currentKeyIdentifier = base64_encode($value);
}
}



















function computeKeyIdentifier($key = null, $method = 1)
{
if (is_null($key)) {
$key = $this;
}

switch (true) {
case is_string($key):
break;
case is_array($key) && isset($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
return $this->computeKeyIdentifier($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], $method);
case is_array($key) && isset($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
return $this->computeKeyIdentifier($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'], $method);
case !is_object($key):
return false;
case $key instanceof Element:

 $asn1 = new ASN1();
$decoded = $asn1->decodeBER($key->element);
if (empty($decoded)) {
return false;
}
$raw = $asn1->asn1map($decoded[0], array('type' => ASN1::TYPE_BIT_STRING));
if (empty($raw)) {
return false;
}
$raw = base64_decode($raw);

 $key = new RSA();
if (!$key->loadKey($raw)) {
return false; 
 }
if ($key->getPrivateKey() !== false) { 
 return $this->computeKeyIdentifier($key, $method);
}
$key = $raw; 
 break;
case $key instanceof X509:
if (isset($key->publicKey)) {
return $this->computeKeyIdentifier($key->publicKey, $method);
}
if (isset($key->privateKey)) {
return $this->computeKeyIdentifier($key->privateKey, $method);
}
if (isset($key->currentCert['tbsCertificate']) || isset($key->currentCert['certificationRequestInfo'])) {
return $this->computeKeyIdentifier($key->currentCert, $method);
}
return false;
default: 
 $key = $key->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1);
break;
}


 $key = $this->_extractBER($key);


 $hash = new Hash('sha1');
$hash = $hash->hash($key);

if ($method == 2) {
$hash = substr($hash, -8);
$hash[0] = chr((ord($hash[0]) & 0x0F) | 0x40);
}

return $hash;
}







function _formatSubjectPublicKey()
{
if ($this->publicKey instanceof RSA) {

 
 
 return array(
'algorithm' => array('algorithm' => 'rsaEncryption'),
'subjectPublicKey' => $this->publicKey->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1)
);
}

return false;
}







function setDomain()
{
$this->domains = func_get_args();
$this->removeDNProp('id-at-commonName');
$this->setDNProp('id-at-commonName', $this->domains[0]);
}






function setIPAddress()
{
$this->ipAddresses = func_get_args();






}








function _dnsName($domain)
{
return array('dNSName' => $domain);
}










function _iPAddress($address)
{
return array('iPAddress' => $address);
}










function _revokedCertificate(&$rclist, $serial, $create = false)
{
$serial = new BigInteger($serial);

foreach ($rclist as $i => $rc) {
if (!($serial->compare($rc['userCertificate']))) {
return $i;
}
}

if (!$create) {
return false;
}

$i = count($rclist);
$revocationDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
$rclist[] = array('userCertificate' => $serial,
'revocationDate' => $this->_timeField($revocationDate->format('D, d M Y H:i:s O')));
return $i;
}









function revoke($serial, $date = null)
{
if (isset($this->currentCert['tbsCertList'])) {
if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
if ($this->_revokedCertificate($rclist, $serial) === false) { 
 if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) {
if (!empty($date)) {
$rclist[$i]['revocationDate'] = $this->_timeField($date);
}

return true;
}
}
}
}

return false;
}








function unrevoke($serial)
{
if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
unset($rclist[$i]);
$rclist = array_values($rclist);
return true;
}
}

return false;
}








function getRevoked($serial)
{
if (is_array($rclist = $this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
return $rclist[$i];
}
}

return false;
}








function listRevoked($crl = null)
{
if (!isset($crl)) {
$crl = $this->currentCert;
}

if (!isset($crl['tbsCertList'])) {
return false;
}

$result = array();

if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
foreach ($rclist as $rc) {
$result[] = $rc['userCertificate']->toString();
}
}

return $result;
}









function removeRevokedCertificateExtension($serial, $id)
{
if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
return $this->_removeExtension($id, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
}
}

return false;
}












function getRevokedCertificateExtension($serial, $id, $crl = null)
{
if (!isset($crl)) {
$crl = $this->currentCert;
}

if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
return $this->_getExtension($id, $crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
}
}

return false;
}









function getRevokedCertificateExtensions($serial, $crl = null)
{
if (!isset($crl)) {
$crl = $this->currentCert;
}

if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
return $this->_getExtensions($crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
}
}

return false;
}












function setRevokedCertificateExtension($serial, $id, $value, $critical = false, $replace = true)
{
if (isset($this->currentCert['tbsCertList'])) {
if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) {
return $this->_setExtension($id, $value, $critical, $replace, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
}
}
}

return false;
}








function _extractBER($str)
{









if (strlen($str) > ini_get('pcre.backtrack_limit')) {
$temp = $str;
} else {
$temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
$temp = preg_replace('#-+END.*[\r\n ]*.*#ms', '', $temp, 1);
}

 $temp = str_replace(array("\r", "\n", ' '), '', $temp);

 $temp = preg_replace('#^-+[^-]+-+|-+[^-]+-+$#', '', $temp);
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
return $temp != false ? $temp : $str;
}



















function getOID($name)
{
static $reverseMap;
if (!isset($reverseMap)) {
$reverseMap = array_flip($this->oids);
}
return isset($reverseMap[$name]) ? $reverseMap[$name] : $name;
}
}
<?php



















namespace phpseclib\File;








class ANSI
{






var $max_x;







var $max_y;







var $max_history;







var $history;







var $history_attrs;







var $x;







var $y;







var $old_x;







var $old_y;







var $base_attr_cell;







var $attr_cell;







var $attr_row;







var $screen;







var $attrs;







var $ansi;







var $tokenization;







function __construct()
{
$attr_cell = new \stdClass();
$attr_cell->bold = false;
$attr_cell->underline = false;
$attr_cell->blink = false;
$attr_cell->background = 'black';
$attr_cell->foreground = 'white';
$attr_cell->reverse = false;
$this->base_attr_cell = clone $attr_cell;
$this->attr_cell = clone $attr_cell;

$this->setHistory(200);
$this->setDimensions(80, 24);
}










function setDimensions($x, $y)
{
$this->max_x = $x - 1;
$this->max_y = $y - 1;
$this->x = $this->y = 0;
$this->history = $this->history_attrs = array();
$this->attr_row = array_fill(0, $this->max_x + 2, $this->base_attr_cell);
$this->screen = array_fill(0, $this->max_y + 1, '');
$this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row);
$this->ansi = '';
}







function setHistory($history)
{
$this->max_history = $history;
}







function loadString($source)
{
$this->setDimensions($this->max_x + 1, $this->max_y + 1);
$this->appendString($source);
}







function appendString($source)
{
$this->tokenization = array('');
for ($i = 0; $i < strlen($source); $i++) {
if (strlen($this->ansi)) {
$this->ansi.= $source[$i];
$chr = ord($source[$i]);

 
 switch (true) {
case $this->ansi == "\x1B=":
$this->ansi = '';
continue 2;
case strlen($this->ansi) == 2 && $chr >= 64 && $chr <= 95 && $chr != ord('['):
case strlen($this->ansi) > 2 && $chr >= 64 && $chr <= 126:
break;
default:
continue 2;
}
$this->tokenization[] = $this->ansi;
$this->tokenization[] = '';

 switch ($this->ansi) {
case "\x1B[H": 
 $this->old_x = $this->x;
$this->old_y = $this->y;
$this->x = $this->y = 0;
break;
case "\x1B[J": 
 $this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y));
$this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, ''));

$this->history_attrs = array_merge($this->history_attrs, array_slice(array_splice($this->attrs, $this->y + 1), 0, $this->old_y));
$this->attrs = array_merge($this->attrs, array_fill($this->y, $this->max_y, $this->attr_row));

if (count($this->history) == $this->max_history) {
array_shift($this->history);
array_shift($this->history_attrs);
}
case "\x1B[K": 
 $this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x);

array_splice($this->attrs[$this->y], $this->x + 1, $this->max_x - $this->x, array_fill($this->x, $this->max_x - ($this->x - 1), $this->base_attr_cell));
break;
case "\x1B[2K": 
 $this->screen[$this->y] = str_repeat(' ', $this->x);
$this->attrs[$this->y] = $this->attr_row;
break;
case "\x1B[?1h": 
 case "\x1B[?25h": 
 case "\x1B(B": 
 break;
case "\x1BE": 
 $this->_newLine();
$this->x = 0;
break;
default:
switch (true) {
case preg_match('#\x1B\[(\d+)B#', $this->ansi, $match): 
 $this->old_y = $this->y;
$this->y+= $match[1];
break;
case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): 
 $this->old_x = $this->x;
$this->old_y = $this->y;
$this->x = $match[2] - 1;
$this->y = $match[1] - 1;
break;
case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): 
 $this->old_x = $this->x;
$this->x+= $match[1];
break;
case preg_match('#\x1B\[(\d+)D#', $this->ansi, $match): 
 $this->old_x = $this->x;
$this->x-= $match[1];
if ($this->x < 0) {
$this->x = 0;
}
break;
case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): 
 break;
case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): 
 $attr_cell = &$this->attr_cell;
$mods = explode(';', $match[1]);
foreach ($mods as $mod) {
switch ($mod) {
case '':
case '0': 
 $attr_cell = clone $this->base_attr_cell;
break;
case '1': 
 $attr_cell->bold = true;
break;
case '4': 
 $attr_cell->underline = true;
break;
case '5': 
 $attr_cell->blink = true;
break;
case '7': 
 $attr_cell->reverse = !$attr_cell->reverse;
$temp = $attr_cell->background;
$attr_cell->background = $attr_cell->foreground;
$attr_cell->foreground = $temp;
break;
default: 
 
 $front = &$attr_cell->{ $attr_cell->reverse ? 'background' : 'foreground' };

 $back = &$attr_cell->{ $attr_cell->reverse ? 'foreground' : 'background' };
switch ($mod) {

 case '30': $front = 'black'; break;
case '31': $front = 'red'; break;
case '32': $front = 'green'; break;
case '33': $front = 'yellow'; break;
case '34': $front = 'blue'; break;
case '35': $front = 'magenta'; break;
case '36': $front = 'cyan'; break;
case '37': $front = 'white'; break;

case '40': $back = 'black'; break;
case '41': $back = 'red'; break;
case '42': $back = 'green'; break;
case '43': $back = 'yellow'; break;
case '44': $back = 'blue'; break;
case '45': $back = 'magenta'; break;
case '46': $back = 'cyan'; break;
case '47': $back = 'white'; break;


default:

 $this->ansi = '';
break 2;
}
}
}
break;
default:

 }
}
$this->ansi = '';
continue;
}

$this->tokenization[count($this->tokenization) - 1].= $source[$i];
switch ($source[$i]) {
case "\r":
$this->x = 0;
break;
case "\n":
$this->_newLine();
break;
case "\x08": 
 if ($this->x) {
$this->x--;
$this->attrs[$this->y][$this->x] = clone $this->base_attr_cell;
$this->screen[$this->y] = substr_replace(
$this->screen[$this->y],
$source[$i],
$this->x,
1
);
}
break;
case "\x0F": 
 break;
case "\x1B": 
 $this->tokenization[count($this->tokenization) - 1] = substr($this->tokenization[count($this->tokenization) - 1], 0, -1);

 
 
 $this->ansi.= "\x1B";
break;
default:
$this->attrs[$this->y][$this->x] = clone $this->attr_cell;
if ($this->x > strlen($this->screen[$this->y])) {
$this->screen[$this->y] = str_repeat(' ', $this->x);
}
$this->screen[$this->y] = substr_replace(
$this->screen[$this->y],
$source[$i],
$this->x,
1
);

if ($this->x > $this->max_x) {
$this->x = 0;
$this->_newLine();
} else {
$this->x++;
}
}
}
}








function _newLine()
{

 
 

while ($this->y >= $this->max_y) {
$this->history = array_merge($this->history, array(array_shift($this->screen)));
$this->screen[] = '';

$this->history_attrs = array_merge($this->history_attrs, array(array_shift($this->attrs)));
$this->attrs[] = $this->attr_row;

if (count($this->history) >= $this->max_history) {
array_shift($this->history);
array_shift($this->history_attrs);
}

$this->y--;
}
$this->y++;
}







function _processCoordinate($last_attr, $cur_attr, $char)
{
$output = '';

if ($last_attr != $cur_attr) {
$close = $open = '';
if ($last_attr->foreground != $cur_attr->foreground) {
if ($cur_attr->foreground != 'white') {
$open.= '<span style="color: ' . $cur_attr->foreground . '">';
}
if ($last_attr->foreground != 'white') {
$close = '</span>' . $close;
}
}
if ($last_attr->background != $cur_attr->background) {
if ($cur_attr->background != 'black') {
$open.= '<span style="background: ' . $cur_attr->background . '">';
}
if ($last_attr->background != 'black') {
$close = '</span>' . $close;
}
}
if ($last_attr->bold != $cur_attr->bold) {
if ($cur_attr->bold) {
$open.= '<b>';
} else {
$close = '</b>' . $close;
}
}
if ($last_attr->underline != $cur_attr->underline) {
if ($cur_attr->underline) {
$open.= '<u>';
} else {
$close = '</u>' . $close;
}
}
if ($last_attr->blink != $cur_attr->blink) {
if ($cur_attr->blink) {
$open.= '<blink>';
} else {
$close = '</blink>' . $close;
}
}
$output.= $close . $open;
}

$output.= htmlspecialchars($char);

return $output;
}







function _getScreen()
{
$output = '';
$last_attr = $this->base_attr_cell;
for ($i = 0; $i <= $this->max_y; $i++) {
for ($j = 0; $j <= $this->max_x; $j++) {
$cur_attr = $this->attrs[$i][$j];
$output.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->screen[$i][$j]) ? $this->screen[$i][$j] : '');
$last_attr = $this->attrs[$i][$j];
}
$output.= "\r\n";
}
$output = substr($output, 0, -2);

 $output.= $this->_processCoordinate($last_attr, $this->base_attr_cell, '');
return rtrim($output);
}







function getScreen()
{
return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $this->_getScreen() . '</pre>';
}







function getHistory()
{
$scrollback = '';
$last_attr = $this->base_attr_cell;
for ($i = 0; $i < count($this->history); $i++) {
for ($j = 0; $j <= $this->max_x + 1; $j++) {
$cur_attr = $this->history_attrs[$i][$j];
$scrollback.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->history[$i][$j]) ? $this->history[$i][$j] : '');
$last_attr = $this->history_attrs[$i][$j];
}
$scrollback.= "\r\n";
}
$base_attr_cell = $this->base_attr_cell;
$this->base_attr_cell = $last_attr;
$scrollback.= $this->_getScreen();
$this->base_attr_cell = $base_attr_cell;

return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $scrollback . '</span></pre>';
}
}
<?php













namespace phpseclib\File\ASN1;










class Element
{






var $element;








function __construct($encoded)
{
$this->element = $encoded;
}
}
<?php






















namespace phpseclib\File;

use phpseclib\File\ASN1\Element;
use phpseclib\Math\BigInteger;
use DateTime;
use DateTimeZone;








class ASN1
{






const CLASS_UNIVERSAL = 0;
const CLASS_APPLICATION = 1;
const CLASS_CONTEXT_SPECIFIC = 2;
const CLASS_PRIVATE = 3;








const TYPE_BOOLEAN = 1;
const TYPE_INTEGER = 2;
const TYPE_BIT_STRING = 3;
const TYPE_OCTET_STRING = 4;
const TYPE_NULL = 5;
const TYPE_OBJECT_IDENTIFIER = 6;

 
 const TYPE_REAL = 9;
const TYPE_ENUMERATED = 10;

 const TYPE_UTF8_STRING = 12;

 const TYPE_SEQUENCE = 16; 
 const TYPE_SET = 17; 
 






const TYPE_NUMERIC_STRING = 18;
const TYPE_PRINTABLE_STRING = 19;
const TYPE_TELETEX_STRING = 20; 
 const TYPE_VIDEOTEX_STRING = 21;
const TYPE_IA5_STRING = 22;
const TYPE_UTC_TIME = 23;
const TYPE_GENERALIZED_TIME = 24;
const TYPE_GRAPHIC_STRING = 25;
const TYPE_VISIBLE_STRING = 26; 
 const TYPE_GENERAL_STRING = 27;
const TYPE_UNIVERSAL_STRING = 28;

 const TYPE_BMP_STRING = 30;









const TYPE_CHOICE = -1;
const TYPE_ANY = -2;









var $oids = array();








var $format = 'D, d M Y H:i:s O';










var $encoded;










var $filters;











var $ANYmap = array(
self::TYPE_BOOLEAN => true,
self::TYPE_INTEGER => true,
self::TYPE_BIT_STRING => 'bitString',
self::TYPE_OCTET_STRING => 'octetString',
self::TYPE_NULL => 'null',
self::TYPE_OBJECT_IDENTIFIER => 'objectIdentifier',
self::TYPE_REAL => true,
self::TYPE_ENUMERATED => 'enumerated',
self::TYPE_UTF8_STRING => 'utf8String',
self::TYPE_NUMERIC_STRING => 'numericString',
self::TYPE_PRINTABLE_STRING => 'printableString',
self::TYPE_TELETEX_STRING => 'teletexString',
self::TYPE_VIDEOTEX_STRING => 'videotexString',
self::TYPE_IA5_STRING => 'ia5String',
self::TYPE_UTC_TIME => 'utcTime',
self::TYPE_GENERALIZED_TIME => 'generalTime',
self::TYPE_GRAPHIC_STRING => 'graphicString',
self::TYPE_VISIBLE_STRING => 'visibleString',
self::TYPE_GENERAL_STRING => 'generalString',
self::TYPE_UNIVERSAL_STRING => 'universalString',

 self::TYPE_BMP_STRING => 'bmpString'
);










var $stringTypeSize = array(
self::TYPE_UTF8_STRING => 0,
self::TYPE_BMP_STRING => 2,
self::TYPE_UNIVERSAL_STRING => 4,
self::TYPE_PRINTABLE_STRING => 1,
self::TYPE_TELETEX_STRING => 1,
self::TYPE_IA5_STRING => 1,
self::TYPE_VISIBLE_STRING => 1,
);










function decodeBER($encoded)
{
if ($encoded instanceof Element) {
$encoded = $encoded->element;
}

$this->encoded = $encoded;

 return array($this->_decode_ber($encoded));
}














function _decode_ber($encoded, $start = 0, $encoded_pos = 0)
{
$current = array('start' => $start);

if (!isset($encoded[$encoded_pos])) {
return false;
}
$type = ord($encoded[$encoded_pos++]);
$startOffset = 1;

$constructed = ($type >> 5) & 1;

$tag = $type & 0x1F;
if ($tag == 0x1F) {
$tag = 0;

 do {
if (!isset($encoded[$encoded_pos])) {
return false;
}
$temp = ord($encoded[$encoded_pos++]);
$startOffset++;
$loop = $temp >> 7;
$tag <<= 7;
$temp &= 0x7F;

 if ($startOffset == 2 && $temp == 0) {
return false;
}
$tag |= $temp;
} while ($loop);
}

$start+= $startOffset;


 if (!isset($encoded[$encoded_pos])) {
return false;
}
$length = ord($encoded[$encoded_pos++]);
$start++;
if ($length == 0x80) { 
 
 
 $length = strlen($encoded) - $encoded_pos;
} elseif ($length & 0x80) { 
 
 
 $length&= 0x7F;
$temp = substr($encoded, $encoded_pos, $length);
$encoded_pos += $length;

 $current+= array('headerlength' => $length + 2);
$start+= $length;
extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)));
} else {
$current+= array('headerlength' => 2);
}

if ($length > (strlen($encoded) - $encoded_pos)) {
return false;
}

$content = substr($encoded, $encoded_pos, $length);
$content_pos = 0;












$class = ($type >> 6) & 3;
switch ($class) {
case self::CLASS_APPLICATION:
case self::CLASS_PRIVATE:
case self::CLASS_CONTEXT_SPECIFIC:
if (!$constructed) {
return array(
'type' => $class,
'constant' => $tag,
'content' => $content,
'length' => $length + $start - $current['start']
);
}

$newcontent = array();
$remainingLength = $length;
while ($remainingLength > 0) {
$temp = $this->_decode_ber($content, $start, $content_pos);
if ($temp === false) {
break;
}
$length = $temp['length'];

 if (substr($content, $content_pos + $length, 2) == "\0\0") {
$length+= 2;
$start+= $length;
$newcontent[] = $temp;
break;
}
$start+= $length;
$remainingLength-= $length;
$newcontent[] = $temp;
$content_pos += $length;
}

return array(
'type' => $class,
'constant' => $tag,

 'content' => $newcontent,

 
 
 'length' => $start - $current['start']
) + $current;
}

$current+= array('type' => $tag);


 switch ($tag) {
case self::TYPE_BOOLEAN:

 if ($constructed || strlen($content) != 1) {
return false;
}
$current['content'] = (bool) ord($content[$content_pos]);
break;
case self::TYPE_INTEGER:
case self::TYPE_ENUMERATED:
if ($constructed) {
return false;
}
$current['content'] = new BigInteger(substr($content, $content_pos), -256);
break;
case self::TYPE_REAL: 
 return false;
case self::TYPE_BIT_STRING:

 
 
 if (!$constructed) {
$current['content'] = substr($content, $content_pos);
} else {
$temp = $this->_decode_ber($content, $start, $content_pos);
if ($temp === false) {
return false;
}
$length-= (strlen($content) - $content_pos);
$last = count($temp) - 1;
for ($i = 0; $i < $last; $i++) {

 if ($temp[$i]['type'] != self::TYPE_BIT_STRING) {
return false;
}
$current['content'].= substr($temp[$i]['content'], 1);
}

 if ($temp[$last]['type'] != self::TYPE_BIT_STRING) {
return false;
}
$current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1);
}
break;
case self::TYPE_OCTET_STRING:
if (!$constructed) {
$current['content'] = substr($content, $content_pos);
} else {
$current['content'] = '';
$length = 0;
while (substr($content, $content_pos, 2) != "\0\0") {
$temp = $this->_decode_ber($content, $length + $start, $content_pos);
if ($temp === false) {
return false;
}
$content_pos += $temp['length'];

 if ($temp['type'] != self::TYPE_OCTET_STRING) {
return false;
}
$current['content'].= $temp['content'];
$length+= $temp['length'];
}
if (substr($content, $content_pos, 2) == "\0\0") {
$length+= 2; 
 }
}
break;
case self::TYPE_NULL:

 if ($constructed || strlen($content)) {
return false;
}
break;
case self::TYPE_SEQUENCE:
case self::TYPE_SET:
if (!$constructed) {
return false;
}
$offset = 0;
$current['content'] = array();
$content_len = strlen($content);
while ($content_pos < $content_len) {

 
 if (!isset($current['headerlength']) && substr($content, $content_pos, 2) == "\0\0") {
$length = $offset + 2; 
 break 2;
}
$temp = $this->_decode_ber($content, $start + $offset, $content_pos);
if ($temp === false) {
return false;
}
$content_pos += $temp['length'];
$current['content'][] = $temp;
$offset+= $temp['length'];
}
break;
case self::TYPE_OBJECT_IDENTIFIER:
if ($constructed) {
return false;
}
$current['content'] = $this->_decodeOID(substr($content, $content_pos));
if ($current['content'] === false) {
return false;
}
break;







case self::TYPE_NUMERIC_STRING:

 case self::TYPE_PRINTABLE_STRING:

 
 case self::TYPE_TELETEX_STRING:

 
 case self::TYPE_VIDEOTEX_STRING:

 case self::TYPE_VISIBLE_STRING:

 case self::TYPE_IA5_STRING:

 case self::TYPE_GRAPHIC_STRING:

 case self::TYPE_GENERAL_STRING:

 case self::TYPE_UTF8_STRING:

 case self::TYPE_BMP_STRING:
if ($constructed) {
return false;
}
$current['content'] = substr($content, $content_pos);
break;
case self::TYPE_UTC_TIME:
case self::TYPE_GENERALIZED_TIME:
if ($constructed) {
return false;
}
$current['content'] = $this->_decodeTime(substr($content, $content_pos), $tag);
break;
default:
return false;
}

$start+= $length;


 return $current + array('length' => $start - $current['start']);
}














function asn1map($decoded, $mapping, $special = array())
{
if (!is_array($decoded)) {
return false;
}

if (isset($mapping['explicit']) && is_array($decoded['content'])) {
$decoded = $decoded['content'][0];
}

switch (true) {
case $mapping['type'] == self::TYPE_ANY:
$intype = $decoded['type'];
if (isset($decoded['constant']) || !isset($this->ANYmap[$intype]) || (ord($this->encoded[$decoded['start']]) & 0x20)) {
return new Element(substr($this->encoded, $decoded['start'], $decoded['length']));
}
$inmap = $this->ANYmap[$intype];
if (is_string($inmap)) {
return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping, $special));
}
break;
case $mapping['type'] == self::TYPE_CHOICE:
foreach ($mapping['children'] as $key => $option) {
switch (true) {
case isset($option['constant']) && $option['constant'] == $decoded['constant']:
case !isset($option['constant']) && $option['type'] == $decoded['type']:
$value = $this->asn1map($decoded, $option, $special);
break;
case !isset($option['constant']) && $option['type'] == self::TYPE_CHOICE:
$v = $this->asn1map($decoded, $option, $special);
if (isset($v)) {
$value = $v;
}
}
if (isset($value)) {
if (isset($special[$key])) {
$value = call_user_func($special[$key], $value);
}
return array($key => $value);
}
}
return null;
case isset($mapping['implicit']):
case isset($mapping['explicit']):
case $decoded['type'] == $mapping['type']:
break;
default:

 
 switch (true) {
case $decoded['type'] < 18: 
 case $decoded['type'] > 30: 
 case $mapping['type'] < 18:
case $mapping['type'] > 30:
return null;
}
}

if (isset($mapping['implicit'])) {
$decoded['type'] = $mapping['type'];
}

switch ($decoded['type']) {
case self::TYPE_SEQUENCE:
$map = array();


 if (isset($mapping['min']) && isset($mapping['max'])) {
$child = $mapping['children'];
foreach ($decoded['content'] as $content) {
if (($map[] = $this->asn1map($content, $child, $special)) === null) {
return null;
}
}

return $map;
}

$n = count($decoded['content']);
$i = 0;

foreach ($mapping['children'] as $key => $child) {
$maymatch = $i < $n; 
 if ($maymatch) {
$temp = $decoded['content'][$i];

if ($child['type'] != self::TYPE_CHOICE) {

 $childClass = $tempClass = self::CLASS_UNIVERSAL;
$constant = null;
if (isset($temp['constant'])) {
$tempClass = $temp['type'];
}
if (isset($child['class'])) {
$childClass = $child['class'];
$constant = $child['cast'];
} elseif (isset($child['constant'])) {
$childClass = self::CLASS_CONTEXT_SPECIFIC;
$constant = $child['constant'];
}

if (isset($constant) && isset($temp['constant'])) {

 $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
} else {

 $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], self::TYPE_ANY, self::TYPE_CHOICE)) !== false;
}
}
}

if ($maymatch) {

 $candidate = $this->asn1map($temp, $child, $special);
$maymatch = $candidate !== null;
}

if ($maymatch) {

 if (isset($special[$key])) {
$candidate = call_user_func($special[$key], $candidate);
}
$map[$key] = $candidate;
$i++;
} elseif (isset($child['default'])) {
$map[$key] = $child['default']; 
 } elseif (!isset($child['optional'])) {
return null; 
 }
}


 return $i < $n ? null: $map;


 case self::TYPE_SET:
$map = array();


 if (isset($mapping['min']) && isset($mapping['max'])) {
$child = $mapping['children'];
foreach ($decoded['content'] as $content) {
if (($map[] = $this->asn1map($content, $child, $special)) === null) {
return null;
}
}

return $map;
}

for ($i = 0; $i < count($decoded['content']); $i++) {
$temp = $decoded['content'][$i];
$tempClass = self::CLASS_UNIVERSAL;
if (isset($temp['constant'])) {
$tempClass = $temp['type'];
}

foreach ($mapping['children'] as $key => $child) {
if (isset($map[$key])) {
continue;
}
$maymatch = true;
if ($child['type'] != self::TYPE_CHOICE) {
$childClass = self::CLASS_UNIVERSAL;
$constant = null;
if (isset($child['class'])) {
$childClass = $child['class'];
$constant = $child['cast'];
} elseif (isset($child['constant'])) {
$childClass = self::CLASS_CONTEXT_SPECIFIC;
$constant = $child['constant'];
}

if (isset($constant) && isset($temp['constant'])) {

 $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
} else {

 $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], self::TYPE_ANY, self::TYPE_CHOICE)) !== false;
}
}

if ($maymatch) {

 $candidate = $this->asn1map($temp, $child, $special);
$maymatch = $candidate !== null;
}

if (!$maymatch) {
break;
}


 if (isset($special[$key])) {
$candidate = call_user_func($special[$key], $candidate);
}
$map[$key] = $candidate;
break;
}
}

foreach ($mapping['children'] as $key => $child) {
if (!isset($map[$key])) {
if (isset($child['default'])) {
$map[$key] = $child['default'];
} elseif (!isset($child['optional'])) {
return null;
}
}
}
return $map;
case self::TYPE_OBJECT_IDENTIFIER:
return isset($this->oids[$decoded['content']]) ? $this->oids[$decoded['content']] : $decoded['content'];
case self::TYPE_UTC_TIME:
case self::TYPE_GENERALIZED_TIME:

 if (is_array($decoded['content'])) {
$decoded['content'] = $decoded['content'][0]['content'];
}

 
 
 if (!is_object($decoded['content'])) {
$decoded['content'] = $this->_decodeTime($decoded['content'], $decoded['type']);
}
return $decoded['content'] ? $decoded['content']->format($this->format) : false;
case self::TYPE_BIT_STRING:
if (isset($mapping['mapping'])) {
$offset = ord($decoded['content'][0]);
$size = (strlen($decoded['content']) - 1) * 8 - $offset;








$bits = count($mapping['mapping']) == $size ? array() : array_fill(0, count($mapping['mapping']) - $size, false);
for ($i = strlen($decoded['content']) - 1; $i > 0; $i--) {
$current = ord($decoded['content'][$i]);
for ($j = $offset; $j < 8; $j++) {
$bits[] = (bool) ($current & (1 << $j));
}
$offset = 0;
}
$values = array();
$map = array_reverse($mapping['mapping']);
foreach ($map as $i => $value) {
if ($bits[$i]) {
$values[] = $value;
}
}
return $values;
}
case self::TYPE_OCTET_STRING:
return base64_encode($decoded['content']);
case self::TYPE_NULL:
return '';
case self::TYPE_BOOLEAN:
return $decoded['content'];
case self::TYPE_NUMERIC_STRING:
case self::TYPE_PRINTABLE_STRING:
case self::TYPE_TELETEX_STRING:
case self::TYPE_VIDEOTEX_STRING:
case self::TYPE_IA5_STRING:
case self::TYPE_GRAPHIC_STRING:
case self::TYPE_VISIBLE_STRING:
case self::TYPE_GENERAL_STRING:
case self::TYPE_UNIVERSAL_STRING:
case self::TYPE_UTF8_STRING:
case self::TYPE_BMP_STRING:
return $decoded['content'];
case self::TYPE_INTEGER:
case self::TYPE_ENUMERATED:
$temp = $decoded['content'];
if (isset($mapping['implicit'])) {
$temp = new BigInteger($decoded['content'], -256);
}
if (isset($mapping['mapping'])) {
$temp = (int) $temp->toString();
return isset($mapping['mapping'][$temp]) ?
$mapping['mapping'][$temp] :
false;
}
return $temp;
}
}















function encodeDER($source, $mapping, $special = array())
{
$this->location = array();
return $this->_encode_der($source, $mapping, null, $special);
}











function _encode_der($source, $mapping, $idx = null, $special = array())
{
if ($source instanceof Element) {
return $source->element;
}


 if (isset($mapping['default']) && $source === $mapping['default']) {
return '';
}

if (isset($idx)) {
if (isset($special[$idx])) {
$source = call_user_func($special[$idx], $source);
}
$this->location[] = $idx;
}

$tag = $mapping['type'];

switch ($tag) {
case self::TYPE_SET: 
 case self::TYPE_SEQUENCE:
$tag|= 0x20; 


 if (isset($mapping['min']) && isset($mapping['max'])) {
$value = array();
$child = $mapping['children'];

foreach ($source as $content) {
$temp = $this->_encode_der($content, $child, null, $special);
if ($temp === false) {
return false;
}
$value[]= $temp;
}





if ($mapping['type'] == self::TYPE_SET) {
sort($value);
}
$value = implode('', $value);
break;
}

$value = '';
foreach ($mapping['children'] as $key => $child) {
if (!array_key_exists($key, $source)) {
if (!isset($child['optional'])) {
return false;
}
continue;
}

$temp = $this->_encode_der($source[$key], $child, $key, $special);
if ($temp === false) {
return false;
}


 
 if ($temp === '') {
continue;
}


 if (isset($child['constant'])) {









if (isset($child['explicit']) || $child['type'] == self::TYPE_CHOICE) {
$subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
$temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
} else {
$subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
$temp = $subtag . substr($temp, 1);
}
}
$value.= $temp;
}
break;
case self::TYPE_CHOICE:
$temp = false;

foreach ($mapping['children'] as $key => $child) {
if (!isset($source[$key])) {
continue;
}

$temp = $this->_encode_der($source[$key], $child, $key, $special);
if ($temp === false) {
return false;
}


 
 if ($temp === '') {
continue;
}

$tag = ord($temp[0]);


 if (isset($child['constant'])) {
if (isset($child['explicit']) || $child['type'] == self::TYPE_CHOICE) {
$subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
$temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
} else {
$subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
$temp = $subtag . substr($temp, 1);
}
}
}

if (isset($idx)) {
array_pop($this->location);
}

if ($temp && isset($mapping['cast'])) {
$temp[0] = chr(($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast']);
}

return $temp;
case self::TYPE_INTEGER:
case self::TYPE_ENUMERATED:
if (!isset($mapping['mapping'])) {
if (is_numeric($source)) {
$source = new BigInteger($source);
}
$value = $source->toBytes(true);
} else {
$value = array_search($source, $mapping['mapping']);
if ($value === false) {
return false;
}
$value = new BigInteger($value);
$value = $value->toBytes(true);
}
if (!strlen($value)) {
$value = chr(0);
}
break;
case self::TYPE_UTC_TIME:
case self::TYPE_GENERALIZED_TIME:
$format = $mapping['type'] == self::TYPE_UTC_TIME ? 'y' : 'Y';
$format.= 'mdHis';

 $date = new DateTime($source, new DateTimeZone('GMT'));

 $date->setTimezone(new DateTimeZone('GMT'));
$value = $date->format($format) . 'Z';
break;
case self::TYPE_BIT_STRING:
if (isset($mapping['mapping'])) {
$bits = array_fill(0, count($mapping['mapping']), 0);
$size = 0;
for ($i = 0; $i < count($mapping['mapping']); $i++) {
if (in_array($mapping['mapping'][$i], $source)) {
$bits[$i] = 1;
$size = $i;
}
}

if (isset($mapping['min']) && $mapping['min'] >= 1 && $size < $mapping['min']) {
$size = $mapping['min'] - 1;
}

$offset = 8 - (($size + 1) & 7);
$offset = $offset !== 8 ? $offset : 0;

$value = chr($offset);

for ($i = $size + 1; $i < count($mapping['mapping']); $i++) {
unset($bits[$i]);
}

$bits = implode('', array_pad($bits, $size + $offset + 1, 0));
$bytes = explode(' ', rtrim(chunk_split($bits, 8, ' ')));
foreach ($bytes as $byte) {
$value.= chr(bindec($byte));
}

break;
}
case self::TYPE_OCTET_STRING:




$value = base64_decode($source);
break;
case self::TYPE_OBJECT_IDENTIFIER:
$value = $this->_encodeOID($source);
break;
case self::TYPE_ANY:
$loc = $this->location;
if (isset($idx)) {
array_pop($this->location);
}

switch (true) {
case !isset($source):
return $this->_encode_der(null, array('type' => self::TYPE_NULL) + $mapping, null, $special);
case is_int($source):
case $source instanceof BigInteger:
return $this->_encode_der($source, array('type' => self::TYPE_INTEGER) + $mapping, null, $special);
case is_float($source):
return $this->_encode_der($source, array('type' => self::TYPE_REAL) + $mapping, null, $special);
case is_bool($source):
return $this->_encode_der($source, array('type' => self::TYPE_BOOLEAN) + $mapping, null, $special);
case is_array($source) && count($source) == 1:
$typename = implode('', array_keys($source));
$outtype = array_search($typename, $this->ANYmap, true);
if ($outtype !== false) {
return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping, null, $special);
}
}

$filters = $this->filters;
foreach ($loc as $part) {
if (!isset($filters[$part])) {
$filters = false;
break;
}
$filters = $filters[$part];
}
if ($filters === false) {
user_error('No filters defined for ' . implode('/', $loc));
return false;
}
return $this->_encode_der($source, $filters + $mapping, null, $special);
case self::TYPE_NULL:
$value = '';
break;
case self::TYPE_NUMERIC_STRING:
case self::TYPE_TELETEX_STRING:
case self::TYPE_PRINTABLE_STRING:
case self::TYPE_UNIVERSAL_STRING:
case self::TYPE_UTF8_STRING:
case self::TYPE_BMP_STRING:
case self::TYPE_IA5_STRING:
case self::TYPE_VISIBLE_STRING:
case self::TYPE_VIDEOTEX_STRING:
case self::TYPE_GRAPHIC_STRING:
case self::TYPE_GENERAL_STRING:
$value = $source;
break;
case self::TYPE_BOOLEAN:
$value = $source ? "\xFF" : "\x00";
break;
default:
user_error('Mapping provides no type definition for ' . implode('/', $this->location));
return false;
}

if (isset($idx)) {
array_pop($this->location);
}

if (isset($mapping['cast'])) {
if (isset($mapping['explicit']) || $mapping['type'] == self::TYPE_CHOICE) {
$value = chr($tag) . $this->_encodeLength(strlen($value)) . $value;
$tag = ($mapping['class'] << 6) | 0x20 | $mapping['cast'];
} else {
$tag = ($mapping['class'] << 6) | (ord($temp[0]) & 0x20) | $mapping['cast'];
}
}

return chr($tag) . $this->_encodeLength(strlen($value)) . $value;
}











function _encodeLength($length)
{
if ($length <= 0x7F) {
return chr($length);
}

$temp = ltrim(pack('N', $length), chr(0));
return pack('Ca*', 0x80 | strlen($temp), $temp);
}










function _decodeOID($content)
{
static $eighty;
if (!$eighty) {
$eighty = new BigInteger(80);
}

$oid = array();
$pos = 0;
$len = strlen($content);

if (ord($content[$len - 1]) & 0x80) {
return false;
}

$n = new BigInteger();
while ($pos < $len) {
$temp = ord($content[$pos++]);
$n = $n->bitwise_leftShift(7);
$n = $n->bitwise_or(new BigInteger($temp & 0x7F));
if (~$temp & 0x80) {
$oid[] = $n;
$n = new BigInteger();
}
}
$part1 = array_shift($oid);
$first = floor(ord($content[0]) / 40);






if ($first <= 2) { 
 array_unshift($oid, ord($content[0]) % 40);
array_unshift($oid, $first);
} else {
array_unshift($oid, $part1->subtract($eighty));
array_unshift($oid, 2);
}

return implode('.', $oid);
}










function _encodeOID($source)
{
static $mask, $zero, $forty;
if (!$mask) {
$mask = new BigInteger(0x7F);
$zero = new BigInteger();
$forty = new BigInteger(40);
}

$oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
if ($oid === false) {
user_error('Invalid OID');
return false;
}
$parts = explode('.', $oid);
$part1 = array_shift($parts);
$part2 = array_shift($parts);

$first = new BigInteger($part1);
$first = $first->multiply($forty);
$first = $first->add(new BigInteger($part2));

array_unshift($parts, $first->toString());

$value = '';
foreach ($parts as $part) {
if (!$part) {
$temp = "\0";
} else {
$temp = '';
$part = new BigInteger($part);
while (!$part->equals($zero)) {
$submask = $part->bitwise_and($mask);
$submask->setPrecision(8);
$temp = (chr(0x80) | $submask->toBytes()) . $temp;
$part = $part->bitwise_rightShift(7);
}
$temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
}
$value.= $temp;
}

return $value;
}











function _decodeTime($content, $tag)
{








$format = 'YmdHis';

if ($tag == self::TYPE_UTC_TIME) {

 
 
 if (preg_match('#^(\d{10})(Z|[+-]\d{4})$#', $content, $matches)) {
$content = $matches[1] . '00' . $matches[2];
}
$prefix = substr($content, 0, 2) >= 50 ? '19' : '20';
$content = $prefix . $content;
} elseif (strpos($content, '.') !== false) {
$format.= '.u';
}

if ($content[strlen($content) - 1] == 'Z') {
$content = substr($content, 0, -1) . '+0000';
}

if (strpos($content, '-') !== false || strpos($content, '+') !== false) {
$format.= 'O';
}


 
 return @DateTime::createFromFormat($format, $content);
}









function setTimeFormat($format)
{
$this->format = $format;
}









function loadOIDs($oids)
{
$this->oids = $oids;
}









function loadFilters($filters)
{
$this->filters = $filters;
}











function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}













function convert($in, $from = self::TYPE_UTF8_STRING, $to = self::TYPE_UTF8_STRING)
{
if (!isset($this->stringTypeSize[$from]) || !isset($this->stringTypeSize[$to])) {
return false;
}
$insize = $this->stringTypeSize[$from];
$outsize = $this->stringTypeSize[$to];
$inlength = strlen($in);
$out = '';

for ($i = 0; $i < $inlength;) {
if ($inlength - $i < $insize) {
return false;
}


 $c = ord($in[$i++]);
switch (true) {
case $insize == 4:
$c = ($c << 8) | ord($in[$i++]);
$c = ($c << 8) | ord($in[$i++]);
case $insize == 2:
$c = ($c << 8) | ord($in[$i++]);
case $insize == 1:
break;
case ($c & 0x80) == 0x00:
break;
case ($c & 0x40) == 0x00:
return false;
default:
$bit = 6;
do {
if ($bit > 25 || $i >= $inlength || (ord($in[$i]) & 0xC0) != 0x80) {
return false;
}
$c = ($c << 6) | (ord($in[$i++]) & 0x3F);
$bit += 5;
$mask = 1 << $bit;
} while ($c & $bit);
$c &= $mask - 1;
break;
}


 $v = '';
switch (true) {
case $outsize == 4:
$v .= chr($c & 0xFF);
$c >>= 8;
$v .= chr($c & 0xFF);
$c >>= 8;
case $outsize == 2:
$v .= chr($c & 0xFF);
$c >>= 8;
case $outsize == 1:
$v .= chr($c & 0xFF);
$c >>= 8;
if ($c) {
return false;
}
break;
case ($c & 0x80000000) != 0:
return false;
case $c >= 0x04000000:
$v .= chr(0x80 | ($c & 0x3F));
$c = ($c >> 6) | 0x04000000;
case $c >= 0x00200000:
$v .= chr(0x80 | ($c & 0x3F));
$c = ($c >> 6) | 0x00200000;
case $c >= 0x00010000:
$v .= chr(0x80 | ($c & 0x3F));
$c = ($c >> 6) | 0x00010000;
case $c >= 0x00000800:
$v .= chr(0x80 | ($c & 0x3F));
$c = ($c >> 6) | 0x00000800;
case $c >= 0x00000080:
$v .= chr(0x80 | ($c & 0x3F));
$c = ($c >> 6) | 0x000000C0;
default:
$v .= chr($c);
break;
}
$out .= strrev($v);
}
return $out;
}
}
<?php
































namespace phpseclib\System\SSH;

use phpseclib\Crypt\RSA;
use phpseclib\System\SSH\Agent\Identity;










class Agent
{






 const SSH_AGENTC_REQUEST_IDENTITIES = 11;

 const SSH_AGENT_IDENTITIES_ANSWER = 12;

 const SSH_AGENTC_SIGN_REQUEST = 13;

 const SSH_AGENT_SIGN_RESPONSE = 14;








 const FORWARD_NONE = 0;

 const FORWARD_REQUEST = 1;

 const FORWARD_ACTIVE = 2;





const SSH_AGENT_FAILURE = 5;







var $fsock;






var $forward_status = self::FORWARD_NONE;








var $socket_buffer = '';






var $expected_bytes = 0;







function __construct($address = null)
{
if (!$address) {
switch (true) {
case isset($_SERVER['SSH_AUTH_SOCK']):
$address = $_SERVER['SSH_AUTH_SOCK'];
break;
case isset($_ENV['SSH_AUTH_SOCK']):
$address = $_ENV['SSH_AUTH_SOCK'];
break;
default:
user_error('SSH_AUTH_SOCK not found');
return false;
}
}

$this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
if (!$this->fsock) {
user_error("Unable to connect to ssh-agent (Error $errno: $errstr)");
}
}










function requestIdentities()
{
if (!$this->fsock) {
return array();
}

$packet = pack('NC', 1, self::SSH_AGENTC_REQUEST_IDENTITIES);
if (strlen($packet) != fputs($this->fsock, $packet)) {
user_error('Connection closed while requesting identities');
return array();
}

$temp = fread($this->fsock, 4);
if (strlen($temp) != 4) {
user_error('Connection closed while requesting identities');
return array();
}
$length = current(unpack('N', $temp));
$type = ord(fread($this->fsock, 1));
if ($type != self::SSH_AGENT_IDENTITIES_ANSWER) {
user_error('Unable to request identities');
return array();
}

$identities = array();
$temp = fread($this->fsock, 4);
if (strlen($temp) != 4) {
user_error('Connection closed while requesting identities');
return array();
}
$keyCount = current(unpack('N', $temp));
for ($i = 0; $i < $keyCount; $i++) {
$temp = fread($this->fsock, 4);
if (strlen($temp) != 4) {
user_error('Connection closed while requesting identities');
return array();
}
$length = current(unpack('N', $temp));
$key_blob = fread($this->fsock, $length);
if (strlen($key_blob) != $length) {
user_error('Connection closed while requesting identities');
return array();
}
$key_str = 'ssh-rsa ' . base64_encode($key_blob);
$temp = fread($this->fsock, 4);
if (strlen($temp) != 4) {
user_error('Connection closed while requesting identities');
return array();
}
$length = current(unpack('N', $temp));
if ($length) {
$temp = fread($this->fsock, $length);
if (strlen($temp) != $length) {
user_error('Connection closed while requesting identities');
return array();
}
$key_str.= ' ' . $temp;
}
$length = current(unpack('N', substr($key_blob, 0, 4)));
$key_type = substr($key_blob, 4, $length);
switch ($key_type) {
case 'ssh-rsa':
$key = new RSA();
$key->loadKey($key_str);
break;
case 'ssh-dss':

 break;
}

 if (isset($key)) {
$identity = new Identity($this->fsock);
$identity->setPublicKey($key);
$identity->setPublicKeyBlob($key_blob);
$identities[] = $identity;
unset($key);
}
}

return $identities;
}









function startSSHForwarding($ssh)
{
if ($this->forward_status == self::FORWARD_NONE) {
$this->forward_status = self::FORWARD_REQUEST;
}
}








function _request_forwarding($ssh)
{
$request_channel = $ssh->_get_open_channel();
if ($request_channel === false) {
return false;
}

$packet = pack(
'CNNa*C',
NET_SSH2_MSG_CHANNEL_REQUEST,
$ssh->server_channels[$request_channel],
strlen('auth-agent-req@openssh.com'),
'auth-agent-req@openssh.com',
1
);

$ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_REQUEST;

if (!$ssh->_send_binary_packet($packet)) {
return false;
}

$response = $ssh->_get_channel_packet($request_channel);
if ($response === false) {
return false;
}

$ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_OPEN;
$this->forward_status = self::FORWARD_ACTIVE;

return true;
}











function _on_channel_open($ssh)
{
if ($this->forward_status == self::FORWARD_REQUEST) {
$this->_request_forwarding($ssh);
}
}








function _forward_data($data)
{
if ($this->expected_bytes > 0) {
$this->socket_buffer.= $data;
$this->expected_bytes -= strlen($data);
} else {
$agent_data_bytes = current(unpack('N', $data));
$current_data_bytes = strlen($data);
$this->socket_buffer = $data;
if ($current_data_bytes != $agent_data_bytes + 4) {
$this->expected_bytes = ($agent_data_bytes + 4) - $current_data_bytes;
return false;
}
}

if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) {
user_error('Connection closed attempting to forward data to SSH agent');
return false;
}

$this->socket_buffer = '';
$this->expected_bytes = 0;

$temp = fread($this->fsock, 4);
if (strlen($temp) != 4) {
user_error('Connection closed while reading data response');
return false;
}
$agent_reply_bytes = current(unpack('N', $temp));

$agent_reply_data = fread($this->fsock, $agent_reply_bytes);
if (strlen($agent_reply_data) != $agent_reply_bytes) {
user_error('Connection closed while reading data response');
return false;
}
$agent_reply_data = current(unpack('a*', $agent_reply_data));

return pack('Na*', $agent_reply_bytes, $agent_reply_data);
}
}
<?php














namespace phpseclib\System\SSH\Agent;

use phpseclib\System\SSH\Agent;














class Identity
{







const SSH_AGENT_RSA2_256 = 2;
const SSH_AGENT_RSA2_512 = 4;









var $key;








var $key_blob;








var $fsock;









var $flags = 0;








function __construct($fsock)
{
$this->fsock = $fsock;
}









function setPublicKey($key)
{
$this->key = $key;
$this->key->setPublicKey();
}










function setPublicKeyBlob($key_blob)
{
$this->key_blob = $key_blob;
}










function getPublicKey($format = null)
{
return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format);
}










function setSignatureMode($mode)
{
}









function setHash($hash)
{
$this->flags = 0;
switch ($hash) {
case 'sha1':
break;
case 'sha256':
$this->flags = self::SSH_AGENT_RSA2_256;
break;
case 'sha512':
$this->flags = self::SSH_AGENT_RSA2_512;
break;
default:
user_error('The only supported hashes for RSA are sha1, sha256 and sha512');
}
}










function sign($message)
{

 $packet = pack('CNa*Na*N', Agent::SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, $this->flags);
$packet = pack('Na*', strlen($packet), $packet);
if (strlen($packet) != fputs($this->fsock, $packet)) {
user_error('Connection closed during signing');
return false;
}

$temp = fread($this->fsock, 4);
if (strlen($temp) != 4) {
user_error('Connection closed during signing');
return false;
}
$length = current(unpack('N', $temp));
$type = ord(fread($this->fsock, 1));
if ($type != Agent::SSH_AGENT_SIGN_RESPONSE) {
user_error('Unable to retrieve signature');
return false;
}

$signature_blob = fread($this->fsock, $length - 1);
if (strlen($signature_blob) != $length - 1) {
user_error('Connection closed during signing');
return false;
}
$length = current(unpack('N', $this->_string_shift($signature_blob, 4)));
if ($length != strlen($signature_blob)) {
user_error('Malformed signature blob');
}
$length = current(unpack('N', $this->_string_shift($signature_blob, 4)));
if ($length > strlen($signature_blob) + 4) {
user_error('Malformed signature blob');
}
$type = $this->_string_shift($signature_blob, $length);
$this->_string_shift($signature_blob, 4);

return $signature_blob;
}











function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
}
<?php





namespace Webmozart\Assert;

use ArrayAccess;
use Closure;
use Countable;
use Throwable;





trait Mixin
{











public static function nullOrString($value, $message = '')
{
static::__callStatic('nullOrString', array($value, $message));
}












public static function allString($value, $message = '')
{
static::__callStatic('allString', array($value, $message));
}












public static function nullOrStringNotEmpty($value, $message = '')
{
static::__callStatic('nullOrStringNotEmpty', array($value, $message));
}












public static function allStringNotEmpty($value, $message = '')
{
static::__callStatic('allStringNotEmpty', array($value, $message));
}












public static function nullOrInteger($value, $message = '')
{
static::__callStatic('nullOrInteger', array($value, $message));
}












public static function allInteger($value, $message = '')
{
static::__callStatic('allInteger', array($value, $message));
}












public static function nullOrIntegerish($value, $message = '')
{
static::__callStatic('nullOrIntegerish', array($value, $message));
}












public static function allIntegerish($value, $message = '')
{
static::__callStatic('allIntegerish', array($value, $message));
}












public static function nullOrPositiveInteger($value, $message = '')
{
static::__callStatic('nullOrPositiveInteger', array($value, $message));
}












public static function allPositiveInteger($value, $message = '')
{
static::__callStatic('allPositiveInteger', array($value, $message));
}












public static function nullOrFloat($value, $message = '')
{
static::__callStatic('nullOrFloat', array($value, $message));
}












public static function allFloat($value, $message = '')
{
static::__callStatic('allFloat', array($value, $message));
}












public static function nullOrNumeric($value, $message = '')
{
static::__callStatic('nullOrNumeric', array($value, $message));
}












public static function allNumeric($value, $message = '')
{
static::__callStatic('allNumeric', array($value, $message));
}












public static function nullOrNatural($value, $message = '')
{
static::__callStatic('nullOrNatural', array($value, $message));
}












public static function allNatural($value, $message = '')
{
static::__callStatic('allNatural', array($value, $message));
}












public static function nullOrBoolean($value, $message = '')
{
static::__callStatic('nullOrBoolean', array($value, $message));
}












public static function allBoolean($value, $message = '')
{
static::__callStatic('allBoolean', array($value, $message));
}












public static function nullOrScalar($value, $message = '')
{
static::__callStatic('nullOrScalar', array($value, $message));
}












public static function allScalar($value, $message = '')
{
static::__callStatic('allScalar', array($value, $message));
}












public static function nullOrObject($value, $message = '')
{
static::__callStatic('nullOrObject', array($value, $message));
}












public static function allObject($value, $message = '')
{
static::__callStatic('allObject', array($value, $message));
}













public static function nullOrResource($value, $type = null, $message = '')
{
static::__callStatic('nullOrResource', array($value, $type, $message));
}













public static function allResource($value, $type = null, $message = '')
{
static::__callStatic('allResource', array($value, $type, $message));
}












public static function nullOrIsCallable($value, $message = '')
{
static::__callStatic('nullOrIsCallable', array($value, $message));
}












public static function allIsCallable($value, $message = '')
{
static::__callStatic('allIsCallable', array($value, $message));
}












public static function nullOrIsArray($value, $message = '')
{
static::__callStatic('nullOrIsArray', array($value, $message));
}












public static function allIsArray($value, $message = '')
{
static::__callStatic('allIsArray', array($value, $message));
}














public static function nullOrIsTraversable($value, $message = '')
{
static::__callStatic('nullOrIsTraversable', array($value, $message));
}














public static function allIsTraversable($value, $message = '')
{
static::__callStatic('allIsTraversable', array($value, $message));
}












public static function nullOrIsArrayAccessible($value, $message = '')
{
static::__callStatic('nullOrIsArrayAccessible', array($value, $message));
}












public static function allIsArrayAccessible($value, $message = '')
{
static::__callStatic('allIsArrayAccessible', array($value, $message));
}












public static function nullOrIsCountable($value, $message = '')
{
static::__callStatic('nullOrIsCountable', array($value, $message));
}












public static function allIsCountable($value, $message = '')
{
static::__callStatic('allIsCountable', array($value, $message));
}












public static function nullOrIsIterable($value, $message = '')
{
static::__callStatic('nullOrIsIterable', array($value, $message));
}












public static function allIsIterable($value, $message = '')
{
static::__callStatic('allIsIterable', array($value, $message));
}















public static function nullOrIsInstanceOf($value, $class, $message = '')
{
static::__callStatic('nullOrIsInstanceOf', array($value, $class, $message));
}















public static function allIsInstanceOf($value, $class, $message = '')
{
static::__callStatic('allIsInstanceOf', array($value, $class, $message));
}














public static function nullOrNotInstanceOf($value, $class, $message = '')
{
static::__callStatic('nullOrNotInstanceOf', array($value, $class, $message));
}














public static function allNotInstanceOf($value, $class, $message = '')
{
static::__callStatic('allNotInstanceOf', array($value, $class, $message));
}













public static function nullOrIsInstanceOfAny($value, $classes, $message = '')
{
static::__callStatic('nullOrIsInstanceOfAny', array($value, $classes, $message));
}













public static function allIsInstanceOfAny($value, $classes, $message = '')
{
static::__callStatic('allIsInstanceOfAny', array($value, $classes, $message));
}















public static function nullOrIsAOf($value, $class, $message = '')
{
static::__callStatic('nullOrIsAOf', array($value, $class, $message));
}















public static function allIsAOf($value, $class, $message = '')
{
static::__callStatic('allIsAOf', array($value, $class, $message));
}














public static function nullOrIsNotA($value, $class, $message = '')
{
static::__callStatic('nullOrIsNotA', array($value, $class, $message));
}














public static function allIsNotA($value, $class, $message = '')
{
static::__callStatic('allIsNotA', array($value, $class, $message));
}













public static function nullOrIsAnyOf($value, $classes, $message = '')
{
static::__callStatic('nullOrIsAnyOf', array($value, $classes, $message));
}













public static function allIsAnyOf($value, $classes, $message = '')
{
static::__callStatic('allIsAnyOf', array($value, $classes, $message));
}












public static function nullOrIsEmpty($value, $message = '')
{
static::__callStatic('nullOrIsEmpty', array($value, $message));
}












public static function allIsEmpty($value, $message = '')
{
static::__callStatic('allIsEmpty', array($value, $message));
}











public static function nullOrNotEmpty($value, $message = '')
{
static::__callStatic('nullOrNotEmpty', array($value, $message));
}











public static function allNotEmpty($value, $message = '')
{
static::__callStatic('allNotEmpty', array($value, $message));
}












public static function allNull($value, $message = '')
{
static::__callStatic('allNull', array($value, $message));
}











public static function allNotNull($value, $message = '')
{
static::__callStatic('allNotNull', array($value, $message));
}












public static function nullOrTrue($value, $message = '')
{
static::__callStatic('nullOrTrue', array($value, $message));
}












public static function allTrue($value, $message = '')
{
static::__callStatic('allTrue', array($value, $message));
}












public static function nullOrFalse($value, $message = '')
{
static::__callStatic('nullOrFalse', array($value, $message));
}












public static function allFalse($value, $message = '')
{
static::__callStatic('allFalse', array($value, $message));
}











public static function nullOrNotFalse($value, $message = '')
{
static::__callStatic('nullOrNotFalse', array($value, $message));
}











public static function allNotFalse($value, $message = '')
{
static::__callStatic('allNotFalse', array($value, $message));
}









public static function nullOrIp($value, $message = '')
{
static::__callStatic('nullOrIp', array($value, $message));
}









public static function allIp($value, $message = '')
{
static::__callStatic('allIp', array($value, $message));
}









public static function nullOrIpv4($value, $message = '')
{
static::__callStatic('nullOrIpv4', array($value, $message));
}









public static function allIpv4($value, $message = '')
{
static::__callStatic('allIpv4', array($value, $message));
}









public static function nullOrIpv6($value, $message = '')
{
static::__callStatic('nullOrIpv6', array($value, $message));
}









public static function allIpv6($value, $message = '')
{
static::__callStatic('allIpv6', array($value, $message));
}









public static function nullOrEmail($value, $message = '')
{
static::__callStatic('nullOrEmail', array($value, $message));
}









public static function allEmail($value, $message = '')
{
static::__callStatic('allEmail', array($value, $message));
}









public static function nullOrUniqueValues($values, $message = '')
{
static::__callStatic('nullOrUniqueValues', array($values, $message));
}









public static function allUniqueValues($values, $message = '')
{
static::__callStatic('allUniqueValues', array($values, $message));
}










public static function nullOrEq($value, $expect, $message = '')
{
static::__callStatic('nullOrEq', array($value, $expect, $message));
}










public static function allEq($value, $expect, $message = '')
{
static::__callStatic('allEq', array($value, $expect, $message));
}










public static function nullOrNotEq($value, $expect, $message = '')
{
static::__callStatic('nullOrNotEq', array($value, $expect, $message));
}










public static function allNotEq($value, $expect, $message = '')
{
static::__callStatic('allNotEq', array($value, $expect, $message));
}












public static function nullOrSame($value, $expect, $message = '')
{
static::__callStatic('nullOrSame', array($value, $expect, $message));
}












public static function allSame($value, $expect, $message = '')
{
static::__callStatic('allSame', array($value, $expect, $message));
}












public static function nullOrNotSame($value, $expect, $message = '')
{
static::__callStatic('nullOrNotSame', array($value, $expect, $message));
}












public static function allNotSame($value, $expect, $message = '')
{
static::__callStatic('allNotSame', array($value, $expect, $message));
}












public static function nullOrGreaterThan($value, $limit, $message = '')
{
static::__callStatic('nullOrGreaterThan', array($value, $limit, $message));
}












public static function allGreaterThan($value, $limit, $message = '')
{
static::__callStatic('allGreaterThan', array($value, $limit, $message));
}












public static function nullOrGreaterThanEq($value, $limit, $message = '')
{
static::__callStatic('nullOrGreaterThanEq', array($value, $limit, $message));
}












public static function allGreaterThanEq($value, $limit, $message = '')
{
static::__callStatic('allGreaterThanEq', array($value, $limit, $message));
}












public static function nullOrLessThan($value, $limit, $message = '')
{
static::__callStatic('nullOrLessThan', array($value, $limit, $message));
}












public static function allLessThan($value, $limit, $message = '')
{
static::__callStatic('allLessThan', array($value, $limit, $message));
}












public static function nullOrLessThanEq($value, $limit, $message = '')
{
static::__callStatic('nullOrLessThanEq', array($value, $limit, $message));
}












public static function allLessThanEq($value, $limit, $message = '')
{
static::__callStatic('allLessThanEq', array($value, $limit, $message));
}













public static function nullOrRange($value, $min, $max, $message = '')
{
static::__callStatic('nullOrRange', array($value, $min, $max, $message));
}













public static function allRange($value, $min, $max, $message = '')
{
static::__callStatic('allRange', array($value, $min, $max, $message));
}












public static function nullOrOneOf($value, $values, $message = '')
{
static::__callStatic('nullOrOneOf', array($value, $values, $message));
}












public static function allOneOf($value, $values, $message = '')
{
static::__callStatic('allOneOf', array($value, $values, $message));
}












public static function nullOrInArray($value, $values, $message = '')
{
static::__callStatic('nullOrInArray', array($value, $values, $message));
}












public static function allInArray($value, $values, $message = '')
{
static::__callStatic('allInArray', array($value, $values, $message));
}












public static function nullOrContains($value, $subString, $message = '')
{
static::__callStatic('nullOrContains', array($value, $subString, $message));
}












public static function allContains($value, $subString, $message = '')
{
static::__callStatic('allContains', array($value, $subString, $message));
}












public static function nullOrNotContains($value, $subString, $message = '')
{
static::__callStatic('nullOrNotContains', array($value, $subString, $message));
}












public static function allNotContains($value, $subString, $message = '')
{
static::__callStatic('allNotContains', array($value, $subString, $message));
}











public static function nullOrNotWhitespaceOnly($value, $message = '')
{
static::__callStatic('nullOrNotWhitespaceOnly', array($value, $message));
}











public static function allNotWhitespaceOnly($value, $message = '')
{
static::__callStatic('allNotWhitespaceOnly', array($value, $message));
}












public static function nullOrStartsWith($value, $prefix, $message = '')
{
static::__callStatic('nullOrStartsWith', array($value, $prefix, $message));
}












public static function allStartsWith($value, $prefix, $message = '')
{
static::__callStatic('allStartsWith', array($value, $prefix, $message));
}












public static function nullOrNotStartsWith($value, $prefix, $message = '')
{
static::__callStatic('nullOrNotStartsWith', array($value, $prefix, $message));
}












public static function allNotStartsWith($value, $prefix, $message = '')
{
static::__callStatic('allNotStartsWith', array($value, $prefix, $message));
}











public static function nullOrStartsWithLetter($value, $message = '')
{
static::__callStatic('nullOrStartsWithLetter', array($value, $message));
}











public static function allStartsWithLetter($value, $message = '')
{
static::__callStatic('allStartsWithLetter', array($value, $message));
}












public static function nullOrEndsWith($value, $suffix, $message = '')
{
static::__callStatic('nullOrEndsWith', array($value, $suffix, $message));
}












public static function allEndsWith($value, $suffix, $message = '')
{
static::__callStatic('allEndsWith', array($value, $suffix, $message));
}












public static function nullOrNotEndsWith($value, $suffix, $message = '')
{
static::__callStatic('nullOrNotEndsWith', array($value, $suffix, $message));
}












public static function allNotEndsWith($value, $suffix, $message = '')
{
static::__callStatic('allNotEndsWith', array($value, $suffix, $message));
}












public static function nullOrRegex($value, $pattern, $message = '')
{
static::__callStatic('nullOrRegex', array($value, $pattern, $message));
}












public static function allRegex($value, $pattern, $message = '')
{
static::__callStatic('allRegex', array($value, $pattern, $message));
}












public static function nullOrNotRegex($value, $pattern, $message = '')
{
static::__callStatic('nullOrNotRegex', array($value, $pattern, $message));
}












public static function allNotRegex($value, $pattern, $message = '')
{
static::__callStatic('allNotRegex', array($value, $pattern, $message));
}











public static function nullOrUnicodeLetters($value, $message = '')
{
static::__callStatic('nullOrUnicodeLetters', array($value, $message));
}











public static function allUnicodeLetters($value, $message = '')
{
static::__callStatic('allUnicodeLetters', array($value, $message));
}











public static function nullOrAlpha($value, $message = '')
{
static::__callStatic('nullOrAlpha', array($value, $message));
}











public static function allAlpha($value, $message = '')
{
static::__callStatic('allAlpha', array($value, $message));
}











public static function nullOrDigits($value, $message = '')
{
static::__callStatic('nullOrDigits', array($value, $message));
}











public static function allDigits($value, $message = '')
{
static::__callStatic('allDigits', array($value, $message));
}











public static function nullOrAlnum($value, $message = '')
{
static::__callStatic('nullOrAlnum', array($value, $message));
}











public static function allAlnum($value, $message = '')
{
static::__callStatic('allAlnum', array($value, $message));
}












public static function nullOrLower($value, $message = '')
{
static::__callStatic('nullOrLower', array($value, $message));
}












public static function allLower($value, $message = '')
{
static::__callStatic('allLower', array($value, $message));
}











public static function nullOrUpper($value, $message = '')
{
static::__callStatic('nullOrUpper', array($value, $message));
}











public static function allUpper($value, $message = '')
{
static::__callStatic('allUpper', array($value, $message));
}












public static function nullOrLength($value, $length, $message = '')
{
static::__callStatic('nullOrLength', array($value, $length, $message));
}












public static function allLength($value, $length, $message = '')
{
static::__callStatic('allLength', array($value, $length, $message));
}












public static function nullOrMinLength($value, $min, $message = '')
{
static::__callStatic('nullOrMinLength', array($value, $min, $message));
}












public static function allMinLength($value, $min, $message = '')
{
static::__callStatic('allMinLength', array($value, $min, $message));
}












public static function nullOrMaxLength($value, $max, $message = '')
{
static::__callStatic('nullOrMaxLength', array($value, $max, $message));
}












public static function allMaxLength($value, $max, $message = '')
{
static::__callStatic('allMaxLength', array($value, $max, $message));
}













public static function nullOrLengthBetween($value, $min, $max, $message = '')
{
static::__callStatic('nullOrLengthBetween', array($value, $min, $max, $message));
}













public static function allLengthBetween($value, $min, $max, $message = '')
{
static::__callStatic('allLengthBetween', array($value, $min, $max, $message));
}









public static function nullOrFileExists($value, $message = '')
{
static::__callStatic('nullOrFileExists', array($value, $message));
}









public static function allFileExists($value, $message = '')
{
static::__callStatic('allFileExists', array($value, $message));
}









public static function nullOrFile($value, $message = '')
{
static::__callStatic('nullOrFile', array($value, $message));
}









public static function allFile($value, $message = '')
{
static::__callStatic('allFile', array($value, $message));
}









public static function nullOrDirectory($value, $message = '')
{
static::__callStatic('nullOrDirectory', array($value, $message));
}









public static function allDirectory($value, $message = '')
{
static::__callStatic('allDirectory', array($value, $message));
}









public static function nullOrReadable($value, $message = '')
{
static::__callStatic('nullOrReadable', array($value, $message));
}









public static function allReadable($value, $message = '')
{
static::__callStatic('allReadable', array($value, $message));
}









public static function nullOrWritable($value, $message = '')
{
static::__callStatic('nullOrWritable', array($value, $message));
}









public static function allWritable($value, $message = '')
{
static::__callStatic('allWritable', array($value, $message));
}











public static function nullOrClassExists($value, $message = '')
{
static::__callStatic('nullOrClassExists', array($value, $message));
}











public static function allClassExists($value, $message = '')
{
static::__callStatic('allClassExists', array($value, $message));
}















public static function nullOrSubclassOf($value, $class, $message = '')
{
static::__callStatic('nullOrSubclassOf', array($value, $class, $message));
}















public static function allSubclassOf($value, $class, $message = '')
{
static::__callStatic('allSubclassOf', array($value, $class, $message));
}











public static function nullOrInterfaceExists($value, $message = '')
{
static::__callStatic('nullOrInterfaceExists', array($value, $message));
}











public static function allInterfaceExists($value, $message = '')
{
static::__callStatic('allInterfaceExists', array($value, $message));
}















public static function nullOrImplementsInterface($value, $interface, $message = '')
{
static::__callStatic('nullOrImplementsInterface', array($value, $interface, $message));
}















public static function allImplementsInterface($value, $interface, $message = '')
{
static::__callStatic('allImplementsInterface', array($value, $interface, $message));
}













public static function nullOrPropertyExists($classOrObject, $property, $message = '')
{
static::__callStatic('nullOrPropertyExists', array($classOrObject, $property, $message));
}













public static function allPropertyExists($classOrObject, $property, $message = '')
{
static::__callStatic('allPropertyExists', array($classOrObject, $property, $message));
}













public static function nullOrPropertyNotExists($classOrObject, $property, $message = '')
{
static::__callStatic('nullOrPropertyNotExists', array($classOrObject, $property, $message));
}













public static function allPropertyNotExists($classOrObject, $property, $message = '')
{
static::__callStatic('allPropertyNotExists', array($classOrObject, $property, $message));
}













public static function nullOrMethodExists($classOrObject, $method, $message = '')
{
static::__callStatic('nullOrMethodExists', array($classOrObject, $method, $message));
}













public static function allMethodExists($classOrObject, $method, $message = '')
{
static::__callStatic('allMethodExists', array($classOrObject, $method, $message));
}













public static function nullOrMethodNotExists($classOrObject, $method, $message = '')
{
static::__callStatic('nullOrMethodNotExists', array($classOrObject, $method, $message));
}













public static function allMethodNotExists($classOrObject, $method, $message = '')
{
static::__callStatic('allMethodNotExists', array($classOrObject, $method, $message));
}












public static function nullOrKeyExists($array, $key, $message = '')
{
static::__callStatic('nullOrKeyExists', array($array, $key, $message));
}












public static function allKeyExists($array, $key, $message = '')
{
static::__callStatic('allKeyExists', array($array, $key, $message));
}












public static function nullOrKeyNotExists($array, $key, $message = '')
{
static::__callStatic('nullOrKeyNotExists', array($array, $key, $message));
}












public static function allKeyNotExists($array, $key, $message = '')
{
static::__callStatic('allKeyNotExists', array($array, $key, $message));
}












public static function nullOrValidArrayKey($value, $message = '')
{
static::__callStatic('nullOrValidArrayKey', array($value, $message));
}












public static function allValidArrayKey($value, $message = '')
{
static::__callStatic('allValidArrayKey', array($value, $message));
}










public static function nullOrCount($array, $number, $message = '')
{
static::__callStatic('nullOrCount', array($array, $number, $message));
}










public static function allCount($array, $number, $message = '')
{
static::__callStatic('allCount', array($array, $number, $message));
}










public static function nullOrMinCount($array, $min, $message = '')
{
static::__callStatic('nullOrMinCount', array($array, $min, $message));
}










public static function allMinCount($array, $min, $message = '')
{
static::__callStatic('allMinCount', array($array, $min, $message));
}










public static function nullOrMaxCount($array, $max, $message = '')
{
static::__callStatic('nullOrMaxCount', array($array, $max, $message));
}










public static function allMaxCount($array, $max, $message = '')
{
static::__callStatic('allMaxCount', array($array, $max, $message));
}











public static function nullOrCountBetween($array, $min, $max, $message = '')
{
static::__callStatic('nullOrCountBetween', array($array, $min, $max, $message));
}











public static function allCountBetween($array, $min, $max, $message = '')
{
static::__callStatic('allCountBetween', array($array, $min, $max, $message));
}












public static function nullOrIsList($array, $message = '')
{
static::__callStatic('nullOrIsList', array($array, $message));
}












public static function allIsList($array, $message = '')
{
static::__callStatic('allIsList', array($array, $message));
}












public static function nullOrIsNonEmptyList($array, $message = '')
{
static::__callStatic('nullOrIsNonEmptyList', array($array, $message));
}












public static function allIsNonEmptyList($array, $message = '')
{
static::__callStatic('allIsNonEmptyList', array($array, $message));
}














public static function nullOrIsMap($array, $message = '')
{
static::__callStatic('nullOrIsMap', array($array, $message));
}














public static function allIsMap($array, $message = '')
{
static::__callStatic('allIsMap', array($array, $message));
}













public static function nullOrIsNonEmptyMap($array, $message = '')
{
static::__callStatic('nullOrIsNonEmptyMap', array($array, $message));
}













public static function allIsNonEmptyMap($array, $message = '')
{
static::__callStatic('allIsNonEmptyMap', array($array, $message));
}











public static function nullOrUuid($value, $message = '')
{
static::__callStatic('nullOrUuid', array($value, $message));
}











public static function allUuid($value, $message = '')
{
static::__callStatic('allUuid', array($value, $message));
}












public static function nullOrThrows($expression, $class = 'Exception', $message = '')
{
static::__callStatic('nullOrThrows', array($expression, $class, $message));
}












public static function allThrows($expression, $class = 'Exception', $message = '')
{
static::__callStatic('allThrows', array($expression, $class, $message));
}
}
<?php










namespace Webmozart\Assert;

class InvalidArgumentException extends \InvalidArgumentException
{
}
<?php










namespace Webmozart\Assert;

use ArrayAccess;
use BadMethodCallException;
use Closure;
use Countable;
use DateTime;
use DateTimeImmutable;
use Exception;
use ResourceBundle;
use SimpleXMLElement;
use Throwable;
use Traversable;








class Assert
{
use Mixin;










public static function string($value, $message = '')
{
if (!\is_string($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a string. Got: %s',
static::typeToString($value)
));
}
}










public static function stringNotEmpty($value, $message = '')
{
static::string($value, $message);
static::notEq($value, '', $message);
}










public static function integer($value, $message = '')
{
if (!\is_int($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an integer. Got: %s',
static::typeToString($value)
));
}
}










public static function integerish($value, $message = '')
{
if (!\is_numeric($value) || $value != (int) $value) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an integerish value. Got: %s',
static::typeToString($value)
));
}
}










public static function positiveInteger($value, $message = '')
{
if (!(\is_int($value) && $value > 0)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a positive integer. Got: %s',
static::valueToString($value)
));
}
}










public static function float($value, $message = '')
{
if (!\is_float($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a float. Got: %s',
static::typeToString($value)
));
}
}










public static function numeric($value, $message = '')
{
if (!\is_numeric($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a numeric. Got: %s',
static::typeToString($value)
));
}
}










public static function natural($value, $message = '')
{
if (!\is_int($value) || $value < 0) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a non-negative integer. Got: %s',
static::valueToString($value)
));
}
}










public static function boolean($value, $message = '')
{
if (!\is_bool($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a boolean. Got: %s',
static::typeToString($value)
));
}
}










public static function scalar($value, $message = '')
{
if (!\is_scalar($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a scalar. Got: %s',
static::typeToString($value)
));
}
}










public static function object($value, $message = '')
{
if (!\is_object($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an object. Got: %s',
static::typeToString($value)
));
}
}











public static function resource($value, $type = null, $message = '')
{
if (!\is_resource($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a resource. Got: %s',
static::typeToString($value)
));
}

if ($type && $type !== \get_resource_type($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a resource of type %2$s. Got: %s',
static::typeToString($value),
$type
));
}
}










public static function isCallable($value, $message = '')
{
if (!\is_callable($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a callable. Got: %s',
static::typeToString($value)
));
}
}










public static function isArray($value, $message = '')
{
if (!\is_array($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an array. Got: %s',
static::typeToString($value)
));
}
}












public static function isTraversable($value, $message = '')
{
@\trigger_error(
\sprintf(
'The "%s" assertion is deprecated. You should stop using it, as it will soon be removed in 2.0 version. Use "isIterable" or "isInstanceOf" instead.',
__METHOD__
),
\E_USER_DEPRECATED
);

if (!\is_array($value) && !($value instanceof Traversable)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a traversable. Got: %s',
static::typeToString($value)
));
}
}










public static function isArrayAccessible($value, $message = '')
{
if (!\is_array($value) && !($value instanceof ArrayAccess)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an array accessible. Got: %s',
static::typeToString($value)
));
}
}










public static function isCountable($value, $message = '')
{
if (
!\is_array($value)
&& !($value instanceof Countable)
&& !($value instanceof ResourceBundle)
&& !($value instanceof SimpleXMLElement)
) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a countable. Got: %s',
static::typeToString($value)
));
}
}










public static function isIterable($value, $message = '')
{
if (!\is_array($value) && !($value instanceof Traversable)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an iterable. Got: %s',
static::typeToString($value)
));
}
}













public static function isInstanceOf($value, $class, $message = '')
{
if (!($value instanceof $class)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an instance of %2$s. Got: %s',
static::typeToString($value),
$class
));
}
}













public static function notInstanceOf($value, $class, $message = '')
{
if ($value instanceof $class) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an instance other than %2$s. Got: %s',
static::typeToString($value),
$class
));
}
}











public static function isInstanceOfAny($value, array $classes, $message = '')
{
foreach ($classes as $class) {
if ($value instanceof $class) {
return;
}
}

static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an instance of any of %2$s. Got: %s',
static::typeToString($value),
\implode(', ', \array_map(array('static', 'valueToString'), $classes))
));
}













public static function isAOf($value, $class, $message = '')
{
static::string($class, 'Expected class as a string. Got: %s');

if (!\is_a($value, $class, \is_string($value))) {
static::reportInvalidArgument(sprintf(
$message ?: 'Expected an instance of this class or to this class among his parents %2$s. Got: %s',
static::typeToString($value),
$class
));
}
}














public static function isNotA($value, $class, $message = '')
{
static::string($class, 'Expected class as a string. Got: %s');

if (\is_a($value, $class, \is_string($value))) {
static::reportInvalidArgument(sprintf(
$message ?: 'Expected an instance of this class or to this class among his parents other than %2$s. Got: %s',
static::typeToString($value),
$class
));
}
}











public static function isAnyOf($value, array $classes, $message = '')
{
foreach ($classes as $class) {
static::string($class, 'Expected class as a string. Got: %s');

if (\is_a($value, $class, \is_string($value))) {
return;
}
}

static::reportInvalidArgument(sprintf(
$message ?: 'Expected an any of instance of this class or to this class among his parents other than %2$s. Got: %s',
static::typeToString($value),
\implode(', ', \array_map(array('static', 'valueToString'), $classes))
));
}










public static function isEmpty($value, $message = '')
{
if (!empty($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an empty value. Got: %s',
static::valueToString($value)
));
}
}










public static function notEmpty($value, $message = '')
{
if (empty($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a non-empty value. Got: %s',
static::valueToString($value)
));
}
}










public static function null($value, $message = '')
{
if (null !== $value) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected null. Got: %s',
static::valueToString($value)
));
}
}










public static function notNull($value, $message = '')
{
if (null === $value) {
static::reportInvalidArgument(
$message ?: 'Expected a value other than null.'
);
}
}










public static function true($value, $message = '')
{
if (true !== $value) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to be true. Got: %s',
static::valueToString($value)
));
}
}










public static function false($value, $message = '')
{
if (false !== $value) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to be false. Got: %s',
static::valueToString($value)
));
}
}










public static function notFalse($value, $message = '')
{
if (false === $value) {
static::reportInvalidArgument(
$message ?: 'Expected a value other than false.'
);
}
}







public static function ip($value, $message = '')
{
if (false === \filter_var($value, \FILTER_VALIDATE_IP)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to be an IP. Got: %s',
static::valueToString($value)
));
}
}







public static function ipv4($value, $message = '')
{
if (false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to be an IPv4. Got: %s',
static::valueToString($value)
));
}
}







public static function ipv6($value, $message = '')
{
if (false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to be an IPv6. Got: %s',
static::valueToString($value)
));
}
}







public static function email($value, $message = '')
{
if (false === \filter_var($value, FILTER_VALIDATE_EMAIL)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to be a valid e-mail address. Got: %s',
static::valueToString($value)
));
}
}









public static function uniqueValues(array $values, $message = '')
{
$allValues = \count($values);
$uniqueValues = \count(\array_unique($values));

if ($allValues !== $uniqueValues) {
$difference = $allValues - $uniqueValues;

static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an array of unique values, but %s of them %s duplicated',
$difference,
(1 === $difference ? 'is' : 'are')
));
}
}








public static function eq($value, $expect, $message = '')
{
if ($expect != $value) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value equal to %2$s. Got: %s',
static::valueToString($value),
static::valueToString($expect)
));
}
}








public static function notEq($value, $expect, $message = '')
{
if ($expect == $value) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a different value than %s.',
static::valueToString($expect)
));
}
}










public static function same($value, $expect, $message = '')
{
if ($expect !== $value) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value identical to %2$s. Got: %s',
static::valueToString($value),
static::valueToString($expect)
));
}
}










public static function notSame($value, $expect, $message = '')
{
if ($expect === $value) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value not identical to %s.',
static::valueToString($expect)
));
}
}










public static function greaterThan($value, $limit, $message = '')
{
if ($value <= $limit) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value greater than %2$s. Got: %s',
static::valueToString($value),
static::valueToString($limit)
));
}
}










public static function greaterThanEq($value, $limit, $message = '')
{
if ($value < $limit) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value greater than or equal to %2$s. Got: %s',
static::valueToString($value),
static::valueToString($limit)
));
}
}










public static function lessThan($value, $limit, $message = '')
{
if ($value >= $limit) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value less than %2$s. Got: %s',
static::valueToString($value),
static::valueToString($limit)
));
}
}










public static function lessThanEq($value, $limit, $message = '')
{
if ($value > $limit) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value less than or equal to %2$s. Got: %s',
static::valueToString($value),
static::valueToString($limit)
));
}
}













public static function range($value, $min, $max, $message = '')
{
if ($value < $min || $value > $max) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value between %2$s and %3$s. Got: %s',
static::valueToString($value),
static::valueToString($min),
static::valueToString($max)
));
}
}












public static function oneOf($value, array $values, $message = '')
{
static::inArray($value, $values, $message);
}












public static function inArray($value, array $values, $message = '')
{
if (!\in_array($value, $values, true)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected one of: %2$s. Got: %s',
static::valueToString($value),
\implode(', ', \array_map(array('static', 'valueToString'), $values))
));
}
}










public static function contains($value, $subString, $message = '')
{
if (false === \strpos($value, $subString)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to contain %2$s. Got: %s',
static::valueToString($value),
static::valueToString($subString)
));
}
}










public static function notContains($value, $subString, $message = '')
{
if (false !== \strpos($value, $subString)) {
static::reportInvalidArgument(\sprintf(
$message ?: '%2$s was not expected to be contained in a value. Got: %s',
static::valueToString($value),
static::valueToString($subString)
));
}
}









public static function notWhitespaceOnly($value, $message = '')
{
if (\preg_match('/^\s*$/', $value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a non-whitespace string. Got: %s',
static::valueToString($value)
));
}
}










public static function startsWith($value, $prefix, $message = '')
{
if (0 !== \strpos($value, $prefix)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to start with %2$s. Got: %s',
static::valueToString($value),
static::valueToString($prefix)
));
}
}










public static function notStartsWith($value, $prefix, $message = '')
{
if (0 === \strpos($value, $prefix)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value not to start with %2$s. Got: %s',
static::valueToString($value),
static::valueToString($prefix)
));
}
}









public static function startsWithLetter($value, $message = '')
{
static::string($value);

$valid = isset($value[0]);

if ($valid) {
$locale = \setlocale(LC_CTYPE, 0);
\setlocale(LC_CTYPE, 'C');
$valid = \ctype_alpha($value[0]);
\setlocale(LC_CTYPE, $locale);
}

if (!$valid) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to start with a letter. Got: %s',
static::valueToString($value)
));
}
}










public static function endsWith($value, $suffix, $message = '')
{
if ($suffix !== \substr($value, -\strlen($suffix))) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to end with %2$s. Got: %s',
static::valueToString($value),
static::valueToString($suffix)
));
}
}










public static function notEndsWith($value, $suffix, $message = '')
{
if ($suffix === \substr($value, -\strlen($suffix))) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value not to end with %2$s. Got: %s',
static::valueToString($value),
static::valueToString($suffix)
));
}
}










public static function regex($value, $pattern, $message = '')
{
if (!\preg_match($pattern, $value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'The value %s does not match the expected pattern.',
static::valueToString($value)
));
}
}










public static function notRegex($value, $pattern, $message = '')
{
if (\preg_match($pattern, $value, $matches, PREG_OFFSET_CAPTURE)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'The value %s matches the pattern %s (at offset %d).',
static::valueToString($value),
static::valueToString($pattern),
$matches[0][1]
));
}
}









public static function unicodeLetters($value, $message = '')
{
static::string($value);

if (!\preg_match('/^\p{L}+$/u', $value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to contain only Unicode letters. Got: %s',
static::valueToString($value)
));
}
}









public static function alpha($value, $message = '')
{
static::string($value);

$locale = \setlocale(LC_CTYPE, 0);
\setlocale(LC_CTYPE, 'C');
$valid = !\ctype_alpha($value);
\setlocale(LC_CTYPE, $locale);

if ($valid) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to contain only letters. Got: %s',
static::valueToString($value)
));
}
}









public static function digits($value, $message = '')
{
$locale = \setlocale(LC_CTYPE, 0);
\setlocale(LC_CTYPE, 'C');
$valid = !\ctype_digit($value);
\setlocale(LC_CTYPE, $locale);

if ($valid) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to contain digits only. Got: %s',
static::valueToString($value)
));
}
}









public static function alnum($value, $message = '')
{
$locale = \setlocale(LC_CTYPE, 0);
\setlocale(LC_CTYPE, 'C');
$valid = !\ctype_alnum($value);
\setlocale(LC_CTYPE, $locale);

if ($valid) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to contain letters and digits only. Got: %s',
static::valueToString($value)
));
}
}










public static function lower($value, $message = '')
{
$locale = \setlocale(LC_CTYPE, 0);
\setlocale(LC_CTYPE, 'C');
$valid = !\ctype_lower($value);
\setlocale(LC_CTYPE, $locale);

if ($valid) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to contain lowercase characters only. Got: %s',
static::valueToString($value)
));
}
}










public static function upper($value, $message = '')
{
$locale = \setlocale(LC_CTYPE, 0);
\setlocale(LC_CTYPE, 'C');
$valid = !\ctype_upper($value);
\setlocale(LC_CTYPE, $locale);

if ($valid) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to contain uppercase characters only. Got: %s',
static::valueToString($value)
));
}
}










public static function length($value, $length, $message = '')
{
if ($length !== static::strlen($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to contain %2$s characters. Got: %s',
static::valueToString($value),
$length
));
}
}












public static function minLength($value, $min, $message = '')
{
if (static::strlen($value) < $min) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to contain at least %2$s characters. Got: %s',
static::valueToString($value),
$min
));
}
}












public static function maxLength($value, $max, $message = '')
{
if (static::strlen($value) > $max) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to contain at most %2$s characters. Got: %s',
static::valueToString($value),
$max
));
}
}













public static function lengthBetween($value, $min, $max, $message = '')
{
$length = static::strlen($value);

if ($length < $min || $length > $max) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a value to contain between %2$s and %3$s characters. Got: %s',
static::valueToString($value),
$min,
$max
));
}
}









public static function fileExists($value, $message = '')
{
static::string($value);

if (!\file_exists($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'The file %s does not exist.',
static::valueToString($value)
));
}
}







public static function file($value, $message = '')
{
static::fileExists($value, $message);

if (!\is_file($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'The path %s is not a file.',
static::valueToString($value)
));
}
}







public static function directory($value, $message = '')
{
static::fileExists($value, $message);

if (!\is_dir($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'The path %s is no directory.',
static::valueToString($value)
));
}
}







public static function readable($value, $message = '')
{
if (!\is_readable($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'The path %s is not readable.',
static::valueToString($value)
));
}
}







public static function writable($value, $message = '')
{
if (!\is_writable($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'The path %s is not writable.',
static::valueToString($value)
));
}
}









public static function classExists($value, $message = '')
{
if (!\class_exists($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an existing class name. Got: %s',
static::valueToString($value)
));
}
}













public static function subclassOf($value, $class, $message = '')
{
if (!\is_subclass_of($value, $class)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected a sub-class of %2$s. Got: %s',
static::valueToString($value),
static::valueToString($class)
));
}
}









public static function interfaceExists($value, $message = '')
{
if (!\interface_exists($value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an existing interface name. got %s',
static::valueToString($value)
));
}
}













public static function implementsInterface($value, $interface, $message = '')
{
if (!\in_array($interface, \class_implements($value))) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an implementation of %2$s. Got: %s',
static::valueToString($value),
static::valueToString($interface)
));
}
}











public static function propertyExists($classOrObject, $property, $message = '')
{
if (!\property_exists($classOrObject, $property)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected the property %s to exist.',
static::valueToString($property)
));
}
}











public static function propertyNotExists($classOrObject, $property, $message = '')
{
if (\property_exists($classOrObject, $property)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected the property %s to not exist.',
static::valueToString($property)
));
}
}











public static function methodExists($classOrObject, $method, $message = '')
{
if (!(\is_string($classOrObject) || \is_object($classOrObject)) || !\method_exists($classOrObject, $method)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected the method %s to exist.',
static::valueToString($method)
));
}
}











public static function methodNotExists($classOrObject, $method, $message = '')
{
if ((\is_string($classOrObject) || \is_object($classOrObject)) && \method_exists($classOrObject, $method)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected the method %s to not exist.',
static::valueToString($method)
));
}
}










public static function keyExists($array, $key, $message = '')
{
if (!(isset($array[$key]) || \array_key_exists($key, $array))) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected the key %s to exist.',
static::valueToString($key)
));
}
}










public static function keyNotExists($array, $key, $message = '')
{
if (isset($array[$key]) || \array_key_exists($key, $array)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected the key %s to not exist.',
static::valueToString($key)
));
}
}












public static function validArrayKey($value, $message = '')
{
if (!(\is_int($value) || \is_string($value))) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected string or integer. Got: %s',
static::typeToString($value)
));
}
}










public static function count($array, $number, $message = '')
{
static::eq(
\count($array),
$number,
\sprintf(
$message ?: 'Expected an array to contain %d elements. Got: %d.',
$number,
\count($array)
)
);
}










public static function minCount($array, $min, $message = '')
{
if (\count($array) < $min) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an array to contain at least %2$d elements. Got: %d',
\count($array),
$min
));
}
}










public static function maxCount($array, $max, $message = '')
{
if (\count($array) > $max) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an array to contain at most %2$d elements. Got: %d',
\count($array),
$max
));
}
}











public static function countBetween($array, $min, $max, $message = '')
{
$count = \count($array);

if ($count < $min || $count > $max) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Expected an array to contain between %2$d and %3$d elements. Got: %d',
$count,
$min,
$max
));
}
}










public static function isList($array, $message = '')
{
if (!\is_array($array) || $array !== \array_values($array)) {
static::reportInvalidArgument(
$message ?: 'Expected list - non-associative array.'
);
}
}










public static function isNonEmptyList($array, $message = '')
{
static::isList($array, $message);
static::notEmpty($array, $message);
}












public static function isMap($array, $message = '')
{
if (
!\is_array($array) ||
\array_keys($array) !== \array_filter(\array_keys($array), '\is_string')
) {
static::reportInvalidArgument(
$message ?: 'Expected map - associative array with string keys.'
);
}
}













public static function isNonEmptyMap($array, $message = '')
{
static::isMap($array, $message);
static::notEmpty($array, $message);
}









public static function uuid($value, $message = '')
{
$value = \str_replace(array('urn:', 'uuid:', '{', '}'), '', $value);


 
 if ('00000000-0000-0000-0000-000000000000' === $value) {
return;
}

if (!\preg_match('/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/', $value)) {
static::reportInvalidArgument(\sprintf(
$message ?: 'Value %s is not a valid UUID.',
static::valueToString($value)
));
}
}










public static function throws(Closure $expression, $class = 'Exception', $message = '')
{
static::string($class);

$actual = 'none';

try {
$expression();
} catch (Exception $e) {
$actual = \get_class($e);
if ($e instanceof $class) {
return;
}
} catch (Throwable $e) {
$actual = \get_class($e);
if ($e instanceof $class) {
return;
}
}

static::reportInvalidArgument($message ?: \sprintf(
'Expected to throw "%s", got "%s"',
$class,
$actual
));
}




public static function __callStatic($name, $arguments)
{
if ('nullOr' === \substr($name, 0, 6)) {
if (null !== $arguments[0]) {
$method = \lcfirst(\substr($name, 6));
\call_user_func_array(array('static', $method), $arguments);
}

return;
}

if ('all' === \substr($name, 0, 3)) {
static::isIterable($arguments[0]);

$method = \lcfirst(\substr($name, 3));
$args = $arguments;

foreach ($arguments[0] as $entry) {
$args[0] = $entry;

\call_user_func_array(array('static', $method), $args);
}

return;
}

throw new BadMethodCallException('No such method: '.$name);
}






protected static function valueToString($value)
{
if (null === $value) {
return 'null';
}

if (true === $value) {
return 'true';
}

if (false === $value) {
return 'false';
}

if (\is_array($value)) {
return 'array';
}

if (\is_object($value)) {
if (\method_exists($value, '__toString')) {
return \get_class($value).': '.self::valueToString($value->__toString());
}

if ($value instanceof DateTime || $value instanceof DateTimeImmutable) {
return \get_class($value).': '.self::valueToString($value->format('c'));
}

return \get_class($value);
}

if (\is_resource($value)) {
return 'resource';
}

if (\is_string($value)) {
return '"'.$value.'"';
}

return (string) $value;
}






protected static function typeToString($value)
{
return \is_object($value) ? \get_class($value) : \gettype($value);
}

protected static function strlen($value)
{
if (!\function_exists('mb_detect_encoding')) {
return \strlen($value);
}

if (false === $encoding = \mb_detect_encoding($value)) {
return \strlen($value);
}

return \mb_strlen($value, $encoding);
}








protected static function reportInvalidArgument($message)
{
throw new InvalidArgumentException($message);
}

private function __construct()
{
}
}
<?php

namespace Facebook\WebDriver;








class WebDriverBy
{



private $mechanism;



private $value;

protected function __construct($mechanism, $value)
{
$this->mechanism = $mechanism;
$this->value = $value;
}




public function getMechanism()
{
return $this->mechanism;
}




public function getValue()
{
return $this->value;
}








public static function className($class_name)
{
return new static('class name', $class_name);
}







public static function cssSelector($css_selector)
{
return new static('css selector', $css_selector);
}







public static function id($id)
{
return new static('id', $id);
}







public static function name($name)
{
return new static('name', $name);
}







public static function linkText($link_text)
{
return new static('link text', $link_text);
}








public static function partialLinkText($partial_link_text)
{
return new static('partial link text', $partial_link_text);
}







public static function tagName($tag_name)
{
return new static('tag name', $tag_name);
}







public static function xpath($xpath)
{
return new static('xpath', $xpath);
}
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Remote\DriverCommand;
use Facebook\WebDriver\Remote\ExecuteMethod;




class WebDriverAlert
{



protected $executor;

public function __construct(ExecuteMethod $executor)
{
$this->executor = $executor;
}






public function accept()
{
$this->executor->execute(DriverCommand::ACCEPT_ALERT);

return $this;
}






public function dismiss()
{
$this->executor->execute(DriverCommand::DISMISS_ALERT);

return $this;
}






public function getText()
{
return $this->executor->execute(DriverCommand::GET_ALERT_TEXT);
}







public function sendKeys($value)
{
$this->executor->execute(
DriverCommand::SET_ALERT_VALUE,
['text' => $value]
);

return $this;
}
}
<?php

namespace Facebook\WebDriver;





interface WebDriverSearchContext
{









public function findElement(WebDriverBy $locator);









public function findElements(WebDriverBy $locator);
}
<?php

namespace Facebook\WebDriver;

interface WebDriverCapabilities
{



public function getBrowserName();





public function getCapability($name);




public function getPlatform();




public function getVersion();





public function is($capability_name);






public function isJavascriptEnabled();


 
 
 
 
}
<?php

namespace Facebook\WebDriver;




interface WebDriverAction
{
public function perform();
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Exception\NoSuchElementException;
use Facebook\WebDriver\Exception\UnexpectedTagNameException;
use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\Support\XPathEscaper;




abstract class AbstractWebDriverCheckboxOrRadio implements WebDriverSelectInterface
{

protected $element;


protected $type;


protected $name;

public function __construct(WebDriverElement $element)
{
$tagName = $element->getTagName();
if ($tagName !== 'input') {
throw new UnexpectedTagNameException('input', $tagName);
}

$this->name = $element->getAttribute('name');
if ($this->name === null) {
throw new WebDriverException('The input does not have a "name" attribute.');
}

$this->element = $element;
}

public function getOptions()
{
return $this->getRelatedElements();
}

public function getAllSelectedOptions()
{
$selectedElement = [];
foreach ($this->getRelatedElements() as $element) {
if ($element->isSelected()) {
$selectedElement[] = $element;

if (!$this->isMultiple()) {
return $selectedElement;
}
}
}

return $selectedElement;
}

public function getFirstSelectedOption()
{
foreach ($this->getRelatedElements() as $element) {
if ($element->isSelected()) {
return $element;
}
}

throw new NoSuchElementException(
sprintf('No %s are selected', $this->type === 'radio' ? 'radio buttons' : 'checkboxes')
);
}

public function selectByIndex($index)
{
$this->byIndex($index);
}

public function selectByValue($value)
{
$this->byValue($value);
}

public function selectByVisibleText($text)
{
$this->byVisibleText($text);
}

public function selectByVisiblePartialText($text)
{
$this->byVisibleText($text, true);
}








protected function byValue($value, $select = true)
{
$matched = false;
foreach ($this->getRelatedElements($value) as $element) {
$select ? $this->selectOption($element) : $this->deselectOption($element);
if (!$this->isMultiple()) {
return;
}

$matched = true;
}

if (!$matched) {
throw new NoSuchElementException(
sprintf('Cannot locate %s with value: %s', $this->type, $value)
);
}
}








protected function byIndex($index, $select = true)
{
$elements = $this->getRelatedElements();
if (!isset($elements[$index])) {
throw new NoSuchElementException(sprintf('Cannot locate %s with index: %d', $this->type, $index));
}

$select ? $this->selectOption($elements[$index]) : $this->deselectOption($elements[$index]);
}








protected function byVisibleText($text, $partial = false, $select = true)
{
foreach ($this->getRelatedElements() as $element) {
$normalizeFilter = sprintf(
$partial ? 'contains(normalize-space(.), %s)' : 'normalize-space(.) = %s',
XPathEscaper::escapeQuotes($text)
);

$xpath = 'ancestor::label';
$xpathNormalize = sprintf('%s[%s]', $xpath, $normalizeFilter);

$id = $element->getAttribute('id');
if ($id !== null) {
$idFilter = sprintf('@for = %s', XPathEscaper::escapeQuotes($id));

$xpath .= sprintf(' | //label[%s]', $idFilter);
$xpathNormalize .= sprintf(' | //label[%s and %s]', $idFilter, $normalizeFilter);
}

try {
$element->findElement(WebDriverBy::xpath($xpathNormalize));
} catch (NoSuchElementException $e) {
if ($partial) {
continue;
}

try {

 
 if ($text !== $element->findElement(WebDriverBy::xpath($xpath))->getText()) {
continue;
}
} catch (NoSuchElementException $e) {
continue;
}
}

$select ? $this->selectOption($element) : $this->deselectOption($element);
if (!$this->isMultiple()) {
return;
}
}
}







protected function getRelatedElements($value = null)
{
$valueSelector = $value ? sprintf(' and @value = %s', XPathEscaper::escapeQuotes($value)) : '';
$formId = $this->element->getAttribute('form');
if ($formId === null) {
$form = $this->element->findElement(WebDriverBy::xpath('ancestor::form'));

$formId = $form->getAttribute('id');
if ($formId === '' || $formId === null) {
return $form->findElements(WebDriverBy::xpath(
sprintf('.//input[@name = %s%s]', XPathEscaper::escapeQuotes($this->name), $valueSelector)
));
}
}


 return $this->element->findElements(
WebDriverBy::xpath(sprintf(
'//form[@id = %1$s]//input[@name = %2$s%3$s'
. ' and ((boolean(@form) = true() and @form = %1$s) or boolean(@form) = false())]'
. ' | //input[@form = %1$s and @name = %2$s%3$s]',
XPathEscaper::escapeQuotes($formId),
XPathEscaper::escapeQuotes($this->name),
$valueSelector
))
);
}




protected function selectOption(WebDriverElement $element)
{
if (!$element->isSelected()) {
$element->click();
}
}




protected function deselectOption(WebDriverElement $element)
{
if ($element->isSelected()) {
$element->click();
}
}
}
<?php

namespace Facebook\WebDriver;

use InvalidArgumentException;








class Cookie implements \ArrayAccess
{

protected $cookie = [];





public function __construct($name, $value)
{
$this->validateCookieName($name);
$this->validateCookieValue($value);

$this->cookie['name'] = $name;
$this->cookie['value'] = $value;
}





public static function createFromArray(array $cookieArray)
{
if (!isset($cookieArray['name'])) {
throw new InvalidArgumentException('Cookie name should be set');
}
if (!isset($cookieArray['value'])) {
throw new InvalidArgumentException('Cookie value should be set');
}
$cookie = new self($cookieArray['name'], $cookieArray['value']);

if (isset($cookieArray['path'])) {
$cookie->setPath($cookieArray['path']);
}
if (isset($cookieArray['domain'])) {
$cookie->setDomain($cookieArray['domain']);
}
if (isset($cookieArray['expiry'])) {
$cookie->setExpiry($cookieArray['expiry']);
}
if (isset($cookieArray['secure'])) {
$cookie->setSecure($cookieArray['secure']);
}
if (isset($cookieArray['httpOnly'])) {
$cookie->setHttpOnly($cookieArray['httpOnly']);
}
if (isset($cookieArray['sameSite'])) {
$cookie->setSameSite($cookieArray['sameSite']);
}

return $cookie;
}




public function getName()
{
return $this->offsetGet('name');
}




public function getValue()
{
return $this->offsetGet('value');
}






public function setPath($path)
{
$this->offsetSet('path', $path);
}




public function getPath()
{
return $this->offsetGet('path');
}






public function setDomain($domain)
{
if (mb_strpos($domain, ':') !== false) {
throw new InvalidArgumentException(sprintf('Cookie domain "%s" should not contain a port', $domain));
}

$this->offsetSet('domain', $domain);
}




public function getDomain()
{
return $this->offsetGet('domain');
}






public function setExpiry($expiry)
{
$this->offsetSet('expiry', (int) $expiry);
}




public function getExpiry()
{
return $this->offsetGet('expiry');
}






public function setSecure($secure)
{
$this->offsetSet('secure', $secure);
}




public function isSecure()
{
return $this->offsetGet('secure');
}






public function setHttpOnly($httpOnly)
{
$this->offsetSet('httpOnly', $httpOnly);
}




public function isHttpOnly()
{
return $this->offsetGet('httpOnly');
}






public function setSameSite($sameSite)
{
$this->offsetSet('sameSite', $sameSite);
}




public function getSameSite()
{
return $this->offsetGet('sameSite');
}




public function toArray()
{
$cookie = $this->cookie;
if (!isset($cookie['secure'])) {

 $cookie['secure'] = false;
}

return $cookie;
}

public function offsetExists($offset)
{
return isset($this->cookie[$offset]);
}

public function offsetGet($offset)
{
return $this->offsetExists($offset) ? $this->cookie[$offset] : null;
}

public function offsetSet($offset, $value)
{
if ($value === null) {
unset($this->cookie[$offset]);
} else {
$this->cookie[$offset] = $value;
}
}

public function offsetUnset($offset)
{
unset($this->cookie[$offset]);
}




protected function validateCookieName($name)
{
if ($name === null || $name === '') {
throw new InvalidArgumentException('Cookie name should be non-empty');
}

if (mb_strpos($name, ';') !== false) {
throw new InvalidArgumentException('Cookie name should not contain a ";"');
}
}




protected function validateCookieValue($value)
{
if ($value === null) {
throw new InvalidArgumentException('Cookie value is required when setting a cookie');
}
}
}
<?php

namespace Facebook\WebDriver\Net;

use Exception;
use Facebook\WebDriver\Exception\TimeoutException;

class URLChecker
{
const POLL_INTERVAL_MS = 500;
const CONNECT_TIMEOUT_MS = 500;

public function waitUntilAvailable($timeout_in_ms, $url)
{
$end = microtime(true) + $timeout_in_ms / 1000;

while ($end > microtime(true)) {
if ($this->getHTTPResponseCode($url) === 200) {
return $this;
}
usleep(self::POLL_INTERVAL_MS);
}

throw new TimeoutException(sprintf(
'Timed out waiting for %s to become available after %d ms.',
$url,
$timeout_in_ms
));
}

public function waitUntilUnavailable($timeout_in_ms, $url)
{
$end = microtime(true) + $timeout_in_ms / 1000;

while ($end > microtime(true)) {
if ($this->getHTTPResponseCode($url) !== 200) {
return $this;
}
usleep(self::POLL_INTERVAL_MS);
}

throw new TimeoutException(sprintf(
'Timed out waiting for %s to become unavailable after %d ms.',
$url,
$timeout_in_ms
));
}

private function getHTTPResponseCode($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

 
 if (!defined('CURLOPT_CONNECTTIMEOUT_MS')) {
define('CURLOPT_CONNECTTIMEOUT_MS', 156); 
 }
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, self::CONNECT_TIMEOUT_MS);

$code = null;

try {
curl_exec($ch);
$info = curl_getinfo($ch);
$code = $info['http_code'];
} catch (Exception $e) {
}
curl_close($ch);

return $code;
}
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Exception\UnsupportedOperationException;
use Facebook\WebDriver\Exception\WebDriverException;




class WebDriverRadios extends AbstractWebDriverCheckboxOrRadio
{
public function __construct(WebDriverElement $element)
{
parent::__construct($element);

$this->type = $element->getAttribute('type');
if ($this->type !== 'radio') {
throw new WebDriverException('The input must be of type "radio".');
}
}

public function isMultiple()
{
return false;
}

public function deselectAll()
{
throw new UnsupportedOperationException('You cannot deselect radio buttons');
}

public function deselectByIndex($index)
{
throw new UnsupportedOperationException('You cannot deselect radio buttons');
}

public function deselectByValue($value)
{
throw new UnsupportedOperationException('You cannot deselect radio buttons');
}

public function deselectByVisibleText($text)
{
throw new UnsupportedOperationException('You cannot deselect radio buttons');
}

public function deselectByVisiblePartialText($text)
{
throw new UnsupportedOperationException('You cannot deselect radio buttons');
}
}
<?php

namespace Facebook\WebDriver;





interface WebDriverNavigationInterface
{






public function back();







public function forward();







public function refresh();








public function to($url);
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Exception\NoSuchElementException;
use Facebook\WebDriver\Exception\UnexpectedTagNameException;
use Facebook\WebDriver\Exception\UnsupportedOperationException;
use Facebook\WebDriver\Support\XPathEscaper;




class WebDriverSelect implements WebDriverSelectInterface
{

private $element;

private $isMulti;

public function __construct(WebDriverElement $element)
{
$tag_name = $element->getTagName();

if ($tag_name !== 'select') {
throw new UnexpectedTagNameException('select', $tag_name);
}
$this->element = $element;
$value = $element->getAttribute('multiple');
$this->isMulti = $value === 'true';
}

public function isMultiple()
{
return $this->isMulti;
}

public function getOptions()
{
return $this->element->findElements(WebDriverBy::tagName('option'));
}

public function getAllSelectedOptions()
{
$selected_options = [];
foreach ($this->getOptions() as $option) {
if ($option->isSelected()) {
$selected_options[] = $option;

if (!$this->isMultiple()) {
return $selected_options;
}
}
}

return $selected_options;
}

public function getFirstSelectedOption()
{
foreach ($this->getOptions() as $option) {
if ($option->isSelected()) {
return $option;
}
}

throw new NoSuchElementException('No options are selected');
}

public function selectByIndex($index)
{
foreach ($this->getOptions() as $option) {
if ($option->getAttribute('index') === (string) $index) {
$this->selectOption($option);

return;
}
}

throw new NoSuchElementException(sprintf('Cannot locate option with index: %d', $index));
}

public function selectByValue($value)
{
$matched = false;
$xpath = './/option[@value = ' . XPathEscaper::escapeQuotes($value) . ']';
$options = $this->element->findElements(WebDriverBy::xpath($xpath));

foreach ($options as $option) {
$this->selectOption($option);
if (!$this->isMultiple()) {
return;
}
$matched = true;
}

if (!$matched) {
throw new NoSuchElementException(
sprintf('Cannot locate option with value: %s', $value)
);
}
}

public function selectByVisibleText($text)
{
$matched = false;
$xpath = './/option[normalize-space(.) = ' . XPathEscaper::escapeQuotes($text) . ']';
$options = $this->element->findElements(WebDriverBy::xpath($xpath));

foreach ($options as $option) {
$this->selectOption($option);
if (!$this->isMultiple()) {
return;
}
$matched = true;
}


 
 if (!$matched) {
foreach ($this->getOptions() as $option) {
if ($option->getText() === $text) {
$this->selectOption($option);
if (!$this->isMultiple()) {
return;
}
$matched = true;
}
}
}

if (!$matched) {
throw new NoSuchElementException(
sprintf('Cannot locate option with text: %s', $text)
);
}
}

public function selectByVisiblePartialText($text)
{
$matched = false;
$xpath = './/option[contains(normalize-space(.), ' . XPathEscaper::escapeQuotes($text) . ')]';
$options = $this->element->findElements(WebDriverBy::xpath($xpath));

foreach ($options as $option) {
$this->selectOption($option);
if (!$this->isMultiple()) {
return;
}
$matched = true;
}

if (!$matched) {
throw new NoSuchElementException(
sprintf('Cannot locate option with text: %s', $text)
);
}
}

public function deselectAll()
{
if (!$this->isMultiple()) {
throw new UnsupportedOperationException('You may only deselect all options of a multi-select');
}

foreach ($this->getOptions() as $option) {
$this->deselectOption($option);
}
}

public function deselectByIndex($index)
{
if (!$this->isMultiple()) {
throw new UnsupportedOperationException('You may only deselect options of a multi-select');
}

foreach ($this->getOptions() as $option) {
if ($option->getAttribute('index') === (string) $index) {
$this->deselectOption($option);

return;
}
}
}

public function deselectByValue($value)
{
if (!$this->isMultiple()) {
throw new UnsupportedOperationException('You may only deselect options of a multi-select');
}

$xpath = './/option[@value = ' . XPathEscaper::escapeQuotes($value) . ']';
$options = $this->element->findElements(WebDriverBy::xpath($xpath));
foreach ($options as $option) {
$this->deselectOption($option);
}
}

public function deselectByVisibleText($text)
{
if (!$this->isMultiple()) {
throw new UnsupportedOperationException('You may only deselect options of a multi-select');
}

$xpath = './/option[normalize-space(.) = ' . XPathEscaper::escapeQuotes($text) . ']';
$options = $this->element->findElements(WebDriverBy::xpath($xpath));
foreach ($options as $option) {
$this->deselectOption($option);
}
}

public function deselectByVisiblePartialText($text)
{
if (!$this->isMultiple()) {
throw new UnsupportedOperationException('You may only deselect options of a multi-select');
}

$xpath = './/option[contains(normalize-space(.), ' . XPathEscaper::escapeQuotes($text) . ')]';
$options = $this->element->findElements(WebDriverBy::xpath($xpath));
foreach ($options as $option) {
$this->deselectOption($option);
}
}





protected function selectOption(WebDriverElement $option)
{
if (!$option->isSelected()) {
$option->click();
}
}





protected function deselectOption(WebDriverElement $option)
{
if ($option->isSelected()) {
$option->click();
}
}
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Remote\DriverCommand;
use Facebook\WebDriver\Remote\ExecuteMethod;

class WebDriverNavigation implements WebDriverNavigationInterface
{
protected $executor;

public function __construct(ExecuteMethod $executor)
{
$this->executor = $executor;
}

public function back()
{
$this->executor->execute(DriverCommand::GO_BACK);

return $this;
}

public function forward()
{
$this->executor->execute(DriverCommand::GO_FORWARD);

return $this;
}

public function refresh()
{
$this->executor->execute(DriverCommand::REFRESH);

return $this;
}

public function to($url)
{
$params = ['url' => (string) $url];
$this->executor->execute(DriverCommand::GET, $params);

return $this;
}
}
<?php

namespace Facebook\WebDriver;






class WebDriverKeys
{
const NULL = "\xEE\x80\x80";
const CANCEL = "\xEE\x80\x81";
const HELP = "\xEE\x80\x82";
const BACKSPACE = "\xEE\x80\x83";
const TAB = "\xEE\x80\x84";
const CLEAR = "\xEE\x80\x85";
const RETURN_KEY = "\xEE\x80\x86";
const ENTER = "\xEE\x80\x87";
const SHIFT = "\xEE\x80\x88";
const CONTROL = "\xEE\x80\x89";
const ALT = "\xEE\x80\x8A";
const PAUSE = "\xEE\x80\x8B";
const ESCAPE = "\xEE\x80\x8C";
const SPACE = "\xEE\x80\x8D";
const PAGE_UP = "\xEE\x80\x8E";
const PAGE_DOWN = "\xEE\x80\x8F";
const END = "\xEE\x80\x90";
const HOME = "\xEE\x80\x91";
const ARROW_LEFT = "\xEE\x80\x92";
const ARROW_UP = "\xEE\x80\x93";
const ARROW_RIGHT = "\xEE\x80\x94";
const ARROW_DOWN = "\xEE\x80\x95";
const INSERT = "\xEE\x80\x96";
const DELETE = "\xEE\x80\x97";
const SEMICOLON = "\xEE\x80\x98";
const EQUALS = "\xEE\x80\x99";
const NUMPAD0 = "\xEE\x80\x9A";
const NUMPAD1 = "\xEE\x80\x9B";
const NUMPAD2 = "\xEE\x80\x9C";
const NUMPAD3 = "\xEE\x80\x9D";
const NUMPAD4 = "\xEE\x80\x9E";
const NUMPAD5 = "\xEE\x80\x9F";
const NUMPAD6 = "\xEE\x80\xA0";
const NUMPAD7 = "\xEE\x80\xA1";
const NUMPAD8 = "\xEE\x80\xA2";
const NUMPAD9 = "\xEE\x80\xA3";
const MULTIPLY = "\xEE\x80\xA4";
const ADD = "\xEE\x80\xA5";
const SEPARATOR = "\xEE\x80\xA6";
const SUBTRACT = "\xEE\x80\xA7";
const DECIMAL = "\xEE\x80\xA8";
const DIVIDE = "\xEE\x80\xA9";
const F1 = "\xEE\x80\xB1";
const F2 = "\xEE\x80\xB2";
const F3 = "\xEE\x80\xB3";
const F4 = "\xEE\x80\xB4";
const F5 = "\xEE\x80\xB5";
const F6 = "\xEE\x80\xB6";
const F7 = "\xEE\x80\xB7";
const F8 = "\xEE\x80\xB8";
const F9 = "\xEE\x80\xB9";
const F10 = "\xEE\x80\xBA";
const F11 = "\xEE\x80\xBB";
const F12 = "\xEE\x80\xBC";
const META = "\xEE\x80\xBD";
const ZENKAKU_HANKAKU = "\xEE\x80\xC0";
const RIGHT_SHIFT = "\xEE\x81\x90";
const RIGHT_CONTROL = "\xEE\x81\x91";
const RIGHT_ALT = "\xEE\x81\x92";
const RIGHT_META = "\xEE\x81\x93";
const NUMPAD_PAGE_UP = "\xEE\x81\x94";
const NUMPAD_PAGE_DOWN = "\xEE\x81\x95";
const NUMPAD_END = "\xEE\x81\x96";
const NUMPAD_HOME = "\xEE\x81\x97";
const NUMPAD_ARROW_LEFT = "\xEE\x81\x98";
const NUMPAD_ARROW_UP = "\xEE\x81\x99";
const NUMPAD_ARROW_RIGHT = "\xEE\x81\x9A";
const NUMPAD_ARROW_DOWN = "\xEE\x81\x9B";
const NUMPAD_ARROW_INSERT = "\xEE\x81\x9C";
const NUMPAD_ARROW_DELETE = "\xEE\x81\x9D";

 const LEFT_SHIFT = self::SHIFT;
const LEFT_CONTROL = self::CONTROL;
const LEFT_ALT = self::ALT;
const LEFT = self::ARROW_LEFT;
const UP = self::ARROW_UP;
const RIGHT = self::ARROW_RIGHT;
const DOWN = self::ARROW_DOWN;
const COMMAND = self::META;








public static function encode($keys, $isW3cCompliant = false)
{
if (is_numeric($keys)) {
$keys = (string) $keys;
}

if (is_string($keys)) {
$keys = [$keys];
}

if (!is_array($keys)) {
if (!$isW3cCompliant) {
return [];
}

return '';
}

$encoded = [];
foreach ($keys as $key) {
if (is_array($key)) {

 $key = implode('', $key) . self::NULL; 
 }
$encoded[] = (string) $key;
}

if (!$isW3cCompliant) {
return $encoded;
}

return implode('', $encoded);
}
}
<?php

namespace Facebook\WebDriver;






class WebDriverPlatform
{
const ANDROID = 'ANDROID';

const ANY = 'ANY';
const LINUX = 'LINUX';
const MAC = 'MAC';
const UNIX = 'UNIX';
const VISTA = 'VISTA';
const WINDOWS = 'WINDOWS';
const XP = 'XP';

private function __construct()
{
}
}
<?php

namespace Facebook\WebDriver;




interface JavaScriptExecutor
{









public function executeScript($script, array $arguments = []);














public function executeAsyncScript($script, array $arguments = []);
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Exception\NoSuchCookieException;
use Facebook\WebDriver\Remote\DriverCommand;
use Facebook\WebDriver\Remote\ExecuteMethod;
use InvalidArgumentException;




class WebDriverOptions
{



protected $executor;



protected $isW3cCompliant;

public function __construct(ExecuteMethod $executor, $isW3cCompliant = false)
{
$this->executor = $executor;
$this->isW3cCompliant = $isW3cCompliant;
}








public function addCookie($cookie)
{
if (is_array($cookie)) { 
 $cookie = Cookie::createFromArray($cookie);
}
if (!$cookie instanceof Cookie) {
throw new InvalidArgumentException('Cookie must be set from instance of Cookie class or from array.');
}

$this->executor->execute(
DriverCommand::ADD_COOKIE,
['cookie' => $cookie->toArray()]
);

return $this;
}






public function deleteAllCookies()
{
$this->executor->execute(DriverCommand::DELETE_ALL_COOKIES);

return $this;
}







public function deleteCookieNamed($name)
{
$this->executor->execute(
DriverCommand::DELETE_COOKIE,
[':name' => $name]
);

return $this;
}








public function getCookieNamed($name)
{
if ($this->isW3cCompliant) {
$cookieArray = $this->executor->execute(
DriverCommand::GET_NAMED_COOKIE,
[':name' => $name]
);

if (!is_array($cookieArray)) { 
 throw new NoSuchCookieException('no such cookie');
}

return Cookie::createFromArray($cookieArray);
}

$cookies = $this->getCookies();
foreach ($cookies as $cookie) {
if ($cookie['name'] === $name) {
return $cookie;
}
}

return null;
}






public function getCookies()
{
$cookieArrays = $this->executor->execute(DriverCommand::GET_ALL_COOKIES);
if (!is_array($cookieArrays)) { 
 return [];
}

$cookies = [];
foreach ($cookieArrays as $cookieArray) {
$cookies[] = Cookie::createFromArray($cookieArray);
}

return $cookies;
}






public function timeouts()
{
return new WebDriverTimeouts($this->executor, $this->isW3cCompliant);
}







public function window()
{
return new WebDriverWindow($this->executor, $this->isW3cCompliant);
}








public function getLog($log_type)
{
return $this->executor->execute(
DriverCommand::GET_LOG,
['type' => $log_type]
);
}







public function getAvailableLogTypes()
{
return $this->executor->execute(DriverCommand::GET_AVAILABLE_LOG_TYPES);
}
}
<?php

namespace Facebook\WebDriver;




class WebDriverPoint
{
private $x;
private $y;

public function __construct($x, $y)
{
$this->x = $x;
$this->y = $y;
}






public function getX()
{
return (int) $this->x;
}






public function getY()
{
return (int) $this->y;
}








public function move($new_x, $new_y)
{
$this->x = $new_x;
$this->y = $new_y;

return $this;
}








public function moveBy($x_offset, $y_offset)
{
$this->x += $x_offset;
$this->y += $y_offset;

return $this;
}







public function equals(self $point)
{
return $this->x === $point->getX() &&
$this->y === $point->getY();
}
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Exception\NoSuchElementException;
use Facebook\WebDriver\Exception\UnsupportedOperationException;




interface WebDriverSelectInterface
{



public function isMultiple();




public function getOptions();




public function getAllSelectedOptions();







public function getFirstSelectedOption();








public function selectByIndex($index);











public function selectByValue($value);











public function selectByVisibleText($text);











public function selectByVisiblePartialText($text);






public function deselectAll();







public function deselectByIndex($index);










public function deselectByValue($value);










public function deselectByVisibleText($text);










public function deselectByVisiblePartialText($text);
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Exception\NoSuchElementException;
use Facebook\WebDriver\Exception\TimeoutException;






class WebDriverWait
{



protected $driver;



protected $timeout;



protected $interval;

public function __construct(WebDriver $driver, $timeout_in_second = null, $interval_in_millisecond = null)
{
$this->driver = $driver;
$this->timeout = isset($timeout_in_second) ? $timeout_in_second : 30;
$this->interval = $interval_in_millisecond ?: 250;
}












public function until($func_or_ec, $message = '')
{
$end = microtime(true) + $this->timeout;
$last_exception = null;

while ($end > microtime(true)) {
try {
if ($func_or_ec instanceof WebDriverExpectedCondition) {
$ret_val = call_user_func($func_or_ec->getApply(), $this->driver);
} else {
$ret_val = call_user_func($func_or_ec, $this->driver);
}
if ($ret_val) {
return $ret_val;
}
} catch (NoSuchElementException $e) {
$last_exception = $e;
}
usleep($this->interval * 1000);
}

if ($last_exception) {
throw $last_exception;
}

throw new TimeoutException($message);
}
}
<?php

namespace Facebook\WebDriver\Remote;

class UselessFileDetector implements FileDetector
{
public function getLocalFile($file)
{
return null;
}
}
<?php

namespace Facebook\WebDriver\Remote;

use Facebook\WebDriver\Exception\ElementNotInteractableException;
use Facebook\WebDriver\Exception\UnsupportedOperationException;
use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates;
use Facebook\WebDriver\Internal\WebDriverLocatable;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\WebDriverDimension;
use Facebook\WebDriver\WebDriverElement;
use Facebook\WebDriver\WebDriverKeys;
use Facebook\WebDriver\WebDriverPoint;
use ZipArchive;




class RemoteWebElement implements WebDriverElement, WebDriverLocatable
{



protected $executor;



protected $id;



protected $fileDetector;



protected $isW3cCompliant;






public function __construct(RemoteExecuteMethod $executor, $id, $isW3cCompliant = false)
{
$this->executor = $executor;
$this->id = $id;
$this->fileDetector = new UselessFileDetector();
$this->isW3cCompliant = $isW3cCompliant;
}






public function clear()
{
$this->executor->execute(
DriverCommand::CLEAR_ELEMENT,
[':id' => $this->id]
);

return $this;
}






public function click()
{
try {
$this->executor->execute(
DriverCommand::CLICK_ELEMENT,
[':id' => $this->id]
);
} catch (ElementNotInteractableException $e) {

 
 
 $this->clickChildElement($e);
}

return $this;
}








public function findElement(WebDriverBy $by)
{
$params = JsonWireCompat::getUsing($by, $this->isW3cCompliant);
$params[':id'] = $this->id;

$raw_element = $this->executor->execute(
DriverCommand::FIND_CHILD_ELEMENT,
$params
);

return $this->newElement(JsonWireCompat::getElement($raw_element));
}









public function findElements(WebDriverBy $by)
{
$params = JsonWireCompat::getUsing($by, $this->isW3cCompliant);
$params[':id'] = $this->id;
$raw_elements = $this->executor->execute(
DriverCommand::FIND_CHILD_ELEMENTS,
$params
);

$elements = [];
foreach ($raw_elements as $raw_element) {
$elements[] = $this->newElement(JsonWireCompat::getElement($raw_element));
}

return $elements;
}









public function getAttribute($attribute_name)
{
$params = [
':name' => $attribute_name,
':id' => $this->id,
];

if ($this->isW3cCompliant && ($attribute_name === 'value' || $attribute_name === 'index')) {
$value = $this->executor->execute(DriverCommand::GET_ELEMENT_PROPERTY, $params);

if ($value === true) {
return 'true';
}

if ($value === false) {
return 'false';
}

if ($value !== null) {
return (string) $value;
}
}

return $this->executor->execute(DriverCommand::GET_ELEMENT_ATTRIBUTE, $params);
}









public function getDomProperty($propertyName)
{
if (!$this->isW3cCompliant) {
throw new UnsupportedOperationException('This method is only supported in W3C mode');
}

$params = [
':name' => $propertyName,
':id' => $this->id,
];

return $this->executor->execute(DriverCommand::GET_ELEMENT_PROPERTY, $params);
}







public function getCSSValue($css_property_name)
{
$params = [
':propertyName' => $css_property_name,
':id' => $this->id,
];

return $this->executor->execute(
DriverCommand::GET_ELEMENT_VALUE_OF_CSS_PROPERTY,
$params
);
}






public function getLocation()
{
$location = $this->executor->execute(
DriverCommand::GET_ELEMENT_LOCATION,
[':id' => $this->id]
);

return new WebDriverPoint($location['x'], $location['y']);
}







public function getLocationOnScreenOnceScrolledIntoView()
{
if ($this->isW3cCompliant) {
$script = <<<JS
var e = arguments[0];
e.scrollIntoView({ behavior: 'instant', block: 'end', inline: 'nearest' }); 
var rect = e.getBoundingClientRect(); 
return {'x': rect.left, 'y': rect.top};
JS;

$result = $this->executor->execute(DriverCommand::EXECUTE_SCRIPT, [
'script' => $script,
'args' => [[JsonWireCompat::WEB_DRIVER_ELEMENT_IDENTIFIER => $this->id]],
]);
$location = ['x' => $result['x'], 'y' => $result['y']];
} else {
$location = $this->executor->execute(
DriverCommand::GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW,
[':id' => $this->id]
);
}

return new WebDriverPoint($location['x'], $location['y']);
}




public function getCoordinates()
{
$element = $this;

$on_screen = null; 
 $in_view_port = static function () use ($element) {
return $element->getLocationOnScreenOnceScrolledIntoView();
};
$on_page = static function () use ($element) {
return $element->getLocation();
};
$auxiliary = $this->getID();

return new WebDriverCoordinates(
$on_screen,
$in_view_port,
$on_page,
$auxiliary
);
}






public function getSize()
{
$size = $this->executor->execute(
DriverCommand::GET_ELEMENT_SIZE,
[':id' => $this->id]
);

return new WebDriverDimension($size['width'], $size['height']);
}






public function getTagName()
{

 
 
 
 return mb_strtolower($this->executor->execute(
DriverCommand::GET_ELEMENT_TAG_NAME,
[':id' => $this->id]
));
}







public function getText()
{
return $this->executor->execute(
DriverCommand::GET_ELEMENT_TEXT,
[':id' => $this->id]
);
}







public function isDisplayed()
{
return $this->executor->execute(
DriverCommand::IS_ELEMENT_DISPLAYED,
[':id' => $this->id]
);
}







public function isEnabled()
{
return $this->executor->execute(
DriverCommand::IS_ELEMENT_ENABLED,
[':id' => $this->id]
);
}






public function isSelected()
{
return $this->executor->execute(
DriverCommand::IS_ELEMENT_SELECTED,
[':id' => $this->id]
);
}







public function sendKeys($value)
{
$local_file = $this->fileDetector->getLocalFile($value);

$params = [];
if ($local_file === null) {
if ($this->isW3cCompliant) {

 
 $encodedValues = explode(WebDriverKeys::NULL, WebDriverKeys::encode($value, true));
foreach ($encodedValues as $encodedValue) {
$params[] = [
'text' => $encodedValue,
':id' => $this->id,
];
}
} else {
$params[] = [
'value' => WebDriverKeys::encode($value),
':id' => $this->id,
];
}
} else {
if ($this->isW3cCompliant) {
try {

 
 
 $fileName = $this->upload($local_file);
} catch (WebDriverException $e) {
$fileName = $local_file;
}

$params[] = [
'text' => $fileName,
':id' => $this->id,
];
} else {
$params[] = [
'value' => WebDriverKeys::encode($this->upload($local_file)),
':id' => $this->id,
];
}
}

foreach ($params as $param) {
$this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $param);
}

return $this;
}















public function setFileDetector(FileDetector $detector)
{
$this->fileDetector = $detector;

return $this;
}






public function submit()
{
if ($this->isW3cCompliant) {

 
 $submitPolyfill = $script = <<<HTXT
                var form = arguments[0];
                while (form.nodeName !== "FORM" && form.parentNode) { // find the parent form of this element
                    form = form.parentNode;
                }
                if (!form) {
                    throw Error('Unable to find containing form element');
                }
                var event = new Event('submit', {bubbles: true, cancelable: true});
                if (form.dispatchEvent(event)) {
                    HTMLFormElement.prototype.submit.call(form);
                }
HTXT;
$this->executor->execute(DriverCommand::EXECUTE_SCRIPT, [
'script' => $submitPolyfill,
'args' => [[JsonWireCompat::WEB_DRIVER_ELEMENT_IDENTIFIER => $this->id]],
]);

return $this;
}

$this->executor->execute(
DriverCommand::SUBMIT_ELEMENT,
[':id' => $this->id]
);

return $this;
}






public function getID()
{
return $this->id;
}







public function takeElementScreenshot($save_as = null)
{
$screenshot = base64_decode(
$this->executor->execute(
DriverCommand::TAKE_ELEMENT_SCREENSHOT,
[':id' => $this->id]
),
true
);

if ($save_as !== null) {
$directoryPath = dirname($save_as);
if (!file_exists($directoryPath)) {
mkdir($directoryPath, 0777, true);
}

file_put_contents($save_as, $screenshot);
}

return $screenshot;
}







public function equals(WebDriverElement $other)
{
if ($this->isW3cCompliant) {
return $this->getID() === $other->getID();
}

return $this->executor->execute(DriverCommand::ELEMENT_EQUALS, [
':id' => $this->id,
':other' => $other->getID(),
]);
}














protected function clickChildElement(ElementNotInteractableException $originalException)
{
$children = $this->findElements(WebDriverBy::xpath('./*'));
foreach ($children as $child) {
try {

 
 $this->executor->execute(
DriverCommand::CLICK_ELEMENT,
[':id' => $child->id]
);

return;
} catch (ElementNotInteractableException $e) {

 }
}

throw $originalException;
}








protected function newElement($id)
{
return new static($this->executor, $id, $this->isW3cCompliant);
}









protected function upload($local_file)
{
if (!is_file($local_file)) {
throw new WebDriverException('You may only upload files: ' . $local_file);
}

$temp_zip_path = $this->createTemporaryZipArchive($local_file);

$remote_path = $this->executor->execute(
DriverCommand::UPLOAD_FILE,
['file' => base64_encode(file_get_contents($temp_zip_path))]
);

unlink($temp_zip_path);

return $remote_path;
}





protected function createTemporaryZipArchive($fileToZip)
{

 
 $tempZipPath = sys_get_temp_dir() . '/' . uniqid('WebDriverZip', false);

$zip = new ZipArchive();
if (($errorCode = $zip->open($tempZipPath, ZipArchive::CREATE)) !== true) {
throw new WebDriverException(sprintf('Error creating zip archive: %s', $errorCode));
}

$info = pathinfo($fileToZip);
$file_name = $info['basename'];
$zip->addFile($fileToZip, $file_name);
$zip->close();

return $tempZipPath;
}
}
<?php

namespace Facebook\WebDriver\Remote;

use Facebook\WebDriver\Interactions\Touch\WebDriverTouchScreen;
use Facebook\WebDriver\WebDriverElement;




class RemoteTouchScreen implements WebDriverTouchScreen
{



private $executor;




public function __construct(RemoteExecuteMethod $executor)
{
$this->executor = $executor;
}






public function tap(WebDriverElement $element)
{
$this->executor->execute(
DriverCommand::TOUCH_SINGLE_TAP,
['element' => $element->getID()]
);

return $this;
}






public function doubleTap(WebDriverElement $element)
{
$this->executor->execute(
DriverCommand::TOUCH_DOUBLE_TAP,
['element' => $element->getID()]
);

return $this;
}







public function down($x, $y)
{
$this->executor->execute(DriverCommand::TOUCH_DOWN, [
'x' => $x,
'y' => $y,
]);

return $this;
}







public function flick($xspeed, $yspeed)
{
$this->executor->execute(DriverCommand::TOUCH_FLICK, [
'xspeed' => $xspeed,
'yspeed' => $yspeed,
]);

return $this;
}









public function flickFromElement(WebDriverElement $element, $xoffset, $yoffset, $speed)
{
$this->executor->execute(DriverCommand::TOUCH_FLICK, [
'xoffset' => $xoffset,
'yoffset' => $yoffset,
'element' => $element->getID(),
'speed' => $speed,
]);

return $this;
}






public function longPress(WebDriverElement $element)
{
$this->executor->execute(
DriverCommand::TOUCH_LONG_PRESS,
['element' => $element->getID()]
);

return $this;
}







public function move($x, $y)
{
$this->executor->execute(DriverCommand::TOUCH_MOVE, [
'x' => $x,
'y' => $y,
]);

return $this;
}







public function scroll($xoffset, $yoffset)
{
$this->executor->execute(DriverCommand::TOUCH_SCROLL, [
'xoffset' => $xoffset,
'yoffset' => $yoffset,
]);

return $this;
}








public function scrollFromElement(WebDriverElement $element, $xoffset, $yoffset)
{
$this->executor->execute(DriverCommand::TOUCH_SCROLL, [
'element' => $element->getID(),
'xoffset' => $xoffset,
'yoffset' => $yoffset,
]);

return $this;
}







public function up($x, $y)
{
$this->executor->execute(DriverCommand::TOUCH_UP, [
'x' => $x,
'y' => $y,
]);

return $this;
}
}
<?php

namespace Facebook\WebDriver\Remote;

use Facebook\WebDriver\WebDriver;
use Facebook\WebDriver\WebDriverKeyboard;
use Facebook\WebDriver\WebDriverKeys;




class RemoteKeyboard implements WebDriverKeyboard
{

private $executor;

private $driver;

private $isW3cCompliant;




public function __construct(RemoteExecuteMethod $executor, WebDriver $driver, $isW3cCompliant = false)
{
$this->executor = $executor;
$this->driver = $driver;
$this->isW3cCompliant = $isW3cCompliant;
}






public function sendKeys($keys)
{
if ($this->isW3cCompliant) {
$activeElement = $this->driver->switchTo()->activeElement();
$activeElement->sendKeys($keys);
} else {
$this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, [
'value' => WebDriverKeys::encode($keys),
]);
}

return $this;
}








public function pressKey($key)
{
if ($this->isW3cCompliant) {
$this->executor->execute(DriverCommand::ACTIONS, [
'actions' => [
[
'type' => 'key',
'id' => 'keyboard',
'actions' => [['type' => 'keyDown', 'value' => $key]],
],
],
]);
} else {
$this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, [
'value' => [(string) $key],
]);
}

return $this;
}








public function releaseKey($key)
{
if ($this->isW3cCompliant) {
$this->executor->execute(DriverCommand::ACTIONS, [
'actions' => [
[
'type' => 'key',
'id' => 'keyboard',
'actions' => [['type' => 'keyUp', 'value' => $key]],
],
],
]);
} else {
$this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, [
'value' => [(string) $key],
]);
}

return $this;
}
}
<?php

namespace Facebook\WebDriver\Remote;

class RemoteExecuteMethod implements ExecuteMethod
{



private $driver;




public function __construct(RemoteWebDriver $driver)
{
$this->driver = $driver;
}






public function execute($command_name, array $parameters = [])
{
return $this->driver->execute($command_name, $parameters);
}
}
<?php

namespace Facebook\WebDriver\Remote;






class DriverCommand
{
const GET_ALL_SESSIONS = 'getAllSessions';
const GET_CAPABILITIES = 'getCapabilities';
const NEW_SESSION = 'newSession';
const STATUS = 'status';
const CLOSE = 'close';
const QUIT = 'quit';
const GET = 'get';
const GO_BACK = 'goBack';
const GO_FORWARD = 'goForward';
const REFRESH = 'refresh';
const ADD_COOKIE = 'addCookie';
const GET_ALL_COOKIES = 'getCookies';
const DELETE_COOKIE = 'deleteCookie';
const DELETE_ALL_COOKIES = 'deleteAllCookies';
const FIND_ELEMENT = 'findElement';
const FIND_ELEMENTS = 'findElements';
const FIND_CHILD_ELEMENT = 'findChildElement';
const FIND_CHILD_ELEMENTS = 'findChildElements';
const CLEAR_ELEMENT = 'clearElement';
const CLICK_ELEMENT = 'clickElement';
const SEND_KEYS_TO_ELEMENT = 'sendKeysToElement';
const SEND_KEYS_TO_ACTIVE_ELEMENT = 'sendKeysToActiveElement';
const SUBMIT_ELEMENT = 'submitElement';
const UPLOAD_FILE = 'uploadFile';
const GET_CURRENT_WINDOW_HANDLE = 'getCurrentWindowHandle';
const GET_WINDOW_HANDLES = 'getWindowHandles';
const GET_CURRENT_CONTEXT_HANDLE = 'getCurrentContextHandle';
const GET_CONTEXT_HANDLES = 'getContextHandles';

 const SWITCH_TO_WINDOW = 'switchToWindow';
const SWITCH_TO_CONTEXT = 'switchToContext';
const SWITCH_TO_FRAME = 'switchToFrame';
const SWITCH_TO_PARENT_FRAME = 'switchToParentFrame';
const GET_ACTIVE_ELEMENT = 'getActiveElement';

 const GET_CURRENT_URL = 'getCurrentUrl';
const GET_PAGE_SOURCE = 'getPageSource';
const GET_TITLE = 'getTitle';

 const EXECUTE_SCRIPT = 'executeScript';
const EXECUTE_ASYNC_SCRIPT = 'executeAsyncScript';

 const GET_ELEMENT_TEXT = 'getElementText';
const GET_ELEMENT_TAG_NAME = 'getElementTagName';
const IS_ELEMENT_SELECTED = 'isElementSelected';
const IS_ELEMENT_ENABLED = 'isElementEnabled';
const IS_ELEMENT_DISPLAYED = 'isElementDisplayed';
const GET_ELEMENT_LOCATION = 'getElementLocation';
const GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW = 'getElementLocationOnceScrolledIntoView';
const GET_ELEMENT_SIZE = 'getElementSize';
const GET_ELEMENT_ATTRIBUTE = 'getElementAttribute';
const GET_ELEMENT_VALUE_OF_CSS_PROPERTY = 'getElementValueOfCssProperty';
const ELEMENT_EQUALS = 'elementEquals';
const SCREENSHOT = 'screenshot';

 const ACCEPT_ALERT = 'acceptAlert';
const DISMISS_ALERT = 'dismissAlert';
const GET_ALERT_TEXT = 'getAlertText';
const SET_ALERT_VALUE = 'setAlertValue';

 const SET_TIMEOUT = 'setTimeout';
const IMPLICITLY_WAIT = 'implicitlyWait';
const SET_SCRIPT_TIMEOUT = 'setScriptTimeout';

const EXECUTE_SQL = 'executeSQL';
const GET_LOCATION = 'getLocation';
const SET_LOCATION = 'setLocation';
const GET_APP_CACHE = 'getAppCache';
const GET_APP_CACHE_STATUS = 'getStatus';
const CLEAR_APP_CACHE = 'clearAppCache';
const IS_BROWSER_ONLINE = 'isBrowserOnline';
const SET_BROWSER_ONLINE = 'setBrowserOnline';

 const GET_LOCAL_STORAGE_ITEM = 'getLocalStorageItem';
const GET_LOCAL_STORAGE_KEYS = 'getLocalStorageKeys';
const SET_LOCAL_STORAGE_ITEM = 'setLocalStorageItem';
const REMOVE_LOCAL_STORAGE_ITEM = 'removeLocalStorageItem';
const CLEAR_LOCAL_STORAGE = 'clearLocalStorage';
const GET_LOCAL_STORAGE_SIZE = 'getLocalStorageSize';

 const GET_SESSION_STORAGE_ITEM = 'getSessionStorageItem';
const GET_SESSION_STORAGE_KEYS = 'getSessionStorageKey';
const SET_SESSION_STORAGE_ITEM = 'setSessionStorageItem';
const REMOVE_SESSION_STORAGE_ITEM = 'removeSessionStorageItem';
const CLEAR_SESSION_STORAGE = 'clearSessionStorage';
const GET_SESSION_STORAGE_SIZE = 'getSessionStorageSize';

 const SET_SCREEN_ORIENTATION = 'setScreenOrientation';
const GET_SCREEN_ORIENTATION = 'getScreenOrientation';

 const CLICK = 'mouseClick';
const DOUBLE_CLICK = 'mouseDoubleClick';
const MOUSE_DOWN = 'mouseButtonDown';
const MOUSE_UP = 'mouseButtonUp';
const MOVE_TO = 'mouseMoveTo';

 const IME_GET_AVAILABLE_ENGINES = 'imeGetAvailableEngines';
const IME_GET_ACTIVE_ENGINE = 'imeGetActiveEngine';
const IME_IS_ACTIVATED = 'imeIsActivated';
const IME_DEACTIVATE = 'imeDeactivate';
const IME_ACTIVATE_ENGINE = 'imeActivateEngine';

 const TOUCH_SINGLE_TAP = 'touchSingleTap';
const TOUCH_DOWN = 'touchDown';
const TOUCH_UP = 'touchUp';
const TOUCH_MOVE = 'touchMove';
const TOUCH_SCROLL = 'touchScroll';
const TOUCH_DOUBLE_TAP = 'touchDoubleTap';
const TOUCH_LONG_PRESS = 'touchLongPress';
const TOUCH_FLICK = 'touchFlick';

 const SET_WINDOW_SIZE = 'setWindowSize';
const SET_WINDOW_POSITION = 'setWindowPosition';
const GET_WINDOW_SIZE = 'getWindowSize';
const GET_WINDOW_POSITION = 'getWindowPosition';
const MAXIMIZE_WINDOW = 'maximizeWindow';
const FULLSCREEN_WINDOW = 'fullscreenWindow';

 const GET_AVAILABLE_LOG_TYPES = 'getAvailableLogTypes';
const GET_LOG = 'getLog';
const GET_SESSION_LOGS = 'getSessionLogs';

 const GET_NETWORK_CONNECTION = 'getNetworkConnection';
const SET_NETWORK_CONNECTION = 'setNetworkConnection';

 const CUSTOM_COMMAND = 'customCommand';


 const ACTIONS = 'actions';
const GET_ELEMENT_PROPERTY = 'getElementProperty';
const GET_NAMED_COOKIE = 'getNamedCookie';
const NEW_WINDOW = 'newWindow';
const TAKE_ELEMENT_SCREENSHOT = 'takeElementScreenshot';
const MINIMIZE_WINDOW = 'minimizeWindow';

private function __construct()
{
}
}
<?php

namespace Facebook\WebDriver\Remote;

use Facebook\WebDriver\Exception\UnsupportedOperationException;
use Facebook\WebDriver\WebDriverAlert;
use Facebook\WebDriver\WebDriverElement;
use Facebook\WebDriver\WebDriverTargetLocator;




class RemoteTargetLocator implements WebDriverTargetLocator
{

protected $executor;

protected $driver;

protected $isW3cCompliant;

public function __construct(RemoteExecuteMethod $executor, RemoteWebDriver $driver, $isW3cCompliant = false)
{
$this->executor = $executor;
$this->driver = $driver;
$this->isW3cCompliant = $isW3cCompliant;
}




public function defaultContent()
{
$params = ['id' => null];
$this->executor->execute(DriverCommand::SWITCH_TO_FRAME, $params);

return $this->driver;
}







public function frame($frame)
{
if ($this->isW3cCompliant) {
if ($frame instanceof WebDriverElement) {
$id = [JsonWireCompat::WEB_DRIVER_ELEMENT_IDENTIFIER => $frame->getID()];
} elseif ($frame === null) {
$id = null;
} elseif (is_int($frame)) {
$id = $frame;
} else {
throw new \InvalidArgumentException(
'In W3C compliance mode frame must be either instance of WebDriverElement, integer or null'
);
}
} else {
if ($frame instanceof WebDriverElement) {
$id = ['ELEMENT' => $frame->getID()];
} elseif ($frame === null) {
$id = null;
} elseif (is_int($frame)) {
$id = $frame;
} else {
$id = (string) $frame;
}
}

$params = ['id' => $id];
$this->executor->execute(DriverCommand::SWITCH_TO_FRAME, $params);

return $this->driver;
}






public function parent()
{
$this->executor->execute(DriverCommand::SWITCH_TO_PARENT_FRAME, []);

return $this->driver;
}





public function window($handle)
{
if ($this->isW3cCompliant) {
$params = ['handle' => (string) $handle];
} else {
$params = ['name' => (string) $handle];
}

$this->executor->execute(DriverCommand::SWITCH_TO_WINDOW, $params);

return $this->driver;
}











public function newWindow($windowType = self::WINDOW_TYPE_TAB)
{
if ($windowType !== self::WINDOW_TYPE_TAB && $windowType !== self::WINDOW_TYPE_WINDOW) {
throw new \InvalidArgumentException('Window type must by either "tab" or "window"');
}

if (!$this->isW3cCompliant) {
throw new UnsupportedOperationException('New window is only supported in W3C mode');
}

$response = $this->executor->execute(DriverCommand::NEW_WINDOW, ['type' => $windowType]);

$this->window($response['handle']);

return $this->driver;
}

public function alert()
{
return new WebDriverAlert($this->executor);
}




public function activeElement()
{
$response = $this->driver->execute(DriverCommand::GET_ACTIVE_ELEMENT, []);
$method = new RemoteExecuteMethod($this->driver);

return new RemoteWebElement($method, JsonWireCompat::getElement($response), $this->isW3cCompliant);
}
}
<?php

namespace Facebook\WebDriver\Remote;

use Facebook\WebDriver\Exception\WebDriverException;

class CustomWebDriverCommand extends WebDriverCommand
{
const METHOD_GET = 'GET';
const METHOD_POST = 'POST';


private $customUrl;

private $customMethod;







public function __construct($session_id, $url, $method, array $parameters)
{
$this->setCustomRequestParameters($url, $method);

parent::__construct($session_id, DriverCommand::CUSTOM_COMMAND, $parameters);
}





public function getCustomUrl()
{
if ($this->customUrl === null) {
throw new WebDriverException('URL of custom command is not set');
}

return $this->customUrl;
}





public function getCustomMethod()
{
if ($this->customMethod === null) {
throw new WebDriverException('Method of custom command is not set');
}

return $this->customMethod;
}






protected function setCustomRequestParameters($custom_url, $custom_method)
{
$allowedMethods = [static::METHOD_GET, static::METHOD_POST];
if (!in_array($custom_method, $allowedMethods, true)) {
throw new WebDriverException(
sprintf(
'Invalid custom method "%s", must be one of [%s]',
$custom_method,
implode(', ', $allowedMethods)
)
);
}
$this->customMethod = $custom_method;

if (mb_strpos($custom_url, '/') !== 0) {
throw new WebDriverException(
sprintf('URL of custom command has to start with / but is "%s"', $custom_url)
);
}
$this->customUrl = $custom_url;
}
}
<?php

namespace Facebook\WebDriver\Remote\Service;

use Facebook\WebDriver\Exception\DriverServerDiedException;
use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\Remote\DriverCommand;
use Facebook\WebDriver\Remote\HttpCommandExecutor;
use Facebook\WebDriver\Remote\WebDriverCommand;
use Facebook\WebDriver\Remote\WebDriverResponse;




class DriverCommandExecutor extends HttpCommandExecutor
{



private $service;

public function __construct(DriverService $service)
{
parent::__construct($service->getURL());
$this->service = $service;
}








public function execute(WebDriverCommand $command)
{
if ($command->getName() === DriverCommand::NEW_SESSION) {
$this->service->start();
}

try {
$value = parent::execute($command);
if ($command->getName() === DriverCommand::QUIT) {
$this->service->stop();
}

return $value;
} catch (\Exception $e) {
if (!$this->service->isRunning()) {
throw new DriverServerDiedException($e);
}
throw $e;
}
}
}
<?php

namespace Facebook\WebDriver\Remote\Service;

use Exception;
use Facebook\WebDriver\Net\URLChecker;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\ProcessBuilder;





class DriverService
{



private $executable;




private $url;




private $args;




private $environment;




private $process;







public function __construct($executable, $port, $args = [], $environment = null)
{
$this->setExecutable($executable);
$this->url = sprintf('http://localhost:%d', $port);
$this->args = $args;
$this->environment = $environment ?: $_ENV;
}




public function getURL()
{
return $this->url;
}




public function start()
{
if ($this->process !== null) {
return $this;
}

$this->process = $this->createProcess();
$this->process->start();

$this->checkWasStarted($this->process);

$checker = new URLChecker();
$checker->waitUntilAvailable(20 * 1000, $this->url . '/status');

return $this;
}




public function stop()
{
if ($this->process === null) {
return $this;
}

$this->process->stop();
$this->process = null;

$checker = new URLChecker();
$checker->waitUntilUnavailable(3 * 1000, $this->url . '/shutdown');

return $this;
}




public function isRunning()
{
if ($this->process === null) {
return false;
}

return $this->process->isRunning();
}







protected static function checkExecutable($executable)
{
return $executable;
}





protected function setExecutable($executable)
{
if ($this->isExecutable($executable)) {
$this->executable = $executable;

return;
}

throw new Exception(
sprintf(
'"%s" is not executable. Make sure the path is correct or use environment variable to specify'
. ' location of the executable.',
$executable
)
);
}




protected function checkWasStarted($process)
{
usleep(10000); 

if (!$process->isRunning()) {
throw new Exception(
sprintf(
'Error starting driver executable "%s": %s',
$process->getCommandLine(),
$process->getErrorOutput()
)
);
}
}




private function createProcess()
{

 if (class_exists(ProcessBuilder::class)
&& mb_strpos('@deprecated', (new \ReflectionClass(ProcessBuilder::class))->getDocComment()) === false
) {
$processBuilder = (new ProcessBuilder())
->setPrefix($this->executable)
->setArguments($this->args)
->addEnvironmentVariables($this->environment);

return $processBuilder->getProcess();
}

 $commandLine = array_merge([$this->executable], $this->args);

return new Process($commandLine, null, $this->environment);
}







private function isExecutable($filename)
{
if (is_executable($filename)) {
return true;
}
if ($filename !== basename($filename)) { 
 return false;
}

$paths = explode(PATH_SEPARATOR, getenv('PATH'));
foreach ($paths as $path) {
if (is_executable($path . DIRECTORY_SEPARATOR . $filename)) {
return true;
}
}

return false;
}
}
<?php

namespace Facebook\WebDriver\Remote;






class WebDriverCapabilityType
{
const BROWSER_NAME = 'browserName';
const VERSION = 'version';
const PLATFORM = 'platform';
const JAVASCRIPT_ENABLED = 'javascriptEnabled';
const TAKES_SCREENSHOT = 'takesScreenshot';
const HANDLES_ALERTS = 'handlesAlerts';
const DATABASE_ENABLED = 'databaseEnabled';
const LOCATION_CONTEXT_ENABLED = 'locationContextEnabled';
const APPLICATION_CACHE_ENABLED = 'applicationCacheEnabled';
const BROWSER_CONNECTION_ENABLED = 'browserConnectionEnabled';
const CSS_SELECTORS_ENABLED = 'cssSelectorsEnabled';
const WEB_STORAGE_ENABLED = 'webStorageEnabled';
const ROTATABLE = 'rotatable';
const ACCEPT_SSL_CERTS = 'acceptSslCerts';
const NATIVE_EVENTS = 'nativeEvents';
const PROXY = 'proxy';

private function __construct()
{
}
}
<?php

namespace Facebook\WebDriver\Remote;

class WebDriverCommand
{

protected $sessionID;

protected $name;

protected $parameters;








public function __construct($session_id, $name, $parameters)
{
$this->sessionID = $session_id;
$this->name = $name;
$this->parameters = $parameters;
}




public static function newSession(array $parameters)
{

 return new self(null, DriverCommand::NEW_SESSION, $parameters);
}




public function getName()
{
return $this->name;
}




public function getSessionID()
{
return $this->sessionID;
}




public function getParameters()
{
return $this->parameters;
}
}
<?php

namespace Facebook\WebDriver\Remote;

interface FileDetector
{








public function getLocalFile($file);
}
<?php

namespace Facebook\WebDriver\Remote;

use BadMethodCallException;
use Facebook\WebDriver\Exception\WebDriverCurlException;
use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\WebDriverCommandExecutor;
use InvalidArgumentException;




class HttpCommandExecutor implements WebDriverCommandExecutor
{
const DEFAULT_HTTP_HEADERS = [
'Content-Type: application/json;charset=UTF-8',
'Accept: application/json',
];




protected static $commands = [
DriverCommand::ACCEPT_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/accept_alert'],
DriverCommand::ADD_COOKIE => ['method' => 'POST', 'url' => '/session/:sessionId/cookie'],
DriverCommand::CLEAR_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/clear'],
DriverCommand::CLICK_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/click'],
DriverCommand::CLOSE => ['method' => 'DELETE', 'url' => '/session/:sessionId/window'],
DriverCommand::DELETE_ALL_COOKIES => ['method' => 'DELETE', 'url' => '/session/:sessionId/cookie'],
DriverCommand::DELETE_COOKIE => ['method' => 'DELETE', 'url' => '/session/:sessionId/cookie/:name'],
DriverCommand::DISMISS_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/dismiss_alert'],
DriverCommand::ELEMENT_EQUALS => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/equals/:other'],
DriverCommand::FIND_CHILD_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/element'],
DriverCommand::FIND_CHILD_ELEMENTS => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/elements'],
DriverCommand::EXECUTE_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute'],
DriverCommand::EXECUTE_ASYNC_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute_async'],
DriverCommand::FIND_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element'],
DriverCommand::FIND_ELEMENTS => ['method' => 'POST', 'url' => '/session/:sessionId/elements'],
DriverCommand::SWITCH_TO_FRAME => ['method' => 'POST', 'url' => '/session/:sessionId/frame'],
DriverCommand::SWITCH_TO_PARENT_FRAME => ['method' => 'POST', 'url' => '/session/:sessionId/frame/parent'],
DriverCommand::SWITCH_TO_WINDOW => ['method' => 'POST', 'url' => '/session/:sessionId/window'],
DriverCommand::GET => ['method' => 'POST', 'url' => '/session/:sessionId/url'],
DriverCommand::GET_ACTIVE_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/active'],
DriverCommand::GET_ALERT_TEXT => ['method' => 'GET', 'url' => '/session/:sessionId/alert_text'],
DriverCommand::GET_ALL_COOKIES => ['method' => 'GET', 'url' => '/session/:sessionId/cookie'],
DriverCommand::GET_NAMED_COOKIE => ['method' => 'GET', 'url' => '/session/:sessionId/cookie/:name'],
DriverCommand::GET_ALL_SESSIONS => ['method' => 'GET', 'url' => '/sessions'],
DriverCommand::GET_AVAILABLE_LOG_TYPES => ['method' => 'GET', 'url' => '/session/:sessionId/log/types'],
DriverCommand::GET_CURRENT_URL => ['method' => 'GET', 'url' => '/session/:sessionId/url'],
DriverCommand::GET_CURRENT_WINDOW_HANDLE => ['method' => 'GET', 'url' => '/session/:sessionId/window_handle'],
DriverCommand::GET_ELEMENT_ATTRIBUTE => [
'method' => 'GET',
'url' => '/session/:sessionId/element/:id/attribute/:name',
],
DriverCommand::GET_ELEMENT_VALUE_OF_CSS_PROPERTY => [
'method' => 'GET',
'url' => '/session/:sessionId/element/:id/css/:propertyName',
],
DriverCommand::GET_ELEMENT_LOCATION => [
'method' => 'GET',
'url' => '/session/:sessionId/element/:id/location',
],
DriverCommand::GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW => [
'method' => 'GET',
'url' => '/session/:sessionId/element/:id/location_in_view',
],
DriverCommand::GET_ELEMENT_SIZE => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/size'],
DriverCommand::GET_ELEMENT_TAG_NAME => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/name'],
DriverCommand::GET_ELEMENT_TEXT => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/text'],
DriverCommand::GET_LOG => ['method' => 'POST', 'url' => '/session/:sessionId/log'],
DriverCommand::GET_PAGE_SOURCE => ['method' => 'GET', 'url' => '/session/:sessionId/source'],
DriverCommand::GET_SCREEN_ORIENTATION => ['method' => 'GET', 'url' => '/session/:sessionId/orientation'],
DriverCommand::GET_CAPABILITIES => ['method' => 'GET', 'url' => '/session/:sessionId'],
DriverCommand::GET_TITLE => ['method' => 'GET', 'url' => '/session/:sessionId/title'],
DriverCommand::GET_WINDOW_HANDLES => ['method' => 'GET', 'url' => '/session/:sessionId/window_handles'],
DriverCommand::GET_WINDOW_POSITION => [
'method' => 'GET',
'url' => '/session/:sessionId/window/:windowHandle/position',
],
DriverCommand::GET_WINDOW_SIZE => ['method' => 'GET', 'url' => '/session/:sessionId/window/:windowHandle/size'],
DriverCommand::GO_BACK => ['method' => 'POST', 'url' => '/session/:sessionId/back'],
DriverCommand::GO_FORWARD => ['method' => 'POST', 'url' => '/session/:sessionId/forward'],
DriverCommand::IS_ELEMENT_DISPLAYED => [
'method' => 'GET',
'url' => '/session/:sessionId/element/:id/displayed',
],
DriverCommand::IS_ELEMENT_ENABLED => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/enabled'],
DriverCommand::IS_ELEMENT_SELECTED => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/selected'],
DriverCommand::MAXIMIZE_WINDOW => [
'method' => 'POST',
'url' => '/session/:sessionId/window/:windowHandle/maximize',
],
DriverCommand::MOUSE_DOWN => ['method' => 'POST', 'url' => '/session/:sessionId/buttondown'],
DriverCommand::MOUSE_UP => ['method' => 'POST', 'url' => '/session/:sessionId/buttonup'],
DriverCommand::CLICK => ['method' => 'POST', 'url' => '/session/:sessionId/click'],
DriverCommand::DOUBLE_CLICK => ['method' => 'POST', 'url' => '/session/:sessionId/doubleclick'],
DriverCommand::MOVE_TO => ['method' => 'POST', 'url' => '/session/:sessionId/moveto'],
DriverCommand::NEW_SESSION => ['method' => 'POST', 'url' => '/session'],
DriverCommand::QUIT => ['method' => 'DELETE', 'url' => '/session/:sessionId'],
DriverCommand::REFRESH => ['method' => 'POST', 'url' => '/session/:sessionId/refresh'],
DriverCommand::UPLOAD_FILE => ['method' => 'POST', 'url' => '/session/:sessionId/file'], 
 DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/keys'],
DriverCommand::SET_ALERT_VALUE => ['method' => 'POST', 'url' => '/session/:sessionId/alert_text'],
DriverCommand::SEND_KEYS_TO_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/value'],
DriverCommand::IMPLICITLY_WAIT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts/implicit_wait'],
DriverCommand::SET_SCREEN_ORIENTATION => ['method' => 'POST', 'url' => '/session/:sessionId/orientation'],
DriverCommand::SET_TIMEOUT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts'],
DriverCommand::SET_SCRIPT_TIMEOUT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts/async_script'],
DriverCommand::SET_WINDOW_POSITION => [
'method' => 'POST',
'url' => '/session/:sessionId/window/:windowHandle/position',
],
DriverCommand::SET_WINDOW_SIZE => [
'method' => 'POST',
'url' => '/session/:sessionId/window/:windowHandle/size',
],
DriverCommand::STATUS => ['method' => 'GET', 'url' => '/status'],
DriverCommand::SUBMIT_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/submit'],
DriverCommand::SCREENSHOT => ['method' => 'GET', 'url' => '/session/:sessionId/screenshot'],
DriverCommand::TAKE_ELEMENT_SCREENSHOT => [
'method' => 'GET',
'url' => '/session/:sessionId/element/:id/screenshot',
],
DriverCommand::TOUCH_SINGLE_TAP => ['method' => 'POST', 'url' => '/session/:sessionId/touch/click'],
DriverCommand::TOUCH_DOWN => ['method' => 'POST', 'url' => '/session/:sessionId/touch/down'],
DriverCommand::TOUCH_DOUBLE_TAP => ['method' => 'POST', 'url' => '/session/:sessionId/touch/doubleclick'],
DriverCommand::TOUCH_FLICK => ['method' => 'POST', 'url' => '/session/:sessionId/touch/flick'],
DriverCommand::TOUCH_LONG_PRESS => ['method' => 'POST', 'url' => '/session/:sessionId/touch/longclick'],
DriverCommand::TOUCH_MOVE => ['method' => 'POST', 'url' => '/session/:sessionId/touch/move'],
DriverCommand::TOUCH_SCROLL => ['method' => 'POST', 'url' => '/session/:sessionId/touch/scroll'],
DriverCommand::TOUCH_UP => ['method' => 'POST', 'url' => '/session/:sessionId/touch/up'],
DriverCommand::CUSTOM_COMMAND => [],
];



protected static $w3cCompliantCommands = [
DriverCommand::ACCEPT_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/alert/accept'],
DriverCommand::ACTIONS => ['method' => 'POST', 'url' => '/session/:sessionId/actions'],
DriverCommand::DISMISS_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/alert/dismiss'],
DriverCommand::EXECUTE_ASYNC_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute/async'],
DriverCommand::EXECUTE_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute/sync'],
DriverCommand::FULLSCREEN_WINDOW => ['method' => 'POST', 'url' => '/session/:sessionId/window/fullscreen'],
DriverCommand::GET_ACTIVE_ELEMENT => ['method' => 'GET', 'url' => '/session/:sessionId/element/active'],
DriverCommand::GET_ALERT_TEXT => ['method' => 'GET', 'url' => '/session/:sessionId/alert/text'],
DriverCommand::GET_CURRENT_WINDOW_HANDLE => ['method' => 'GET', 'url' => '/session/:sessionId/window'],
DriverCommand::GET_ELEMENT_LOCATION => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/rect'],
DriverCommand::GET_ELEMENT_PROPERTY => [
'method' => 'GET',
'url' => '/session/:sessionId/element/:id/property/:name',
],
DriverCommand::GET_ELEMENT_SIZE => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/rect'],
DriverCommand::GET_WINDOW_HANDLES => ['method' => 'GET', 'url' => '/session/:sessionId/window/handles'],
DriverCommand::GET_WINDOW_POSITION => ['method' => 'GET', 'url' => '/session/:sessionId/window/rect'],
DriverCommand::GET_WINDOW_SIZE => ['method' => 'GET', 'url' => '/session/:sessionId/window/rect'],
DriverCommand::IMPLICITLY_WAIT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts'],
DriverCommand::MAXIMIZE_WINDOW => ['method' => 'POST', 'url' => '/session/:sessionId/window/maximize'],
DriverCommand::MINIMIZE_WINDOW => ['method' => 'POST', 'url' => '/session/:sessionId/window/minimize'],
DriverCommand::NEW_WINDOW => ['method' => 'POST', 'url' => '/session/:sessionId/window/new'],
DriverCommand::SET_ALERT_VALUE => ['method' => 'POST', 'url' => '/session/:sessionId/alert/text'],
DriverCommand::SET_SCRIPT_TIMEOUT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts'],
DriverCommand::SET_TIMEOUT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts'],
DriverCommand::SET_WINDOW_SIZE => ['method' => 'POST', 'url' => '/session/:sessionId/window/rect'],
DriverCommand::SET_WINDOW_POSITION => ['method' => 'POST', 'url' => '/session/:sessionId/window/rect'],
];



protected $url;



protected $curl;



protected $isW3cCompliant = true;






public function __construct($url, $http_proxy = null, $http_proxy_port = null)
{
self::$w3cCompliantCommands = array_merge(self::$commands, self::$w3cCompliantCommands);

$this->url = $url;
$this->curl = curl_init();

if (!empty($http_proxy)) {
curl_setopt($this->curl, CURLOPT_PROXY, $http_proxy);
if ($http_proxy_port !== null) {
curl_setopt($this->curl, CURLOPT_PROXYPORT, $http_proxy_port);
}
}


 $matches = null;
if (preg_match("/^(https?:\/\/)(.*):(.*)@(.*?)/U", $url, $matches)) {
$this->url = $matches[1] . $matches[4];
$auth_creds = $matches[2] . ':' . $matches[3];
curl_setopt($this->curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($this->curl, CURLOPT_USERPWD, $auth_creds);
}

curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($this->curl, CURLOPT_HTTPHEADER, static::DEFAULT_HTTP_HEADERS);
$this->setRequestTimeout(30000);
$this->setConnectionTimeout(30000);
}

public function disableW3cCompliance()
{
$this->isW3cCompliant = false;
}







public function setConnectionTimeout($timeout_in_ms)
{

 curl_setopt(
$this->curl,

156,
$timeout_in_ms
);

return $this;
}







public function setRequestTimeout($timeout_in_ms)
{

 
 curl_setopt(
$this->curl,

155,
$timeout_in_ms
);

return $this;
}







public function execute(WebDriverCommand $command)
{
$http_options = $this->getCommandHttpOptions($command);
$http_method = $http_options['method'];
$url = $http_options['url'];

$sessionID = $command->getSessionID();
$url = str_replace(':sessionId', $sessionID === null ? '' : $sessionID, $url);
$params = $command->getParameters();
foreach ($params as $name => $value) {
if ($name[0] === ':') {
$url = str_replace($name, $value, $url);
unset($params[$name]);
}
}

if (is_array($params) && !empty($params) && $http_method !== 'POST') {
throw new BadMethodCallException(sprintf(
'The http method called for %s is %s but it has to be POST' .
' if you want to pass the JSON params %s',
$url,
$http_method,
json_encode($params)
));
}

curl_setopt($this->curl, CURLOPT_URL, $this->url . $url);


 if ($command->getName() === DriverCommand::NEW_SESSION) {
curl_setopt($this->curl, CURLOPT_POST, 1);
} else {
curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $http_method);
}

if (in_array($http_method, ['POST', 'PUT'], true)) {

 
 curl_setopt($this->curl, CURLOPT_HTTPHEADER, array_merge(static::DEFAULT_HTTP_HEADERS, ['Expect:']));
} else {
curl_setopt($this->curl, CURLOPT_HTTPHEADER, static::DEFAULT_HTTP_HEADERS);
}

$encoded_params = null;

if ($http_method === 'POST') {
if (is_array($params) && !empty($params)) {
$encoded_params = json_encode($params);
} elseif ($this->isW3cCompliant) {

 $encoded_params = '{}';
}
}

curl_setopt($this->curl, CURLOPT_POSTFIELDS, $encoded_params);

$raw_results = trim(curl_exec($this->curl));

if ($error = curl_error($this->curl)) {
$msg = sprintf(
'Curl error thrown for http %s to %s',
$http_method,
$url
);
if (is_array($params) && !empty($params)) {
$msg .= sprintf(' with params: %s', json_encode($params, JSON_UNESCAPED_SLASHES));
}

throw new WebDriverCurlException($msg . "\n\n" . $error);
}

$results = json_decode($raw_results, true);

if ($results === null && json_last_error() !== JSON_ERROR_NONE) {
throw new WebDriverException(
sprintf(
"JSON decoding of remote response failed.\n" .
"Error code: %d\n" .
"The response: '%s'\n",
json_last_error(),
$raw_results
)
);
}

$value = null;
if (is_array($results) && array_key_exists('value', $results)) {
$value = $results['value'];
}

$message = null;
if (is_array($value) && array_key_exists('message', $value)) {
$message = $value['message'];
}

$sessionId = null;
if (is_array($value) && array_key_exists('sessionId', $value)) {

 $sessionId = $value['sessionId'];
} elseif (is_array($results) && array_key_exists('sessionId', $results)) {

 $sessionId = $results['sessionId'];
}


 if (isset($value['error'])) {

 WebDriverException::throwException($value['error'], $message, $results);
}

$status = isset($results['status']) ? $results['status'] : 0;
if ($status !== 0) {

 WebDriverException::throwException($status, $message, $results);
}

$response = new WebDriverResponse($sessionId);

return $response
->setStatus($status)
->setValue($value);
}




public function getAddressOfRemoteServer()
{
return $this->url;
}




protected function getCommandHttpOptions(WebDriverCommand $command)
{
$commandName = $command->getName();
if (!isset(self::$commands[$commandName])) {
if ($this->isW3cCompliant && !isset(self::$w3cCompliantCommands[$commandName])) {
throw new InvalidArgumentException($command->getName() . ' is not a valid command.');
}
}

if ($this->isW3cCompliant) {
$raw = self::$w3cCompliantCommands[$command->getName()];
} else {
$raw = self::$commands[$command->getName()];
}

if ($command instanceof CustomWebDriverCommand) {
$url = $command->getCustomUrl();
$method = $command->getCustomMethod();
} else {
$url = $raw['url'];
$method = $raw['method'];
}

return [
'url' => $url,
'method' => $method,
];
}
}
<?php

namespace Facebook\WebDriver\Remote;

interface ExecuteMethod
{





public function execute($command_name, array $parameters = []);
}
<?php

namespace Facebook\WebDriver\Remote;

class LocalFileDetector implements FileDetector
{





public function getLocalFile($file)
{
if (is_file($file)) {
return realpath($file);
}

return null;
}
}
<?php

namespace Facebook\WebDriver\Remote;






class WebDriverBrowserType
{
const FIREFOX = 'firefox';
const FIREFOX_PROXY = 'firefoxproxy';
const FIREFOX_CHROME = 'firefoxchrome';
const GOOGLECHROME = 'googlechrome';
const SAFARI = 'safari';
const SAFARI_PROXY = 'safariproxy';
const OPERA = 'opera';
const MICROSOFT_EDGE = 'MicrosoftEdge';
const IEXPLORE = 'iexplore';
const IEXPLORE_PROXY = 'iexploreproxy';
const CHROME = 'chrome';
const KONQUEROR = 'konqueror';
const MOCK = 'mock';
const IE_HTA = 'iehta';
const ANDROID = 'android';
const HTMLUNIT = 'htmlunit';
const IE = 'internet explorer';
const IPHONE = 'iphone';
const IPAD = 'iPad';




const PHANTOMJS = 'phantomjs';

private function __construct()
{
}
}
<?php

namespace Facebook\WebDriver\Remote;

use Facebook\WebDriver\Interactions\WebDriverActions;
use Facebook\WebDriver\JavaScriptExecutor;
use Facebook\WebDriver\WebDriver;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\WebDriverCapabilities;
use Facebook\WebDriver\WebDriverCommandExecutor;
use Facebook\WebDriver\WebDriverElement;
use Facebook\WebDriver\WebDriverHasInputDevices;
use Facebook\WebDriver\WebDriverNavigation;
use Facebook\WebDriver\WebDriverOptions;
use Facebook\WebDriver\WebDriverWait;

class RemoteWebDriver implements WebDriver, JavaScriptExecutor, WebDriverHasInputDevices
{



protected $executor;



protected $capabilities;




protected $sessionID;



protected $mouse;



protected $keyboard;



protected $touch;



protected $executeMethod;



protected $isW3cCompliant;







protected function __construct(
HttpCommandExecutor $commandExecutor,
$sessionId,
WebDriverCapabilities $capabilities = null,
$isW3cCompliant = false
) {
$this->executor = $commandExecutor;
$this->sessionID = $sessionId;
$this->isW3cCompliant = $isW3cCompliant;

if ($capabilities !== null) {
$this->capabilities = $capabilities;
}
}














public static function create(
$selenium_server_url = 'http://localhost:4444/wd/hub',
$desired_capabilities = null,
$connection_timeout_in_ms = null,
$request_timeout_in_ms = null,
$http_proxy = null,
$http_proxy_port = null,
DesiredCapabilities $required_capabilities = null
) {
$selenium_server_url = preg_replace('#/+$#', '', $selenium_server_url);

$desired_capabilities = self::castToDesiredCapabilitiesObject($desired_capabilities);

$executor = new HttpCommandExecutor($selenium_server_url, $http_proxy, $http_proxy_port);
if ($connection_timeout_in_ms !== null) {
$executor->setConnectionTimeout($connection_timeout_in_ms);
}
if ($request_timeout_in_ms !== null) {
$executor->setRequestTimeout($request_timeout_in_ms);
}


 $parameters = [
'capabilities' => [
'firstMatch' => [(object) $desired_capabilities->toW3cCompatibleArray()],
],
];

if ($required_capabilities !== null && !empty($required_capabilities->toArray())) {
$parameters['capabilities']['alwaysMatch'] = (object) $required_capabilities->toW3cCompatibleArray();
}


 if ($required_capabilities !== null) {

 
 
 $desired_capabilities->setCapability('requiredCapabilities', (object) $required_capabilities->toArray());
}

$parameters['desiredCapabilities'] = (object) $desired_capabilities->toArray();

$command = WebDriverCommand::newSession($parameters);

$response = $executor->execute($command);

return static::createFromResponse($response, $executor);
}














public static function createBySessionID(
$session_id,
$selenium_server_url = 'http://localhost:4444/wd/hub',
$connection_timeout_in_ms = null,
$request_timeout_in_ms = null
) {

 $isW3cCompliant = func_num_args() > 4 ? func_get_arg(4) : true;

$executor = new HttpCommandExecutor($selenium_server_url, null, null);
if ($connection_timeout_in_ms !== null) {
$executor->setConnectionTimeout($connection_timeout_in_ms);
}
if ($request_timeout_in_ms !== null) {
$executor->setRequestTimeout($request_timeout_in_ms);
}

if (!$isW3cCompliant) {
$executor->disableW3cCompliance();
}

return new static($executor, $session_id, null, $isW3cCompliant);
}






public function close()
{
$this->execute(DriverCommand::CLOSE, []);

return $this;
}








public function newWindow()
{
return $this->switchTo()->newWindow();
}








public function findElement(WebDriverBy $by)
{
$raw_element = $this->execute(
DriverCommand::FIND_ELEMENT,
JsonWireCompat::getUsing($by, $this->isW3cCompliant)
);

return $this->newElement(JsonWireCompat::getElement($raw_element));
}








public function findElements(WebDriverBy $by)
{
$raw_elements = $this->execute(
DriverCommand::FIND_ELEMENTS,
JsonWireCompat::getUsing($by, $this->isW3cCompliant)
);

$elements = [];
foreach ($raw_elements as $raw_element) {
$elements[] = $this->newElement(JsonWireCompat::getElement($raw_element));
}

return $elements;
}








public function get($url)
{
$params = ['url' => (string) $url];
$this->execute(DriverCommand::GET, $params);

return $this;
}






public function getCurrentURL()
{
return $this->execute(DriverCommand::GET_CURRENT_URL);
}






public function getPageSource()
{
return $this->execute(DriverCommand::GET_PAGE_SOURCE);
}






public function getTitle()
{
return $this->execute(DriverCommand::GET_TITLE);
}






public function getWindowHandle()
{
return $this->execute(
DriverCommand::GET_CURRENT_WINDOW_HANDLE,
[]
);
}









public function getWindowHandles()
{
return $this->execute(DriverCommand::GET_WINDOW_HANDLES, []);
}




public function quit()
{
$this->execute(DriverCommand::QUIT);
$this->executor = null;
}









public function executeScript($script, array $arguments = [])
{
$params = [
'script' => $script,
'args' => $this->prepareScriptArguments($arguments),
];

return $this->execute(DriverCommand::EXECUTE_SCRIPT, $params);
}













public function executeAsyncScript($script, array $arguments = [])
{
$params = [
'script' => $script,
'args' => $this->prepareScriptArguments($arguments),
];

return $this->execute(
DriverCommand::EXECUTE_ASYNC_SCRIPT,
$params
);
}







public function takeScreenshot($save_as = null)
{
$screenshot = base64_decode($this->execute(DriverCommand::SCREENSHOT), true);

if ($save_as !== null) {
$directoryPath = dirname($save_as);

if (!file_exists($directoryPath)) {
mkdir($directoryPath, 0777, true);
}

file_put_contents($save_as, $screenshot);
}

return $screenshot;
}




public function getStatus()
{
$response = $this->execute(DriverCommand::STATUS);

return RemoteStatus::createFromResponse($response);
}















public function wait($timeout_in_second = 30, $interval_in_millisecond = 250)
{
return new WebDriverWait(
$this,
$timeout_in_second,
$interval_in_millisecond
);
}






public function manage()
{
return new WebDriverOptions($this->getExecuteMethod(), $this->isW3cCompliant);
}







public function navigate()
{
return new WebDriverNavigation($this->getExecuteMethod());
}







public function switchTo()
{
return new RemoteTargetLocator($this->getExecuteMethod(), $this, $this->isW3cCompliant);
}




public function getMouse()
{
if (!$this->mouse) {
$this->mouse = new RemoteMouse($this->getExecuteMethod(), $this->isW3cCompliant);
}

return $this->mouse;
}




public function getKeyboard()
{
if (!$this->keyboard) {
$this->keyboard = new RemoteKeyboard($this->getExecuteMethod(), $this, $this->isW3cCompliant);
}

return $this->keyboard;
}




public function getTouch()
{
if (!$this->touch) {
$this->touch = new RemoteTouchScreen($this->getExecuteMethod());
}

return $this->touch;
}






public function action()
{
return new WebDriverActions($this);
}










public function setCommandExecutor(WebDriverCommandExecutor $executor)
{
$this->executor = $executor;

return $this;
}






public function getCommandExecutor()
{
return $this->executor;
}










public function setSessionID($session_id)
{
$this->sessionID = $session_id;

return $this;
}






public function getSessionID()
{
return $this->sessionID;
}






public function getCapabilities()
{
return $this->capabilities;
}








public static function getAllSessions($selenium_server_url = 'http://localhost:4444/wd/hub', $timeout_in_ms = 30000)
{
$executor = new HttpCommandExecutor($selenium_server_url, null, null);
$executor->setConnectionTimeout($timeout_in_ms);

$command = new WebDriverCommand(
null,
DriverCommand::GET_ALL_SESSIONS,
[]
);

return $executor->execute($command)->getValue();
}

public function execute($command_name, $params = [])
{
$command = new WebDriverCommand(
$this->sessionID,
$command_name,
$params
);

if ($this->executor) {
$response = $this->executor->execute($command);

return $response->getValue();
}

return null;
}











public function executeCustomCommand($endpointUrl, $method = 'GET', $params = [])
{
$command = new CustomWebDriverCommand(
$this->sessionID,
$endpointUrl,
$method,
$params
);

if ($this->executor) {
$response = $this->executor->execute($command);

return $response->getValue();
}

return null;
}





public function isW3cCompliant()
{
return $this->isW3cCompliant;
}








protected static function createFromResponse(WebDriverResponse $response, HttpCommandExecutor $commandExecutor)
{
$responseValue = $response->getValue();

if (!$isW3cCompliant = isset($responseValue['capabilities'])) {
$commandExecutor->disableW3cCompliance();
}

if ($isW3cCompliant) {
$returnedCapabilities = DesiredCapabilities::createFromW3cCapabilities($responseValue['capabilities']);
} else {
$returnedCapabilities = new DesiredCapabilities($responseValue);
}

return new static($commandExecutor, $response->getSessionID(), $returnedCapabilities, $isW3cCompliant);
}







protected function prepareScriptArguments(array $arguments)
{
$args = [];
foreach ($arguments as $key => $value) {
if ($value instanceof WebDriverElement) {
$args[$key] = [
$this->isW3cCompliant ?
JsonWireCompat::WEB_DRIVER_ELEMENT_IDENTIFIER
: 'ELEMENT' => $value->getID(),
];
} else {
if (is_array($value)) {
$value = $this->prepareScriptArguments($value);
}
$args[$key] = $value;
}
}

return $args;
}




protected function getExecuteMethod()
{
if (!$this->executeMethod) {
$this->executeMethod = new RemoteExecuteMethod($this);
}

return $this->executeMethod;
}







protected function newElement($id)
{
return new RemoteWebElement($this->getExecuteMethod(), $id, $this->isW3cCompliant);
}








protected static function castToDesiredCapabilitiesObject($desired_capabilities = null)
{
if ($desired_capabilities === null) {
return new DesiredCapabilities();
}

if (is_array($desired_capabilities)) {
return new DesiredCapabilities($desired_capabilities);
}

return $desired_capabilities;
}
}
<?php

namespace Facebook\WebDriver\Remote;

use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates;
use Facebook\WebDriver\WebDriverMouse;




class RemoteMouse implements WebDriverMouse
{

const BUTTON_LEFT = 0;

const BUTTON_MIDDLE = 1;

const BUTTON_RIGHT = 2;




private $executor;



private $isW3cCompliant;





public function __construct(RemoteExecuteMethod $executor, $isW3cCompliant = false)
{
$this->executor = $executor;
$this->isW3cCompliant = $isW3cCompliant;
}






public function click(WebDriverCoordinates $where = null)
{
if ($this->isW3cCompliant) {
$moveAction = $where ? [$this->createMoveAction($where)] : [];
$this->executor->execute(DriverCommand::ACTIONS, [
'actions' => [
[
'type' => 'pointer',
'id' => 'mouse',
'parameters' => ['pointerType' => 'mouse'],
'actions' => array_merge($moveAction, $this->createClickActions()),
],
],
]);

return $this;
}

$this->moveIfNeeded($where);
$this->executor->execute(DriverCommand::CLICK, [
'button' => self::BUTTON_LEFT,
]);

return $this;
}






public function contextClick(WebDriverCoordinates $where = null)
{
if ($this->isW3cCompliant) {
$moveAction = $where ? [$this->createMoveAction($where)] : [];
$this->executor->execute(DriverCommand::ACTIONS, [
'actions' => [
[
'type' => 'pointer',
'id' => 'mouse',
'parameters' => ['pointerType' => 'mouse'],
'actions' => array_merge($moveAction, [
[
'type' => 'pointerDown',
'button' => self::BUTTON_RIGHT,
],
[
'type' => 'pointerUp',
'button' => self::BUTTON_RIGHT,
],
]),
],
],
]);

return $this;
}

$this->moveIfNeeded($where);
$this->executor->execute(DriverCommand::CLICK, [
'button' => self::BUTTON_RIGHT,
]);

return $this;
}






public function doubleClick(WebDriverCoordinates $where = null)
{
if ($this->isW3cCompliant) {
$clickActions = $this->createClickActions();
$moveAction = $where === null ? [] : [$this->createMoveAction($where)];
$this->executor->execute(DriverCommand::ACTIONS, [
'actions' => [
[
'type' => 'pointer',
'id' => 'mouse',
'parameters' => ['pointerType' => 'mouse'],
'actions' => array_merge($moveAction, $clickActions, $clickActions),
],
],
]);

return $this;
}

$this->moveIfNeeded($where);
$this->executor->execute(DriverCommand::DOUBLE_CLICK);

return $this;
}






public function mouseDown(WebDriverCoordinates $where = null)
{
if ($this->isW3cCompliant) {
$this->executor->execute(DriverCommand::ACTIONS, [
'actions' => [
[
'type' => 'pointer',
'id' => 'mouse',
'parameters' => ['pointerType' => 'mouse'],
'actions' => [
$this->createMoveAction($where),
[
'type' => 'pointerDown',
'button' => self::BUTTON_LEFT,
],
],
],
],
]);

return $this;
}

$this->moveIfNeeded($where);
$this->executor->execute(DriverCommand::MOUSE_DOWN);

return $this;
}








public function mouseMove(
WebDriverCoordinates $where = null,
$x_offset = null,
$y_offset = null
) {
if ($this->isW3cCompliant) {
$this->executor->execute(DriverCommand::ACTIONS, [
'actions' => [
[
'type' => 'pointer',
'id' => 'mouse',
'parameters' => ['pointerType' => 'mouse'],
'actions' => [$this->createMoveAction($where, $x_offset, $y_offset)],
],
],
]);

return $this;
}

$params = [];
if ($where !== null) {
$params['element'] = $where->getAuxiliary();
}
if ($x_offset !== null) {
$params['xoffset'] = $x_offset;
}
if ($y_offset !== null) {
$params['yoffset'] = $y_offset;
}

$this->executor->execute(DriverCommand::MOVE_TO, $params);

return $this;
}






public function mouseUp(WebDriverCoordinates $where = null)
{
if ($this->isW3cCompliant) {
$moveAction = $where ? [$this->createMoveAction($where)] : [];

$this->executor->execute(DriverCommand::ACTIONS, [
'actions' => [
[
'type' => 'pointer',
'id' => 'mouse',
'parameters' => ['pointerType' => 'mouse'],
'actions' => array_merge($moveAction, [
[
'type' => 'pointerUp',
'button' => self::BUTTON_LEFT,
],
]),
],
],
]);

return $this;
}

$this->moveIfNeeded($where);
$this->executor->execute(DriverCommand::MOUSE_UP);

return $this;
}




protected function moveIfNeeded(WebDriverCoordinates $where = null)
{
if ($where) {
$this->mouseMove($where);
}
}








private function createMoveAction(
WebDriverCoordinates $where = null,
$x_offset = null,
$y_offset = null
) {
$move_action = [
'type' => 'pointerMove',
'duration' => 100, 
 'x' => $x_offset === null ? 0 : $x_offset,
'y' => $y_offset === null ? 0 : $y_offset,
];

if ($where !== null) {
$move_action['origin'] = [JsonWireCompat::WEB_DRIVER_ELEMENT_IDENTIFIER => $where->getAuxiliary()];
} else {
$move_action['origin'] = 'pointer';
}

return $move_action;
}




private function createClickActions()
{
return [
[
'type' => 'pointerDown',
'button' => self::BUTTON_LEFT,
],
[
'type' => 'pointerUp',
'button' => self::BUTTON_LEFT,
],
];
}
}
<?php

namespace Facebook\WebDriver\Remote;






class RemoteStatus
{

protected $isReady;

protected $message;

protected $meta = [];





protected function __construct($isReady, $message, array $meta = [])
{
$this->isReady = (bool) $isReady;
$this->message = (string) $message;

$this->setMeta($meta);
}





public static function createFromResponse(array $responseBody)
{
$object = new static($responseBody['ready'], $responseBody['message'], $responseBody);

return $object;
}








public function isReady()
{
return $this->isReady;
}






public function getMessage()
{
return $this->message;
}






public function getMeta()
{
return $this->meta;
}

protected function setMeta(array $meta)
{
unset($meta['ready'], $meta['message']);

$this->meta = $meta;
}
}
<?php

namespace Facebook\WebDriver\Remote;

use Facebook\WebDriver\WebDriverBy;






abstract class JsonWireCompat
{





const WEB_DRIVER_ELEMENT_IDENTIFIER = 'element-6066-11e4-a52e-4f735466cecf';

public static function getElement(array $rawElement)
{
if (array_key_exists(self::WEB_DRIVER_ELEMENT_IDENTIFIER, $rawElement)) {

 return $rawElement[self::WEB_DRIVER_ELEMENT_IDENTIFIER];
}


 return $rawElement['ELEMENT'];
}







public static function getUsing(WebDriverBy $by, $isW3cCompliant)
{
$mechanism = $by->getMechanism();
$value = $by->getValue();

if ($isW3cCompliant) {
switch ($mechanism) {

 case 'class name':
$mechanism = 'css selector';
$value = sprintf('.%s', self::escapeSelector($value));
break;
case 'id':
$mechanism = 'css selector';
$value = sprintf('#%s', self::escapeSelector($value));
break;
case 'name':
$mechanism = 'css selector';
$value = sprintf('[name=\'%s\']', self::escapeSelector($value));
break;
}
}

return ['using' => $mechanism, 'value' => $value];
}












private static function escapeSelector($selector)
{
return preg_replace_callback('/[^a-z0-9]/iSu', function ($matches) {
$chr = $matches[0];
if (mb_strlen($chr) === 1) {
$ord = ord($chr);
} else {
$chr = mb_convert_encoding($chr, 'UTF-32BE', 'UTF-8');
$ord = hexdec(bin2hex($chr));
}

return sprintf('\\%X ', $ord);
}, $selector);
}
}
<?php

namespace Facebook\WebDriver\Remote;

class WebDriverResponse
{



private $status;



private $value;



private $sessionID;




public function __construct($session_id = null)
{
$this->sessionID = $session_id;
}




public function getStatus()
{
return $this->status;
}





public function setStatus($status)
{
$this->status = $status;

return $this;
}




public function getValue()
{
return $this->value;
}





public function setValue($value)
{
$this->value = $value;

return $this;
}




public function getSessionID()
{
return $this->sessionID;
}





public function setSessionID($session_id)
{
$this->sessionID = $session_id;

return $this;
}
}
<?php

namespace Facebook\WebDriver\Remote;

use Exception;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Firefox\FirefoxDriver;
use Facebook\WebDriver\Firefox\FirefoxOptions;
use Facebook\WebDriver\Firefox\FirefoxProfile;
use Facebook\WebDriver\WebDriverCapabilities;
use Facebook\WebDriver\WebDriverPlatform;

class DesiredCapabilities implements WebDriverCapabilities
{

private $capabilities;


private static $ossToW3c = [
WebDriverCapabilityType::PLATFORM => 'platformName',
WebDriverCapabilityType::VERSION => 'browserVersion',
WebDriverCapabilityType::ACCEPT_SSL_CERTS => 'acceptInsecureCerts',
ChromeOptions::CAPABILITY => ChromeOptions::CAPABILITY_W3C,
];

public function __construct(array $capabilities = [])
{
$this->capabilities = $capabilities;
}

public static function createFromW3cCapabilities(array $capabilities = [])
{
$w3cToOss = array_flip(self::$ossToW3c);

foreach ($w3cToOss as $w3cCapability => $ossCapability) {

 if (array_key_exists($w3cCapability, $capabilities)) {
$capabilities[$ossCapability] = $capabilities[$w3cCapability];
}
}

return new self($capabilities);
}




public function getBrowserName()
{
return $this->get(WebDriverCapabilityType::BROWSER_NAME, '');
}





public function setBrowserName($browser_name)
{
$this->set(WebDriverCapabilityType::BROWSER_NAME, $browser_name);

return $this;
}




public function getVersion()
{
return $this->get(WebDriverCapabilityType::VERSION, '');
}





public function setVersion($version)
{
$this->set(WebDriverCapabilityType::VERSION, $version);

return $this;
}





public function getCapability($name)
{
return $this->get($name);
}






public function setCapability($name, $value)
{

 
 
 
 if ($name === FirefoxOptions::CAPABILITY && is_array($value)) {
$defaultOptions = (new FirefoxOptions())->toArray();
$value = array_merge($defaultOptions, $value);
}

$this->set($name, $value);

return $this;
}




public function getPlatform()
{
return $this->get(WebDriverCapabilityType::PLATFORM, '');
}





public function setPlatform($platform)
{
$this->set(WebDriverCapabilityType::PLATFORM, $platform);

return $this;
}





public function is($capability_name)
{
return (bool) $this->get($capability_name);
}






public function isJavascriptEnabled()
{
return $this->get(WebDriverCapabilityType::JAVASCRIPT_ENABLED, false);
}









public function setJavascriptEnabled($enabled)
{
$browser = $this->getBrowserName();
if ($browser && $browser !== WebDriverBrowserType::HTMLUNIT) {
throw new Exception(
'isJavascriptEnabled() is a htmlunit-only option. ' .
'See https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities#read-write-capabilities.'
);
}

$this->set(WebDriverCapabilityType::JAVASCRIPT_ENABLED, $enabled);

return $this;
}





public function toArray()
{
if (isset($this->capabilities[ChromeOptions::CAPABILITY]) &&
$this->capabilities[ChromeOptions::CAPABILITY] instanceof ChromeOptions
) {
$this->capabilities[ChromeOptions::CAPABILITY] =
$this->capabilities[ChromeOptions::CAPABILITY]->toArray();
}

if (isset($this->capabilities[FirefoxOptions::CAPABILITY]) &&
$this->capabilities[FirefoxOptions::CAPABILITY] instanceof FirefoxOptions
) {
$this->capabilities[FirefoxOptions::CAPABILITY] =
$this->capabilities[FirefoxOptions::CAPABILITY]->toArray();
}

if (isset($this->capabilities[FirefoxDriver::PROFILE]) &&
$this->capabilities[FirefoxDriver::PROFILE] instanceof FirefoxProfile
) {
$this->capabilities[FirefoxDriver::PROFILE] =
$this->capabilities[FirefoxDriver::PROFILE]->encode();
}

return $this->capabilities;
}




public function toW3cCompatibleArray()
{
$allowedW3cCapabilities = [
'browserName',
'browserVersion',
'platformName',
'acceptInsecureCerts',
'pageLoadStrategy',
'proxy',
'setWindowRect',
'timeouts',
'strictFileInteractability',
'unhandledPromptBehavior',
];

$ossCapabilities = $this->toArray();
$w3cCapabilities = [];

foreach ($ossCapabilities as $capabilityKey => $capabilityValue) {

 if (in_array($capabilityKey, $allowedW3cCapabilities, true)) {
$w3cCapabilities[$capabilityKey] = $capabilityValue;
}


 if (array_key_exists($capabilityKey, self::$ossToW3c)) {
if ($capabilityKey === WebDriverCapabilityType::PLATFORM) {
$w3cCapabilities[self::$ossToW3c[$capabilityKey]] = mb_strtolower($capabilityValue);


 if ($w3cCapabilities[self::$ossToW3c[$capabilityKey]] === 'any') {
unset($w3cCapabilities[self::$ossToW3c[$capabilityKey]]);
}
} else {
$w3cCapabilities[self::$ossToW3c[$capabilityKey]] = $capabilityValue;
}
}


 if (mb_strpos($capabilityKey, ':') !== false) {
$w3cCapabilities[$capabilityKey] = $capabilityValue;
}
}


 if (array_key_exists(ChromeOptions::CAPABILITY, $ossCapabilities)) {
if (array_key_exists(ChromeOptions::CAPABILITY_W3C, $ossCapabilities)) {
$w3cCapabilities[ChromeOptions::CAPABILITY_W3C] = new \ArrayObject(
array_merge_recursive(
(array) $ossCapabilities[ChromeOptions::CAPABILITY],
(array) $ossCapabilities[ChromeOptions::CAPABILITY_W3C]
)
);
} else {
$w3cCapabilities[ChromeOptions::CAPABILITY_W3C] = $ossCapabilities[ChromeOptions::CAPABILITY];
}
}


 if (array_key_exists(FirefoxDriver::PROFILE, $ossCapabilities)) {

 if (!array_key_exists(FirefoxOptions::CAPABILITY, $ossCapabilities)
|| !array_key_exists('profile', $ossCapabilities[FirefoxOptions::CAPABILITY])) {
$w3cCapabilities[FirefoxOptions::CAPABILITY]['profile'] = $ossCapabilities[FirefoxDriver::PROFILE];
}
}

return $w3cCapabilities;
}




public static function android()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::ANDROID,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANDROID,
]);
}




public static function chrome()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::CHROME,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
]);
}




public static function firefox()
{
$caps = new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::FIREFOX,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
]);

$caps->setCapability(FirefoxOptions::CAPABILITY, new FirefoxOptions()); 

return $caps;
}




public static function htmlUnit()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::HTMLUNIT,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
]);
}




public static function htmlUnitWithJS()
{
$caps = new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::HTMLUNIT,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
]);

return $caps->setJavascriptEnabled(true);
}




public static function internetExplorer()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IE,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::WINDOWS,
]);
}




public static function microsoftEdge()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::MICROSOFT_EDGE,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::WINDOWS,
]);
}




public static function iphone()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IPHONE,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC,
]);
}




public static function ipad()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IPAD,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC,
]);
}




public static function opera()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::OPERA,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
]);
}




public static function safari()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::SAFARI,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
]);
}






public static function phantomjs()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::PHANTOMJS,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
]);
}






private function set($key, $value)
{
$this->capabilities[$key] = $value;

return $this;
}






private function get($key, $default = null)
{
return isset($this->capabilities[$key])
? $this->capabilities[$key]
: $default;
}
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Exception\NoSuchAlertException;
use Facebook\WebDriver\Exception\NoSuchElementException;
use Facebook\WebDriver\Exception\NoSuchFrameException;
use Facebook\WebDriver\Exception\StaleElementReferenceException;






class WebDriverExpectedCondition
{





private $apply;

protected function __construct(callable $apply)
{
$this->apply = $apply;
}




public function getApply()
{
return $this->apply;
}







public static function titleIs($title)
{
return new static(
function (WebDriver $driver) use ($title) {
return $title === $driver->getTitle();
}
);
}







public static function titleContains($title)
{
return new static(
function (WebDriver $driver) use ($title) {
return mb_strpos($driver->getTitle(), $title) !== false;
}
);
}







public static function titleMatches($titleRegexp)
{
return new static(
function (WebDriver $driver) use ($titleRegexp) {
return (bool) preg_match($titleRegexp, $driver->getTitle());
}
);
}







public static function urlIs($url)
{
return new static(
function (WebDriver $driver) use ($url) {
return $url === $driver->getCurrentURL();
}
);
}







public static function urlContains($url)
{
return new static(
function (WebDriver $driver) use ($url) {
return mb_strpos($driver->getCurrentURL(), $url) !== false;
}
);
}







public static function urlMatches($urlRegexp)
{
return new static(
function (WebDriver $driver) use ($urlRegexp) {
return (bool) preg_match($urlRegexp, $driver->getCurrentURL());
}
);
}








public static function presenceOfElementLocated(WebDriverBy $by)
{
return new static(
function (WebDriver $driver) use ($by) {
try {
return $driver->findElement($by);
} catch (NoSuchElementException $e) {
return false;
}
}
);
}







public static function presenceOfAllElementsLocatedBy(WebDriverBy $by)
{
return new static(
function (WebDriver $driver) use ($by) {
$elements = $driver->findElements($by);

return count($elements) > 0 ? $elements : null;
}
);
}








public static function visibilityOfElementLocated(WebDriverBy $by)
{
return new static(
function (WebDriver $driver) use ($by) {
try {
$element = $driver->findElement($by);

return $element->isDisplayed() ? $element : null;
} catch (StaleElementReferenceException $e) {
return null;
}
}
);
}









public static function visibilityOfAnyElementLocated(WebDriverBy $by)
{
return new static(
function (WebDriver $driver) use ($by) {
$elements = $driver->findElements($by);
$visibleElements = [];

foreach ($elements as $element) {
try {
if ($element->isDisplayed()) {
$visibleElements[] = $element;
}
} catch (StaleElementReferenceException $e) {
}
}

return count($visibleElements) > 0 ? $visibleElements : null;
}
);
}








public static function visibilityOf(WebDriverElement $element)
{
return new static(
function () use ($element) {
return $element->isDisplayed() ? $element : null;
}
);
}











public static function textToBePresentInElement(WebDriverBy $by, $text)
{
return self::elementTextContains($by, $text);
}









public static function elementTextContains(WebDriverBy $by, $text)
{
return new static(
function (WebDriver $driver) use ($by, $text) {
try {
$element_text = $driver->findElement($by)->getText();

return mb_strpos($element_text, $text) !== false;
} catch (StaleElementReferenceException $e) {
return null;
}
}
);
}









public static function elementTextIs(WebDriverBy $by, $text)
{
return new static(
function (WebDriver $driver) use ($by, $text) {
try {
return $driver->findElement($by)->getText() == $text;
} catch (StaleElementReferenceException $e) {
return null;
}
}
);
}








public static function elementTextMatches(WebDriverBy $by, $regexp)
{
return new static(
function (WebDriver $driver) use ($by, $regexp) {
try {
return (bool) preg_match($regexp, $driver->findElement($by)->getText());
} catch (StaleElementReferenceException $e) {
return null;
}
}
);
}










public static function textToBePresentInElementValue(WebDriverBy $by, $text)
{
return self::elementValueContains($by, $text);
}








public static function elementValueContains(WebDriverBy $by, $text)
{
return new static(
function (WebDriver $driver) use ($by, $text) {
try {
$element_text = $driver->findElement($by)->getAttribute('value');

return mb_strpos($element_text, $text) !== false;
} catch (StaleElementReferenceException $e) {
return null;
}
}
);
}








public static function frameToBeAvailableAndSwitchToIt($frame_locator)
{
return new static(
function (WebDriver $driver) use ($frame_locator) {
try {
return $driver->switchTo()->frame($frame_locator);
} catch (NoSuchFrameException $e) {
return false;
}
}
);
}







public static function invisibilityOfElementLocated(WebDriverBy $by)
{
return new static(
function (WebDriver $driver) use ($by) {
try {
return !$driver->findElement($by)->isDisplayed();
} catch (NoSuchElementException $e) {
return true;
} catch (StaleElementReferenceException $e) {
return true;
}
}
);
}








public static function invisibilityOfElementWithText(WebDriverBy $by, $text)
{
return new static(
function (WebDriver $driver) use ($by, $text) {
try {
return !($driver->findElement($by)->getText() === $text);
} catch (NoSuchElementException $e) {
return true;
} catch (StaleElementReferenceException $e) {
return true;
}
}
);
}







public static function elementToBeClickable(WebDriverBy $by)
{
$visibility_of_element_located = self::visibilityOfElementLocated($by);

return new static(
function (WebDriver $driver) use ($visibility_of_element_located) {
$element = call_user_func(
$visibility_of_element_located->getApply(),
$driver
);

try {
if ($element !== null && $element->isEnabled()) {
return $element;
}

return null;
} catch (StaleElementReferenceException $e) {
return null;
}
}
);
}







public static function stalenessOf(WebDriverElement $element)
{
return new static(
function () use ($element) {
try {
$element->isEnabled();

return false;
} catch (StaleElementReferenceException $e) {
return true;
}
}
);
}












public static function refreshed(self $condition)
{
return new static(
function (WebDriver $driver) use ($condition) {
try {
return call_user_func($condition->getApply(), $driver);
} catch (StaleElementReferenceException $e) {
return null;
}
}
);
}







public static function elementToBeSelected($element_or_by)
{
return self::elementSelectionStateToBe(
$element_or_by,
true
);
}








public static function elementSelectionStateToBe($element_or_by, $selected)
{
if ($element_or_by instanceof WebDriverElement) {
return new static(
function () use ($element_or_by, $selected) {
return $element_or_by->isSelected() === $selected;
}
);
}

if ($element_or_by instanceof WebDriverBy) {
return new static(
function (WebDriver $driver) use ($element_or_by, $selected) {
try {
$element = $driver->findElement($element_or_by);

return $element->isSelected() === $selected;
} catch (StaleElementReferenceException $e) {
return null;
}
}
);
}

throw new \InvalidArgumentException('Instance of either WebDriverElement or WebDriverBy must be given');
}






public static function alertIsPresent()
{
return new static(
function (WebDriver $driver) {
try {

 
 
 $alert = $driver->switchTo()->alert();
$alert->getText();

return $alert;
} catch (NoSuchAlertException $e) {
return null;
}
}
);
}







public static function numberOfWindowsToBe($expectedNumberOfWindows)
{
return new static(
function (WebDriver $driver) use ($expectedNumberOfWindows) {
return count($driver->getWindowHandles()) == $expectedNumberOfWindows;
}
);
}







public static function not(self $condition)
{
return new static(
function (WebDriver $driver) use ($condition) {
$result = call_user_func($condition->getApply(), $driver);

return !$result;
}
);
}
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Exception\IndexOutOfBoundsException;
use Facebook\WebDriver\Exception\UnsupportedOperationException;
use Facebook\WebDriver\Remote\DriverCommand;
use Facebook\WebDriver\Remote\ExecuteMethod;




class WebDriverWindow
{



protected $executor;



protected $isW3cCompliant;

public function __construct(ExecuteMethod $executor, $isW3cCompliant = false)
{
$this->executor = $executor;
$this->isW3cCompliant = $isW3cCompliant;
}







public function getPosition()
{
$position = $this->executor->execute(
DriverCommand::GET_WINDOW_POSITION,
[':windowHandle' => 'current']
);

return new WebDriverPoint(
$position['x'],
$position['y']
);
}







public function getSize()
{
$size = $this->executor->execute(
DriverCommand::GET_WINDOW_SIZE,
[':windowHandle' => 'current']
);

return new WebDriverDimension(
$size['width'],
$size['height']
);
}






public function minimize()
{
if (!$this->isW3cCompliant) {
throw new UnsupportedOperationException('Minimize window is only supported in W3C mode');
}

$this->executor->execute(DriverCommand::MINIMIZE_WINDOW, []);

return $this;
}






public function maximize()
{
if ($this->isW3cCompliant) {
$this->executor->execute(DriverCommand::MAXIMIZE_WINDOW, []);
} else {
$this->executor->execute(
DriverCommand::MAXIMIZE_WINDOW,
[':windowHandle' => 'current']
);
}

return $this;
}






public function fullscreen()
{
if (!$this->isW3cCompliant) {
throw new UnsupportedOperationException('The Fullscreen window command is only supported in W3C mode');
}

$this->executor->execute(DriverCommand::FULLSCREEN_WINDOW, []);

return $this;
}








public function setSize(WebDriverDimension $size)
{
$params = [
'width' => $size->getWidth(),
'height' => $size->getHeight(),
':windowHandle' => 'current',
];
$this->executor->execute(DriverCommand::SET_WINDOW_SIZE, $params);

return $this;
}








public function setPosition(WebDriverPoint $position)
{
$params = [
'x' => $position->getX(),
'y' => $position->getY(),
':windowHandle' => 'current',
];
$this->executor->execute(DriverCommand::SET_WINDOW_POSITION, $params);

return $this;
}






public function getScreenOrientation()
{
return $this->executor->execute(DriverCommand::GET_SCREEN_ORIENTATION);
}









public function setScreenOrientation($orientation)
{
$orientation = mb_strtoupper($orientation);
if (!in_array($orientation, ['PORTRAIT', 'LANDSCAPE'], true)) {
throw new IndexOutOfBoundsException(
'Orientation must be either PORTRAIT, or LANDSCAPE'
);
}

$this->executor->execute(
DriverCommand::SET_SCREEN_ORIENTATION,
['orientation' => $orientation]
);

return $this;
}
}
<?php

namespace Facebook\WebDriver;

interface WebDriverKeyboard
{






public function sendKeys($keys);








public function pressKey($key);








public function releaseKey($key);
}
<?php

namespace Facebook\WebDriver;




interface WebDriverHasInputDevices
{



public function getKeyboard();




public function getMouse();
}
<?php

namespace Facebook\WebDriver;




interface WebDriverTargetLocator
{

const WINDOW_TYPE_WINDOW = 'window';

const WINDOW_TYPE_TAB = 'tab';







public function defaultContent();











public function frame($frame);


 
 
 
 
 
 








public function window($handle);


 






public function alert();







public function activeElement();
}
<?php

namespace Facebook\WebDriver\Chrome;

use Facebook\WebDriver\Remote\Service\DriverService;

class ChromeDriverService extends DriverService
{




const CHROME_DRIVER_EXE_PROPERTY = 'webdriver.chrome.driver';

const CHROME_DRIVER_EXECUTABLE = 'WEBDRIVER_CHROME_DRIVER';




const DEFAULT_EXECUTABLE = 'chromedriver';




public static function createDefaultService()
{
$pathToExecutable = getenv(self::CHROME_DRIVER_EXECUTABLE) ?: getenv(self::CHROME_DRIVER_EXE_PROPERTY);
if ($pathToExecutable === false || $pathToExecutable === '') {
$pathToExecutable = static::DEFAULT_EXECUTABLE;
}

$port = 9515; 
 $args = ['--port=' . $port];

return new static($pathToExecutable, $port, $args);
}
}
<?php

namespace Facebook\WebDriver\Chrome;

use Facebook\WebDriver\Remote\DesiredCapabilities;
use JsonSerializable;
use ReturnTypeWillChange;






class ChromeOptions implements JsonSerializable
{




const CAPABILITY = 'chromeOptions';



const CAPABILITY_W3C = 'goog:chromeOptions';



private $arguments = [];



private $binary = '';



private $extensions = [];



private $experimentalOptions = [];







 public function jsonSerialize()
{
return $this->toArray();
}








public function setBinary($path)
{
$this->binary = $path;

return $this;
}





public function addArguments(array $arguments)
{
$this->arguments = array_merge($this->arguments, $arguments);

return $this;
}








public function addExtensions(array $paths)
{
foreach ($paths as $path) {
$this->addExtension($path);
}

return $this;
}





public function addEncodedExtensions(array $encoded_extensions)
{
foreach ($encoded_extensions as $encoded_extension) {
$this->addEncodedExtension($encoded_extension);
}

return $this;
}








public function setExperimentalOption($name, $value)
{
$this->experimentalOptions[$name] = $value;

return $this;
}




public function toCapabilities()
{
$capabilities = DesiredCapabilities::chrome();
$capabilities->setCapability(self::CAPABILITY, $this);

return $capabilities;
}




public function toArray()
{

 
 
 
 $options = new \ArrayObject($this->experimentalOptions);

if (!empty($this->binary)) {
$options['binary'] = $this->binary;
}

if (!empty($this->arguments)) {
$options['args'] = $this->arguments;
}

if (!empty($this->extensions)) {
$options['extensions'] = $this->extensions;
}

return $options;
}








private function addExtension($path)
{
$this->addEncodedExtension(base64_encode(file_get_contents($path)));

return $this;
}





private function addEncodedExtension($encoded_extension)
{
$this->extensions[] = $encoded_extension;

return $this;
}
}
<?php

namespace Facebook\WebDriver\Chrome;

use Facebook\WebDriver\Remote\RemoteWebDriver;






class ChromeDevToolsDriver
{
const SEND_COMMAND = [
'method' => 'POST',
'url' => '/session/:sessionId/goog/cdp/execute',
];




private $driver;

public function __construct(RemoteWebDriver $driver)
{
$this->driver = $driver;
}








public function execute($command, array $parameters = [])
{
$params = ['cmd' => $command, 'params' => (object) $parameters];

return $this->driver->executeCustomCommand(
self::SEND_COMMAND['url'],
self::SEND_COMMAND['method'],
$params
);
}
}
<?php

namespace Facebook\WebDriver\Chrome;

use Facebook\WebDriver\Local\LocalWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\Service\DriverCommandExecutor;
use Facebook\WebDriver\Remote\WebDriverCommand;

class ChromeDriver extends LocalWebDriver
{

private $devTools;










public static function start(DesiredCapabilities $desired_capabilities = null, ChromeDriverService $service = null)
{
if ($service === null) { 
 $service = ChromeDriverService::createDefaultService();
}

return static::startUsingDriverService($service, $desired_capabilities);
}









public static function startUsingDriverService(
ChromeDriverService $service,
DesiredCapabilities $capabilities = null
) {
if ($capabilities === null) {
$capabilities = DesiredCapabilities::chrome();
}

$executor = new DriverCommandExecutor($service);
$newSessionCommand = WebDriverCommand::newSession(
[
'capabilities' => [
'firstMatch' => [(object) $capabilities->toW3cCompatibleArray()],
],
'desiredCapabilities' => (object) $capabilities->toArray(),
]
);

$response = $executor->execute($newSessionCommand);





return static::createFromResponse($response, $executor);
}







public function startSession(DesiredCapabilities $desired_capabilities)
{
$command = WebDriverCommand::newSession(
[
'capabilities' => [
'firstMatch' => [(object) $desired_capabilities->toW3cCompatibleArray()],
],
'desiredCapabilities' => (object) $desired_capabilities->toArray(),
]
);
$response = $this->executor->execute($command);
$value = $response->getValue();

if (!$this->isW3cCompliant = isset($value['capabilities'])) {
$this->executor->disableW3cCompliance();
}

$this->sessionID = $response->getSessionID();
}




public function getDevTools()
{
if ($this->devTools === null) {
$this->devTools = new ChromeDevToolsDriver($this);
}

return $this->devTools;
}
}
<?php

namespace Facebook\WebDriver\Support;

class XPathEscaper
{







public static function escapeQuotes($xpathToEscape)
{

 if (mb_strpos($xpathToEscape, "'") === false) {
return sprintf("'%s'", $xpathToEscape);
}


 if (mb_strpos($xpathToEscape, '"') === false) {
return sprintf('"%s"', $xpathToEscape);
}


 return sprintf(
"concat('%s')",
str_replace("'", "', \"'\" ,'", $xpathToEscape)
);
}
}
<?php

namespace Facebook\WebDriver\Support\Events;

use Facebook\WebDriver\Exception\UnsupportedOperationException;
use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\Interactions\Touch\WebDriverTouchScreen;
use Facebook\WebDriver\JavaScriptExecutor;
use Facebook\WebDriver\WebDriver;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\WebDriverDispatcher;
use Facebook\WebDriver\WebDriverElement;
use Facebook\WebDriver\WebDriverOptions;
use Facebook\WebDriver\WebDriverTargetLocator;
use Facebook\WebDriver\WebDriverWait;

class EventFiringWebDriver implements WebDriver, JavaScriptExecutor
{



protected $driver;




protected $dispatcher;





public function __construct(WebDriver $driver, WebDriverDispatcher $dispatcher = null)
{
$this->dispatcher = $dispatcher ?: new WebDriverDispatcher();
if (!$this->dispatcher->getDefaultDriver()) {
$this->dispatcher->setDefaultDriver($this);
}
$this->driver = $driver;
}




public function getDispatcher()
{
return $this->dispatcher;
}




public function getWebDriver()
{
return $this->driver;
}






public function get($url)
{
$this->dispatch('beforeNavigateTo', $url, $this);

try {
$this->driver->get($url);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
$this->dispatch('afterNavigateTo', $url, $this);

return $this;
}






public function findElements(WebDriverBy $by)
{
$this->dispatch('beforeFindBy', $by, null, $this);
$elements = [];

try {
foreach ($this->driver->findElements($by) as $element) {
$elements[] = $this->newElement($element);
}
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}

$this->dispatch('afterFindBy', $by, null, $this);

return $elements;
}






public function findElement(WebDriverBy $by)
{
$this->dispatch('beforeFindBy', $by, null, $this);

try {
$element = $this->newElement($this->driver->findElement($by));
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}

$this->dispatch('afterFindBy', $by, null, $this);

return $element;
}







public function executeScript($script, array $arguments = [])
{
if (!$this->driver instanceof JavaScriptExecutor) {
throw new UnsupportedOperationException(
'driver does not implement JavaScriptExecutor'
);
}

$this->dispatch('beforeScript', $script, $this);

try {
$result = $this->driver->executeScript($script, $arguments);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}

$this->dispatch('afterScript', $script, $this);

return $result;
}







public function executeAsyncScript($script, array $arguments = [])
{
if (!$this->driver instanceof JavaScriptExecutor) {
throw new UnsupportedOperationException(
'driver does not implement JavaScriptExecutor'
);
}

$this->dispatch('beforeScript', $script, $this);

try {
$result = $this->driver->executeAsyncScript($script, $arguments);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
$this->dispatch('afterScript', $script, $this);

return $result;
}





public function close()
{
try {
$this->driver->close();

return $this;
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function getCurrentURL()
{
try {
return $this->driver->getCurrentURL();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function getPageSource()
{
try {
return $this->driver->getPageSource();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function getTitle()
{
try {
return $this->driver->getTitle();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function getWindowHandle()
{
try {
return $this->driver->getWindowHandle();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function getWindowHandles()
{
try {
return $this->driver->getWindowHandles();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}




public function quit()
{
try {
$this->driver->quit();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}






public function takeScreenshot($save_as = null)
{
try {
return $this->driver->takeScreenshot($save_as);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}







public function wait($timeout_in_second = 30, $interval_in_millisecond = 250)
{
try {
return $this->driver->wait($timeout_in_second, $interval_in_millisecond);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function manage()
{
try {
return $this->driver->manage();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function navigate()
{
try {
return new EventFiringWebDriverNavigation(
$this->driver->navigate(),
$this->getDispatcher()
);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function switchTo()
{
try {
return $this->driver->switchTo();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function getTouch()
{
try {
return $this->driver->getTouch();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}

public function execute($name, $params)
{
try {
return $this->driver->execute($name, $params);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





protected function newElement(WebDriverElement $element)
{
return new EventFiringWebElement($element, $this->getDispatcher());
}





protected function dispatch($method, ...$arguments)
{
if (!$this->dispatcher) {
return;
}

$this->dispatcher->dispatch($method, $arguments);
}




protected function dispatchOnException(WebDriverException $exception)
{
$this->dispatch('onException', $exception, $this);
}
}
<?php

namespace Facebook\WebDriver\Support\Events;

use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates;
use Facebook\WebDriver\Internal\WebDriverLocatable;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\WebDriverDimension;
use Facebook\WebDriver\WebDriverDispatcher;
use Facebook\WebDriver\WebDriverElement;
use Facebook\WebDriver\WebDriverPoint;

class EventFiringWebElement implements WebDriverElement, WebDriverLocatable
{



protected $element;



protected $dispatcher;





public function __construct(WebDriverElement $element, WebDriverDispatcher $dispatcher)
{
$this->element = $element;
$this->dispatcher = $dispatcher;
}




public function getDispatcher()
{
return $this->dispatcher;
}




public function getElement()
{
return $this->element;
}






public function sendKeys($value)
{
$this->dispatch('beforeChangeValueOf', $this);

try {
$this->element->sendKeys($value);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
$this->dispatch('afterChangeValueOf', $this);

return $this;
}





public function click()
{
$this->dispatch('beforeClickOn', $this);

try {
$this->element->click();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
$this->dispatch('afterClickOn', $this);

return $this;
}






public function findElement(WebDriverBy $by)
{
$this->dispatch(
'beforeFindBy',
$by,
$this,
$this->dispatcher->getDefaultDriver()
);

try {
$element = $this->newElement($this->element->findElement($by));
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}

$this->dispatch(
'afterFindBy',
$by,
$this,
$this->dispatcher->getDefaultDriver()
);

return $element;
}






public function findElements(WebDriverBy $by)
{
$this->dispatch(
'beforeFindBy',
$by,
$this,
$this->dispatcher->getDefaultDriver()
);

try {
$elements = [];
foreach ($this->element->findElements($by) as $element) {
$elements[] = $this->newElement($element);
}
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
$this->dispatch(
'afterFindBy',
$by,
$this,
$this->dispatcher->getDefaultDriver()
);

return $elements;
}





public function clear()
{
try {
$this->element->clear();

return $this;
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}






public function getAttribute($attribute_name)
{
try {
return $this->element->getAttribute($attribute_name);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}






public function getCSSValue($css_property_name)
{
try {
return $this->element->getCSSValue($css_property_name);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function getLocation()
{
try {
return $this->element->getLocation();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function getLocationOnScreenOnceScrolledIntoView()
{
try {
return $this->element->getLocationOnScreenOnceScrolledIntoView();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}




public function getCoordinates()
{
try {
return $this->element->getCoordinates();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function getSize()
{
try {
return $this->element->getSize();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function getTagName()
{
try {
return $this->element->getTagName();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function getText()
{
try {
return $this->element->getText();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function isDisplayed()
{
try {
return $this->element->isDisplayed();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function isEnabled()
{
try {
return $this->element->isEnabled();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function isSelected()
{
try {
return $this->element->isSelected();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function submit()
{
try {
$this->element->submit();

return $this;
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}





public function getID()
{
try {
return $this->element->getID();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}







public function equals(WebDriverElement $other)
{
try {
return $this->element->equals($other);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}




protected function dispatchOnException(WebDriverException $exception)
{
$this->dispatch(
'onException',
$exception,
$this->dispatcher->getDefaultDriver()
);
}





protected function dispatch($method, ...$arguments)
{
if (!$this->dispatcher) {
return;
}

$this->dispatcher->dispatch($method, $arguments);
}





protected function newElement(WebDriverElement $element)
{
return new static($element, $this->getDispatcher());
}
}
<?php

namespace Facebook\WebDriver\Support\Events;

use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\WebDriverDispatcher;
use Facebook\WebDriver\WebDriverNavigationInterface;

class EventFiringWebDriverNavigation implements WebDriverNavigationInterface
{



protected $navigator;



protected $dispatcher;





public function __construct(WebDriverNavigationInterface $navigator, WebDriverDispatcher $dispatcher)
{
$this->navigator = $navigator;
$this->dispatcher = $dispatcher;
}




public function getDispatcher()
{
return $this->dispatcher;
}




public function getNavigator()
{
return $this->navigator;
}

public function back()
{
$this->dispatch(
'beforeNavigateBack',
$this->getDispatcher()->getDefaultDriver()
);

try {
$this->navigator->back();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
$this->dispatch(
'afterNavigateBack',
$this->getDispatcher()->getDefaultDriver()
);

return $this;
}

public function forward()
{
$this->dispatch(
'beforeNavigateForward',
$this->getDispatcher()->getDefaultDriver()
);

try {
$this->navigator->forward();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
$this->dispatch(
'afterNavigateForward',
$this->getDispatcher()->getDefaultDriver()
);

return $this;
}

public function refresh()
{
try {
$this->navigator->refresh();

return $this;
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}
}

public function to($url)
{
$this->dispatch(
'beforeNavigateTo',
$url,
$this->getDispatcher()->getDefaultDriver()
);

try {
$this->navigator->to($url);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
throw $exception;
}

$this->dispatch(
'afterNavigateTo',
$url,
$this->getDispatcher()->getDefaultDriver()
);

return $this;
}





protected function dispatch($method, ...$arguments)
{
if (!$this->dispatcher) {
return;
}

$this->dispatcher->dispatch($method, $arguments);
}




protected function dispatchOnException(WebDriverException $exception)
{
$this->dispatch('onException', $exception);
}
}
<?php

namespace Facebook\WebDriver\Internal;

use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates;




interface WebDriverLocatable
{



public function getCoordinates();
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Remote\DriverCommand;
use Facebook\WebDriver\Remote\ExecuteMethod;




class WebDriverTimeouts
{



protected $executor;



protected $isW3cCompliant;

public function __construct(ExecuteMethod $executor, $isW3cCompliant = false)
{
$this->executor = $executor;
$this->isW3cCompliant = $isW3cCompliant;
}







public function implicitlyWait($seconds)
{
if ($this->isW3cCompliant) {
$this->executor->execute(
DriverCommand::IMPLICITLY_WAIT,
['implicit' => $seconds * 1000]
);

return $this;
}

$this->executor->execute(
DriverCommand::IMPLICITLY_WAIT,
['ms' => $seconds * 1000]
);

return $this;
}







public function setScriptTimeout($seconds)
{
if ($this->isW3cCompliant) {
$this->executor->execute(
DriverCommand::SET_SCRIPT_TIMEOUT,
['script' => $seconds * 1000]
);

return $this;
}

$this->executor->execute(
DriverCommand::SET_SCRIPT_TIMEOUT,
['ms' => $seconds * 1000]
);

return $this;
}







public function pageLoadTimeout($seconds)
{
if ($this->isW3cCompliant) {
$this->executor->execute(
DriverCommand::SET_SCRIPT_TIMEOUT,
['pageLoad' => $seconds * 1000]
);

return $this;
}

$this->executor->execute(DriverCommand::SET_TIMEOUT, [
'type' => 'page load',
'ms' => $seconds * 1000,
]);

return $this;
}
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\Support\Events\EventFiringWebDriver;
use Facebook\WebDriver\Support\Events\EventFiringWebElement;

interface WebDriverEventListener
{




public function beforeNavigateTo($url, EventFiringWebDriver $driver);





public function afterNavigateTo($url, EventFiringWebDriver $driver);




public function beforeNavigateBack(EventFiringWebDriver $driver);




public function afterNavigateBack(EventFiringWebDriver $driver);




public function beforeNavigateForward(EventFiringWebDriver $driver);




public function afterNavigateForward(EventFiringWebDriver $driver);






public function beforeFindBy(WebDriverBy $by, $element, EventFiringWebDriver $driver);






public function afterFindBy(WebDriverBy $by, $element, EventFiringWebDriver $driver);





public function beforeScript($script, EventFiringWebDriver $driver);





public function afterScript($script, EventFiringWebDriver $driver);




public function beforeClickOn(EventFiringWebElement $element);




public function afterClickOn(EventFiringWebElement $element);




public function beforeChangeValueOf(EventFiringWebElement $element);




public function afterChangeValueOf(EventFiringWebElement $element);





public function onException(WebDriverException $exception, EventFiringWebDriver $driver = null);
}
<?php

namespace Facebook\WebDriver;




class WebDriverDimension
{



private $height;



private $width;





public function __construct($width, $height)
{
$this->width = $width;
$this->height = $height;
}






public function getHeight()
{
return (int) $this->height;
}






public function getWidth()
{
return (int) $this->width;
}







public function equals(self $dimension)
{
return $this->height === $dimension->getHeight() && $this->width === $dimension->getWidth();
}
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Support\Events\EventFiringWebDriver;

class WebDriverDispatcher
{



protected $listeners = [];



protected $driver;








public function setDefaultDriver(EventFiringWebDriver $driver)
{
$this->driver = $driver;

return $this;
}




public function getDefaultDriver()
{
return $this->driver;
}





public function register(WebDriverEventListener $listener)
{
$this->listeners[] = $listener;

return $this;
}





public function unregister(WebDriverEventListener $listener)
{
$key = array_search($listener, $this->listeners, true);
if ($key !== false) {
unset($this->listeners[$key]);
}

return $this;
}






public function dispatch($method, $arguments)
{
foreach ($this->listeners as $listener) {
call_user_func_array([$listener, $method], $arguments);
}

return $this;
}
}
<?php

namespace Facebook\WebDriver\Local;

use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;




abstract class LocalWebDriver extends RemoteWebDriver
{












public static function create(
$selenium_server_url = 'http://localhost:4444/wd/hub',
$desired_capabilities = null,
$connection_timeout_in_ms = null,
$request_timeout_in_ms = null,
$http_proxy = null,
$http_proxy_port = null,
DesiredCapabilities $required_capabilities = null
) {
throw new WebDriverException('Use start() method to start local WebDriver.');
}










public static function createBySessionID(
$session_id,
$selenium_server_url = 'http://localhost:4444/wd/hub',
$connection_timeout_in_ms = null,
$request_timeout_in_ms = null
) {
throw new WebDriverException('Use start() method to start local WebDriver.');
}
}
<?php

namespace Facebook\WebDriver;




interface WebDriverElement extends WebDriverSearchContext
{





public function clear();






public function click();









public function getAttribute($attribute_name);


















public function getCSSValue($css_property_name);






public function getLocation();







public function getLocationOnScreenOnceScrolledIntoView();






public function getSize();






public function getTagName();







public function getText();







public function isDisplayed();







public function isEnabled();






public function isSelected();







public function sendKeys($value);







public function submit();






public function getID();









}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Interactions\Touch\WebDriverTouchAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverTouchScreen;

class WebDriverUpAction extends WebDriverTouchAction implements WebDriverAction
{
private $x;
private $y;






public function __construct(WebDriverTouchScreen $touch_screen, $x, $y)
{
$this->x = $x;
$this->y = $y;
parent::__construct($touch_screen);
}

public function perform()
{
$this->touchScreen->up($this->x, $this->y);
}
}
<?php

namespace Facebook\WebDriver\Exception;




class InvalidCookieDomainException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class NoAlertOpenException extends NoSuchAlertException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class ExpectedException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class ElementNotInteractableException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class UnsupportedOperationException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class UnknownErrorException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;





class NoSuchCookieException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class ScriptTimeoutException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class IMEEngineActivationFailedException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class NoSuchAlertException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class NoStringException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;





class InvalidSessionIdException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class XPathLookupException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class NoSuchWindowException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class ElementNotSelectableException extends ElementNotInteractableException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class UnexpectedAlertOpenException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class JavascriptErrorException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;





class InvalidElementStateException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class ElementNotVisibleException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class StaleElementReferenceException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class IndexOutOfBoundsException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class UnknownMethodException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;

class UnrecognizedExceptionException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class InvalidSelectorException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class TimeoutException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class NoSuchDocumentException extends NoSuchWindowException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class UnableToCaptureScreenException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;





class ElementClickInterceptedException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class NoCollectionException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class NoSuchElementException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class NoSuchCollectionException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class UnknownCommandException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;

class UnexpectedTagNameException extends WebDriverException
{




public function __construct(
$expected_tag_name,
$actual_tag_name
) {
parent::__construct(
sprintf(
'Element should have been "%s" but was "%s"',
$expected_tag_name,
$actual_tag_name
)
);
}
}
<?php

namespace Facebook\WebDriver\Exception;





class InsecureCertificateException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class UnexpectedJavascriptException extends JavascriptErrorException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class NoScriptResultException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;

class WebDriverCurlException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class NoStringLengthException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class SessionNotCreatedException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class UnknownServerException extends UnknownErrorException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class IMENotAvailableException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class InvalidArgumentException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class DriverServerDiedException extends WebDriverException
{
public function __construct(\Exception $previous = null)
{
parent::__construct('The driver server has died.');
\Exception::__construct($this->getMessage(), $this->getCode(), $previous);
}
}
<?php

namespace Facebook\WebDriver\Exception;




class NoSuchFrameException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class InvalidCoordinatesException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;

use Exception;




class WebDriverException extends Exception
{
private $results;





public function __construct($message, $results = null)
{
parent::__construct($message);
$this->results = $results;
}




public function getResults()
{
return $this->results;
}
























































public static function throwException($status_code, $message, $results)
{
if (is_string($status_code)) {

 switch ($status_code) {
case 'element click intercepted':
throw new ElementClickInterceptedException($message, $results);
case 'element not interactable':
throw new ElementNotInteractableException($message, $results);
case 'insecure certificate':
throw new InsecureCertificateException($message, $results);
case 'invalid argument':
throw new InvalidArgumentException($message, $results);
case 'invalid cookie domain':
throw new InvalidCookieDomainException($message, $results);
case 'invalid element state':
throw new InvalidElementStateException($message, $results);
case 'invalid selector':
throw new InvalidSelectorException($message, $results);
case 'invalid session id':
throw new InvalidSessionIdException($message, $results);
case 'javascript error':
throw new JavascriptErrorException($message, $results);
case 'move target out of bounds':
throw new MoveTargetOutOfBoundsException($message, $results);
case 'no such alert':
throw new NoSuchAlertException($message, $results);
case 'no such cookie':
throw new NoSuchCookieException($message, $results);
case 'no such element':
throw new NoSuchElementException($message, $results);
case 'no such frame':
throw new NoSuchFrameException($message, $results);
case 'no such window':
throw new NoSuchWindowException($message, $results);
case 'script timeout':
throw new ScriptTimeoutException($message, $results);
case 'session not created':
throw new SessionNotCreatedException($message, $results);
case 'stale element reference':
throw new StaleElementReferenceException($message, $results);
case 'timeout':
throw new TimeoutException($message, $results);
case 'unable to set cookie':
throw new UnableToSetCookieException($message, $results);
case 'unable to capture screen':
throw new UnableToCaptureScreenException($message, $results);
case 'unexpected alert open':
throw new UnexpectedAlertOpenException($message, $results);
case 'unknown command':
throw new UnknownCommandException($message, $results);
case 'unknown error':
throw new UnknownErrorException($message, $results);
case 'unknown method':
throw new UnknownMethodException($message, $results);
case 'unsupported operation':
throw new UnsupportedOperationException($message, $results);
default:
throw new UnrecognizedExceptionException($message, $results);
}
}

switch ($status_code) {
case 1:
throw new IndexOutOfBoundsException($message, $results);
case 2:
throw new NoCollectionException($message, $results);
case 3:
throw new NoStringException($message, $results);
case 4:
throw new NoStringLengthException($message, $results);
case 5:
throw new NoStringWrapperException($message, $results);
case 6:
throw new NoSuchDriverException($message, $results);
case 7:
throw new NoSuchElementException($message, $results);
case 8:
throw new NoSuchFrameException($message, $results);
case 9:
throw new UnknownCommandException($message, $results);
case 10:
throw new StaleElementReferenceException($message, $results);
case 11:
throw new ElementNotVisibleException($message, $results);
case 12:
throw new InvalidElementStateException($message, $results);
case 13:
throw new UnknownServerException($message, $results);
case 14:
throw new ExpectedException($message, $results);
case 15:
throw new ElementNotSelectableException($message, $results);
case 16:
throw new NoSuchDocumentException($message, $results);
case 17:
throw new UnexpectedJavascriptException($message, $results);
case 18:
throw new NoScriptResultException($message, $results);
case 19:
throw new XPathLookupException($message, $results);
case 20:
throw new NoSuchCollectionException($message, $results);
case 21:
throw new TimeoutException($message, $results);
case 22:
throw new NullPointerException($message, $results);
case 23:
throw new NoSuchWindowException($message, $results);
case 24:
throw new InvalidCookieDomainException($message, $results);
case 25:
throw new UnableToSetCookieException($message, $results);
case 26:
throw new UnexpectedAlertOpenException($message, $results);
case 27:
throw new NoAlertOpenException($message, $results);
case 28:
throw new ScriptTimeoutException($message, $results);
case 29:
throw new InvalidCoordinatesException($message, $results);
case 30:
throw new IMENotAvailableException($message, $results);
case 31:
throw new IMEEngineActivationFailedException($message, $results);
case 32:
throw new InvalidSelectorException($message, $results);
case 33:
throw new SessionNotCreatedException($message, $results);
case 34:
throw new MoveTargetOutOfBoundsException($message, $results);
default:
throw new UnrecognizedExceptionException($message, $results);
}
}
}
<?php

namespace Facebook\WebDriver\Exception;




class NoSuchDriverException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class MoveTargetOutOfBoundsException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class NoStringWrapperException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class UnableToSetCookieException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver\Exception;




class NullPointerException extends WebDriverException
{
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Exception\WebDriverException;




class WebDriverCheckboxes extends AbstractWebDriverCheckboxOrRadio
{
public function __construct(WebDriverElement $element)
{
parent::__construct($element);

$this->type = $element->getAttribute('type');
if ($this->type !== 'checkbox') {
throw new WebDriverException('The input must be of type "checkbox".');
}
}

public function isMultiple()
{
return true;
}

public function deselectAll()
{
foreach ($this->getRelatedElements() as $checkbox) {
$this->deselectOption($checkbox);
}
}

public function deselectByIndex($index)
{
$this->byIndex($index, false);
}

public function deselectByValue($value)
{
$this->byValue($value, false);
}

public function deselectByVisibleText($text)
{
$this->byVisibleText($text, false, false);
}

public function deselectByVisiblePartialText($text)
{
$this->byVisibleText($text, true, false);
}
}
<?php

namespace Facebook\WebDriver\Firefox;

use Facebook\WebDriver\Local\LocalWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\Service\DriverCommandExecutor;
use Facebook\WebDriver\Remote\WebDriverCommand;

class FirefoxDriver extends LocalWebDriver
{
const PROFILE = 'firefox_profile';









public static function start(DesiredCapabilities $capabilities = null)
{
$service = FirefoxDriverService::createDefaultService();

return static::startUsingDriverService($service, $capabilities);
}









public static function startUsingDriverService(
FirefoxDriverService $service,
DesiredCapabilities $capabilities = null
) {
if ($capabilities === null) {
$capabilities = DesiredCapabilities::firefox();
}

$executor = new DriverCommandExecutor($service);
$newSessionCommand = WebDriverCommand::newSession(
[
'capabilities' => [
'firstMatch' => [(object) $capabilities->toW3cCompatibleArray()],
],
]
);

$response = $executor->execute($newSessionCommand);

$returnedCapabilities = DesiredCapabilities::createFromW3cCapabilities($response->getValue()['capabilities']);
$sessionId = $response->getSessionID();

return new static($executor, $sessionId, $returnedCapabilities, true);
}
}
<?php

namespace Facebook\WebDriver\Firefox;

use Facebook\WebDriver\Remote\Service\DriverService;

class FirefoxDriverService extends DriverService
{



const WEBDRIVER_FIREFOX_DRIVER = 'WEBDRIVER_FIREFOX_DRIVER';




const DEFAULT_EXECUTABLE = 'geckodriver';




public static function createDefaultService()
{
$pathToExecutable = getenv(static::WEBDRIVER_FIREFOX_DRIVER);
if ($pathToExecutable === false || $pathToExecutable === '') {
$pathToExecutable = static::DEFAULT_EXECUTABLE;
}

$port = 9515; 
 $args = ['-p=' . $port];

return new static($pathToExecutable, $port, $args);
}
}
<?php

namespace Facebook\WebDriver\Firefox;

use ReturnTypeWillChange;






class FirefoxOptions implements \JsonSerializable
{

const CAPABILITY = 'moz:firefoxOptions';

const OPTION_ARGS = 'args';

const OPTION_PREFS = 'prefs';


private $options = [];

private $arguments = [];

private $preferences = [];

public function __construct()
{

 
 $this->setPreference(FirefoxPreferences::READER_PARSE_ON_LOAD_ENABLED, false);

 $this->setPreference(FirefoxPreferences::DEVTOOLS_JSONVIEW, false);
}









public function setOption($name, $value)
{
if ($name === self::OPTION_PREFS) {
throw new \InvalidArgumentException('Use setPreference() method to set Firefox preferences');
}
if ($name === self::OPTION_ARGS) {
throw new \InvalidArgumentException('Use addArguments() method to add Firefox arguments');
}

$this->options[$name] = $value;

return $this;
}









public function addArguments(array $arguments)
{
$this->arguments = array_merge($this->arguments, $arguments);

return $this;
}










public function setPreference($name, $value)
{
$this->preferences[$name] = $value;

return $this;
}




public function toArray()
{
$array = $this->options;
if (!empty($this->arguments)) {
$array[self::OPTION_ARGS] = $this->arguments;
}
if (!empty($this->preferences)) {
$array[self::OPTION_PREFS] = $this->preferences;
}

return $array;
}


 public function jsonSerialize()
{
return new \ArrayObject($this->toArray());
}
}
<?php

namespace Facebook\WebDriver\Firefox;







class FirefoxPreferences
{

const WEBDRIVER_FIREFOX_PORT = 'webdriver_firefox_port';

const READER_PARSE_ON_LOAD_ENABLED = 'reader.parse-on-load.enabled';

const BROWSER_STARTUP_HOMEPAGE = 'browser.startup.homepage';

const DEVTOOLS_JSONVIEW = 'devtools.jsonview.enabled';

private function __construct()
{
}
}
<?php

namespace Facebook\WebDriver\Firefox;

use Facebook\WebDriver\Exception\WebDriverException;
use FilesystemIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use ZipArchive;

class FirefoxProfile
{



private $preferences = [];



private $extensions = [];



private $extensions_datas = [];



private $rdf_file;





public function addExtension($extension)
{
$this->extensions[] = $extension;

return $this;
}





public function addExtensionDatas($extension_datas)
{
if (!is_dir($extension_datas)) {
return null;
}

$this->extensions_datas[basename($extension_datas)] = $extension_datas;

return $this;
}





public function setRdfFile($rdf_file)
{
if (!is_file($rdf_file)) {
return null;
}

$this->rdf_file = $rdf_file;

return $this;
}







public function setPreference($key, $value)
{
if (is_string($value)) {
$value = sprintf('"%s"', $value);
} else {
if (is_int($value)) {
$value = sprintf('%d', $value);
} else {
if (is_bool($value)) {
$value = $value ? 'true' : 'false';
} else {
throw new WebDriverException(
'The value of the preference should be either a string, int or bool.'
);
}
}
}
$this->preferences[$key] = $value;

return $this;
}





public function getPreference($key)
{
if (array_key_exists($key, $this->preferences)) {
return $this->preferences[$key];
}

return null;
}




public function encode()
{
$temp_dir = $this->createTempDirectory('WebDriverFirefoxProfile');

if (isset($this->rdf_file)) {
copy($this->rdf_file, $temp_dir . DIRECTORY_SEPARATOR . 'mimeTypes.rdf');
}

foreach ($this->extensions as $extension) {
$this->installExtension($extension, $temp_dir);
}

foreach ($this->extensions_datas as $dirname => $extension_datas) {
mkdir($temp_dir . DIRECTORY_SEPARATOR . $dirname);
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($extension_datas, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $item) {
$target_dir = $temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR
. $iterator->getSubPathName();

if ($item->isDir()) {
mkdir($target_dir);
} else {
copy($item, $target_dir);
}
}
}

$content = '';
foreach ($this->preferences as $key => $value) {
$content .= sprintf("user_pref(\"%s\", %s);\n", $key, $value);
}
file_put_contents($temp_dir . '/user.js', $content);


 $temp_zip = sys_get_temp_dir() . '/' . uniqid('WebDriverFirefoxProfileZip', false);

$zip = new ZipArchive();
$zip->open($temp_zip, ZipArchive::CREATE);

$dir = new RecursiveDirectoryIterator($temp_dir);
$files = new RecursiveIteratorIterator($dir);

$dir_prefix = preg_replace(
'#\\\\#',
'\\\\\\\\',
$temp_dir . DIRECTORY_SEPARATOR
);

foreach ($files as $name => $object) {
if (is_dir($name)) {
continue;
}

$path = preg_replace("#^{$dir_prefix}#", '', $name);
$zip->addFile($name, $path);
}
$zip->close();

$profile = base64_encode(file_get_contents($temp_zip));


 $this->deleteDirectory($temp_dir);
unlink($temp_zip);

return $profile;
}






private function installExtension($extension, $profile_dir)
{
$temp_dir = $this->createTempDirectory('WebDriverFirefoxProfileExtension');
$this->extractTo($extension, $temp_dir);


 
 $install_rdf_path = $temp_dir . '/install.rdf';
$xml = simplexml_load_file($install_rdf_path);
$ns = $xml->getDocNamespaces();
$prefix = '';
if (!empty($ns)) {
foreach ($ns as $key => $value) {
if (mb_strpos($value, '//www.mozilla.org/2004/em-rdf') > 0) {
if ($key != '') {
$prefix = $key . ':'; 
 }
break;
}
}
}

 $matches = [];
preg_match('#<' . $prefix . 'id>([^<]+)</' . $prefix . 'id>#', $xml->asXML(), $matches);
if (isset($matches[1])) {
$ext_dir = $profile_dir . '/extensions/' . $matches[1];
mkdir($ext_dir, 0777, true);
$this->extractTo($extension, $ext_dir);
} else {
$this->deleteDirectory($temp_dir);

throw new WebDriverException('Cannot get the extension id from the install manifest.');
}

$this->deleteDirectory($temp_dir);

return $ext_dir;
}







private function createTempDirectory($prefix = '')
{
$temp_dir = tempnam(sys_get_temp_dir(), $prefix);
if (file_exists($temp_dir)) {
unlink($temp_dir);
mkdir($temp_dir);
if (!is_dir($temp_dir)) {
throw new WebDriverException('Cannot create firefox profile.');
}
}

return $temp_dir;
}




private function deleteDirectory($directory)
{
$dir = new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS);
$paths = new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::CHILD_FIRST);

foreach ($paths as $path) {
if ($path->isDir() && !$path->isLink()) {
rmdir($path->getPathname());
} else {
unlink($path->getPathname());
}
}

rmdir($directory);
}








private function extractTo($xpi, $target_dir)
{
$zip = new ZipArchive();
if (file_exists($xpi)) {
if ($zip->open($xpi)) {
$zip->extractTo($target_dir);
$zip->close();
} else {
throw new \Exception("Failed to open the firefox extension. '$xpi'");
}
} else {
throw new \Exception("Firefox extension doesn't exist. '$xpi'");
}

return $this;
}
}
<?php

namespace Facebook\WebDriver\Interactions\Touch;

use Facebook\WebDriver\WebDriverElement;




interface WebDriverTouchScreen
{






public function tap(WebDriverElement $element);







public function doubleTap(WebDriverElement $element);








public function down($x, $y);









public function flick($xspeed, $yspeed);











public function flickFromElement(
WebDriverElement $element,
$xoffset,
$yoffset,
$speed
);







public function longPress(WebDriverElement $element);








public function move($x, $y);









public function scroll($xoffset, $yoffset);










public function scrollFromElement(
WebDriverElement $element,
$xoffset,
$yoffset
);








public function up($x, $y);
}
<?php

namespace Facebook\WebDriver\Interactions\Touch;

use Facebook\WebDriver\WebDriverAction;

class WebDriverScrollAction extends WebDriverTouchAction implements WebDriverAction
{
private $x;
private $y;






public function __construct(WebDriverTouchScreen $touch_screen, $x, $y)
{
$this->x = $x;
$this->y = $y;
parent::__construct($touch_screen);
}

public function perform()
{
$this->touchScreen->scroll($this->x, $this->y);
}
}
<?php

namespace Facebook\WebDriver\Interactions\Touch;

use Facebook\WebDriver\WebDriverAction;

class WebDriverDoubleTapAction extends WebDriverTouchAction implements WebDriverAction
{
public function perform()
{
$this->touchScreen->doubleTap($this->locationProvider);
}
}
<?php

namespace Facebook\WebDriver\Interactions\Touch;

use Facebook\WebDriver\WebDriverAction;

class WebDriverTapAction extends WebDriverTouchAction implements WebDriverAction
{
public function perform()
{
$this->touchScreen->tap($this->locationProvider);
}
}
<?php

namespace Facebook\WebDriver\Interactions\Touch;

use Facebook\WebDriver\WebDriverAction;

class WebDriverDownAction extends WebDriverTouchAction implements WebDriverAction
{



private $x;



private $y;






public function __construct(WebDriverTouchScreen $touch_screen, $x, $y)
{
$this->x = $x;
$this->y = $y;
parent::__construct($touch_screen);
}

public function perform()
{
$this->touchScreen->down($this->x, $this->y);
}
}
<?php

namespace Facebook\WebDriver\Interactions\Touch;

use Facebook\WebDriver\WebDriverAction;

class WebDriverLongPressAction extends WebDriverTouchAction implements WebDriverAction
{
public function perform()
{
$this->touchScreen->longPress($this->locationProvider);
}
}
<?php

namespace Facebook\WebDriver\Interactions\Touch;

use Facebook\WebDriver\WebDriverAction;
use Facebook\WebDriver\WebDriverElement;

class WebDriverScrollFromElementAction extends WebDriverTouchAction implements WebDriverAction
{
private $x;
private $y;







public function __construct(
WebDriverTouchScreen $touch_screen,
WebDriverElement $element,
$x,
$y
) {
$this->x = $x;
$this->y = $y;
parent::__construct($touch_screen, $element);
}

public function perform()
{
$this->touchScreen->scrollFromElement(
$this->locationProvider,
$this->x,
$this->y
);
}
}
<?php

namespace Facebook\WebDriver\Interactions\Touch;

use Facebook\WebDriver\WebDriverAction;
use Facebook\WebDriver\WebDriverElement;

class WebDriverFlickFromElementAction extends WebDriverTouchAction implements WebDriverAction
{



private $x;



private $y;



private $speed;








public function __construct(
WebDriverTouchScreen $touch_screen,
WebDriverElement $element,
$x,
$y,
$speed
) {
$this->x = $x;
$this->y = $y;
$this->speed = $speed;
parent::__construct($touch_screen, $element);
}

public function perform()
{
$this->touchScreen->flickFromElement(
$this->locationProvider,
$this->x,
$this->y,
$this->speed
);
}
}
<?php

namespace Facebook\WebDriver\Interactions\Touch;

use Facebook\WebDriver\WebDriverAction;

class WebDriverFlickAction extends WebDriverTouchAction implements WebDriverAction
{



private $x;



private $y;






public function __construct(WebDriverTouchScreen $touch_screen, $x, $y)
{
$this->x = $x;
$this->y = $y;
parent::__construct($touch_screen);
}

public function perform()
{
$this->touchScreen->flick($this->x, $this->y);
}
}
<?php

namespace Facebook\WebDriver\Interactions\Touch;

use Facebook\WebDriver\WebDriverAction;

class WebDriverMoveAction extends WebDriverTouchAction implements WebDriverAction
{
private $x;
private $y;






public function __construct(WebDriverTouchScreen $touch_screen, $x, $y)
{
$this->x = $x;
$this->y = $y;
parent::__construct($touch_screen);
}

public function perform()
{
$this->touchScreen->move($this->x, $this->y);
}
}
<?php

namespace Facebook\WebDriver\Interactions\Touch;

use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates;
use Facebook\WebDriver\Internal\WebDriverLocatable;




abstract class WebDriverTouchAction
{



protected $touchScreen;



protected $locationProvider;





public function __construct(
WebDriverTouchScreen $touch_screen,
WebDriverLocatable $location_provider = null
) {
$this->touchScreen = $touch_screen;
$this->locationProvider = $location_provider;
}




protected function getActionLocation()
{
return $this->locationProvider !== null
? $this->locationProvider->getCoordinates() : null;
}
}
<?php

namespace Facebook\WebDriver\Interactions;

use Facebook\WebDriver\Interactions\Internal\WebDriverButtonReleaseAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverClickAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverClickAndHoldAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverContextClickAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverDoubleClickAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverKeyDownAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverKeyUpAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverMouseMoveAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverMoveToOffsetAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverSendKeysAction;
use Facebook\WebDriver\WebDriverElement;
use Facebook\WebDriver\WebDriverHasInputDevices;




class WebDriverActions
{
protected $driver;
protected $keyboard;
protected $mouse;
protected $action;




public function __construct(WebDriverHasInputDevices $driver)
{
$this->driver = $driver;
$this->keyboard = $driver->getKeyboard();
$this->mouse = $driver->getMouse();
$this->action = new WebDriverCompositeAction();
}




public function perform()
{
$this->action->perform();
}








public function click(WebDriverElement $element = null)
{
$this->action->addAction(
new WebDriverClickAction($this->mouse, $element)
);

return $this;
}








public function clickAndHold(WebDriverElement $element = null)
{
$this->action->addAction(
new WebDriverClickAndHoldAction($this->mouse, $element)
);

return $this;
}








public function contextClick(WebDriverElement $element = null)
{
$this->action->addAction(
new WebDriverContextClickAction($this->mouse, $element)
);

return $this;
}








public function doubleClick(WebDriverElement $element = null)
{
$this->action->addAction(
new WebDriverDoubleClickAction($this->mouse, $element)
);

return $this;
}








public function dragAndDrop(WebDriverElement $source, WebDriverElement $target)
{
$this->action->addAction(
new WebDriverClickAndHoldAction($this->mouse, $source)
);
$this->action->addAction(
new WebDriverMouseMoveAction($this->mouse, $target)
);
$this->action->addAction(
new WebDriverButtonReleaseAction($this->mouse, $target)
);

return $this;
}









public function dragAndDropBy(WebDriverElement $source, $x_offset, $y_offset)
{
$this->action->addAction(
new WebDriverClickAndHoldAction($this->mouse, $source)
);
$this->action->addAction(
new WebDriverMoveToOffsetAction($this->mouse, null, $x_offset, $y_offset)
);
$this->action->addAction(
new WebDriverButtonReleaseAction($this->mouse, null)
);

return $this;
}








public function moveByOffset($x_offset, $y_offset)
{
$this->action->addAction(
new WebDriverMoveToOffsetAction($this->mouse, null, $x_offset, $y_offset)
);

return $this;
}











public function moveToElement(WebDriverElement $element, $x_offset = null, $y_offset = null)
{
$this->action->addAction(new WebDriverMoveToOffsetAction(
$this->mouse,
$element,
$x_offset,
$y_offset
));

return $this;
}








public function release(WebDriverElement $element = null)
{
$this->action->addAction(
new WebDriverButtonReleaseAction($this->mouse, $element)
);

return $this;
}










public function keyDown(WebDriverElement $element = null, $key = null)
{
$this->action->addAction(
new WebDriverKeyDownAction($this->keyboard, $this->mouse, $element, $key)
);

return $this;
}










public function keyUp(WebDriverElement $element = null, $key = null)
{
$this->action->addAction(
new WebDriverKeyUpAction($this->keyboard, $this->mouse, $element, $key)
);

return $this;
}










public function sendKeys(WebDriverElement $element = null, $keys = null)
{
$this->action->addAction(
new WebDriverSendKeysAction(
$this->keyboard,
$this->mouse,
$element,
$keys
)
);

return $this;
}
}
<?php

namespace Facebook\WebDriver\Interactions;

use Facebook\WebDriver\Interactions\Touch\WebDriverDoubleTapAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverDownAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverFlickAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverFlickFromElementAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverLongPressAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverMoveAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverScrollAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverScrollFromElementAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverTapAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverTouchScreen;
use Facebook\WebDriver\WebDriver;
use Facebook\WebDriver\WebDriverElement;
use Facebook\WebDriver\WebDriverUpAction;




class WebDriverTouchActions extends WebDriverActions
{



protected $touchScreen;

public function __construct(WebDriver $driver)
{
parent::__construct($driver);
$this->touchScreen = $driver->getTouch();
}





public function tap(WebDriverElement $element)
{
$this->action->addAction(
new WebDriverTapAction($this->touchScreen, $element)
);

return $this;
}






public function down($x, $y)
{
$this->action->addAction(
new WebDriverDownAction($this->touchScreen, $x, $y)
);

return $this;
}






public function up($x, $y)
{
$this->action->addAction(
new WebDriverUpAction($this->touchScreen, $x, $y)
);

return $this;
}






public function move($x, $y)
{
$this->action->addAction(
new WebDriverMoveAction($this->touchScreen, $x, $y)
);

return $this;
}






public function scroll($x, $y)
{
$this->action->addAction(
new WebDriverScrollAction($this->touchScreen, $x, $y)
);

return $this;
}







public function scrollFromElement(WebDriverElement $element, $x, $y)
{
$this->action->addAction(
new WebDriverScrollFromElementAction($this->touchScreen, $element, $x, $y)
);

return $this;
}





public function doubleTap(WebDriverElement $element)
{
$this->action->addAction(
new WebDriverDoubleTapAction($this->touchScreen, $element)
);

return $this;
}





public function longPress(WebDriverElement $element)
{
$this->action->addAction(
new WebDriverLongPressAction($this->touchScreen, $element)
);

return $this;
}






public function flick($x, $y)
{
$this->action->addAction(
new WebDriverFlickAction($this->touchScreen, $x, $y)
);

return $this;
}








public function flickFromElement(WebDriverElement $element, $x, $y, $speed)
{
$this->action->addAction(
new WebDriverFlickFromElementAction(
$this->touchScreen,
$element,
$x,
$y,
$speed
)
);

return $this;
}
}
<?php

namespace Facebook\WebDriver\Interactions\Internal;

class WebDriverKeyUpAction extends WebDriverSingleKeyAction
{
public function perform()
{
$this->focusOnElement();
$this->keyboard->releaseKey($this->key);
}
}
<?php

namespace Facebook\WebDriver\Interactions\Internal;

use Facebook\WebDriver\Internal\WebDriverLocatable;
use Facebook\WebDriver\WebDriverAction;
use Facebook\WebDriver\WebDriverKeyboard;
use Facebook\WebDriver\WebDriverMouse;

class WebDriverSendKeysAction extends WebDriverKeysRelatedAction implements WebDriverAction
{



private $keys = '';







public function __construct(
WebDriverKeyboard $keyboard,
WebDriverMouse $mouse,
WebDriverLocatable $location_provider = null,
$keys = ''
) {
parent::__construct($keyboard, $mouse, $location_provider);
$this->keys = $keys;
}

public function perform()
{
$this->focusOnElement();
$this->keyboard->sendKeys($this->keys);
}
}
<?php

namespace Facebook\WebDriver\Interactions\Internal;

use Facebook\WebDriver\WebDriverAction;




class WebDriverClickAndHoldAction extends WebDriverMouseAction implements WebDriverAction
{
public function perform()
{
$this->mouse->mouseDown($this->getActionLocation());
}
}
<?php

namespace Facebook\WebDriver\Interactions\Internal;

use Facebook\WebDriver\WebDriverAction;

class WebDriverClickAction extends WebDriverMouseAction implements WebDriverAction
{
public function perform()
{
$this->mouse->click($this->getActionLocation());
}
}
<?php

namespace Facebook\WebDriver\Interactions\Internal;

use Facebook\WebDriver\Internal\WebDriverLocatable;
use Facebook\WebDriver\WebDriverAction;
use Facebook\WebDriver\WebDriverMouse;

class WebDriverMoveToOffsetAction extends WebDriverMouseAction implements WebDriverAction
{



private $xOffset;



private $yOffset;







public function __construct(
WebDriverMouse $mouse,
WebDriverLocatable $location_provider = null,
$x_offset = null,
$y_offset = null
) {
parent::__construct($mouse, $location_provider);
$this->xOffset = $x_offset;
$this->yOffset = $y_offset;
}

public function perform()
{
$this->mouse->mouseMove(
$this->getActionLocation(),
$this->xOffset,
$this->yOffset
);
}
}
<?php

namespace Facebook\WebDriver\Interactions\Internal;

use Facebook\WebDriver\WebDriverAction;

class WebDriverDoubleClickAction extends WebDriverMouseAction implements WebDriverAction
{
public function perform()
{
$this->mouse->doubleClick($this->getActionLocation());
}
}
<?php

namespace Facebook\WebDriver\Interactions\Internal;

use Facebook\WebDriver\WebDriverAction;

class WebDriverMouseMoveAction extends WebDriverMouseAction implements WebDriverAction
{
public function perform()
{
$this->mouse->mouseMove($this->getActionLocation());
}
}
<?php

namespace Facebook\WebDriver\Interactions\Internal;

use Facebook\WebDriver\Internal\WebDriverLocatable;
use Facebook\WebDriver\WebDriverKeyboard;
use Facebook\WebDriver\WebDriverMouse;




abstract class WebDriverKeysRelatedAction
{



protected $keyboard;



protected $mouse;



protected $locationProvider;






public function __construct(
WebDriverKeyboard $keyboard,
WebDriverMouse $mouse,
WebDriverLocatable $location_provider = null
) {
$this->keyboard = $keyboard;
$this->mouse = $mouse;
$this->locationProvider = $location_provider;
}

protected function focusOnElement()
{
if ($this->locationProvider) {
$this->mouse->click($this->locationProvider->getCoordinates());
}
}
}
<?php

namespace Facebook\WebDriver\Interactions\Internal;

use Facebook\WebDriver\WebDriverAction;




class WebDriverContextClickAction extends WebDriverMouseAction implements WebDriverAction
{
public function perform()
{
$this->mouse->contextClick($this->getActionLocation());
}
}
<?php

namespace Facebook\WebDriver\Interactions\Internal;

use Facebook\WebDriver\Internal\WebDriverLocatable;
use Facebook\WebDriver\WebDriverMouse;




class WebDriverMouseAction
{



protected $mouse;



protected $locationProvider;





public function __construct(WebDriverMouse $mouse, WebDriverLocatable $location_provider = null)
{
$this->mouse = $mouse;
$this->locationProvider = $location_provider;
}




protected function getActionLocation()
{
if ($this->locationProvider !== null) {
return $this->locationProvider->getCoordinates();
}

return null;
}

protected function moveToLocation()
{
$this->mouse->mouseMove($this->locationProvider);
}
}
<?php

namespace Facebook\WebDriver\Interactions\Internal;

class WebDriverKeyDownAction extends WebDriverSingleKeyAction
{
public function perform()
{
$this->focusOnElement();
$this->keyboard->pressKey($this->key);
}
}
<?php

namespace Facebook\WebDriver\Interactions\Internal;

use Facebook\WebDriver\WebDriverAction;




class WebDriverButtonReleaseAction extends WebDriverMouseAction implements WebDriverAction
{
public function perform()
{
$this->mouse->mouseUp($this->getActionLocation());
}
}
<?php

namespace Facebook\WebDriver\Interactions\Internal;

use Facebook\WebDriver\Internal\WebDriverLocatable;
use Facebook\WebDriver\WebDriverAction;
use Facebook\WebDriver\WebDriverKeyboard;
use Facebook\WebDriver\WebDriverKeys;
use Facebook\WebDriver\WebDriverMouse;

abstract class WebDriverSingleKeyAction extends WebDriverKeysRelatedAction implements WebDriverAction
{
const MODIFIER_KEYS = [
WebDriverKeys::SHIFT,
WebDriverKeys::LEFT_SHIFT,
WebDriverKeys::RIGHT_SHIFT,
WebDriverKeys::CONTROL,
WebDriverKeys::LEFT_CONTROL,
WebDriverKeys::RIGHT_CONTROL,
WebDriverKeys::ALT,
WebDriverKeys::LEFT_ALT,
WebDriverKeys::RIGHT_ALT,
WebDriverKeys::META,
WebDriverKeys::RIGHT_META,
WebDriverKeys::COMMAND,
];


protected $key;





public function __construct(
WebDriverKeyboard $keyboard,
WebDriverMouse $mouse,
WebDriverLocatable $location_provider = null,
$key = ''
) {
parent::__construct($keyboard, $mouse, $location_provider);

if (!in_array($key, self::MODIFIER_KEYS, true)) {
throw new \InvalidArgumentException(
sprintf(
'keyDown / keyUp actions can only be used for modifier keys, but "%s" was given',
$key
)
);
}
$this->key = $key;
}
}
<?php

namespace Facebook\WebDriver\Interactions\Internal;

use Facebook\WebDriver\Exception\UnsupportedOperationException;
use Facebook\WebDriver\WebDriverPoint;




class WebDriverCoordinates
{



private $onScreen;



private $inViewPort;



private $onPage;



private $auxiliary;







public function __construct($on_screen, callable $in_view_port, callable $on_page, $auxiliary)
{
$this->onScreen = $on_screen;
$this->inViewPort = $in_view_port;
$this->onPage = $on_page;
$this->auxiliary = $auxiliary;
}





public function onScreen()
{
throw new UnsupportedOperationException(
'onScreen is planned but not yet supported by Selenium'
);
}




public function inViewPort()
{
return call_user_func($this->inViewPort);
}




public function onPage()
{
return call_user_func($this->onPage);
}




public function getAuxiliary()
{
return $this->auxiliary;
}
}
<?php

namespace Facebook\WebDriver\Interactions;

use Facebook\WebDriver\WebDriverAction;




class WebDriverCompositeAction implements WebDriverAction
{



private $actions = [];







public function addAction(WebDriverAction $action)
{
$this->actions[] = $action;

return $this;
}






public function getNumberOfActions()
{
return count($this->actions);
}




public function perform()
{
foreach ($this->actions as $action) {
$action->perform();
}
}
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Interactions\Touch\WebDriverTouchScreen;




interface WebDriver extends WebDriverSearchContext
{





public function close();







public function get($url);






public function getCurrentURL();






public function getPageSource();






public function getTitle();







public function getWindowHandle();






public function getWindowHandles();




public function quit();







public function takeScreenshot($save_as = null);













public function wait(
$timeout_in_second = 30,
$interval_in_millisecond = 250
);







public function manage();








public function navigate();







public function switchTo();


 
 
 
 






public function execute($name, $params);


 
 
 
 
 
 
 
 
 
 
 
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates;




interface WebDriverMouse
{




public function click(WebDriverCoordinates $where);





public function contextClick(WebDriverCoordinates $where);





public function doubleClick(WebDriverCoordinates $where);





public function mouseDown(WebDriverCoordinates $where);







public function mouseMove(
WebDriverCoordinates $where,
$x_offset = null,
$y_offset = null
);





public function mouseUp(WebDriverCoordinates $where);
}
<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Remote\WebDriverCommand;
use Facebook\WebDriver\Remote\WebDriverResponse;




interface WebDriverCommandExecutor
{





public function execute(WebDriverCommand $command);
}
<?php










namespace Predis;

use Predis\Command\CommandInterface;
use Predis\Command\RawCommand;
use Predis\Command\ScriptCommand;
use Predis\Configuration\Options;
use Predis\Configuration\OptionsInterface;
use Predis\Connection\AggregateConnectionInterface;
use Predis\Connection\ConnectionInterface;
use Predis\Connection\ParametersInterface;
use Predis\Monitor\Consumer as MonitorConsumer;
use Predis\Pipeline\Pipeline;
use Predis\PubSub\Consumer as PubSubConsumer;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\ResponseInterface;
use Predis\Response\ServerException;
use Predis\Transaction\MultiExec as MultiExecTransaction;












class Client implements ClientInterface, \IteratorAggregate
{
const VERSION = '1.1.9';

protected $connection;
protected $options;
private $profile;





public function __construct($parameters = null, $options = null)
{
$this->options = $this->createOptions($options ?: array());
$this->connection = $this->createConnection($parameters ?: array());
$this->profile = $this->options->profile;
}












protected function createOptions($options)
{
if (is_array($options)) {
return new Options($options);
}

if ($options instanceof OptionsInterface) {
return $options;
}

throw new \InvalidArgumentException('Invalid type for client options.');
}




















protected function createConnection($parameters)
{
if ($parameters instanceof ConnectionInterface) {
return $parameters;
}

if ($parameters instanceof ParametersInterface || is_string($parameters)) {
return $this->options->connections->create($parameters);
}

if (is_array($parameters)) {
if (!isset($parameters[0])) {
return $this->options->connections->create($parameters);
}

$options = $this->options;

if ($options->defined('aggregate')) {
$initializer = $this->getConnectionInitializerWrapper($options->aggregate);
$connection = $initializer($parameters, $options);
} elseif ($options->defined('replication')) {
$replication = $options->replication;

if ($replication instanceof AggregateConnectionInterface) {
$connection = $replication;
$options->connections->aggregate($connection, $parameters);
} else {
$initializer = $this->getConnectionInitializerWrapper($replication);
$connection = $initializer($parameters, $options);
}
} else {
$connection = $options->cluster;
$options->connections->aggregate($connection, $parameters);
}

return $connection;
}

if (is_callable($parameters)) {
$initializer = $this->getConnectionInitializerWrapper($parameters);
$connection = $initializer($this->options);

return $connection;
}

throw new \InvalidArgumentException('Invalid type for connection parameters.');
}









protected function getConnectionInitializerWrapper($callable)
{
return function () use ($callable) {
$connection = call_user_func_array($callable, func_get_args());

if (!$connection instanceof ConnectionInterface) {
throw new \UnexpectedValueException(
'The callable connection initializer returned an invalid type.'
);
}

return $connection;
};
}




public function getProfile()
{
return $this->profile;
}




public function getOptions()
{
return $this->options;
}












public function getClientFor($connectionID)
{
if (!$connection = $this->getConnectionById($connectionID)) {
throw new \InvalidArgumentException("Invalid connection ID: $connectionID.");
}

return new static($connection, $this->options);
}




public function connect()
{
$this->connection->connect();
}




public function disconnect()
{
$this->connection->disconnect();
}







public function quit()
{
$this->disconnect();
}






public function isConnected()
{
return $this->connection->isConnected();
}




public function getConnection()
{
return $this->connection;
}











public function getConnectionById($connectionID)
{
if (!$this->connection instanceof AggregateConnectionInterface) {
throw new NotSupportedException(
'Retrieving connections by ID is supported only by aggregate connections.'
);
}

return $this->connection->getConnectionById($connectionID);
}














public function executeRaw(array $arguments, &$error = null)
{
$error = false;

$response = $this->connection->executeCommand(
new RawCommand($arguments)
);

if ($response instanceof ResponseInterface) {
if ($response instanceof ErrorResponseInterface) {
$error = true;
}

return (string) $response;
}

return $response;
}




public function __call($commandID, $arguments)
{
return $this->executeCommand(
$this->createCommand($commandID, $arguments)
);
}




public function createCommand($commandID, $arguments = array())
{
return $this->profile->createCommand($commandID, $arguments);
}




public function executeCommand(CommandInterface $command)
{
$response = $this->connection->executeCommand($command);

if ($response instanceof ResponseInterface) {
if ($response instanceof ErrorResponseInterface) {
$response = $this->onErrorResponse($command, $response);
}

return $response;
}

return $command->parseResponse($response);
}











protected function onErrorResponse(CommandInterface $command, ErrorResponseInterface $response)
{
if ($command instanceof ScriptCommand && $response->getErrorType() === 'NOSCRIPT') {
$eval = $this->createCommand('EVAL');
$eval->setRawArguments($command->getEvalArguments());

$response = $this->executeCommand($eval);

if (!$response instanceof ResponseInterface) {
$response = $command->parseResponse($response);
}

return $response;
}

if ($this->options->exceptions) {
throw new ServerException($response->getMessage());
}

return $response;
}












private function sharedContextFactory($initializer, $argv = null)
{
switch (count($argv)) {
case 0:
return $this->$initializer();

case 1:
return is_array($argv[0])
? $this->$initializer($argv[0])
: $this->$initializer(null, $argv[0]);

case 2:
list($arg0, $arg1) = $argv;

return $this->$initializer($arg0, $arg1);

default:
return $this->$initializer($this, $argv);
}
}









public function pipeline()
{
return $this->sharedContextFactory('createPipeline', func_get_args());
}









protected function createPipeline(array $options = null, $callable = null)
{
if (isset($options['atomic']) && $options['atomic']) {
$class = 'Predis\Pipeline\Atomic';
} elseif (isset($options['fire-and-forget']) && $options['fire-and-forget']) {
$class = 'Predis\Pipeline\FireAndForget';
} else {
$class = 'Predis\Pipeline\Pipeline';
}




$pipeline = new $class($this);

if (isset($callable)) {
return $pipeline->execute($callable);
}

return $pipeline;
}









public function transaction()
{
return $this->sharedContextFactory('createTransaction', func_get_args());
}









protected function createTransaction(array $options = null, $callable = null)
{
$transaction = new MultiExecTransaction($this, $options);

if (isset($callable)) {
return $transaction->execute($callable);
}

return $transaction;
}









public function pubSubLoop()
{
return $this->sharedContextFactory('createPubSub', func_get_args());
}









protected function createPubSub(array $options = null, $callable = null)
{
$pubsub = new PubSubConsumer($this, $options);

if (!isset($callable)) {
return $pubsub;
}

foreach ($pubsub as $message) {
if (call_user_func($callable, $pubsub, $message) === false) {
$pubsub->stop();
}
}
}






public function monitor()
{
return new MonitorConsumer($this);
}





 public function getIterator()
{
$clients = array();
$connection = $this->getConnection();

if (!$connection instanceof \Traversable) {
return new \ArrayIterator(array(
(string) $connection => new static($connection, $this->getOptions())
));
}

foreach ($connection as $node) {
$clients[(string) $node] = new static($node, $this->getOptions());
}

return new \ArrayIterator($clients);
}
}
<?php










namespace Predis\Replication;

use Predis\ClientException;






class MissingMasterException extends ClientException
{
}
<?php










namespace Predis\Replication;

use Predis\Command\CommandInterface;
use Predis\NotSupportedException;






class ReplicationStrategy
{
protected $disallowed;
protected $readonly;
protected $readonlySHA1;




public function __construct()
{
$this->disallowed = $this->getDisallowedOperations();
$this->readonly = $this->getReadOnlyOperations();
$this->readonlySHA1 = array();
}











public function isReadOperation(CommandInterface $command)
{
if (isset($this->disallowed[$id = $command->getId()])) {
throw new NotSupportedException(
"The command '$id' is not allowed in replication mode."
);
}

if (isset($this->readonly[$id])) {
if (true === $readonly = $this->readonly[$id]) {
return true;
}

return call_user_func($readonly, $command);
}

if (($eval = $id === 'EVAL') || $id === 'EVALSHA') {
$argument = $command->getArgument(0);
$sha1 = $eval ? sha1(strval($argument)) : $argument;

if (isset($this->readonlySHA1[$sha1])) {
if (true === $readonly = $this->readonlySHA1[$sha1]) {
return true;
}

return call_user_func($readonly, $command);
}
}

return false;
}









public function isDisallowedOperation(CommandInterface $command)
{
return isset($this->disallowed[$command->getId()]);
}









protected function isBitfieldReadOnly(CommandInterface $command)
{
$arguments = $command->getArguments();
$argc = count($arguments);

if ($argc >= 2) {
for ($i = 1; $i < $argc; ++$i) {
$argument = strtoupper($arguments[$i]);
if ($argument === 'SET' || $argument === 'INCRBY') {
return false;
}
}
}

return true;
}









protected function isGeoradiusReadOnly(CommandInterface $command)
{
$arguments = $command->getArguments();
$argc = count($arguments);
$startIndex = $command->getId() === 'GEORADIUS' ? 5 : 4;

if ($argc > $startIndex) {
for ($i = $startIndex; $i < $argc; ++$i) {
$argument = strtoupper($arguments[$i]);
if ($argument === 'STORE' || $argument === 'STOREDIST') {
return false;
}
}
}

return true;
}











public function setCommandReadOnly($commandID, $readonly = true)
{
$commandID = strtoupper($commandID);

if ($readonly) {
$this->readonly[$commandID] = $readonly;
} else {
unset($this->readonly[$commandID]);
}
}











public function setScriptReadOnly($script, $readonly = true)
{
$sha1 = sha1($script);

if ($readonly) {
$this->readonlySHA1[$sha1] = $readonly;
} else {
unset($this->readonlySHA1[$sha1]);
}
}






protected function getDisallowedOperations()
{
return array(
'SHUTDOWN' => true,
'INFO' => true,
'DBSIZE' => true,
'LASTSAVE' => true,
'CONFIG' => true,
'MONITOR' => true,
'SLAVEOF' => true,
'SAVE' => true,
'BGSAVE' => true,
'BGREWRITEAOF' => true,
'SLOWLOG' => true,
);
}






protected function getReadOnlyOperations()
{
return array(
'EXISTS' => true,
'TYPE' => true,
'KEYS' => true,
'SCAN' => true,
'RANDOMKEY' => true,
'TTL' => true,
'GET' => true,
'MGET' => true,
'SUBSTR' => true,
'STRLEN' => true,
'GETRANGE' => true,
'GETBIT' => true,
'LLEN' => true,
'LRANGE' => true,
'LINDEX' => true,
'SCARD' => true,
'SISMEMBER' => true,
'SINTER' => true,
'SUNION' => true,
'SDIFF' => true,
'SMEMBERS' => true,
'SSCAN' => true,
'SRANDMEMBER' => true,
'ZRANGE' => true,
'ZREVRANGE' => true,
'ZRANGEBYSCORE' => true,
'ZREVRANGEBYSCORE' => true,
'ZCARD' => true,
'ZSCORE' => true,
'ZCOUNT' => true,
'ZRANK' => true,
'ZREVRANK' => true,
'ZSCAN' => true,
'ZLEXCOUNT' => true,
'ZRANGEBYLEX' => true,
'ZREVRANGEBYLEX' => true,
'HGET' => true,
'HMGET' => true,
'HEXISTS' => true,
'HLEN' => true,
'HKEYS' => true,
'HVALS' => true,
'HGETALL' => true,
'HSCAN' => true,
'HSTRLEN' => true,
'PING' => true,
'AUTH' => true,
'SELECT' => true,
'ECHO' => true,
'QUIT' => true,
'OBJECT' => true,
'BITCOUNT' => true,
'BITPOS' => true,
'TIME' => true,
'PFCOUNT' => true,
'BITFIELD' => array($this, 'isBitfieldReadOnly'),
'GEOHASH' => true,
'GEOPOS' => true,
'GEODIST' => true,
'GEORADIUS' => array($this, 'isGeoradiusReadOnly'),
'GEORADIUSBYMEMBER' => array($this, 'isGeoradiusReadOnly'),
);
}
}
<?php










namespace Predis\Replication;

use Predis\CommunicationException;







class RoleException extends CommunicationException
{
}
<?php










namespace Predis\Session;

use Predis\ClientInterface;











class Handler implements \SessionHandlerInterface
{
protected $client;
protected $ttl;





public function __construct(ClientInterface $client, array $options = array())
{
$this->client = $client;

if (isset($options['gc_maxlifetime'])) {
$this->ttl = (int) $options['gc_maxlifetime'];
} else {
$this->ttl = ini_get('session.gc_maxlifetime');
}
}




public function register()
{
if (PHP_VERSION_ID >= 50400) {
session_set_save_handler($this, true);
} else {
session_set_save_handler(
array($this, 'open'),
array($this, 'close'),
array($this, 'read'),
array($this, 'write'),
array($this, 'destroy'),
array($this, 'gc')
);
}
}




public function open($save_path, $session_id)
{

 return true;
}




public function close()
{

 return true;
}




public function gc($maxlifetime)
{

 return true;
}




public function read($session_id)
{
if ($data = $this->client->get($session_id)) {
return $data;
}

return '';
}



public function write($session_id, $session_data)
{
$this->client->setex($session_id, $this->ttl, $session_data);

return true;
}




public function destroy($session_id)
{
$this->client->del($session_id);

return true;
}






public function getClient()
{
return $this->client;
}






public function getMaxLifeTime()
{
return $this->ttl;
}
}
<?php










namespace Predis;

use Predis\Command\CommandInterface;
use Predis\Configuration\OptionsInterface;
use Predis\Connection\ConnectionInterface;
use Predis\Profile\ProfileInterface;
































































































































































interface ClientInterface
{





public function getProfile();






public function getOptions();




public function connect();




public function disconnect();






public function getConnection();









public function createCommand($method, $arguments = array());








public function executeCommand(CommandInterface $command);










public function __call($method, $arguments);
}
<?php










namespace Predis\Transaction;

use Predis\ClientContextInterface;
use Predis\ClientException;
use Predis\ClientInterface;
use Predis\Command\CommandInterface;
use Predis\CommunicationException;
use Predis\Connection\AggregateConnectionInterface;
use Predis\NotSupportedException;
use Predis\Protocol\ProtocolException;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\ServerException;
use Predis\Response\Status as StatusResponse;








class MultiExec implements ClientContextInterface
{
private $state;

protected $client;
protected $commands;
protected $exceptions = true;
protected $attempts = 0;
protected $watchKeys = array();
protected $modeCAS = false;





public function __construct(ClientInterface $client, array $options = null)
{
$this->assertClient($client);

$this->client = $client;
$this->state = new MultiExecState();

$this->configure($client, $options ?: array());
$this->reset();
}









private function assertClient(ClientInterface $client)
{
if ($client->getConnection() instanceof AggregateConnectionInterface) {
throw new NotSupportedException(
'Cannot initialize a MULTI/EXEC transaction over aggregate connections.'
);
}

if (!$client->getProfile()->supportsCommands(array('MULTI', 'EXEC', 'DISCARD'))) {
throw new NotSupportedException(
'The current profile does not support MULTI, EXEC and DISCARD.'
);
}
}







protected function configure(ClientInterface $client, array $options)
{
if (isset($options['exceptions'])) {
$this->exceptions = (bool) $options['exceptions'];
} else {
$this->exceptions = $client->getOptions()->exceptions;
}

if (isset($options['cas'])) {
$this->modeCAS = (bool) $options['cas'];
}

if (isset($options['watch']) && $keys = $options['watch']) {
$this->watchKeys = $keys;
}

if (isset($options['retry'])) {
$this->attempts = (int) $options['retry'];
}
}




protected function reset()
{
$this->state->reset();
$this->commands = new \SplQueue();
}




protected function initialize()
{
if ($this->state->isInitialized()) {
return;
}

if ($this->modeCAS) {
$this->state->flag(MultiExecState::CAS);
}

if ($this->watchKeys) {
$this->watch($this->watchKeys);
}

$cas = $this->state->isCAS();
$discarded = $this->state->isDiscarded();

if (!$cas || ($cas && $discarded)) {
$this->call('MULTI');

if ($discarded) {
$this->state->unflag(MultiExecState::CAS);
}
}

$this->state->unflag(MultiExecState::DISCARDED);
$this->state->flag(MultiExecState::INITIALIZED);
}









public function __call($method, $arguments)
{
return $this->executeCommand(
$this->client->createCommand($method, $arguments)
);
}











protected function call($commandID, array $arguments = array())
{
$response = $this->client->executeCommand(
$this->client->createCommand($commandID, $arguments)
);

if ($response instanceof ErrorResponseInterface) {
throw new ServerException($response->getMessage());
}

return $response;
}











public function executeCommand(CommandInterface $command)
{
$this->initialize();

if ($this->state->isCAS()) {
return $this->client->executeCommand($command);
}

$response = $this->client->getConnection()->executeCommand($command);

if ($response instanceof StatusResponse && $response == 'QUEUED') {
$this->commands->enqueue($command);
} elseif ($response instanceof ErrorResponseInterface) {
throw new AbortedMultiExecException($this, $response->getMessage());
} else {
$this->onProtocolError('The server did not return a +QUEUED status response.');
}

return $this;
}











public function watch($keys)
{
if (!$this->client->getProfile()->supportsCommand('WATCH')) {
throw new NotSupportedException('WATCH is not supported by the current profile.');
}

if ($this->state->isWatchAllowed()) {
throw new ClientException('Sending WATCH after MULTI is not allowed.');
}

$response = $this->call('WATCH', is_array($keys) ? $keys : array($keys));
$this->state->flag(MultiExecState::WATCH);

return $response;
}






public function multi()
{
if ($this->state->check(MultiExecState::INITIALIZED | MultiExecState::CAS)) {
$this->state->unflag(MultiExecState::CAS);
$this->call('MULTI');
} else {
$this->initialize();
}

return $this;
}








public function unwatch()
{
if (!$this->client->getProfile()->supportsCommand('UNWATCH')) {
throw new NotSupportedException(
'UNWATCH is not supported by the current profile.'
);
}

$this->state->unflag(MultiExecState::WATCH);
$this->__call('UNWATCH', array());

return $this;
}







public function discard()
{
if ($this->state->isInitialized()) {
$this->call($this->state->isCAS() ? 'UNWATCH' : 'DISCARD');

$this->reset();
$this->state->flag(MultiExecState::DISCARDED);
}

return $this;
}






public function exec()
{
return $this->execute();
}









private function checkBeforeExecution($callable)
{
if ($this->state->isExecuting()) {
throw new ClientException(
'Cannot invoke "execute" or "exec" inside an active transaction context.'
);
}

if ($callable) {
if (!is_callable($callable)) {
throw new \InvalidArgumentException('The argument must be a callable object.');
}

if (!$this->commands->isEmpty()) {
$this->discard();

throw new ClientException(
'Cannot execute a transaction block after using fluent interface.'
);
}
} elseif ($this->attempts) {
$this->discard();

throw new ClientException(
'Automatic retries are supported only when a callable block is provided.'
);
}
}












public function execute($callable = null)
{
$this->checkBeforeExecution($callable);

$execResponse = null;
$attempts = $this->attempts;

do {
if ($callable) {
$this->executeTransactionBlock($callable);
}

if ($this->commands->isEmpty()) {
if ($this->state->isWatching()) {
$this->discard();
}

return;
}

$execResponse = $this->call('EXEC');

if ($execResponse === null) {
if ($attempts === 0) {
throw new AbortedMultiExecException(
$this, 'The current transaction has been aborted by the server.'
);
}

$this->reset();

continue;
}

break;
} while ($attempts-- > 0);

$response = array();
$commands = $this->commands;
$size = count($execResponse);

if ($size !== count($commands)) {
$this->onProtocolError('EXEC returned an unexpected number of response items.');
}

for ($i = 0; $i < $size; ++$i) {
$cmdResponse = $execResponse[$i];

if ($cmdResponse instanceof ErrorResponseInterface && $this->exceptions) {
throw new ServerException($cmdResponse->getMessage());
}

$response[$i] = $commands->dequeue()->parseResponse($cmdResponse);
}

return $response;
}









protected function executeTransactionBlock($callable)
{
$exception = null;
$this->state->flag(MultiExecState::INSIDEBLOCK);

try {
call_user_func($callable, $this);
} catch (CommunicationException $exception) {

 } catch (ServerException $exception) {

 } catch (\Exception $exception) {
$this->discard();
}

$this->state->unflag(MultiExecState::INSIDEBLOCK);

if ($exception) {
throw $exception;
}
}






private function onProtocolError($message)
{

 
 
 CommunicationException::handle(new ProtocolException(
$this->client->getConnection(), $message
));
}
}
<?php










namespace Predis\Transaction;

use Predis\PredisException;






class AbortedMultiExecException extends PredisException
{
private $transaction;






public function __construct(MultiExec $transaction, $message, $code = null)
{
parent::__construct($message, is_null($code) ? 0 : $code);
$this->transaction = $transaction;
}






public function getTransaction()
{
return $this->transaction;
}
}
<?php










namespace Predis\Transaction;






class MultiExecState
{
const INITIALIZED = 1; 
 const INSIDEBLOCK = 2; 
 const DISCARDED = 4; 
 const CAS = 8; 
 const WATCH = 16; 

private $flags;




public function __construct()
{
$this->flags = 0;
}






public function set($flags)
{
$this->flags = $flags;
}






public function get()
{
return $this->flags;
}






public function flag($flags)
{
$this->flags |= $flags;
}






public function unflag($flags)
{
$this->flags &= ~$flags;
}








public function check($flags)
{
return ($this->flags & $flags) === $flags;
}




public function reset()
{
$this->flags = 0;
}






public function isReset()
{
return $this->flags === 0;
}






public function isInitialized()
{
return $this->check(self::INITIALIZED);
}






public function isExecuting()
{
return $this->check(self::INSIDEBLOCK);
}






public function isCAS()
{
return $this->check(self::CAS);
}






public function isWatchAllowed()
{
return $this->check(self::INITIALIZED) && !$this->check(self::CAS);
}






public function isWatching()
{
return $this->check(self::WATCH);
}






public function isDiscarded()
{
return $this->check(self::DISCARDED);
}
}
<?php










namespace Predis\Configuration;









class Options implements OptionsInterface
{
protected $input;
protected $options;
protected $handlers;




public function __construct(array $options = array())
{
$this->input = $options;
$this->options = array();
$this->handlers = $this->getHandlers();
}






protected function getHandlers()
{
return array(
'cluster' => 'Predis\Configuration\ClusterOption',
'connections' => 'Predis\Configuration\ConnectionFactoryOption',
'exceptions' => 'Predis\Configuration\ExceptionsOption',
'prefix' => 'Predis\Configuration\PrefixOption',
'profile' => 'Predis\Configuration\ProfileOption',
'replication' => 'Predis\Configuration\ReplicationOption',
);
}




public function getDefault($option)
{
if (isset($this->handlers[$option])) {
$handler = $this->handlers[$option];
$handler = new $handler();

return $handler->getDefault($this);
}
}




public function defined($option)
{
return
array_key_exists($option, $this->options) ||
array_key_exists($option, $this->input)
;
}




public function __isset($option)
{
return (
array_key_exists($option, $this->options) ||
array_key_exists($option, $this->input)
) && $this->__get($option) !== null;
}




public function __get($option)
{
if (isset($this->options[$option]) || array_key_exists($option, $this->options)) {
return $this->options[$option];
}

if (isset($this->input[$option]) || array_key_exists($option, $this->input)) {
$value = $this->input[$option];
unset($this->input[$option]);

if (is_object($value) && method_exists($value, '__invoke')) {
$value = $value($this, $option);
}

if (isset($this->handlers[$option])) {
$handler = $this->handlers[$option];
$handler = new $handler();
$value = $handler->filter($this, $value);
}

return $this->options[$option] = $value;
}

if (isset($this->handlers[$option])) {
return $this->options[$option] = $this->getDefault($option);
}

return;
}
}
<?php










namespace Predis\Configuration;







interface OptionInterface
{








public function filter(OptionsInterface $options, $value);








public function getDefault(OptionsInterface $options);
}
<?php










namespace Predis\Configuration;

use Predis\Connection\Aggregate\ClusterInterface;
use Predis\Connection\Aggregate\PredisCluster;
use Predis\Connection\Aggregate\RedisCluster;








class ClusterOption implements OptionInterface
{








protected function createByDescription(OptionsInterface $options, $id)
{
switch ($id) {
case 'predis':
case 'predis-cluster':
return new PredisCluster();

case 'redis':
case 'redis-cluster':
return new RedisCluster($options->connections);

default:
return;
}
}




public function filter(OptionsInterface $options, $value)
{
if (is_string($value)) {
$value = $this->createByDescription($options, $value);
}

if (!$value instanceof ClusterInterface) {
throw new \InvalidArgumentException(
"An instance of type 'Predis\Connection\Aggregate\ClusterInterface' was expected."
);
}

return $value;
}




public function getDefault(OptionsInterface $options)
{
return new PredisCluster();
}
}
<?php










namespace Predis\Configuration;

use Predis\Command\Processor\KeyPrefixProcessor;
use Predis\Command\Processor\ProcessorInterface;







class PrefixOption implements OptionInterface
{



public function filter(OptionsInterface $options, $value)
{
if ($value instanceof ProcessorInterface) {
return $value;
}

return new KeyPrefixProcessor($value);
}




public function getDefault(OptionsInterface $options)
{

 }
}
<?php










namespace Predis\Configuration;

use Predis\Command\Processor\ProcessorInterface;
use Predis\Connection\Aggregate\ClusterInterface;
use Predis\Connection\Aggregate\ReplicationInterface;
use Predis\Connection\FactoryInterface;
use Predis\Profile\ProfileInterface;














interface OptionsInterface
{







public function getDefault($option);








public function defined($option);








public function __isset($option);








public function __get($option);
}
<?php










namespace Predis\Configuration;

use Predis\Connection\Aggregate\MasterSlaveReplication;
use Predis\Connection\Aggregate\ReplicationInterface;
use Predis\Connection\Aggregate\SentinelReplication;







class ReplicationOption implements OptionInterface
{







public function filter(OptionsInterface $options, $value)
{
if ($value instanceof ReplicationInterface) {
return $value;
}

if ($value === 'sentinel') {
return function ($sentinels, $options) {
return new SentinelReplication($options->service, $sentinels, $options->connections);
};
}

if (
!is_object($value) &&
null !== $asbool = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)
) {
if (true === $asbool) {
return $this->getDefault($options);
} else {
throw new \InvalidArgumentException(
"Values evaluating to FALSE are not accepted for `replication`"
);
}
}

throw new \InvalidArgumentException(
"An instance of type 'Predis\Connection\Aggregate\ReplicationInterface' was expected."
);
}




public function getDefault(OptionsInterface $options)
{
$replication = new MasterSlaveReplication();

if ($options->autodiscovery) {
$replication->setConnectionFactory($options->connections);
$replication->setAutoDiscovery(true);
}

return $replication;
}
}
<?php










namespace Predis\Configuration;







class ExceptionsOption implements OptionInterface
{



public function filter(OptionsInterface $options, $value)
{
return filter_var($value, FILTER_VALIDATE_BOOLEAN);
}




public function getDefault(OptionsInterface $options)
{
return true;
}
}
<?php










namespace Predis\Configuration;

use Predis\Profile\Factory;
use Predis\Profile\ProfileInterface;
use Predis\Profile\RedisProfile;







class ProfileOption implements OptionInterface
{






protected function setProcessors(OptionsInterface $options, ProfileInterface $profile)
{
if (isset($options->prefix) && $profile instanceof RedisProfile) {

 
 
 

$profile->setProcessor($options->__get('prefix'));
}
}




public function filter(OptionsInterface $options, $value)
{
if (is_string($value)) {
$value = Factory::get($value);
$this->setProcessors($options, $value);
} elseif (!$value instanceof ProfileInterface) {
throw new \InvalidArgumentException('Invalid value for the profile option.');
}

return $value;
}




public function getDefault(OptionsInterface $options)
{
$profile = Factory::getDefault();
$this->setProcessors($options, $profile);

return $profile;
}
}
<?php










namespace Predis\Configuration;

use Predis\Connection\Factory;
use Predis\Connection\FactoryInterface;







class ConnectionFactoryOption implements OptionInterface
{



public function filter(OptionsInterface $options, $value)
{
if ($value instanceof FactoryInterface) {
return $value;
} elseif (is_array($value)) {
$factory = $this->getDefault($options);

foreach ($value as $scheme => $initializer) {
$factory->define($scheme, $initializer);
}

return $factory;
} else {
throw new \InvalidArgumentException(
'Invalid value provided for the connections option.'
);
}
}




public function getDefault(OptionsInterface $options)
{
$factory = new Factory();

if ($options->defined('parameters')) {
$factory->setDefaultParameters($options->parameters);
}

return $factory;
}
}
<?php










namespace Predis\Pipeline;

use Predis\CommunicationException;
use Predis\Connection\Aggregate\ClusterInterface;
use Predis\Connection\ConnectionInterface;
use Predis\Connection\NodeConnectionInterface;
use Predis\NotSupportedException;









class ConnectionErrorProof extends Pipeline
{



protected function getConnection()
{
return $this->getClient()->getConnection();
}




protected function executePipeline(ConnectionInterface $connection, \SplQueue $commands)
{
if ($connection instanceof NodeConnectionInterface) {
return $this->executeSingleNode($connection, $commands);
} elseif ($connection instanceof ClusterInterface) {
return $this->executeCluster($connection, $commands);
} else {
$class = get_class($connection);

throw new NotSupportedException("The connection class '$class' is not supported.");
}
}




protected function executeSingleNode(NodeConnectionInterface $connection, \SplQueue $commands)
{
$responses = array();
$sizeOfPipe = count($commands);

foreach ($commands as $command) {
try {
$connection->writeRequest($command);
} catch (CommunicationException $exception) {
return array_fill(0, $sizeOfPipe, $exception);
}
}

for ($i = 0; $i < $sizeOfPipe; ++$i) {
$command = $commands->dequeue();

try {
$responses[$i] = $connection->readResponse($command);
} catch (CommunicationException $exception) {
$add = count($commands) - count($responses);
$responses = array_merge($responses, array_fill(0, $add, $exception));

break;
}
}

return $responses;
}




protected function executeCluster(ClusterInterface $connection, \SplQueue $commands)
{
$responses = array();
$sizeOfPipe = count($commands);
$exceptions = array();

foreach ($commands as $command) {
$cmdConnection = $connection->getConnection($command);

if (isset($exceptions[spl_object_hash($cmdConnection)])) {
continue;
}

try {
$cmdConnection->writeRequest($command);
} catch (CommunicationException $exception) {
$exceptions[spl_object_hash($cmdConnection)] = $exception;
}
}

for ($i = 0; $i < $sizeOfPipe; ++$i) {
$command = $commands->dequeue();

$cmdConnection = $connection->getConnection($command);
$connectionHash = spl_object_hash($cmdConnection);

if (isset($exceptions[$connectionHash])) {
$responses[$i] = $exceptions[$connectionHash];
continue;
}

try {
$responses[$i] = $cmdConnection->readResponse($command);
} catch (CommunicationException $exception) {
$responses[$i] = $exception;
$exceptions[$connectionHash] = $exception;
}
}

return $responses;
}
}
<?php










namespace Predis\Pipeline;

use Predis\ClientException;
use Predis\ClientInterface;
use Predis\Connection\ConnectionInterface;
use Predis\Connection\NodeConnectionInterface;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\ResponseInterface;
use Predis\Response\ServerException;






class Atomic extends Pipeline
{



public function __construct(ClientInterface $client)
{
if (!$client->getProfile()->supportsCommands(array('multi', 'exec', 'discard'))) {
throw new ClientException(
"The current profile does not support 'MULTI', 'EXEC' and 'DISCARD'."
);
}

parent::__construct($client);
}




protected function getConnection()
{
$connection = $this->getClient()->getConnection();

if (!$connection instanceof NodeConnectionInterface) {
$class = __CLASS__;

throw new ClientException("The class '$class' does not support aggregate connections.");
}

return $connection;
}




protected function executePipeline(ConnectionInterface $connection, \SplQueue $commands)
{
$profile = $this->getClient()->getProfile();
$connection->executeCommand($profile->createCommand('multi'));

foreach ($commands as $command) {
$connection->writeRequest($command);
}

foreach ($commands as $command) {
$response = $connection->readResponse($command);

if ($response instanceof ErrorResponseInterface) {
$connection->executeCommand($profile->createCommand('discard'));
throw new ServerException($response->getMessage());
}
}

$executed = $connection->executeCommand($profile->createCommand('exec'));

if (!isset($executed)) {

 throw new ClientException(
'The underlying transaction has been aborted by the server.'
);
}

if (count($executed) !== count($commands)) {
$expected = count($commands);
$received = count($executed);

throw new ClientException(
"Invalid number of responses [expected $expected, received $received]."
);
}

$responses = array();
$sizeOfPipe = count($commands);
$exceptions = $this->throwServerExceptions();

for ($i = 0; $i < $sizeOfPipe; ++$i) {
$command = $commands->dequeue();
$response = $executed[$i];

if (!$response instanceof ResponseInterface) {
$responses[] = $command->parseResponse($response);
} elseif ($response instanceof ErrorResponseInterface && $exceptions) {
$this->exception($connection, $response);
} else {
$responses[] = $response;
}

unset($executed[$i]);
}

return $responses;
}
}
<?php










namespace Predis\Pipeline;

use Predis\Connection\ConnectionInterface;






class FireAndForget extends Pipeline
{



protected function executePipeline(ConnectionInterface $connection, \SplQueue $commands)
{
while (!$commands->isEmpty()) {
$connection->writeRequest($commands->dequeue());
}

$connection->disconnect();

return array();
}
}
<?php










namespace Predis\Pipeline;

use Predis\ClientContextInterface;
use Predis\ClientException;
use Predis\ClientInterface;
use Predis\Command\CommandInterface;
use Predis\Connection\Aggregate\ReplicationInterface;
use Predis\Connection\ConnectionInterface;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\ResponseInterface;
use Predis\Response\ServerException;









class Pipeline implements ClientContextInterface
{
private $client;
private $pipeline;

private $responses = array();
private $running = false;




public function __construct(ClientInterface $client)
{
$this->client = $client;
$this->pipeline = new \SplQueue();
}









public function __call($method, $arguments)
{
$command = $this->client->createCommand($method, $arguments);
$this->recordCommand($command);

return $this;
}






protected function recordCommand(CommandInterface $command)
{
$this->pipeline->enqueue($command);
}








public function executeCommand(CommandInterface $command)
{
$this->recordCommand($command);

return $this;
}









protected function exception(ConnectionInterface $connection, ErrorResponseInterface $response)
{
$connection->disconnect();
$message = $response->getMessage();

throw new ServerException($message);
}






protected function getConnection()
{
$connection = $this->getClient()->getConnection();

if ($connection instanceof ReplicationInterface) {
$connection->switchTo('master');
}

return $connection;
}










protected function executePipeline(ConnectionInterface $connection, \SplQueue $commands)
{
foreach ($commands as $command) {
$connection->writeRequest($command);
}

$responses = array();
$exceptions = $this->throwServerExceptions();

while (!$commands->isEmpty()) {
$command = $commands->dequeue();
$response = $connection->readResponse($command);

if (!$response instanceof ResponseInterface) {
$responses[] = $command->parseResponse($response);
} elseif ($response instanceof ErrorResponseInterface && $exceptions) {
$this->exception($connection, $response);
} else {
$responses[] = $response;
}
}

return $responses;
}








public function flushPipeline($send = true)
{
if ($send && !$this->pipeline->isEmpty()) {
$responses = $this->executePipeline($this->getConnection(), $this->pipeline);
$this->responses = array_merge($this->responses, $responses);
} else {
$this->pipeline = new \SplQueue();
}

return $this;
}








private function setRunning($bool)
{
if ($bool && $this->running) {
throw new ClientException('The current pipeline context is already being executed.');
}

$this->running = $bool;
}











public function execute($callable = null)
{
if ($callable && !is_callable($callable)) {
throw new \InvalidArgumentException('The argument must be a callable object.');
}

$exception = null;
$this->setRunning(true);

try {
if ($callable) {
call_user_func($callable, $this);
}

$this->flushPipeline();
} catch (\Exception $exception) {

 }

$this->setRunning(false);

if ($exception) {
throw $exception;
}

return $this->responses;
}






protected function throwServerExceptions()
{
return (bool) $this->client->getOptions()->exceptions;
}






public function getClient()
{
return $this->client;
}
}
<?php










namespace Predis\Monitor;

use Predis\ClientInterface;
use Predis\Connection\AggregateConnectionInterface;
use Predis\NotSupportedException;






class Consumer implements \Iterator
{
private $client;
private $valid;
private $position;




public function __construct(ClientInterface $client)
{
$this->assertClient($client);

$this->client = $client;

$this->start();
}




public function __destruct()
{
$this->stop();
}









private function assertClient(ClientInterface $client)
{
if ($client->getConnection() instanceof AggregateConnectionInterface) {
throw new NotSupportedException(
'Cannot initialize a monitor consumer over aggregate connections.'
);
}

if ($client->getProfile()->supportsCommand('MONITOR') === false) {
throw new NotSupportedException("The current profile does not support 'MONITOR'.");
}
}




protected function start()
{
$this->client->executeCommand(
$this->client->createCommand('MONITOR')
);
$this->valid = true;
}





public function stop()
{
$this->client->disconnect();
$this->valid = false;
}





 public function rewind()
{

 }







 public function current()
{
return $this->getValue();
}





 public function key()
{
return $this->position;
}





 public function next()
{
++$this->position;
}







 public function valid()
{
return $this->valid;
}







private function getValue()
{
$database = 0;
$client = null;
$event = $this->client->getConnection()->read();

$callback = function ($matches) use (&$database, &$client) {
if (2 === $count = count($matches)) {

 $database = (int) $matches[1];
}

if (4 === $count) {

 $database = (int) $matches[2];
$client = $matches[3];
}

return ' ';
};

$event = preg_replace_callback('/ \(db (\d+)\) | \[(\d+) (.*?)\] /', $callback, $event, 1);
@list($timestamp, $command, $arguments) = explode(' ', $event, 3);

return (object) array(
'timestamp' => (float) $timestamp,
'database' => $database,
'client' => $client,
'command' => substr($command, 1, -1),
'arguments' => $arguments,
);
}
}
<?php










namespace Predis\PubSub;

use Predis\ClientException;
use Predis\ClientInterface;
use Predis\Command\Command;
use Predis\Connection\AggregateConnectionInterface;
use Predis\NotSupportedException;






class Consumer extends AbstractConsumer
{
private $client;
private $options;





public function __construct(ClientInterface $client, array $options = null)
{
$this->checkCapabilities($client);

$this->options = $options ?: array();
$this->client = $client;

$this->genericSubscribeInit('subscribe');
$this->genericSubscribeInit('psubscribe');
}






public function getClient()
{
return $this->client;
}









private function checkCapabilities(ClientInterface $client)
{
if ($client->getConnection() instanceof AggregateConnectionInterface) {
throw new NotSupportedException(
'Cannot initialize a PUB/SUB consumer over aggregate connections.'
);
}

$commands = array('publish', 'subscribe', 'unsubscribe', 'psubscribe', 'punsubscribe');

if ($client->getProfile()->supportsCommands($commands) === false) {
throw new NotSupportedException(
'The current profile does not support PUB/SUB related commands.'
);
}
}






private function genericSubscribeInit($subscribeAction)
{
if (isset($this->options[$subscribeAction])) {
$this->$subscribeAction($this->options[$subscribeAction]);
}
}




protected function writeRequest($method, $arguments)
{
$this->client->getConnection()->writeRequest(
$this->client->createCommand($method,
Command::normalizeArguments($arguments)
)
);
}




protected function disconnect()
{
$this->client->disconnect();
}




protected function getValue()
{
$response = $this->client->getConnection()->read();

switch ($response[0]) {
case self::SUBSCRIBE:
case self::UNSUBSCRIBE:
case self::PSUBSCRIBE:
case self::PUNSUBSCRIBE:
if ($response[2] === 0) {
$this->invalidate();
}

 
 

case self::MESSAGE:
return (object) array(
'kind' => $response[0],
'channel' => $response[1],
'payload' => $response[2],
);

case self::PMESSAGE:
return (object) array(
'kind' => $response[0],
'pattern' => $response[1],
'channel' => $response[2],
'payload' => $response[3],
);

case self::PONG:
return (object) array(
'kind' => $response[0],
'payload' => $response[1],
);

default:
throw new ClientException(
"Unknown message type '{$response[0]}' received in the PUB/SUB context."
);
}
}
}
<?php










namespace Predis\PubSub;






abstract class AbstractConsumer implements \Iterator
{
const SUBSCRIBE = 'subscribe';
const UNSUBSCRIBE = 'unsubscribe';
const PSUBSCRIBE = 'psubscribe';
const PUNSUBSCRIBE = 'punsubscribe';
const MESSAGE = 'message';
const PMESSAGE = 'pmessage';
const PONG = 'pong';

const STATUS_VALID = 1; 
 const STATUS_SUBSCRIBED = 2; 
 const STATUS_PSUBSCRIBED = 4; 

private $position = null;
private $statusFlags = self::STATUS_VALID;




public function __destruct()
{
$this->stop(true);
}








protected function isFlagSet($value)
{
return ($this->statusFlags & $value) === $value;
}






public function subscribe($channel )
{
$this->writeRequest(self::SUBSCRIBE, func_get_args());
$this->statusFlags |= self::STATUS_SUBSCRIBED;
}






public function unsubscribe()
{
$this->writeRequest(self::UNSUBSCRIBE, func_get_args());
}






public function psubscribe($pattern )
{
$this->writeRequest(self::PSUBSCRIBE, func_get_args());
$this->statusFlags |= self::STATUS_PSUBSCRIBED;
}






public function punsubscribe()
{
$this->writeRequest(self::PUNSUBSCRIBE, func_get_args());
}







public function ping($payload = null)
{
$this->writeRequest('PING', array($payload));
}









public function stop($drop = false)
{
if (!$this->valid()) {
return false;
}

if ($drop) {
$this->invalidate();
$this->disconnect();
} else {
if ($this->isFlagSet(self::STATUS_SUBSCRIBED)) {
$this->unsubscribe();
}
if ($this->isFlagSet(self::STATUS_PSUBSCRIBED)) {
$this->punsubscribe();
}
}

return !$drop;
}




abstract protected function disconnect();







abstract protected function writeRequest($method, $arguments);





 public function rewind()
{

 }








 public function current()
{
return $this->getValue();
}





 public function key()
{
return $this->position;
}





 public function next()
{
if ($this->valid()) {
++$this->position;
}

return $this->position;
}







 public function valid()
{
$isValid = $this->isFlagSet(self::STATUS_VALID);
$subscriptionFlags = self::STATUS_SUBSCRIBED | self::STATUS_PSUBSCRIBED;
$hasSubscriptions = ($this->statusFlags & $subscriptionFlags) > 0;

return $isValid && $hasSubscriptions;
}




protected function invalidate()
{
$this->statusFlags = 0; 
 }







abstract protected function getValue();
}
<?php










namespace Predis\PubSub;







class DispatcherLoop
{
private $pubsub;

protected $callbacks;
protected $defaultCallback;
protected $subscriptionCallback;




public function __construct(Consumer $pubsub)
{
$this->callbacks = array();
$this->pubsub = $pubsub;
}








protected function assertCallback($callable)
{
if (!is_callable($callable)) {
throw new \InvalidArgumentException('The given argument must be a callable object.');
}
}






public function getPubSubConsumer()
{
return $this->pubsub;
}






public function subscriptionCallback($callable = null)
{
if (isset($callable)) {
$this->assertCallback($callable);
}

$this->subscriptionCallback = $callable;
}







public function defaultCallback($callable = null)
{
if (isset($callable)) {
$this->assertCallback($callable);
}

$this->subscriptionCallback = $callable;
}







public function attachCallback($channel, $callback)
{
$callbackName = $this->getPrefixKeys().$channel;

$this->assertCallback($callback);
$this->callbacks[$callbackName] = $callback;
$this->pubsub->subscribe($channel);
}






public function detachCallback($channel)
{
$callbackName = $this->getPrefixKeys().$channel;

if (isset($this->callbacks[$callbackName])) {
unset($this->callbacks[$callbackName]);
$this->pubsub->unsubscribe($channel);
}
}




public function run()
{
foreach ($this->pubsub as $message) {
$kind = $message->kind;

if ($kind !== Consumer::MESSAGE && $kind !== Consumer::PMESSAGE) {
if (isset($this->subscriptionCallback)) {
$callback = $this->subscriptionCallback;
call_user_func($callback, $message);
}

continue;
}

if (isset($this->callbacks[$message->channel])) {
$callback = $this->callbacks[$message->channel];
call_user_func($callback, $message->payload);
} elseif (isset($this->defaultCallback)) {
$callback = $this->defaultCallback;
call_user_func($callback, $message);
}
}
}




public function stop()
{
$this->pubsub->stop();
}






protected function getPrefixKeys()
{
$options = $this->pubsub->getClient()->getOptions();

if (isset($options->prefix)) {
return $options->prefix->getPrefix();
}

return '';
}
}
<?php










namespace Predis\Profile;






class RedisVersion220 extends RedisProfile
{



public function getVersion()
{
return '2.2';
}




public function getSupportedCommands()
{
return array(



'EXISTS' => 'Predis\Command\KeyExists',
'DEL' => 'Predis\Command\KeyDelete',
'TYPE' => 'Predis\Command\KeyType',
'KEYS' => 'Predis\Command\KeyKeys',
'RANDOMKEY' => 'Predis\Command\KeyRandom',
'RENAME' => 'Predis\Command\KeyRename',
'RENAMENX' => 'Predis\Command\KeyRenamePreserve',
'EXPIRE' => 'Predis\Command\KeyExpire',
'EXPIREAT' => 'Predis\Command\KeyExpireAt',
'TTL' => 'Predis\Command\KeyTimeToLive',
'MOVE' => 'Predis\Command\KeyMove',
'SORT' => 'Predis\Command\KeySort',


'SET' => 'Predis\Command\StringSet',
'SETNX' => 'Predis\Command\StringSetPreserve',
'MSET' => 'Predis\Command\StringSetMultiple',
'MSETNX' => 'Predis\Command\StringSetMultiplePreserve',
'GET' => 'Predis\Command\StringGet',
'MGET' => 'Predis\Command\StringGetMultiple',
'GETSET' => 'Predis\Command\StringGetSet',
'INCR' => 'Predis\Command\StringIncrement',
'INCRBY' => 'Predis\Command\StringIncrementBy',
'DECR' => 'Predis\Command\StringDecrement',
'DECRBY' => 'Predis\Command\StringDecrementBy',


'RPUSH' => 'Predis\Command\ListPushTail',
'LPUSH' => 'Predis\Command\ListPushHead',
'LLEN' => 'Predis\Command\ListLength',
'LRANGE' => 'Predis\Command\ListRange',
'LTRIM' => 'Predis\Command\ListTrim',
'LINDEX' => 'Predis\Command\ListIndex',
'LSET' => 'Predis\Command\ListSet',
'LREM' => 'Predis\Command\ListRemove',
'LPOP' => 'Predis\Command\ListPopFirst',
'RPOP' => 'Predis\Command\ListPopLast',
'RPOPLPUSH' => 'Predis\Command\ListPopLastPushHead',


'SADD' => 'Predis\Command\SetAdd',
'SREM' => 'Predis\Command\SetRemove',
'SPOP' => 'Predis\Command\SetPop',
'SMOVE' => 'Predis\Command\SetMove',
'SCARD' => 'Predis\Command\SetCardinality',
'SISMEMBER' => 'Predis\Command\SetIsMember',
'SINTER' => 'Predis\Command\SetIntersection',
'SINTERSTORE' => 'Predis\Command\SetIntersectionStore',
'SUNION' => 'Predis\Command\SetUnion',
'SUNIONSTORE' => 'Predis\Command\SetUnionStore',
'SDIFF' => 'Predis\Command\SetDifference',
'SDIFFSTORE' => 'Predis\Command\SetDifferenceStore',
'SMEMBERS' => 'Predis\Command\SetMembers',
'SRANDMEMBER' => 'Predis\Command\SetRandomMember',


'ZADD' => 'Predis\Command\ZSetAdd',
'ZINCRBY' => 'Predis\Command\ZSetIncrementBy',
'ZREM' => 'Predis\Command\ZSetRemove',
'ZRANGE' => 'Predis\Command\ZSetRange',
'ZREVRANGE' => 'Predis\Command\ZSetReverseRange',
'ZRANGEBYSCORE' => 'Predis\Command\ZSetRangeByScore',
'ZCARD' => 'Predis\Command\ZSetCardinality',
'ZSCORE' => 'Predis\Command\ZSetScore',
'ZREMRANGEBYSCORE' => 'Predis\Command\ZSetRemoveRangeByScore',


'PING' => 'Predis\Command\ConnectionPing',
'AUTH' => 'Predis\Command\ConnectionAuth',
'SELECT' => 'Predis\Command\ConnectionSelect',
'ECHO' => 'Predis\Command\ConnectionEcho',
'QUIT' => 'Predis\Command\ConnectionQuit',


'INFO' => 'Predis\Command\ServerInfo',
'SLAVEOF' => 'Predis\Command\ServerSlaveOf',
'MONITOR' => 'Predis\Command\ServerMonitor',
'DBSIZE' => 'Predis\Command\ServerDatabaseSize',
'FLUSHDB' => 'Predis\Command\ServerFlushDatabase',
'FLUSHALL' => 'Predis\Command\ServerFlushAll',
'SAVE' => 'Predis\Command\ServerSave',
'BGSAVE' => 'Predis\Command\ServerBackgroundSave',
'LASTSAVE' => 'Predis\Command\ServerLastSave',
'SHUTDOWN' => 'Predis\Command\ServerShutdown',
'BGREWRITEAOF' => 'Predis\Command\ServerBackgroundRewriteAOF',




'SETEX' => 'Predis\Command\StringSetExpire',
'APPEND' => 'Predis\Command\StringAppend',
'SUBSTR' => 'Predis\Command\StringSubstr',


'BLPOP' => 'Predis\Command\ListPopFirstBlocking',
'BRPOP' => 'Predis\Command\ListPopLastBlocking',


'ZUNIONSTORE' => 'Predis\Command\ZSetUnionStore',
'ZINTERSTORE' => 'Predis\Command\ZSetIntersectionStore',
'ZCOUNT' => 'Predis\Command\ZSetCount',
'ZRANK' => 'Predis\Command\ZSetRank',
'ZREVRANK' => 'Predis\Command\ZSetReverseRank',
'ZREMRANGEBYRANK' => 'Predis\Command\ZSetRemoveRangeByRank',


'HSET' => 'Predis\Command\HashSet',
'HSETNX' => 'Predis\Command\HashSetPreserve',
'HMSET' => 'Predis\Command\HashSetMultiple',
'HINCRBY' => 'Predis\Command\HashIncrementBy',
'HGET' => 'Predis\Command\HashGet',
'HMGET' => 'Predis\Command\HashGetMultiple',
'HDEL' => 'Predis\Command\HashDelete',
'HEXISTS' => 'Predis\Command\HashExists',
'HLEN' => 'Predis\Command\HashLength',
'HKEYS' => 'Predis\Command\HashKeys',
'HVALS' => 'Predis\Command\HashValues',
'HGETALL' => 'Predis\Command\HashGetAll',


'MULTI' => 'Predis\Command\TransactionMulti',
'EXEC' => 'Predis\Command\TransactionExec',
'DISCARD' => 'Predis\Command\TransactionDiscard',


'SUBSCRIBE' => 'Predis\Command\PubSubSubscribe',
'UNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribe',
'PSUBSCRIBE' => 'Predis\Command\PubSubSubscribeByPattern',
'PUNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribeByPattern',
'PUBLISH' => 'Predis\Command\PubSubPublish',


'CONFIG' => 'Predis\Command\ServerConfig',




'PERSIST' => 'Predis\Command\KeyPersist',


'STRLEN' => 'Predis\Command\StringStrlen',
'SETRANGE' => 'Predis\Command\StringSetRange',
'GETRANGE' => 'Predis\Command\StringGetRange',
'SETBIT' => 'Predis\Command\StringSetBit',
'GETBIT' => 'Predis\Command\StringGetBit',


'RPUSHX' => 'Predis\Command\ListPushTailX',
'LPUSHX' => 'Predis\Command\ListPushHeadX',
'LINSERT' => 'Predis\Command\ListInsert',
'BRPOPLPUSH' => 'Predis\Command\ListPopLastPushHeadBlocking',


'ZREVRANGEBYSCORE' => 'Predis\Command\ZSetReverseRangeByScore',


'WATCH' => 'Predis\Command\TransactionWatch',
'UNWATCH' => 'Predis\Command\TransactionUnwatch',


'OBJECT' => 'Predis\Command\ServerObject',
'SLOWLOG' => 'Predis\Command\ServerSlowlog',
);
}
}
<?php










namespace Predis\Profile;






class RedisVersion200 extends RedisProfile
{



public function getVersion()
{
return '2.0';
}




public function getSupportedCommands()
{
return array(



'EXISTS' => 'Predis\Command\KeyExists',
'DEL' => 'Predis\Command\KeyDelete',
'TYPE' => 'Predis\Command\KeyType',
'KEYS' => 'Predis\Command\KeyKeys',
'RANDOMKEY' => 'Predis\Command\KeyRandom',
'RENAME' => 'Predis\Command\KeyRename',
'RENAMENX' => 'Predis\Command\KeyRenamePreserve',
'EXPIRE' => 'Predis\Command\KeyExpire',
'EXPIREAT' => 'Predis\Command\KeyExpireAt',
'TTL' => 'Predis\Command\KeyTimeToLive',
'MOVE' => 'Predis\Command\KeyMove',
'SORT' => 'Predis\Command\KeySort',


'SET' => 'Predis\Command\StringSet',
'SETNX' => 'Predis\Command\StringSetPreserve',
'MSET' => 'Predis\Command\StringSetMultiple',
'MSETNX' => 'Predis\Command\StringSetMultiplePreserve',
'GET' => 'Predis\Command\StringGet',
'MGET' => 'Predis\Command\StringGetMultiple',
'GETSET' => 'Predis\Command\StringGetSet',
'INCR' => 'Predis\Command\StringIncrement',
'INCRBY' => 'Predis\Command\StringIncrementBy',
'DECR' => 'Predis\Command\StringDecrement',
'DECRBY' => 'Predis\Command\StringDecrementBy',


'RPUSH' => 'Predis\Command\ListPushTail',
'LPUSH' => 'Predis\Command\ListPushHead',
'LLEN' => 'Predis\Command\ListLength',
'LRANGE' => 'Predis\Command\ListRange',
'LTRIM' => 'Predis\Command\ListTrim',
'LINDEX' => 'Predis\Command\ListIndex',
'LSET' => 'Predis\Command\ListSet',
'LREM' => 'Predis\Command\ListRemove',
'LPOP' => 'Predis\Command\ListPopFirst',
'RPOP' => 'Predis\Command\ListPopLast',
'RPOPLPUSH' => 'Predis\Command\ListPopLastPushHead',


'SADD' => 'Predis\Command\SetAdd',
'SREM' => 'Predis\Command\SetRemove',
'SPOP' => 'Predis\Command\SetPop',
'SMOVE' => 'Predis\Command\SetMove',
'SCARD' => 'Predis\Command\SetCardinality',
'SISMEMBER' => 'Predis\Command\SetIsMember',
'SINTER' => 'Predis\Command\SetIntersection',
'SINTERSTORE' => 'Predis\Command\SetIntersectionStore',
'SUNION' => 'Predis\Command\SetUnion',
'SUNIONSTORE' => 'Predis\Command\SetUnionStore',
'SDIFF' => 'Predis\Command\SetDifference',
'SDIFFSTORE' => 'Predis\Command\SetDifferenceStore',
'SMEMBERS' => 'Predis\Command\SetMembers',
'SRANDMEMBER' => 'Predis\Command\SetRandomMember',


'ZADD' => 'Predis\Command\ZSetAdd',
'ZINCRBY' => 'Predis\Command\ZSetIncrementBy',
'ZREM' => 'Predis\Command\ZSetRemove',
'ZRANGE' => 'Predis\Command\ZSetRange',
'ZREVRANGE' => 'Predis\Command\ZSetReverseRange',
'ZRANGEBYSCORE' => 'Predis\Command\ZSetRangeByScore',
'ZCARD' => 'Predis\Command\ZSetCardinality',
'ZSCORE' => 'Predis\Command\ZSetScore',
'ZREMRANGEBYSCORE' => 'Predis\Command\ZSetRemoveRangeByScore',


'PING' => 'Predis\Command\ConnectionPing',
'AUTH' => 'Predis\Command\ConnectionAuth',
'SELECT' => 'Predis\Command\ConnectionSelect',
'ECHO' => 'Predis\Command\ConnectionEcho',
'QUIT' => 'Predis\Command\ConnectionQuit',


'INFO' => 'Predis\Command\ServerInfo',
'SLAVEOF' => 'Predis\Command\ServerSlaveOf',
'MONITOR' => 'Predis\Command\ServerMonitor',
'DBSIZE' => 'Predis\Command\ServerDatabaseSize',
'FLUSHDB' => 'Predis\Command\ServerFlushDatabase',
'FLUSHALL' => 'Predis\Command\ServerFlushAll',
'SAVE' => 'Predis\Command\ServerSave',
'BGSAVE' => 'Predis\Command\ServerBackgroundSave',
'LASTSAVE' => 'Predis\Command\ServerLastSave',
'SHUTDOWN' => 'Predis\Command\ServerShutdown',
'BGREWRITEAOF' => 'Predis\Command\ServerBackgroundRewriteAOF',




'SETEX' => 'Predis\Command\StringSetExpire',
'APPEND' => 'Predis\Command\StringAppend',
'SUBSTR' => 'Predis\Command\StringSubstr',


'BLPOP' => 'Predis\Command\ListPopFirstBlocking',
'BRPOP' => 'Predis\Command\ListPopLastBlocking',


'ZUNIONSTORE' => 'Predis\Command\ZSetUnionStore',
'ZINTERSTORE' => 'Predis\Command\ZSetIntersectionStore',
'ZCOUNT' => 'Predis\Command\ZSetCount',
'ZRANK' => 'Predis\Command\ZSetRank',
'ZREVRANK' => 'Predis\Command\ZSetReverseRank',
'ZREMRANGEBYRANK' => 'Predis\Command\ZSetRemoveRangeByRank',


'HSET' => 'Predis\Command\HashSet',
'HSETNX' => 'Predis\Command\HashSetPreserve',
'HMSET' => 'Predis\Command\HashSetMultiple',
'HINCRBY' => 'Predis\Command\HashIncrementBy',
'HGET' => 'Predis\Command\HashGet',
'HMGET' => 'Predis\Command\HashGetMultiple',
'HDEL' => 'Predis\Command\HashDelete',
'HEXISTS' => 'Predis\Command\HashExists',
'HLEN' => 'Predis\Command\HashLength',
'HKEYS' => 'Predis\Command\HashKeys',
'HVALS' => 'Predis\Command\HashValues',
'HGETALL' => 'Predis\Command\HashGetAll',


'MULTI' => 'Predis\Command\TransactionMulti',
'EXEC' => 'Predis\Command\TransactionExec',
'DISCARD' => 'Predis\Command\TransactionDiscard',


'SUBSCRIBE' => 'Predis\Command\PubSubSubscribe',
'UNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribe',
'PSUBSCRIBE' => 'Predis\Command\PubSubSubscribeByPattern',
'PUNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribeByPattern',
'PUBLISH' => 'Predis\Command\PubSubPublish',


'CONFIG' => 'Predis\Command\ServerConfig',
);
}
}
<?php










namespace Predis\Profile;






class RedisVersion280 extends RedisProfile
{



public function getVersion()
{
return '2.8';
}




public function getSupportedCommands()
{
return array(



'EXISTS' => 'Predis\Command\KeyExists',
'DEL' => 'Predis\Command\KeyDelete',
'TYPE' => 'Predis\Command\KeyType',
'KEYS' => 'Predis\Command\KeyKeys',
'RANDOMKEY' => 'Predis\Command\KeyRandom',
'RENAME' => 'Predis\Command\KeyRename',
'RENAMENX' => 'Predis\Command\KeyRenamePreserve',
'EXPIRE' => 'Predis\Command\KeyExpire',
'EXPIREAT' => 'Predis\Command\KeyExpireAt',
'TTL' => 'Predis\Command\KeyTimeToLive',
'MOVE' => 'Predis\Command\KeyMove',
'SORT' => 'Predis\Command\KeySort',
'DUMP' => 'Predis\Command\KeyDump',
'RESTORE' => 'Predis\Command\KeyRestore',


'SET' => 'Predis\Command\StringSet',
'SETNX' => 'Predis\Command\StringSetPreserve',
'MSET' => 'Predis\Command\StringSetMultiple',
'MSETNX' => 'Predis\Command\StringSetMultiplePreserve',
'GET' => 'Predis\Command\StringGet',
'MGET' => 'Predis\Command\StringGetMultiple',
'GETSET' => 'Predis\Command\StringGetSet',
'INCR' => 'Predis\Command\StringIncrement',
'INCRBY' => 'Predis\Command\StringIncrementBy',
'DECR' => 'Predis\Command\StringDecrement',
'DECRBY' => 'Predis\Command\StringDecrementBy',


'RPUSH' => 'Predis\Command\ListPushTail',
'LPUSH' => 'Predis\Command\ListPushHead',
'LLEN' => 'Predis\Command\ListLength',
'LRANGE' => 'Predis\Command\ListRange',
'LTRIM' => 'Predis\Command\ListTrim',
'LINDEX' => 'Predis\Command\ListIndex',
'LSET' => 'Predis\Command\ListSet',
'LREM' => 'Predis\Command\ListRemove',
'LPOP' => 'Predis\Command\ListPopFirst',
'RPOP' => 'Predis\Command\ListPopLast',
'RPOPLPUSH' => 'Predis\Command\ListPopLastPushHead',


'SADD' => 'Predis\Command\SetAdd',
'SREM' => 'Predis\Command\SetRemove',
'SPOP' => 'Predis\Command\SetPop',
'SMOVE' => 'Predis\Command\SetMove',
'SCARD' => 'Predis\Command\SetCardinality',
'SISMEMBER' => 'Predis\Command\SetIsMember',
'SINTER' => 'Predis\Command\SetIntersection',
'SINTERSTORE' => 'Predis\Command\SetIntersectionStore',
'SUNION' => 'Predis\Command\SetUnion',
'SUNIONSTORE' => 'Predis\Command\SetUnionStore',
'SDIFF' => 'Predis\Command\SetDifference',
'SDIFFSTORE' => 'Predis\Command\SetDifferenceStore',
'SMEMBERS' => 'Predis\Command\SetMembers',
'SRANDMEMBER' => 'Predis\Command\SetRandomMember',


'ZADD' => 'Predis\Command\ZSetAdd',
'ZINCRBY' => 'Predis\Command\ZSetIncrementBy',
'ZREM' => 'Predis\Command\ZSetRemove',
'ZRANGE' => 'Predis\Command\ZSetRange',
'ZREVRANGE' => 'Predis\Command\ZSetReverseRange',
'ZRANGEBYSCORE' => 'Predis\Command\ZSetRangeByScore',
'ZCARD' => 'Predis\Command\ZSetCardinality',
'ZSCORE' => 'Predis\Command\ZSetScore',
'ZREMRANGEBYSCORE' => 'Predis\Command\ZSetRemoveRangeByScore',


'PING' => 'Predis\Command\ConnectionPing',
'AUTH' => 'Predis\Command\ConnectionAuth',
'SELECT' => 'Predis\Command\ConnectionSelect',
'ECHO' => 'Predis\Command\ConnectionEcho',
'QUIT' => 'Predis\Command\ConnectionQuit',


'INFO' => 'Predis\Command\ServerInfoV26x',
'SLAVEOF' => 'Predis\Command\ServerSlaveOf',
'MONITOR' => 'Predis\Command\ServerMonitor',
'DBSIZE' => 'Predis\Command\ServerDatabaseSize',
'FLUSHDB' => 'Predis\Command\ServerFlushDatabase',
'FLUSHALL' => 'Predis\Command\ServerFlushAll',
'SAVE' => 'Predis\Command\ServerSave',
'BGSAVE' => 'Predis\Command\ServerBackgroundSave',
'LASTSAVE' => 'Predis\Command\ServerLastSave',
'SHUTDOWN' => 'Predis\Command\ServerShutdown',
'BGREWRITEAOF' => 'Predis\Command\ServerBackgroundRewriteAOF',




'SETEX' => 'Predis\Command\StringSetExpire',
'APPEND' => 'Predis\Command\StringAppend',
'SUBSTR' => 'Predis\Command\StringSubstr',


'BLPOP' => 'Predis\Command\ListPopFirstBlocking',
'BRPOP' => 'Predis\Command\ListPopLastBlocking',


'ZUNIONSTORE' => 'Predis\Command\ZSetUnionStore',
'ZINTERSTORE' => 'Predis\Command\ZSetIntersectionStore',
'ZCOUNT' => 'Predis\Command\ZSetCount',
'ZRANK' => 'Predis\Command\ZSetRank',
'ZREVRANK' => 'Predis\Command\ZSetReverseRank',
'ZREMRANGEBYRANK' => 'Predis\Command\ZSetRemoveRangeByRank',


'HSET' => 'Predis\Command\HashSet',
'HSETNX' => 'Predis\Command\HashSetPreserve',
'HMSET' => 'Predis\Command\HashSetMultiple',
'HINCRBY' => 'Predis\Command\HashIncrementBy',
'HGET' => 'Predis\Command\HashGet',
'HMGET' => 'Predis\Command\HashGetMultiple',
'HDEL' => 'Predis\Command\HashDelete',
'HEXISTS' => 'Predis\Command\HashExists',
'HLEN' => 'Predis\Command\HashLength',
'HKEYS' => 'Predis\Command\HashKeys',
'HVALS' => 'Predis\Command\HashValues',
'HGETALL' => 'Predis\Command\HashGetAll',


'MULTI' => 'Predis\Command\TransactionMulti',
'EXEC' => 'Predis\Command\TransactionExec',
'DISCARD' => 'Predis\Command\TransactionDiscard',


'SUBSCRIBE' => 'Predis\Command\PubSubSubscribe',
'UNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribe',
'PSUBSCRIBE' => 'Predis\Command\PubSubSubscribeByPattern',
'PUNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribeByPattern',
'PUBLISH' => 'Predis\Command\PubSubPublish',


'CONFIG' => 'Predis\Command\ServerConfig',




'PERSIST' => 'Predis\Command\KeyPersist',


'STRLEN' => 'Predis\Command\StringStrlen',
'SETRANGE' => 'Predis\Command\StringSetRange',
'GETRANGE' => 'Predis\Command\StringGetRange',
'SETBIT' => 'Predis\Command\StringSetBit',
'GETBIT' => 'Predis\Command\StringGetBit',


'RPUSHX' => 'Predis\Command\ListPushTailX',
'LPUSHX' => 'Predis\Command\ListPushHeadX',
'LINSERT' => 'Predis\Command\ListInsert',
'BRPOPLPUSH' => 'Predis\Command\ListPopLastPushHeadBlocking',


'ZREVRANGEBYSCORE' => 'Predis\Command\ZSetReverseRangeByScore',


'WATCH' => 'Predis\Command\TransactionWatch',
'UNWATCH' => 'Predis\Command\TransactionUnwatch',


'OBJECT' => 'Predis\Command\ServerObject',
'SLOWLOG' => 'Predis\Command\ServerSlowlog',




'CLIENT' => 'Predis\Command\ServerClient',




'PTTL' => 'Predis\Command\KeyPreciseTimeToLive',
'PEXPIRE' => 'Predis\Command\KeyPreciseExpire',
'PEXPIREAT' => 'Predis\Command\KeyPreciseExpireAt',
'MIGRATE' => 'Predis\Command\KeyMigrate',


'PSETEX' => 'Predis\Command\StringPreciseSetExpire',
'INCRBYFLOAT' => 'Predis\Command\StringIncrementByFloat',
'BITOP' => 'Predis\Command\StringBitOp',
'BITCOUNT' => 'Predis\Command\StringBitCount',


'HINCRBYFLOAT' => 'Predis\Command\HashIncrementByFloat',


'EVAL' => 'Predis\Command\ServerEval',
'EVALSHA' => 'Predis\Command\ServerEvalSHA',
'SCRIPT' => 'Predis\Command\ServerScript',


'TIME' => 'Predis\Command\ServerTime',
'SENTINEL' => 'Predis\Command\ServerSentinel',




'SCAN' => 'Predis\Command\KeyScan',


'BITPOS' => 'Predis\Command\StringBitPos',


'SSCAN' => 'Predis\Command\SetScan',


'ZSCAN' => 'Predis\Command\ZSetScan',
'ZLEXCOUNT' => 'Predis\Command\ZSetLexCount',
'ZRANGEBYLEX' => 'Predis\Command\ZSetRangeByLex',
'ZREMRANGEBYLEX' => 'Predis\Command\ZSetRemoveRangeByLex',
'ZREVRANGEBYLEX' => 'Predis\Command\ZSetReverseRangeByLex',


'HSCAN' => 'Predis\Command\HashScan',


'PUBSUB' => 'Predis\Command\PubSubPubsub',


'PFADD' => 'Predis\Command\HyperLogLogAdd',
'PFCOUNT' => 'Predis\Command\HyperLogLogCount',
'PFMERGE' => 'Predis\Command\HyperLogLogMerge',


'COMMAND' => 'Predis\Command\ServerCommand',
);
}
}
<?php










namespace Predis\Profile;






class RedisVersion320 extends RedisProfile
{



public function getVersion()
{
return '3.2';
}




public function getSupportedCommands()
{
return array(



'EXISTS' => 'Predis\Command\KeyExists',
'DEL' => 'Predis\Command\KeyDelete',
'TYPE' => 'Predis\Command\KeyType',
'KEYS' => 'Predis\Command\KeyKeys',
'RANDOMKEY' => 'Predis\Command\KeyRandom',
'RENAME' => 'Predis\Command\KeyRename',
'RENAMENX' => 'Predis\Command\KeyRenamePreserve',
'EXPIRE' => 'Predis\Command\KeyExpire',
'EXPIREAT' => 'Predis\Command\KeyExpireAt',
'TTL' => 'Predis\Command\KeyTimeToLive',
'MOVE' => 'Predis\Command\KeyMove',
'SORT' => 'Predis\Command\KeySort',
'DUMP' => 'Predis\Command\KeyDump',
'RESTORE' => 'Predis\Command\KeyRestore',


'SET' => 'Predis\Command\StringSet',
'SETNX' => 'Predis\Command\StringSetPreserve',
'MSET' => 'Predis\Command\StringSetMultiple',
'MSETNX' => 'Predis\Command\StringSetMultiplePreserve',
'GET' => 'Predis\Command\StringGet',
'MGET' => 'Predis\Command\StringGetMultiple',
'GETSET' => 'Predis\Command\StringGetSet',
'INCR' => 'Predis\Command\StringIncrement',
'INCRBY' => 'Predis\Command\StringIncrementBy',
'DECR' => 'Predis\Command\StringDecrement',
'DECRBY' => 'Predis\Command\StringDecrementBy',


'RPUSH' => 'Predis\Command\ListPushTail',
'LPUSH' => 'Predis\Command\ListPushHead',
'LLEN' => 'Predis\Command\ListLength',
'LRANGE' => 'Predis\Command\ListRange',
'LTRIM' => 'Predis\Command\ListTrim',
'LINDEX' => 'Predis\Command\ListIndex',
'LSET' => 'Predis\Command\ListSet',
'LREM' => 'Predis\Command\ListRemove',
'LPOP' => 'Predis\Command\ListPopFirst',
'RPOP' => 'Predis\Command\ListPopLast',
'RPOPLPUSH' => 'Predis\Command\ListPopLastPushHead',


'SADD' => 'Predis\Command\SetAdd',
'SREM' => 'Predis\Command\SetRemove',
'SPOP' => 'Predis\Command\SetPop',
'SMOVE' => 'Predis\Command\SetMove',
'SCARD' => 'Predis\Command\SetCardinality',
'SISMEMBER' => 'Predis\Command\SetIsMember',
'SINTER' => 'Predis\Command\SetIntersection',
'SINTERSTORE' => 'Predis\Command\SetIntersectionStore',
'SUNION' => 'Predis\Command\SetUnion',
'SUNIONSTORE' => 'Predis\Command\SetUnionStore',
'SDIFF' => 'Predis\Command\SetDifference',
'SDIFFSTORE' => 'Predis\Command\SetDifferenceStore',
'SMEMBERS' => 'Predis\Command\SetMembers',
'SRANDMEMBER' => 'Predis\Command\SetRandomMember',


'ZADD' => 'Predis\Command\ZSetAdd',
'ZINCRBY' => 'Predis\Command\ZSetIncrementBy',
'ZREM' => 'Predis\Command\ZSetRemove',
'ZRANGE' => 'Predis\Command\ZSetRange',
'ZREVRANGE' => 'Predis\Command\ZSetReverseRange',
'ZRANGEBYSCORE' => 'Predis\Command\ZSetRangeByScore',
'ZCARD' => 'Predis\Command\ZSetCardinality',
'ZSCORE' => 'Predis\Command\ZSetScore',
'ZREMRANGEBYSCORE' => 'Predis\Command\ZSetRemoveRangeByScore',


'PING' => 'Predis\Command\ConnectionPing',
'AUTH' => 'Predis\Command\ConnectionAuth',
'SELECT' => 'Predis\Command\ConnectionSelect',
'ECHO' => 'Predis\Command\ConnectionEcho',
'QUIT' => 'Predis\Command\ConnectionQuit',


'INFO' => 'Predis\Command\ServerInfoV26x',
'SLAVEOF' => 'Predis\Command\ServerSlaveOf',
'MONITOR' => 'Predis\Command\ServerMonitor',
'DBSIZE' => 'Predis\Command\ServerDatabaseSize',
'FLUSHDB' => 'Predis\Command\ServerFlushDatabase',
'FLUSHALL' => 'Predis\Command\ServerFlushAll',
'SAVE' => 'Predis\Command\ServerSave',
'BGSAVE' => 'Predis\Command\ServerBackgroundSave',
'LASTSAVE' => 'Predis\Command\ServerLastSave',
'SHUTDOWN' => 'Predis\Command\ServerShutdown',
'BGREWRITEAOF' => 'Predis\Command\ServerBackgroundRewriteAOF',




'SETEX' => 'Predis\Command\StringSetExpire',
'APPEND' => 'Predis\Command\StringAppend',
'SUBSTR' => 'Predis\Command\StringSubstr',


'BLPOP' => 'Predis\Command\ListPopFirstBlocking',
'BRPOP' => 'Predis\Command\ListPopLastBlocking',


'ZUNIONSTORE' => 'Predis\Command\ZSetUnionStore',
'ZINTERSTORE' => 'Predis\Command\ZSetIntersectionStore',
'ZCOUNT' => 'Predis\Command\ZSetCount',
'ZRANK' => 'Predis\Command\ZSetRank',
'ZREVRANK' => 'Predis\Command\ZSetReverseRank',
'ZREMRANGEBYRANK' => 'Predis\Command\ZSetRemoveRangeByRank',


'HSET' => 'Predis\Command\HashSet',
'HSETNX' => 'Predis\Command\HashSetPreserve',
'HMSET' => 'Predis\Command\HashSetMultiple',
'HINCRBY' => 'Predis\Command\HashIncrementBy',
'HGET' => 'Predis\Command\HashGet',
'HMGET' => 'Predis\Command\HashGetMultiple',
'HDEL' => 'Predis\Command\HashDelete',
'HEXISTS' => 'Predis\Command\HashExists',
'HLEN' => 'Predis\Command\HashLength',
'HKEYS' => 'Predis\Command\HashKeys',
'HVALS' => 'Predis\Command\HashValues',
'HGETALL' => 'Predis\Command\HashGetAll',


'MULTI' => 'Predis\Command\TransactionMulti',
'EXEC' => 'Predis\Command\TransactionExec',
'DISCARD' => 'Predis\Command\TransactionDiscard',


'SUBSCRIBE' => 'Predis\Command\PubSubSubscribe',
'UNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribe',
'PSUBSCRIBE' => 'Predis\Command\PubSubSubscribeByPattern',
'PUNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribeByPattern',
'PUBLISH' => 'Predis\Command\PubSubPublish',


'CONFIG' => 'Predis\Command\ServerConfig',




'PERSIST' => 'Predis\Command\KeyPersist',


'STRLEN' => 'Predis\Command\StringStrlen',
'SETRANGE' => 'Predis\Command\StringSetRange',
'GETRANGE' => 'Predis\Command\StringGetRange',
'SETBIT' => 'Predis\Command\StringSetBit',
'GETBIT' => 'Predis\Command\StringGetBit',


'RPUSHX' => 'Predis\Command\ListPushTailX',
'LPUSHX' => 'Predis\Command\ListPushHeadX',
'LINSERT' => 'Predis\Command\ListInsert',
'BRPOPLPUSH' => 'Predis\Command\ListPopLastPushHeadBlocking',


'ZREVRANGEBYSCORE' => 'Predis\Command\ZSetReverseRangeByScore',


'WATCH' => 'Predis\Command\TransactionWatch',
'UNWATCH' => 'Predis\Command\TransactionUnwatch',


'OBJECT' => 'Predis\Command\ServerObject',
'SLOWLOG' => 'Predis\Command\ServerSlowlog',




'CLIENT' => 'Predis\Command\ServerClient',




'PTTL' => 'Predis\Command\KeyPreciseTimeToLive',
'PEXPIRE' => 'Predis\Command\KeyPreciseExpire',
'PEXPIREAT' => 'Predis\Command\KeyPreciseExpireAt',
'MIGRATE' => 'Predis\Command\KeyMigrate',


'PSETEX' => 'Predis\Command\StringPreciseSetExpire',
'INCRBYFLOAT' => 'Predis\Command\StringIncrementByFloat',
'BITOP' => 'Predis\Command\StringBitOp',
'BITCOUNT' => 'Predis\Command\StringBitCount',


'HINCRBYFLOAT' => 'Predis\Command\HashIncrementByFloat',


'EVAL' => 'Predis\Command\ServerEval',
'EVALSHA' => 'Predis\Command\ServerEvalSHA',
'SCRIPT' => 'Predis\Command\ServerScript',


'TIME' => 'Predis\Command\ServerTime',
'SENTINEL' => 'Predis\Command\ServerSentinel',




'SCAN' => 'Predis\Command\KeyScan',


'BITPOS' => 'Predis\Command\StringBitPos',


'SSCAN' => 'Predis\Command\SetScan',


'ZSCAN' => 'Predis\Command\ZSetScan',
'ZLEXCOUNT' => 'Predis\Command\ZSetLexCount',
'ZRANGEBYLEX' => 'Predis\Command\ZSetRangeByLex',
'ZREMRANGEBYLEX' => 'Predis\Command\ZSetRemoveRangeByLex',
'ZREVRANGEBYLEX' => 'Predis\Command\ZSetReverseRangeByLex',


'HSCAN' => 'Predis\Command\HashScan',


'PUBSUB' => 'Predis\Command\PubSubPubsub',


'PFADD' => 'Predis\Command\HyperLogLogAdd',
'PFCOUNT' => 'Predis\Command\HyperLogLogCount',
'PFMERGE' => 'Predis\Command\HyperLogLogMerge',


'COMMAND' => 'Predis\Command\ServerCommand',




'HSTRLEN' => 'Predis\Command\HashStringLength',
'BITFIELD' => 'Predis\Command\StringBitField',


'GEOADD' => 'Predis\Command\GeospatialGeoAdd',
'GEOHASH' => 'Predis\Command\GeospatialGeoHash',
'GEOPOS' => 'Predis\Command\GeospatialGeoPos',
'GEODIST' => 'Predis\Command\GeospatialGeoDist',
'GEORADIUS' => 'Predis\Command\GeospatialGeoRadius',
'GEORADIUSBYMEMBER' => 'Predis\Command\GeospatialGeoRadiusByMember',
);
}
}
<?php










namespace Predis\Profile;

use Predis\ClientException;
use Predis\Command\Processor\ProcessorInterface;






abstract class RedisProfile implements ProfileInterface
{
private $commands;
private $processor;




public function __construct()
{
$this->commands = $this->getSupportedCommands();
}







abstract protected function getSupportedCommands();




public function supportsCommand($commandID)
{
return isset($this->commands[strtoupper($commandID)]);
}




public function supportsCommands(array $commandIDs)
{
foreach ($commandIDs as $commandID) {
if (!$this->supportsCommand($commandID)) {
return false;
}
}

return true;
}









public function getCommandClass($commandID)
{
if (isset($this->commands[$commandID = strtoupper($commandID)])) {
return $this->commands[$commandID];
}
}




public function createCommand($commandID, array $arguments = array())
{
$commandID = strtoupper($commandID);

if (!isset($this->commands[$commandID])) {
throw new ClientException("Command '$commandID' is not a registered Redis command.");
}

$commandClass = $this->commands[$commandID];
$command = new $commandClass();
$command->setArguments($arguments);

if (isset($this->processor)) {
$this->processor->process($command);
}

return $command;
}









public function defineCommand($commandID, $class)
{
$reflection = new \ReflectionClass($class);

if (!$reflection->isSubclassOf('Predis\Command\CommandInterface')) {
throw new \InvalidArgumentException("The class '$class' is not a valid command class.");
}

$this->commands[strtoupper($commandID)] = $class;
}




public function setProcessor(ProcessorInterface $processor = null)
{
$this->processor = $processor;
}




public function getProcessor()
{
return $this->processor;
}






public function __toString()
{
return $this->getVersion();
}
}
<?php










namespace Predis\Profile;

use Predis\ClientException;






final class Factory
{
private static $profiles = array(
'2.0' => 'Predis\Profile\RedisVersion200',
'2.2' => 'Predis\Profile\RedisVersion220',
'2.4' => 'Predis\Profile\RedisVersion240',
'2.6' => 'Predis\Profile\RedisVersion260',
'2.8' => 'Predis\Profile\RedisVersion280',
'3.0' => 'Predis\Profile\RedisVersion300',
'3.2' => 'Predis\Profile\RedisVersion320',
'dev' => 'Predis\Profile\RedisUnstable',
'default' => 'Predis\Profile\RedisVersion320',
);




private function __construct()
{

 }






public static function getDefault()
{
return self::get('default');
}






public static function getDevelopment()
{
return self::get('dev');
}









public static function define($alias, $class)
{
$reflection = new \ReflectionClass($class);

if (!$reflection->isSubclassOf('Predis\Profile\ProfileInterface')) {
throw new \InvalidArgumentException("The class '$class' is not a valid profile class.");
}

self::$profiles[$alias] = $class;
}










public static function get($version)
{
if (!isset(self::$profiles[$version])) {
throw new ClientException("Unknown server profile: '$version'.");
}

$profile = self::$profiles[$version];

return new $profile();
}
}
<?php










namespace Predis\Profile;

use Predis\Command\CommandInterface;








interface ProfileInterface
{





public function getVersion();








public function supportsCommand($commandID);








public function supportsCommands(array $commandIDs);









public function createCommand($commandID, array $arguments = array());
}
<?php










namespace Predis\Profile;






class RedisVersion260 extends RedisProfile
{



public function getVersion()
{
return '2.6';
}




public function getSupportedCommands()
{
return array(



'EXISTS' => 'Predis\Command\KeyExists',
'DEL' => 'Predis\Command\KeyDelete',
'TYPE' => 'Predis\Command\KeyType',
'KEYS' => 'Predis\Command\KeyKeys',
'RANDOMKEY' => 'Predis\Command\KeyRandom',
'RENAME' => 'Predis\Command\KeyRename',
'RENAMENX' => 'Predis\Command\KeyRenamePreserve',
'EXPIRE' => 'Predis\Command\KeyExpire',
'EXPIREAT' => 'Predis\Command\KeyExpireAt',
'TTL' => 'Predis\Command\KeyTimeToLive',
'MOVE' => 'Predis\Command\KeyMove',
'SORT' => 'Predis\Command\KeySort',
'DUMP' => 'Predis\Command\KeyDump',
'RESTORE' => 'Predis\Command\KeyRestore',


'SET' => 'Predis\Command\StringSet',
'SETNX' => 'Predis\Command\StringSetPreserve',
'MSET' => 'Predis\Command\StringSetMultiple',
'MSETNX' => 'Predis\Command\StringSetMultiplePreserve',
'GET' => 'Predis\Command\StringGet',
'MGET' => 'Predis\Command\StringGetMultiple',
'GETSET' => 'Predis\Command\StringGetSet',
'INCR' => 'Predis\Command\StringIncrement',
'INCRBY' => 'Predis\Command\StringIncrementBy',
'DECR' => 'Predis\Command\StringDecrement',
'DECRBY' => 'Predis\Command\StringDecrementBy',


'RPUSH' => 'Predis\Command\ListPushTail',
'LPUSH' => 'Predis\Command\ListPushHead',
'LLEN' => 'Predis\Command\ListLength',
'LRANGE' => 'Predis\Command\ListRange',
'LTRIM' => 'Predis\Command\ListTrim',
'LINDEX' => 'Predis\Command\ListIndex',
'LSET' => 'Predis\Command\ListSet',
'LREM' => 'Predis\Command\ListRemove',
'LPOP' => 'Predis\Command\ListPopFirst',
'RPOP' => 'Predis\Command\ListPopLast',
'RPOPLPUSH' => 'Predis\Command\ListPopLastPushHead',


'SADD' => 'Predis\Command\SetAdd',
'SREM' => 'Predis\Command\SetRemove',
'SPOP' => 'Predis\Command\SetPop',
'SMOVE' => 'Predis\Command\SetMove',
'SCARD' => 'Predis\Command\SetCardinality',
'SISMEMBER' => 'Predis\Command\SetIsMember',
'SINTER' => 'Predis\Command\SetIntersection',
'SINTERSTORE' => 'Predis\Command\SetIntersectionStore',
'SUNION' => 'Predis\Command\SetUnion',
'SUNIONSTORE' => 'Predis\Command\SetUnionStore',
'SDIFF' => 'Predis\Command\SetDifference',
'SDIFFSTORE' => 'Predis\Command\SetDifferenceStore',
'SMEMBERS' => 'Predis\Command\SetMembers',
'SRANDMEMBER' => 'Predis\Command\SetRandomMember',


'ZADD' => 'Predis\Command\ZSetAdd',
'ZINCRBY' => 'Predis\Command\ZSetIncrementBy',
'ZREM' => 'Predis\Command\ZSetRemove',
'ZRANGE' => 'Predis\Command\ZSetRange',
'ZREVRANGE' => 'Predis\Command\ZSetReverseRange',
'ZRANGEBYSCORE' => 'Predis\Command\ZSetRangeByScore',
'ZCARD' => 'Predis\Command\ZSetCardinality',
'ZSCORE' => 'Predis\Command\ZSetScore',
'ZREMRANGEBYSCORE' => 'Predis\Command\ZSetRemoveRangeByScore',


'PING' => 'Predis\Command\ConnectionPing',
'AUTH' => 'Predis\Command\ConnectionAuth',
'SELECT' => 'Predis\Command\ConnectionSelect',
'ECHO' => 'Predis\Command\ConnectionEcho',
'QUIT' => 'Predis\Command\ConnectionQuit',


'INFO' => 'Predis\Command\ServerInfoV26x',
'SLAVEOF' => 'Predis\Command\ServerSlaveOf',
'MONITOR' => 'Predis\Command\ServerMonitor',
'DBSIZE' => 'Predis\Command\ServerDatabaseSize',
'FLUSHDB' => 'Predis\Command\ServerFlushDatabase',
'FLUSHALL' => 'Predis\Command\ServerFlushAll',
'SAVE' => 'Predis\Command\ServerSave',
'BGSAVE' => 'Predis\Command\ServerBackgroundSave',
'LASTSAVE' => 'Predis\Command\ServerLastSave',
'SHUTDOWN' => 'Predis\Command\ServerShutdown',
'BGREWRITEAOF' => 'Predis\Command\ServerBackgroundRewriteAOF',




'SETEX' => 'Predis\Command\StringSetExpire',
'APPEND' => 'Predis\Command\StringAppend',
'SUBSTR' => 'Predis\Command\StringSubstr',


'BLPOP' => 'Predis\Command\ListPopFirstBlocking',
'BRPOP' => 'Predis\Command\ListPopLastBlocking',


'ZUNIONSTORE' => 'Predis\Command\ZSetUnionStore',
'ZINTERSTORE' => 'Predis\Command\ZSetIntersectionStore',
'ZCOUNT' => 'Predis\Command\ZSetCount',
'ZRANK' => 'Predis\Command\ZSetRank',
'ZREVRANK' => 'Predis\Command\ZSetReverseRank',
'ZREMRANGEBYRANK' => 'Predis\Command\ZSetRemoveRangeByRank',


'HSET' => 'Predis\Command\HashSet',
'HSETNX' => 'Predis\Command\HashSetPreserve',
'HMSET' => 'Predis\Command\HashSetMultiple',
'HINCRBY' => 'Predis\Command\HashIncrementBy',
'HGET' => 'Predis\Command\HashGet',
'HMGET' => 'Predis\Command\HashGetMultiple',
'HDEL' => 'Predis\Command\HashDelete',
'HEXISTS' => 'Predis\Command\HashExists',
'HLEN' => 'Predis\Command\HashLength',
'HKEYS' => 'Predis\Command\HashKeys',
'HVALS' => 'Predis\Command\HashValues',
'HGETALL' => 'Predis\Command\HashGetAll',


'MULTI' => 'Predis\Command\TransactionMulti',
'EXEC' => 'Predis\Command\TransactionExec',
'DISCARD' => 'Predis\Command\TransactionDiscard',


'SUBSCRIBE' => 'Predis\Command\PubSubSubscribe',
'UNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribe',
'PSUBSCRIBE' => 'Predis\Command\PubSubSubscribeByPattern',
'PUNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribeByPattern',
'PUBLISH' => 'Predis\Command\PubSubPublish',


'CONFIG' => 'Predis\Command\ServerConfig',




'PERSIST' => 'Predis\Command\KeyPersist',


'STRLEN' => 'Predis\Command\StringStrlen',
'SETRANGE' => 'Predis\Command\StringSetRange',
'GETRANGE' => 'Predis\Command\StringGetRange',
'SETBIT' => 'Predis\Command\StringSetBit',
'GETBIT' => 'Predis\Command\StringGetBit',


'RPUSHX' => 'Predis\Command\ListPushTailX',
'LPUSHX' => 'Predis\Command\ListPushHeadX',
'LINSERT' => 'Predis\Command\ListInsert',
'BRPOPLPUSH' => 'Predis\Command\ListPopLastPushHeadBlocking',


'ZREVRANGEBYSCORE' => 'Predis\Command\ZSetReverseRangeByScore',


'WATCH' => 'Predis\Command\TransactionWatch',
'UNWATCH' => 'Predis\Command\TransactionUnwatch',


'OBJECT' => 'Predis\Command\ServerObject',
'SLOWLOG' => 'Predis\Command\ServerSlowlog',




'CLIENT' => 'Predis\Command\ServerClient',




'PTTL' => 'Predis\Command\KeyPreciseTimeToLive',
'PEXPIRE' => 'Predis\Command\KeyPreciseExpire',
'PEXPIREAT' => 'Predis\Command\KeyPreciseExpireAt',
'MIGRATE' => 'Predis\Command\KeyMigrate',


'PSETEX' => 'Predis\Command\StringPreciseSetExpire',
'INCRBYFLOAT' => 'Predis\Command\StringIncrementByFloat',
'BITOP' => 'Predis\Command\StringBitOp',
'BITCOUNT' => 'Predis\Command\StringBitCount',


'HINCRBYFLOAT' => 'Predis\Command\HashIncrementByFloat',


'EVAL' => 'Predis\Command\ServerEval',
'EVALSHA' => 'Predis\Command\ServerEvalSHA',
'SCRIPT' => 'Predis\Command\ServerScript',


'TIME' => 'Predis\Command\ServerTime',
'SENTINEL' => 'Predis\Command\ServerSentinel',
);
}
}
<?php










namespace Predis\Profile;






class RedisUnstable extends RedisVersion320
{



public function getVersion()
{
return '3.2';
}




public function getSupportedCommands()
{
return array_merge(parent::getSupportedCommands(), array(

 ));
}
}
<?php










namespace Predis\Profile;






class RedisVersion240 extends RedisProfile
{



public function getVersion()
{
return '2.4';
}




public function getSupportedCommands()
{
return array(



'EXISTS' => 'Predis\Command\KeyExists',
'DEL' => 'Predis\Command\KeyDelete',
'TYPE' => 'Predis\Command\KeyType',
'KEYS' => 'Predis\Command\KeyKeys',
'RANDOMKEY' => 'Predis\Command\KeyRandom',
'RENAME' => 'Predis\Command\KeyRename',
'RENAMENX' => 'Predis\Command\KeyRenamePreserve',
'EXPIRE' => 'Predis\Command\KeyExpire',
'EXPIREAT' => 'Predis\Command\KeyExpireAt',
'TTL' => 'Predis\Command\KeyTimeToLive',
'MOVE' => 'Predis\Command\KeyMove',
'SORT' => 'Predis\Command\KeySort',


'SET' => 'Predis\Command\StringSet',
'SETNX' => 'Predis\Command\StringSetPreserve',
'MSET' => 'Predis\Command\StringSetMultiple',
'MSETNX' => 'Predis\Command\StringSetMultiplePreserve',
'GET' => 'Predis\Command\StringGet',
'MGET' => 'Predis\Command\StringGetMultiple',
'GETSET' => 'Predis\Command\StringGetSet',
'INCR' => 'Predis\Command\StringIncrement',
'INCRBY' => 'Predis\Command\StringIncrementBy',
'DECR' => 'Predis\Command\StringDecrement',
'DECRBY' => 'Predis\Command\StringDecrementBy',


'RPUSH' => 'Predis\Command\ListPushTail',
'LPUSH' => 'Predis\Command\ListPushHead',
'LLEN' => 'Predis\Command\ListLength',
'LRANGE' => 'Predis\Command\ListRange',
'LTRIM' => 'Predis\Command\ListTrim',
'LINDEX' => 'Predis\Command\ListIndex',
'LSET' => 'Predis\Command\ListSet',
'LREM' => 'Predis\Command\ListRemove',
'LPOP' => 'Predis\Command\ListPopFirst',
'RPOP' => 'Predis\Command\ListPopLast',
'RPOPLPUSH' => 'Predis\Command\ListPopLastPushHead',


'SADD' => 'Predis\Command\SetAdd',
'SREM' => 'Predis\Command\SetRemove',
'SPOP' => 'Predis\Command\SetPop',
'SMOVE' => 'Predis\Command\SetMove',
'SCARD' => 'Predis\Command\SetCardinality',
'SISMEMBER' => 'Predis\Command\SetIsMember',
'SINTER' => 'Predis\Command\SetIntersection',
'SINTERSTORE' => 'Predis\Command\SetIntersectionStore',
'SUNION' => 'Predis\Command\SetUnion',
'SUNIONSTORE' => 'Predis\Command\SetUnionStore',
'SDIFF' => 'Predis\Command\SetDifference',
'SDIFFSTORE' => 'Predis\Command\SetDifferenceStore',
'SMEMBERS' => 'Predis\Command\SetMembers',
'SRANDMEMBER' => 'Predis\Command\SetRandomMember',


'ZADD' => 'Predis\Command\ZSetAdd',
'ZINCRBY' => 'Predis\Command\ZSetIncrementBy',
'ZREM' => 'Predis\Command\ZSetRemove',
'ZRANGE' => 'Predis\Command\ZSetRange',
'ZREVRANGE' => 'Predis\Command\ZSetReverseRange',
'ZRANGEBYSCORE' => 'Predis\Command\ZSetRangeByScore',
'ZCARD' => 'Predis\Command\ZSetCardinality',
'ZSCORE' => 'Predis\Command\ZSetScore',
'ZREMRANGEBYSCORE' => 'Predis\Command\ZSetRemoveRangeByScore',


'PING' => 'Predis\Command\ConnectionPing',
'AUTH' => 'Predis\Command\ConnectionAuth',
'SELECT' => 'Predis\Command\ConnectionSelect',
'ECHO' => 'Predis\Command\ConnectionEcho',
'QUIT' => 'Predis\Command\ConnectionQuit',


'INFO' => 'Predis\Command\ServerInfo',
'SLAVEOF' => 'Predis\Command\ServerSlaveOf',
'MONITOR' => 'Predis\Command\ServerMonitor',
'DBSIZE' => 'Predis\Command\ServerDatabaseSize',
'FLUSHDB' => 'Predis\Command\ServerFlushDatabase',
'FLUSHALL' => 'Predis\Command\ServerFlushAll',
'SAVE' => 'Predis\Command\ServerSave',
'BGSAVE' => 'Predis\Command\ServerBackgroundSave',
'LASTSAVE' => 'Predis\Command\ServerLastSave',
'SHUTDOWN' => 'Predis\Command\ServerShutdown',
'BGREWRITEAOF' => 'Predis\Command\ServerBackgroundRewriteAOF',




'SETEX' => 'Predis\Command\StringSetExpire',
'APPEND' => 'Predis\Command\StringAppend',
'SUBSTR' => 'Predis\Command\StringSubstr',


'BLPOP' => 'Predis\Command\ListPopFirstBlocking',
'BRPOP' => 'Predis\Command\ListPopLastBlocking',


'ZUNIONSTORE' => 'Predis\Command\ZSetUnionStore',
'ZINTERSTORE' => 'Predis\Command\ZSetIntersectionStore',
'ZCOUNT' => 'Predis\Command\ZSetCount',
'ZRANK' => 'Predis\Command\ZSetRank',
'ZREVRANK' => 'Predis\Command\ZSetReverseRank',
'ZREMRANGEBYRANK' => 'Predis\Command\ZSetRemoveRangeByRank',


'HSET' => 'Predis\Command\HashSet',
'HSETNX' => 'Predis\Command\HashSetPreserve',
'HMSET' => 'Predis\Command\HashSetMultiple',
'HINCRBY' => 'Predis\Command\HashIncrementBy',
'HGET' => 'Predis\Command\HashGet',
'HMGET' => 'Predis\Command\HashGetMultiple',
'HDEL' => 'Predis\Command\HashDelete',
'HEXISTS' => 'Predis\Command\HashExists',
'HLEN' => 'Predis\Command\HashLength',
'HKEYS' => 'Predis\Command\HashKeys',
'HVALS' => 'Predis\Command\HashValues',
'HGETALL' => 'Predis\Command\HashGetAll',


'MULTI' => 'Predis\Command\TransactionMulti',
'EXEC' => 'Predis\Command\TransactionExec',
'DISCARD' => 'Predis\Command\TransactionDiscard',


'SUBSCRIBE' => 'Predis\Command\PubSubSubscribe',
'UNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribe',
'PSUBSCRIBE' => 'Predis\Command\PubSubSubscribeByPattern',
'PUNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribeByPattern',
'PUBLISH' => 'Predis\Command\PubSubPublish',


'CONFIG' => 'Predis\Command\ServerConfig',




'PERSIST' => 'Predis\Command\KeyPersist',


'STRLEN' => 'Predis\Command\StringStrlen',
'SETRANGE' => 'Predis\Command\StringSetRange',
'GETRANGE' => 'Predis\Command\StringGetRange',
'SETBIT' => 'Predis\Command\StringSetBit',
'GETBIT' => 'Predis\Command\StringGetBit',


'RPUSHX' => 'Predis\Command\ListPushTailX',
'LPUSHX' => 'Predis\Command\ListPushHeadX',
'LINSERT' => 'Predis\Command\ListInsert',
'BRPOPLPUSH' => 'Predis\Command\ListPopLastPushHeadBlocking',


'ZREVRANGEBYSCORE' => 'Predis\Command\ZSetReverseRangeByScore',


'WATCH' => 'Predis\Command\TransactionWatch',
'UNWATCH' => 'Predis\Command\TransactionUnwatch',


'OBJECT' => 'Predis\Command\ServerObject',
'SLOWLOG' => 'Predis\Command\ServerSlowlog',




'CLIENT' => 'Predis\Command\ServerClient',
);
}
}
<?php










namespace Predis\Profile;






class RedisVersion300 extends RedisProfile
{



public function getVersion()
{
return '3.0';
}




public function getSupportedCommands()
{
return array(



'EXISTS' => 'Predis\Command\KeyExists',
'DEL' => 'Predis\Command\KeyDelete',
'TYPE' => 'Predis\Command\KeyType',
'KEYS' => 'Predis\Command\KeyKeys',
'RANDOMKEY' => 'Predis\Command\KeyRandom',
'RENAME' => 'Predis\Command\KeyRename',
'RENAMENX' => 'Predis\Command\KeyRenamePreserve',
'EXPIRE' => 'Predis\Command\KeyExpire',
'EXPIREAT' => 'Predis\Command\KeyExpireAt',
'TTL' => 'Predis\Command\KeyTimeToLive',
'MOVE' => 'Predis\Command\KeyMove',
'SORT' => 'Predis\Command\KeySort',
'DUMP' => 'Predis\Command\KeyDump',
'RESTORE' => 'Predis\Command\KeyRestore',


'SET' => 'Predis\Command\StringSet',
'SETNX' => 'Predis\Command\StringSetPreserve',
'MSET' => 'Predis\Command\StringSetMultiple',
'MSETNX' => 'Predis\Command\StringSetMultiplePreserve',
'GET' => 'Predis\Command\StringGet',
'MGET' => 'Predis\Command\StringGetMultiple',
'GETSET' => 'Predis\Command\StringGetSet',
'INCR' => 'Predis\Command\StringIncrement',
'INCRBY' => 'Predis\Command\StringIncrementBy',
'DECR' => 'Predis\Command\StringDecrement',
'DECRBY' => 'Predis\Command\StringDecrementBy',


'RPUSH' => 'Predis\Command\ListPushTail',
'LPUSH' => 'Predis\Command\ListPushHead',
'LLEN' => 'Predis\Command\ListLength',
'LRANGE' => 'Predis\Command\ListRange',
'LTRIM' => 'Predis\Command\ListTrim',
'LINDEX' => 'Predis\Command\ListIndex',
'LSET' => 'Predis\Command\ListSet',
'LREM' => 'Predis\Command\ListRemove',
'LPOP' => 'Predis\Command\ListPopFirst',
'RPOP' => 'Predis\Command\ListPopLast',
'RPOPLPUSH' => 'Predis\Command\ListPopLastPushHead',


'SADD' => 'Predis\Command\SetAdd',
'SREM' => 'Predis\Command\SetRemove',
'SPOP' => 'Predis\Command\SetPop',
'SMOVE' => 'Predis\Command\SetMove',
'SCARD' => 'Predis\Command\SetCardinality',
'SISMEMBER' => 'Predis\Command\SetIsMember',
'SINTER' => 'Predis\Command\SetIntersection',
'SINTERSTORE' => 'Predis\Command\SetIntersectionStore',
'SUNION' => 'Predis\Command\SetUnion',
'SUNIONSTORE' => 'Predis\Command\SetUnionStore',
'SDIFF' => 'Predis\Command\SetDifference',
'SDIFFSTORE' => 'Predis\Command\SetDifferenceStore',
'SMEMBERS' => 'Predis\Command\SetMembers',
'SRANDMEMBER' => 'Predis\Command\SetRandomMember',


'ZADD' => 'Predis\Command\ZSetAdd',
'ZINCRBY' => 'Predis\Command\ZSetIncrementBy',
'ZREM' => 'Predis\Command\ZSetRemove',
'ZRANGE' => 'Predis\Command\ZSetRange',
'ZREVRANGE' => 'Predis\Command\ZSetReverseRange',
'ZRANGEBYSCORE' => 'Predis\Command\ZSetRangeByScore',
'ZCARD' => 'Predis\Command\ZSetCardinality',
'ZSCORE' => 'Predis\Command\ZSetScore',
'ZREMRANGEBYSCORE' => 'Predis\Command\ZSetRemoveRangeByScore',


'PING' => 'Predis\Command\ConnectionPing',
'AUTH' => 'Predis\Command\ConnectionAuth',
'SELECT' => 'Predis\Command\ConnectionSelect',
'ECHO' => 'Predis\Command\ConnectionEcho',
'QUIT' => 'Predis\Command\ConnectionQuit',


'INFO' => 'Predis\Command\ServerInfoV26x',
'SLAVEOF' => 'Predis\Command\ServerSlaveOf',
'MONITOR' => 'Predis\Command\ServerMonitor',
'DBSIZE' => 'Predis\Command\ServerDatabaseSize',
'FLUSHDB' => 'Predis\Command\ServerFlushDatabase',
'FLUSHALL' => 'Predis\Command\ServerFlushAll',
'SAVE' => 'Predis\Command\ServerSave',
'BGSAVE' => 'Predis\Command\ServerBackgroundSave',
'LASTSAVE' => 'Predis\Command\ServerLastSave',
'SHUTDOWN' => 'Predis\Command\ServerShutdown',
'BGREWRITEAOF' => 'Predis\Command\ServerBackgroundRewriteAOF',




'SETEX' => 'Predis\Command\StringSetExpire',
'APPEND' => 'Predis\Command\StringAppend',
'SUBSTR' => 'Predis\Command\StringSubstr',


'BLPOP' => 'Predis\Command\ListPopFirstBlocking',
'BRPOP' => 'Predis\Command\ListPopLastBlocking',


'ZUNIONSTORE' => 'Predis\Command\ZSetUnionStore',
'ZINTERSTORE' => 'Predis\Command\ZSetIntersectionStore',
'ZCOUNT' => 'Predis\Command\ZSetCount',
'ZRANK' => 'Predis\Command\ZSetRank',
'ZREVRANK' => 'Predis\Command\ZSetReverseRank',
'ZREMRANGEBYRANK' => 'Predis\Command\ZSetRemoveRangeByRank',


'HSET' => 'Predis\Command\HashSet',
'HSETNX' => 'Predis\Command\HashSetPreserve',
'HMSET' => 'Predis\Command\HashSetMultiple',
'HINCRBY' => 'Predis\Command\HashIncrementBy',
'HGET' => 'Predis\Command\HashGet',
'HMGET' => 'Predis\Command\HashGetMultiple',
'HDEL' => 'Predis\Command\HashDelete',
'HEXISTS' => 'Predis\Command\HashExists',
'HLEN' => 'Predis\Command\HashLength',
'HKEYS' => 'Predis\Command\HashKeys',
'HVALS' => 'Predis\Command\HashValues',
'HGETALL' => 'Predis\Command\HashGetAll',


'MULTI' => 'Predis\Command\TransactionMulti',
'EXEC' => 'Predis\Command\TransactionExec',
'DISCARD' => 'Predis\Command\TransactionDiscard',


'SUBSCRIBE' => 'Predis\Command\PubSubSubscribe',
'UNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribe',
'PSUBSCRIBE' => 'Predis\Command\PubSubSubscribeByPattern',
'PUNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribeByPattern',
'PUBLISH' => 'Predis\Command\PubSubPublish',


'CONFIG' => 'Predis\Command\ServerConfig',




'PERSIST' => 'Predis\Command\KeyPersist',


'STRLEN' => 'Predis\Command\StringStrlen',
'SETRANGE' => 'Predis\Command\StringSetRange',
'GETRANGE' => 'Predis\Command\StringGetRange',
'SETBIT' => 'Predis\Command\StringSetBit',
'GETBIT' => 'Predis\Command\StringGetBit',


'RPUSHX' => 'Predis\Command\ListPushTailX',
'LPUSHX' => 'Predis\Command\ListPushHeadX',
'LINSERT' => 'Predis\Command\ListInsert',
'BRPOPLPUSH' => 'Predis\Command\ListPopLastPushHeadBlocking',


'ZREVRANGEBYSCORE' => 'Predis\Command\ZSetReverseRangeByScore',


'WATCH' => 'Predis\Command\TransactionWatch',
'UNWATCH' => 'Predis\Command\TransactionUnwatch',


'OBJECT' => 'Predis\Command\ServerObject',
'SLOWLOG' => 'Predis\Command\ServerSlowlog',




'CLIENT' => 'Predis\Command\ServerClient',




'PTTL' => 'Predis\Command\KeyPreciseTimeToLive',
'PEXPIRE' => 'Predis\Command\KeyPreciseExpire',
'PEXPIREAT' => 'Predis\Command\KeyPreciseExpireAt',
'MIGRATE' => 'Predis\Command\KeyMigrate',


'PSETEX' => 'Predis\Command\StringPreciseSetExpire',
'INCRBYFLOAT' => 'Predis\Command\StringIncrementByFloat',
'BITOP' => 'Predis\Command\StringBitOp',
'BITCOUNT' => 'Predis\Command\StringBitCount',


'HINCRBYFLOAT' => 'Predis\Command\HashIncrementByFloat',


'EVAL' => 'Predis\Command\ServerEval',
'EVALSHA' => 'Predis\Command\ServerEvalSHA',
'SCRIPT' => 'Predis\Command\ServerScript',


'TIME' => 'Predis\Command\ServerTime',
'SENTINEL' => 'Predis\Command\ServerSentinel',




'SCAN' => 'Predis\Command\KeyScan',


'BITPOS' => 'Predis\Command\StringBitPos',


'SSCAN' => 'Predis\Command\SetScan',


'ZSCAN' => 'Predis\Command\ZSetScan',
'ZLEXCOUNT' => 'Predis\Command\ZSetLexCount',
'ZRANGEBYLEX' => 'Predis\Command\ZSetRangeByLex',
'ZREMRANGEBYLEX' => 'Predis\Command\ZSetRemoveRangeByLex',
'ZREVRANGEBYLEX' => 'Predis\Command\ZSetReverseRangeByLex',


'HSCAN' => 'Predis\Command\HashScan',


'PUBSUB' => 'Predis\Command\PubSubPubsub',


'PFADD' => 'Predis\Command\HyperLogLogAdd',
'PFCOUNT' => 'Predis\Command\HyperLogLogCount',
'PFMERGE' => 'Predis\Command\HyperLogLogMerge',


'COMMAND' => 'Predis\Command\ServerCommand',



);
}
}
<?php










namespace Predis;

use Predis\Command\CommandInterface;



























































































































































interface ClientContextInterface
{







public function executeCommand(CommandInterface $command);









public function __call($method, $arguments);








public function execute($callable = null);
}
<?php










namespace Predis;







class NotSupportedException extends PredisException
{
}
<?php










namespace Predis;






abstract class PredisException extends \Exception
{
}
<?php










namespace Predis\Connection;

use Predis\Command\CommandInterface;
use Predis\CommunicationException;
use Predis\Protocol\ProtocolException;







abstract class AbstractConnection implements NodeConnectionInterface
{
private $resource;
private $cachedId;

protected $parameters;
protected $initCommands = array();




public function __construct(ParametersInterface $parameters)
{
$this->parameters = $this->assertParameters($parameters);
}





public function __destruct()
{
$this->disconnect();
}










abstract protected function assertParameters(ParametersInterface $parameters);






abstract protected function createResource();




public function isConnected()
{
return isset($this->resource);
}




public function connect()
{
if (!$this->isConnected()) {
$this->resource = $this->createResource();

return true;
}

return false;
}




public function disconnect()
{
unset($this->resource);
}




public function addConnectCommand(CommandInterface $command)
{
$this->initCommands[] = $command;
}




public function executeCommand(CommandInterface $command)
{
$this->writeRequest($command);

return $this->readResponse($command);
}




public function readResponse(CommandInterface $command)
{
return $this->read();
}









private function createExceptionMessage($message)
{
$parameters = $this->parameters;

if ($parameters->scheme === 'unix') {
return "$message [$parameters->scheme:$parameters->path]";
}

if (filter_var($parameters->host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
return "$message [$parameters->scheme://[$parameters->host]:$parameters->port]";
}

return "$message [$parameters->scheme://$parameters->host:$parameters->port]";
}







protected function onConnectionError($message, $code = null)
{
CommunicationException::handle(
new ConnectionException($this, static::createExceptionMessage($message), $code)
);
}






protected function onProtocolError($message)
{
CommunicationException::handle(
new ProtocolException($this, static::createExceptionMessage($message))
);
}




public function getResource()
{
if (isset($this->resource)) {
return $this->resource;
}

$this->connect();

return $this->resource;
}




public function getParameters()
{
return $this->parameters;
}






protected function getIdentifier()
{
if ($this->parameters->scheme === 'unix') {
return $this->parameters->path;
}

return "{$this->parameters->host}:{$this->parameters->port}";
}




public function __toString()
{
if (!isset($this->cachedId)) {
$this->cachedId = $this->getIdentifier();
}

return $this->cachedId;
}




public function __sleep()
{
return array('parameters', 'initCommands');
}
}
<?php










namespace Predis\Connection;

use Predis\Command\CommandInterface;
use Predis\NotSupportedException;
use Predis\Response\Error as ErrorResponse;
use Predis\Response\Status as StatusResponse;































class PhpiredisStreamConnection extends StreamConnection
{
private $reader;




public function __construct(ParametersInterface $parameters)
{
$this->assertExtensions();

parent::__construct($parameters);

$this->reader = $this->createReader();
}




public function __destruct()
{
parent::__destruct();

phpiredis_reader_destroy($this->reader);
}




public function disconnect()
{
phpiredis_reader_reset($this->reader);

parent::disconnect();
}




private function assertExtensions()
{
if (!extension_loaded('phpiredis')) {
throw new NotSupportedException(
'The "phpiredis" extension is required by this connection backend.'
);
}
}




protected function assertParameters(ParametersInterface $parameters)
{
switch ($parameters->scheme) {
case 'tcp':
case 'redis':
case 'unix':
break;

case 'tls':
case 'rediss':
throw new \InvalidArgumentException('SSL encryption is not supported by this connection backend.');

default:
throw new \InvalidArgumentException("Invalid scheme: '$parameters->scheme'.");
}

return $parameters;
}




protected function createStreamSocket(ParametersInterface $parameters, $address, $flags, $context = null)
{
$socket = null;
$timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0);

$resource = @stream_socket_client($address, $errno, $errstr, $timeout, $flags);

if (!$resource) {
$this->onConnectionError(trim($errstr), $errno);
}

if (isset($parameters->read_write_timeout) && function_exists('socket_import_stream')) {
$rwtimeout = (float) $parameters->read_write_timeout;
$rwtimeout = $rwtimeout > 0 ? $rwtimeout : -1;

$timeout = array(
'sec' => $timeoutSeconds = floor($rwtimeout),
'usec' => ($rwtimeout - $timeoutSeconds) * 1000000,
);

$socket = $socket ?: socket_import_stream($resource);
@socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, $timeout);
@socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, $timeout);
}

if (isset($parameters->tcp_nodelay) && function_exists('socket_import_stream')) {
$socket = $socket ?: socket_import_stream($resource);
socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $parameters->tcp_nodelay);
}

return $resource;
}






private function createReader()
{
$reader = phpiredis_reader_create();

phpiredis_reader_set_status_handler($reader, $this->getStatusHandler());
phpiredis_reader_set_error_handler($reader, $this->getErrorHandler());

return $reader;
}






protected function getReader()
{
return $this->reader;
}






protected function getStatusHandler()
{
static $statusHandler;

if (!$statusHandler) {
$statusHandler = function ($payload) {
return StatusResponse::get($payload);
};
}

return $statusHandler;
}






protected function getErrorHandler()
{
static $errorHandler;

if (!$errorHandler) {
$errorHandler = function ($errorMessage) {
return new ErrorResponse($errorMessage);
};
}

return $errorHandler;
}




public function read()
{
$socket = $this->getResource();
$reader = $this->reader;

while (PHPIREDIS_READER_STATE_INCOMPLETE === $state = phpiredis_reader_get_state($reader)) {
$buffer = stream_socket_recvfrom($socket, 4096);

if ($buffer === false || $buffer === '') {
$this->onConnectionError('Error while reading bytes from the server.');
}

phpiredis_reader_feed($reader, $buffer);
}

if ($state === PHPIREDIS_READER_STATE_COMPLETE) {
return phpiredis_reader_get_reply($reader);
} else {
$this->onProtocolError(phpiredis_reader_get_error($reader));

return;
}
}




public function writeRequest(CommandInterface $command)
{
$arguments = $command->getArguments();
array_unshift($arguments, $command->getId());

$this->write(phpiredis_format_command($arguments));
}




public function __wakeup()
{
$this->assertExtensions();
$this->reader = $this->createReader();
}
}
<?php










namespace Predis\Connection;

use Predis\Command\CommandInterface;







interface AggregateConnectionInterface extends ConnectionInterface
{





public function add(NodeConnectionInterface $connection);








public function remove(NodeConnectionInterface $connection);








public function getConnection(CommandInterface $command);








public function getConnectionById($connectionID);
}
<?php










namespace Predis\Connection;

use Predis\Command\CommandInterface;
use Predis\Protocol\ProtocolProcessorInterface;
use Predis\Protocol\Text\ProtocolProcessor as TextProtocolProcessor;







class CompositeStreamConnection extends StreamConnection implements CompositeConnectionInterface
{
protected $protocol;





public function __construct(
ParametersInterface $parameters,
ProtocolProcessorInterface $protocol = null
) {
$this->parameters = $this->assertParameters($parameters);
$this->protocol = $protocol ?: new TextProtocolProcessor();
}




public function getProtocol()
{
return $this->protocol;
}




public function writeBuffer($buffer)
{
$this->write($buffer);
}




public function readBuffer($length)
{
if ($length <= 0) {
throw new \InvalidArgumentException('Length parameter must be greater than 0.');
}

$value = '';
$socket = $this->getResource();

do {
$chunk = fread($socket, $length);

if ($chunk === false || $chunk === '') {
$this->onConnectionError('Error while reading bytes from the server.');
}

$value .= $chunk;
} while (($length -= strlen($chunk)) > 0);

return $value;
}




public function readLine()
{
$value = '';
$socket = $this->getResource();

do {
$chunk = fgets($socket);

if ($chunk === false || $chunk === '') {
$this->onConnectionError('Error while reading line from the server.');
}

$value .= $chunk;
} while (substr($value, -2) !== "\r\n");

return substr($value, 0, -2);
}




public function writeRequest(CommandInterface $command)
{
$this->protocol->write($this, $command);
}




public function read()
{
return $this->protocol->read($this);
}




public function __sleep()
{
return array_merge(parent::__sleep(), array('protocol'));
}
}
<?php










namespace Predis\Connection;

use Predis\Command\CommandInterface;
use Predis\NotSupportedException;
use Predis\Protocol\ProtocolException;
use Predis\Response\Error as ErrorResponse;
use Predis\Response\Status as StatusResponse;



























class WebdisConnection implements NodeConnectionInterface
{
private $parameters;
private $resource;
private $reader;






public function __construct(ParametersInterface $parameters)
{
$this->assertExtensions();

if ($parameters->scheme !== 'http') {
throw new \InvalidArgumentException("Invalid scheme: '{$parameters->scheme}'.");
}

$this->parameters = $parameters;

$this->resource = $this->createCurl();
$this->reader = $this->createReader();
}





public function __destruct()
{
curl_close($this->resource);
phpiredis_reader_destroy($this->reader);
}








private function throwNotSupportedException($method)
{
$class = __CLASS__;
throw new NotSupportedException("The method $class::$method() is not supported.");
}




private function assertExtensions()
{
if (!extension_loaded('curl')) {
throw new NotSupportedException(
'The "curl" extension is required by this connection backend.'
);
}

if (!extension_loaded('phpiredis')) {
throw new NotSupportedException(
'The "phpiredis" extension is required by this connection backend.'
);
}
}






private function createCurl()
{
$parameters = $this->getParameters();
$timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0) * 1000;

if (filter_var($host = $parameters->host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$host = "[$host]";
}

$options = array(
CURLOPT_FAILONERROR => true,
CURLOPT_CONNECTTIMEOUT_MS => $timeout,
CURLOPT_URL => "$parameters->scheme://$host:$parameters->port",
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_POST => true,
CURLOPT_WRITEFUNCTION => array($this, 'feedReader'),
);

if (isset($parameters->user, $parameters->pass)) {
$options[CURLOPT_USERPWD] = "{$parameters->user}:{$parameters->pass}";
}

curl_setopt_array($resource = curl_init(), $options);

return $resource;
}






private function createReader()
{
$reader = phpiredis_reader_create();

phpiredis_reader_set_status_handler($reader, $this->getStatusHandler());
phpiredis_reader_set_error_handler($reader, $this->getErrorHandler());

return $reader;
}






protected function getStatusHandler()
{
static $statusHandler;

if (!$statusHandler) {
$statusHandler = function ($payload) {
return StatusResponse::get($payload);
};
}

return $statusHandler;
}






protected function getErrorHandler()
{
static $errorHandler;

if (!$errorHandler) {
$errorHandler = function ($errorMessage) {
return new ErrorResponse($errorMessage);
};
}

return $errorHandler;
}









protected function feedReader($resource, $buffer)
{
phpiredis_reader_feed($this->reader, $buffer);

return strlen($buffer);
}




public function connect()
{

 }




public function disconnect()
{

 }




public function isConnected()
{
return true;
}










protected function getCommandId(CommandInterface $command)
{
switch ($commandID = $command->getId()) {
case 'AUTH':
case 'SELECT':
case 'MULTI':
case 'EXEC':
case 'WATCH':
case 'UNWATCH':
case 'DISCARD':
case 'MONITOR':
throw new NotSupportedException("Command '$commandID' is not allowed by Webdis.");

default:
return $commandID;
}
}




public function writeRequest(CommandInterface $command)
{
$this->throwNotSupportedException(__FUNCTION__);
}




public function readResponse(CommandInterface $command)
{
$this->throwNotSupportedException(__FUNCTION__);
}




public function executeCommand(CommandInterface $command)
{
$resource = $this->resource;
$commandId = $this->getCommandId($command);

if ($arguments = $command->getArguments()) {
$arguments = implode('/', array_map('urlencode', $arguments));
$serializedCommand = "$commandId/$arguments.raw";
} else {
$serializedCommand = "$commandId.raw";
}

curl_setopt($resource, CURLOPT_POSTFIELDS, $serializedCommand);

if (curl_exec($resource) === false) {
$error = curl_error($resource);
$errno = curl_errno($resource);

throw new ConnectionException($this, trim($error), $errno);
}

if (phpiredis_reader_get_state($this->reader) !== PHPIREDIS_READER_STATE_COMPLETE) {
throw new ProtocolException($this, phpiredis_reader_get_error($this->reader));
}

return phpiredis_reader_get_reply($this->reader);
}




public function getResource()
{
return $this->resource;
}




public function getParameters()
{
return $this->parameters;
}




public function addConnectCommand(CommandInterface $command)
{
$this->throwNotSupportedException(__FUNCTION__);
}




public function read()
{
$this->throwNotSupportedException(__FUNCTION__);
}




public function __toString()
{
return "{$this->parameters->host}:{$this->parameters->port}";
}




public function __sleep()
{
return array('parameters');
}




public function __wakeup()
{
$this->assertExtensions();

$this->resource = $this->createCurl();
$this->reader = $this->createReader();
}
}
<?php










namespace Predis\Connection;

use Predis\CommunicationException;






class ConnectionException extends CommunicationException
{
}
<?php










namespace Predis\Connection;








class Parameters implements ParametersInterface
{
private $parameters;

private static $defaults = array(
'scheme' => 'tcp',
'host' => '127.0.0.1',
'port' => 6379,
);




public function __construct(array $parameters = array())
{
$this->parameters = $this->filter($parameters) + $this->getDefaults();
}






protected function getDefaults()
{
return self::$defaults;
}









public static function create($parameters)
{
if (is_string($parameters)) {
$parameters = static::parse($parameters);
}

return new static($parameters ?: array());
}



















public static function parse($uri)
{
if (stripos($uri, 'unix://') === 0) {

 
 $uri = str_ireplace('unix://', 'unix:', $uri);
}

if (!$parsed = parse_url($uri)) {
throw new \InvalidArgumentException("Invalid parameters URI: $uri");
}

if (
isset($parsed['host'])
&& false !== strpos($parsed['host'], '[')
&& false !== strpos($parsed['host'], ']')
) {
$parsed['host'] = substr($parsed['host'], 1, -1);
}

if (isset($parsed['query'])) {
parse_str($parsed['query'], $queryarray);
unset($parsed['query']);

$parsed = array_merge($parsed, $queryarray);
}

if (stripos($uri, 'redis') === 0) {
if (isset($parsed['user'])) {
if (strlen($parsed['user'])) {
$parsed['username'] = $parsed['user'];
}
unset($parsed['user']);
}

if (isset($parsed['pass'])) {
if (strlen($parsed['pass'])) {
$parsed['password'] = $parsed['pass'];
}
unset($parsed['pass']);
}

if (isset($parsed['path']) && preg_match('/^\/(\d+)(\/.*)?/', $parsed['path'], $path)) {
$parsed['database'] = $path[1];

if (isset($path[2])) {
$parsed['path'] = $path[2];
} else {
unset($parsed['path']);
}
}
}

return $parsed;
}








protected function filter(array $parameters)
{
return $parameters ?: array();
}




public function __get($parameter)
{
if (isset($this->parameters[$parameter])) {
return $this->parameters[$parameter];
}
}




public function __isset($parameter)
{
return isset($this->parameters[$parameter]);
}




public function toArray()
{
return $this->parameters;
}




public function __sleep()
{
return array('parameters');
}
}
<?php










namespace Predis\Connection;







interface CompositeConnectionInterface extends NodeConnectionInterface
{



public function getProtocol();






public function writeBuffer($buffer);








public function readBuffer($length);






public function readLine();
}
<?php










namespace Predis\Connection;

use Predis\Command\CommandInterface;







interface ConnectionInterface
{



public function connect();




public function disconnect();






public function isConnected();






public function writeRequest(CommandInterface $command);








public function readResponse(CommandInterface $command);









public function executeCommand(CommandInterface $command);
}
<?php










namespace Predis\Connection;

use Predis\Command\RawCommand;






class Factory implements FactoryInterface
{
private $defaults = array();

protected $schemes = array(
'tcp' => 'Predis\Connection\StreamConnection',
'unix' => 'Predis\Connection\StreamConnection',
'tls' => 'Predis\Connection\StreamConnection',
'redis' => 'Predis\Connection\StreamConnection',
'rediss' => 'Predis\Connection\StreamConnection',
'http' => 'Predis\Connection\WebdisConnection',
);












protected function checkInitializer($initializer)
{
if (is_callable($initializer)) {
return $initializer;
}

$class = new \ReflectionClass($initializer);

if (!$class->isSubclassOf('Predis\Connection\NodeConnectionInterface')) {
throw new \InvalidArgumentException(
'A connection initializer must be a valid connection class or a callable object.'
);
}

return $initializer;
}




public function define($scheme, $initializer)
{
$this->schemes[$scheme] = $this->checkInitializer($initializer);
}




public function undefine($scheme)
{
unset($this->schemes[$scheme]);
}




public function create($parameters)
{
if (!$parameters instanceof ParametersInterface) {
$parameters = $this->createParameters($parameters);
}

$scheme = $parameters->scheme;

if (!isset($this->schemes[$scheme])) {
throw new \InvalidArgumentException("Unknown connection scheme: '$scheme'.");
}

$initializer = $this->schemes[$scheme];

if (is_callable($initializer)) {
$connection = call_user_func($initializer, $parameters, $this);
} else {
$connection = new $initializer($parameters);
$this->prepareConnection($connection);
}

if (!$connection instanceof NodeConnectionInterface) {
throw new \UnexpectedValueException(
'Objects returned by connection initializers must implement '.
"'Predis\Connection\NodeConnectionInterface'."
);
}

return $connection;
}




public function aggregate(AggregateConnectionInterface $connection, array $parameters)
{
foreach ($parameters as $node) {
$connection->add($node instanceof NodeConnectionInterface ? $node : $this->create($node));
}
}









public function setDefaultParameters(array $parameters)
{
$this->defaults = $parameters;
}






public function getDefaultParameters()
{
return $this->defaults;
}








protected function createParameters($parameters)
{
if (is_string($parameters)) {
$parameters = Parameters::parse($parameters);
} else {
$parameters = $parameters ?: array();
}

if ($this->defaults) {
$parameters += $this->defaults;
}

return new Parameters($parameters);
}






protected function prepareConnection(NodeConnectionInterface $connection)
{
$parameters = $connection->getParameters();

if (isset($parameters->password) && strlen($parameters->password)) {
$cmdAuthArgs = isset($parameters->username) && strlen($parameters->username)
? array('AUTH', $parameters->username, $parameters->password)
: array('AUTH', $parameters->password);

$connection->addConnectCommand(
new RawCommand($cmdAuthArgs)
);
}

if (isset($parameters->database) && strlen($parameters->database)) {
$connection->addConnectCommand(
new RawCommand(array('SELECT', $parameters->database))
);
}
}
}
<?php










namespace Predis\Connection;

use Predis\Command\CommandInterface;
use Predis\Response\Error as ErrorResponse;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\Status as StatusResponse;


















class StreamConnection extends AbstractConnection
{





public function __destruct()
{
if (isset($this->parameters->persistent) && $this->parameters->persistent) {
return;
}

$this->disconnect();
}




protected function assertParameters(ParametersInterface $parameters)
{
switch ($parameters->scheme) {
case 'tcp':
case 'redis':
case 'unix':
break;

case 'tls':
case 'rediss':
$this->assertSslSupport($parameters);
break;

default:
throw new \InvalidArgumentException("Invalid scheme: '$parameters->scheme'.");
}

return $parameters;
}








protected function assertSslSupport(ParametersInterface $parameters)
{
if (
filter_var($parameters->persistent, FILTER_VALIDATE_BOOLEAN) &&
version_compare(PHP_VERSION, '7.0.0beta') < 0
) {
throw new \InvalidArgumentException('Persistent SSL connections require PHP >= 7.0.0.');
}
}




protected function createResource()
{
switch ($this->parameters->scheme) {
case 'tcp':
case 'redis':
return $this->tcpStreamInitializer($this->parameters);

case 'unix':
return $this->unixStreamInitializer($this->parameters);

case 'tls':
case 'rediss':
return $this->tlsStreamInitializer($this->parameters);

default:
throw new \InvalidArgumentException("Invalid scheme: '{$this->parameters->scheme}'.");
}
}










protected function createStreamSocket(ParametersInterface $parameters, $address, $flags)
{
$timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0);

if (!$resource = @stream_socket_client($address, $errno, $errstr, $timeout, $flags)) {
$this->onConnectionError(trim($errstr), $errno);
}

if (isset($parameters->read_write_timeout)) {
$rwtimeout = (float) $parameters->read_write_timeout;
$rwtimeout = $rwtimeout > 0 ? $rwtimeout : -1;
$timeoutSeconds = floor($rwtimeout);
$timeoutUSeconds = ($rwtimeout - $timeoutSeconds) * 1000000;
stream_set_timeout($resource, $timeoutSeconds, $timeoutUSeconds);
}

if (isset($parameters->tcp_nodelay) && function_exists('socket_import_stream')) {
$socket = socket_import_stream($resource);
socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $parameters->tcp_nodelay);
}

return $resource;
}








protected function tcpStreamInitializer(ParametersInterface $parameters)
{
if (!filter_var($parameters->host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$address = "tcp://$parameters->host:$parameters->port";
} else {
$address = "tcp://[$parameters->host]:$parameters->port";
}

$flags = STREAM_CLIENT_CONNECT;

if (isset($parameters->async_connect) && $parameters->async_connect) {
$flags |= STREAM_CLIENT_ASYNC_CONNECT;
}

if (isset($parameters->persistent)) {
if (false !== $persistent = filter_var($parameters->persistent, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)) {
$flags |= STREAM_CLIENT_PERSISTENT;

if ($persistent === null) {
$address = "{$address}/{$parameters->persistent}";
}
}
}

$resource = $this->createStreamSocket($parameters, $address, $flags);

return $resource;
}








protected function unixStreamInitializer(ParametersInterface $parameters)
{
if (!isset($parameters->path)) {
throw new \InvalidArgumentException('Missing UNIX domain socket path.');
}

$flags = STREAM_CLIENT_CONNECT;

if (isset($parameters->persistent)) {
if (false !== $persistent = filter_var($parameters->persistent, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)) {
$flags |= STREAM_CLIENT_PERSISTENT;

if ($persistent === null) {
throw new \InvalidArgumentException(
'Persistent connection IDs are not supported when using UNIX domain sockets.'
);
}
}
}

$resource = $this->createStreamSocket($parameters, "unix://{$parameters->path}", $flags);

return $resource;
}








protected function tlsStreamInitializer(ParametersInterface $parameters)
{
$resource = $this->tcpStreamInitializer($parameters);
$metadata = stream_get_meta_data($resource);


 if (isset($metadata['crypto'])) {
return $resource;
}

if (is_array($parameters->ssl)) {
$options = $parameters->ssl;
} else {
$options = array();
}

if (!isset($options['crypto_type'])) {
$options['crypto_type'] = STREAM_CRYPTO_METHOD_TLS_CLIENT;
}

if (!stream_context_set_option($resource, array('ssl' => $options))) {
$this->onConnectionError('Error while setting SSL context options');
}

if (!stream_socket_enable_crypto($resource, true, $options['crypto_type'])) {
$this->onConnectionError('Error while switching to encrypted communication');
}

return $resource;
}




public function connect()
{
if (parent::connect() && $this->initCommands) {
foreach ($this->initCommands as $command) {
$response = $this->executeCommand($command);

if ($response instanceof ErrorResponseInterface) {
$this->onConnectionError("`{$command->getId()}` failed: $response", 0);
}
}
}
}




public function disconnect()
{
if ($this->isConnected()) {
fclose($this->getResource());
parent::disconnect();
}
}







protected function write($buffer)
{
$socket = $this->getResource();

while (($length = strlen($buffer)) > 0) {
$written = @fwrite($socket, $buffer);

if ($length === $written) {
return;
}

if ($written === false || $written === 0) {
$this->onConnectionError('Error while writing bytes to the server.');
}

$buffer = substr($buffer, $written);
}
}




public function read()
{
$socket = $this->getResource();
$chunk = fgets($socket);

if ($chunk === false || $chunk === '') {
$this->onConnectionError('Error while reading line from the server.');
}

$prefix = $chunk[0];
$payload = substr($chunk, 1, -2);

switch ($prefix) {
case '+':
return StatusResponse::get($payload);

case '$':
$size = (int) $payload;

if ($size === -1) {
return;
}

$bulkData = '';
$bytesLeft = ($size += 2);

do {
$chunk = fread($socket, min($bytesLeft, 4096));

if ($chunk === false || $chunk === '') {
$this->onConnectionError('Error while reading bytes from the server.');
}

$bulkData .= $chunk;
$bytesLeft = $size - strlen($bulkData);
} while ($bytesLeft > 0);

return substr($bulkData, 0, -2);

case '*':
$count = (int) $payload;

if ($count === -1) {
return;
}

$multibulk = array();

for ($i = 0; $i < $count; ++$i) {
$multibulk[$i] = $this->read();
}

return $multibulk;

case ':':
$integer = (int) $payload;
return $integer == $payload ? $integer : $payload;

case '-':
return new ErrorResponse($payload);

default:
$this->onProtocolError("Unknown response prefix: '$prefix'.");

return;
}
}




public function writeRequest(CommandInterface $command)
{
$commandID = $command->getId();
$arguments = $command->getArguments();

$cmdlen = strlen($commandID);
$reqlen = count($arguments) + 1;

$buffer = "*{$reqlen}\r\n\${$cmdlen}\r\n{$commandID}\r\n";

foreach ($arguments as $argument) {
$arglen = strlen(strval($argument));
$buffer .= "\${$arglen}\r\n{$argument}\r\n";
}

$this->write($buffer);
}
}
<?php










namespace Predis\Connection;

use Predis\Command\CommandInterface;






interface NodeConnectionInterface extends ConnectionInterface
{





public function __toString();






public function getResource();






public function getParameters();







public function addConnectCommand(CommandInterface $command);






public function read();
}
<?php










namespace Predis\Connection;






interface FactoryInterface
{






public function define($scheme, $initializer);






public function undefine($scheme);








public function create($parameters);







public function aggregate(AggregateConnectionInterface $aggregate, array $parameters);
}
<?php










namespace Predis\Connection;

use Predis\Command\CommandInterface;
use Predis\NotSupportedException;
use Predis\Response\Error as ErrorResponse;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\Status as StatusResponse;




























class PhpiredisSocketConnection extends AbstractConnection
{
private $reader;




public function __construct(ParametersInterface $parameters)
{
$this->assertExtensions();

parent::__construct($parameters);

$this->reader = $this->createReader();
}





public function __destruct()
{
parent::__destruct();

phpiredis_reader_destroy($this->reader);
}




protected function assertExtensions()
{
if (!extension_loaded('sockets')) {
throw new NotSupportedException(
'The "sockets" extension is required by this connection backend.'
);
}

if (!extension_loaded('phpiredis')) {
throw new NotSupportedException(
'The "phpiredis" extension is required by this connection backend.'
);
}
}




protected function assertParameters(ParametersInterface $parameters)
{
switch ($parameters->scheme) {
case 'tcp':
case 'redis':
case 'unix':
break;

default:
throw new \InvalidArgumentException("Invalid scheme: '$parameters->scheme'.");
}

if (isset($parameters->persistent)) {
throw new NotSupportedException(
'Persistent connections are not supported by this connection backend.'
);
}

return $parameters;
}






private function createReader()
{
$reader = phpiredis_reader_create();

phpiredis_reader_set_status_handler($reader, $this->getStatusHandler());
phpiredis_reader_set_error_handler($reader, $this->getErrorHandler());

return $reader;
}






protected function getReader()
{
return $this->reader;
}






protected function getStatusHandler()
{
static $statusHandler;

if (!$statusHandler) {
$statusHandler = function ($payload) {
return StatusResponse::get($payload);
};
}

return $statusHandler;
}






protected function getErrorHandler()
{
static $errorHandler;

if (!$errorHandler) {
$errorHandler = function ($errorMessage) {
return new ErrorResponse($errorMessage);
};
}

return $errorHandler;
}




private function emitSocketError()
{
$errno = socket_last_error();
$errstr = socket_strerror($errno);

$this->disconnect();

$this->onConnectionError(trim($errstr), $errno);
}








protected static function getAddress(ParametersInterface $parameters)
{
if (filter_var($host = $parameters->host, FILTER_VALIDATE_IP)) {
return $host;
}

if ($host === $address = gethostbyname($host)) {
return false;
}

return $address;
}




protected function createResource()
{
$parameters = $this->parameters;

if ($parameters->scheme === 'unix') {
$address = $parameters->path;
$domain = AF_UNIX;
$protocol = 0;
} else {
if (false === $address = self::getAddress($parameters)) {
$this->onConnectionError("Cannot resolve the address of '$parameters->host'.");
}

$domain = filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? AF_INET6 : AF_INET;
$protocol = SOL_TCP;
}

if (false === $socket = @socket_create($domain, SOCK_STREAM, $protocol)) {
$this->emitSocketError();
}

$this->setSocketOptions($socket, $parameters);
$this->connectWithTimeout($socket, $address, $parameters);

return $socket;
}







private function setSocketOptions($socket, ParametersInterface $parameters)
{
if ($parameters->scheme !== 'unix') {
if (!socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1)) {
$this->emitSocketError();
}

if (!socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)) {
$this->emitSocketError();
}
}

if (isset($parameters->read_write_timeout)) {
$rwtimeout = (float) $parameters->read_write_timeout;
$timeoutSec = floor($rwtimeout);
$timeoutUsec = ($rwtimeout - $timeoutSec) * 1000000;

$timeout = array(
'sec' => $timeoutSec,
'usec' => $timeoutUsec,
);

if (!socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, $timeout)) {
$this->emitSocketError();
}

if (!socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, $timeout)) {
$this->emitSocketError();
}
}
}










private function connectWithTimeout($socket, $address, ParametersInterface $parameters)
{
socket_set_nonblock($socket);

if (@socket_connect($socket, $address, (int) $parameters->port) === false) {
$error = socket_last_error();

if ($error != SOCKET_EINPROGRESS && $error != SOCKET_EALREADY) {
$this->emitSocketError();
}
}

socket_set_block($socket);

$null = null;
$selectable = array($socket);

$timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0);
$timeoutSecs = floor($timeout);
$timeoutUSecs = ($timeout - $timeoutSecs) * 1000000;

$selected = socket_select($selectable, $selectable, $null, $timeoutSecs, $timeoutUSecs);

if ($selected === 2) {
$this->onConnectionError('Connection refused.', SOCKET_ECONNREFUSED);
}

if ($selected === 0) {
$this->onConnectionError('Connection timed out.', SOCKET_ETIMEDOUT);
}

if ($selected === false) {
$this->emitSocketError();
}
}




public function connect()
{
if (parent::connect() && $this->initCommands) {
foreach ($this->initCommands as $command) {
$response = $this->executeCommand($command);

if ($response instanceof ErrorResponseInterface) {
$this->onConnectionError("`{$command->getId()}` failed: $response", 0);
}
}
}
}




public function disconnect()
{
if ($this->isConnected()) {
phpiredis_reader_reset($this->reader);
socket_close($this->getResource());

parent::disconnect();
}
}




protected function write($buffer)
{
$socket = $this->getResource();

while (($length = strlen($buffer)) > 0) {
$written = socket_write($socket, $buffer, $length);

if ($length === $written) {
return;
}

if ($written === false) {
$this->onConnectionError('Error while writing bytes to the server.');
}

$buffer = substr($buffer, $written);
}
}




public function read()
{
$socket = $this->getResource();
$reader = $this->reader;

while (PHPIREDIS_READER_STATE_INCOMPLETE === $state = phpiredis_reader_get_state($reader)) {
if (@socket_recv($socket, $buffer, 4096, 0) === false || $buffer === '' || $buffer === null) {
$this->emitSocketError();
}

phpiredis_reader_feed($reader, $buffer);
}

if ($state === PHPIREDIS_READER_STATE_COMPLETE) {
return phpiredis_reader_get_reply($reader);
} else {
$this->onProtocolError(phpiredis_reader_get_error($reader));

return;
}
}




public function writeRequest(CommandInterface $command)
{
$arguments = $command->getArguments();
array_unshift($arguments, $command->getId());

$this->write(phpiredis_format_command($arguments));
}




public function __wakeup()
{
$this->assertExtensions();
$this->reader = $this->createReader();
}
}
<?php










namespace Predis\Connection;























interface ParametersInterface
{







public function __isset($parameter);








public function __get($parameter);






public function toArray();
}
<?php










namespace Predis\Connection\Aggregate;

use Predis\ClientException;
use Predis\Command\CommandInterface;
use Predis\Command\RawCommand;
use Predis\Connection\ConnectionException;
use Predis\Connection\FactoryInterface;
use Predis\Connection\NodeConnectionInterface;
use Predis\Replication\MissingMasterException;
use Predis\Replication\ReplicationStrategy;
use Predis\Response\ErrorInterface as ResponseErrorInterface;







class MasterSlaveReplication implements ReplicationInterface
{



protected $strategy;




protected $master;




protected $slaves = array();




protected $current;




protected $autoDiscovery = false;




protected $connectionFactory;




public function __construct(ReplicationStrategy $strategy = null)
{
$this->strategy = $strategy ?: new ReplicationStrategy();
}






public function setAutoDiscovery($value)
{
if (!$this->connectionFactory) {
throw new ClientException('Automatic discovery requires a connection factory');
}

$this->autoDiscovery = (bool) $value;
}







public function setConnectionFactory(FactoryInterface $connectionFactory)
{
$this->connectionFactory = $connectionFactory;
}




protected function reset()
{
$this->current = null;
}




public function add(NodeConnectionInterface $connection)
{
$alias = $connection->getParameters()->alias;

if ($alias === 'master') {
$this->master = $connection;
} else {
$this->slaves[$alias ?: "slave-$connection"] = $connection;
}

$this->reset();
}




public function remove(NodeConnectionInterface $connection)
{
if ($connection->getParameters()->alias === 'master') {
$this->master = null;
$this->reset();

return true;
} else {
if (($id = array_search($connection, $this->slaves, true)) !== false) {
unset($this->slaves[$id]);
$this->reset();

return true;
}
}

return false;
}




public function getConnection(CommandInterface $command)
{
if (!$this->current) {
if ($this->strategy->isReadOperation($command) && $slave = $this->pickSlave()) {
$this->current = $slave;
} else {
$this->current = $this->getMasterOrDie();
}

return $this->current;
}

if ($this->current === $master = $this->getMasterOrDie()) {
return $master;
}

if (!$this->strategy->isReadOperation($command) || !$this->slaves) {
$this->current = $master;
}

return $this->current;
}




public function getConnectionById($connectionId)
{
if ($connectionId === 'master') {
return $this->master;
}

if (isset($this->slaves[$connectionId])) {
return $this->slaves[$connectionId];
}

return;
}




public function switchTo($connection)
{
if (!$connection instanceof NodeConnectionInterface) {
$connection = $this->getConnectionById($connection);
}

if (!$connection) {
throw new \InvalidArgumentException('Invalid connection or connection not found.');
}

if ($connection !== $this->master && !in_array($connection, $this->slaves, true)) {
throw new \InvalidArgumentException('Invalid connection or connection not found.');
}

$this->current = $connection;
}




public function switchToMaster()
{
$this->switchTo('master');
}




public function switchToSlave()
{
$connection = $this->pickSlave();
$this->switchTo($connection);
}




public function getCurrent()
{
return $this->current;
}




public function getMaster()
{
return $this->master;
}






private function getMasterOrDie()
{
if (!$connection = $this->getMaster()) {
throw new MissingMasterException('No master server available for replication');
}

return $connection;
}




public function getSlaves()
{
return array_values($this->slaves);
}






public function getReplicationStrategy()
{
return $this->strategy;
}






protected function pickSlave()
{
if ($this->slaves) {
return $this->slaves[array_rand($this->slaves)];
}
}




public function isConnected()
{
return $this->current ? $this->current->isConnected() : false;
}




public function connect()
{
if (!$this->current) {
if (!$this->current = $this->pickSlave()) {
if (!$this->current = $this->getMaster()) {
throw new ClientException('No available connection for replication');
}
}
}

$this->current->connect();
}




public function disconnect()
{
if ($this->master) {
$this->master->disconnect();
}

foreach ($this->slaves as $connection) {
$connection->disconnect();
}
}








private function handleInfoResponse($response)
{
$info = array();

foreach (preg_split('/\r?\n/', $response) as $row) {
if (strpos($row, ':') === false) {
continue;
}

list($k, $v) = explode(':', $row, 2);
$info[$k] = $v;
}

return $info;
}




public function discover()
{
if (!$this->connectionFactory) {
throw new ClientException('Discovery requires a connection factory');
}

RETRY_FETCH: {
try {
if ($connection = $this->getMaster()) {
$this->discoverFromMaster($connection, $this->connectionFactory);
} elseif ($connection = $this->pickSlave()) {
$this->discoverFromSlave($connection, $this->connectionFactory);
} else {
throw new ClientException('No connection available for discovery');
}
} catch (ConnectionException $exception) {
$this->remove($connection);
goto RETRY_FETCH;
}
}
}







protected function discoverFromMaster(NodeConnectionInterface $connection, FactoryInterface $connectionFactory)
{
$response = $connection->executeCommand(RawCommand::create('INFO', 'REPLICATION'));
$replication = $this->handleInfoResponse($response);

if ($replication['role'] !== 'master') {
throw new ClientException("Role mismatch (expected master, got slave) [$connection]");
}

$this->slaves = array();

foreach ($replication as $k => $v) {
$parameters = null;

if (strpos($k, 'slave') === 0 && preg_match('/ip=(?P<host>.*),port=(?P<port>\d+)/', $v, $parameters)) {
$slaveConnection = $connectionFactory->create(array(
'host' => $parameters['host'],
'port' => $parameters['port'],
));

$this->add($slaveConnection);
}
}
}







protected function discoverFromSlave(NodeConnectionInterface $connection, FactoryInterface $connectionFactory)
{
$response = $connection->executeCommand(RawCommand::create('INFO', 'REPLICATION'));
$replication = $this->handleInfoResponse($response);

if ($replication['role'] !== 'slave') {
throw new ClientException("Role mismatch (expected slave, got master) [$connection]");
}

$masterConnection = $connectionFactory->create(array(
'host' => $replication['master_host'],
'port' => $replication['master_port'],
'alias' => 'master',
));

$this->add($masterConnection);

$this->discoverFromMaster($masterConnection, $connectionFactory);
}









private function retryCommandOnFailure(CommandInterface $command, $method)
{
RETRY_COMMAND: {
try {
$connection = $this->getConnection($command);
$response = $connection->$method($command);

if ($response instanceof ResponseErrorInterface && $response->getErrorType() === 'LOADING') {
throw new ConnectionException($connection, "Redis is loading the dataset in memory [$connection]");
}
} catch (ConnectionException $exception) {
$connection = $exception->getConnection();
$connection->disconnect();

if ($connection === $this->master && !$this->autoDiscovery) {

 
 
 throw $exception;
} else {

 
 $this->remove($connection);
}


 if (!$this->slaves && !$this->master) {
throw $exception;
} elseif ($this->autoDiscovery) {
$this->discover();
}

goto RETRY_COMMAND;
} catch (MissingMasterException $exception) {
if ($this->autoDiscovery) {
$this->discover();
} else {
throw $exception;
}

goto RETRY_COMMAND;
}
}

return $response;
}




public function writeRequest(CommandInterface $command)
{
$this->retryCommandOnFailure($command, __FUNCTION__);
}




public function readResponse(CommandInterface $command)
{
return $this->retryCommandOnFailure($command, __FUNCTION__);
}




public function executeCommand(CommandInterface $command)
{
return $this->retryCommandOnFailure($command, __FUNCTION__);
}




public function __sleep()
{
return array('master', 'slaves', 'strategy');
}
}
<?php










namespace Predis\Connection\Aggregate;

use Predis\Connection\AggregateConnectionInterface;
use Predis\Connection\NodeConnectionInterface;






interface ReplicationInterface extends AggregateConnectionInterface
{





public function switchTo($connection);







public function getCurrent();






public function getMaster();






public function getSlaves();
}
<?php










namespace Predis\Connection\Aggregate;

use Predis\Connection\AggregateConnectionInterface;







interface ClusterInterface extends AggregateConnectionInterface
{
}
<?php










namespace Predis\Connection\Aggregate;

use Predis\Cluster\PredisStrategy;
use Predis\Cluster\StrategyInterface;
use Predis\Command\CommandInterface;
use Predis\Connection\NodeConnectionInterface;
use Predis\NotSupportedException;









class PredisCluster implements ClusterInterface, \IteratorAggregate, \Countable
{
private $pool;
private $strategy;
private $distributor;




public function __construct(StrategyInterface $strategy = null)
{
$this->pool = array();
$this->strategy = $strategy ?: new PredisStrategy();
$this->distributor = $this->strategy->getDistributor();
}




public function isConnected()
{
foreach ($this->pool as $connection) {
if ($connection->isConnected()) {
return true;
}
}

return false;
}




public function connect()
{
foreach ($this->pool as $connection) {
$connection->connect();
}
}




public function disconnect()
{
foreach ($this->pool as $connection) {
$connection->disconnect();
}
}




public function add(NodeConnectionInterface $connection)
{
$parameters = $connection->getParameters();

if (isset($parameters->alias)) {
$this->pool[$parameters->alias] = $connection;
} else {
$this->pool[] = $connection;
}

$weight = isset($parameters->weight) ? $parameters->weight : null;
$this->distributor->add($connection, $weight);
}




public function remove(NodeConnectionInterface $connection)
{
if (($id = array_search($connection, $this->pool, true)) !== false) {
unset($this->pool[$id]);
$this->distributor->remove($connection);

return true;
}

return false;
}








public function removeById($connectionID)
{
if ($connection = $this->getConnectionById($connectionID)) {
return $this->remove($connection);
}

return false;
}




public function getConnection(CommandInterface $command)
{
$slot = $this->strategy->getSlot($command);

if (!isset($slot)) {
throw new NotSupportedException(
"Cannot use '{$command->getId()}' over clusters of connections."
);
}

$node = $this->distributor->getBySlot($slot);

return $node;
}




public function getConnectionById($connectionID)
{
return isset($this->pool[$connectionID]) ? $this->pool[$connectionID] : null;
}








public function getConnectionByKey($key)
{
$hash = $this->strategy->getSlotByKey($key);
$node = $this->distributor->getBySlot($hash);

return $node;
}







public function getClusterStrategy()
{
return $this->strategy;
}





 public function count()
{
return count($this->pool);
}





 public function getIterator()
{
return new \ArrayIterator($this->pool);
}




public function writeRequest(CommandInterface $command)
{
$this->getConnection($command)->writeRequest($command);
}




public function readResponse(CommandInterface $command)
{
return $this->getConnection($command)->readResponse($command);
}




public function executeCommand(CommandInterface $command)
{
return $this->getConnection($command)->executeCommand($command);
}








public function executeCommandOnNodes(CommandInterface $command)
{
$responses = array();

foreach ($this->pool as $connection) {
$responses[] = $connection->executeCommand($command);
}

return $responses;
}
}
<?php










namespace Predis\Connection\Aggregate;

use Predis\Command\CommandInterface;
use Predis\Command\RawCommand;
use Predis\CommunicationException;
use Predis\Connection\ConnectionException;
use Predis\Connection\FactoryInterface as ConnectionFactoryInterface;
use Predis\Connection\NodeConnectionInterface;
use Predis\Connection\Parameters;
use Predis\Replication\ReplicationStrategy;
use Predis\Replication\RoleException;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\ServerException;





class SentinelReplication implements ReplicationInterface
{



protected $master;




protected $slaves = array();




protected $current;




protected $service;




protected $connectionFactory;




protected $strategy;




protected $sentinels = array();




protected $sentinelConnection;




protected $sentinelTimeout = 0.100;










protected $retryLimit = 20;







protected $retryWait = 1000;






protected $updateSentinels = false;







public function __construct(
$service,
array $sentinels,
ConnectionFactoryInterface $connectionFactory,
ReplicationStrategy $strategy = null
) {
$this->sentinels = $sentinels;
$this->service = $service;
$this->connectionFactory = $connectionFactory;
$this->strategy = $strategy ?: new ReplicationStrategy();
}









public function setSentinelTimeout($timeout)
{
$this->sentinelTimeout = (float) $timeout;
}










public function setRetryLimit($retry)
{
$this->retryLimit = (int) $retry;
}







public function setRetryWait($milliseconds)
{
$this->retryWait = (float) $milliseconds;
}






public function setUpdateSentinels($update)
{
$this->updateSentinels = (bool) $update;
}




protected function reset()
{
$this->current = null;
}




protected function wipeServerList()
{
$this->reset();

$this->master = null;
$this->slaves = array();
}




public function add(NodeConnectionInterface $connection)
{
$alias = $connection->getParameters()->alias;

if ($alias === 'master') {
$this->master = $connection;
} else {
$this->slaves[$alias ?: count($this->slaves)] = $connection;
}

$this->reset();
}




public function remove(NodeConnectionInterface $connection)
{
if ($connection === $this->master) {
$this->master = null;
$this->reset();

return true;
}

if (false !== $id = array_search($connection, $this->slaves, true)) {
unset($this->slaves[$id]);
$this->reset();

return true;
}

return false;
}






protected function createSentinelConnection($parameters)
{
if ($parameters instanceof NodeConnectionInterface) {
return $parameters;
}

if (is_string($parameters)) {
$parameters = Parameters::parse($parameters);
}

if (is_array($parameters)) {

 
 
 
 
 
 $parameters['database'] = null;
$parameters['username'] = null;
$parameters['password'] = null;

if (!isset($parameters['timeout'])) {
$parameters['timeout'] = $this->sentinelTimeout;
}
}

$connection = $this->connectionFactory->create($parameters);

return $connection;
}








public function getSentinelConnection()
{
if (!$this->sentinelConnection) {
if (!$this->sentinels) {
throw new \Predis\ClientException('No sentinel server available for autodiscovery.');
}

$sentinel = array_shift($this->sentinels);
$this->sentinelConnection = $this->createSentinelConnection($sentinel);
}

return $this->sentinelConnection;
}




public function updateSentinels()
{
SENTINEL_QUERY: {
$sentinel = $this->getSentinelConnection();

try {
$payload = $sentinel->executeCommand(
RawCommand::create('SENTINEL', 'sentinels', $this->service)
);

$this->sentinels = array();

 $this->sentinels[] = $sentinel->getParameters()->toArray();

foreach ($payload as $sentinel) {
$this->sentinels[] = array(
'host' => $sentinel[3],
'port' => $sentinel[5],
);
}
} catch (ConnectionException $exception) {
$this->sentinelConnection = null;

goto SENTINEL_QUERY;
}
}
}




public function querySentinel()
{
$this->wipeServerList();

$this->updateSentinels();
$this->getMaster();
$this->getSlaves();
}







private function handleSentinelErrorResponse(NodeConnectionInterface $sentinel, ErrorResponseInterface $error)
{
if ($error->getErrorType() === 'IDONTKNOW') {
throw new ConnectionException($sentinel, $error->getMessage());
} else {
throw new ServerException($error->getMessage());
}
}









protected function querySentinelForMaster(NodeConnectionInterface $sentinel, $service)
{
$payload = $sentinel->executeCommand(
RawCommand::create('SENTINEL', 'get-master-addr-by-name', $service)
);

if ($payload === null) {
throw new ServerException('ERR No such master with that name');
}

if ($payload instanceof ErrorResponseInterface) {
$this->handleSentinelErrorResponse($sentinel, $payload);
}

return array(
'host' => $payload[0],
'port' => $payload[1],
'alias' => 'master',
);
}









protected function querySentinelForSlaves(NodeConnectionInterface $sentinel, $service)
{
$slaves = array();

$payload = $sentinel->executeCommand(
RawCommand::create('SENTINEL', 'slaves', $service)
);

if ($payload instanceof ErrorResponseInterface) {
$this->handleSentinelErrorResponse($sentinel, $payload);
}

foreach ($payload as $slave) {
$flags = explode(',', $slave[9]);

if (array_intersect($flags, array('s_down', 'o_down', 'disconnected'))) {
continue;
}

$slaves[] = array(
'host' => $slave[3],
'port' => $slave[5],
'alias' => "slave-$slave[1]",
);
}

return $slaves;
}




public function getCurrent()
{
return $this->current;
}




public function getMaster()
{
if ($this->master) {
return $this->master;
}

if ($this->updateSentinels) {
$this->updateSentinels();
}

SENTINEL_QUERY: {
$sentinel = $this->getSentinelConnection();

try {
$masterParameters = $this->querySentinelForMaster($sentinel, $this->service);
$masterConnection = $this->connectionFactory->create($masterParameters);

$this->add($masterConnection);
} catch (ConnectionException $exception) {
$this->sentinelConnection = null;

goto SENTINEL_QUERY;
}
}

return $masterConnection;
}




public function getSlaves()
{
if ($this->slaves) {
return array_values($this->slaves);
}

if ($this->updateSentinels) {
$this->updateSentinels();
}

SENTINEL_QUERY: {
$sentinel = $this->getSentinelConnection();

try {
$slavesParameters = $this->querySentinelForSlaves($sentinel, $this->service);

foreach ($slavesParameters as $slaveParameters) {
$this->add($this->connectionFactory->create($slaveParameters));
}
} catch (ConnectionException $exception) {
$this->sentinelConnection = null;

goto SENTINEL_QUERY;
}
}

return array_values($this->slaves ?: array());
}






protected function pickSlave()
{
if ($slaves = $this->getSlaves()) {
return $slaves[rand(1, count($slaves)) - 1];
}
}








private function getConnectionInternal(CommandInterface $command)
{
if (!$this->current) {
if ($this->strategy->isReadOperation($command) && $slave = $this->pickSlave()) {
$this->current = $slave;
} else {
$this->current = $this->getMaster();
}

return $this->current;
}

if ($this->current === $this->master) {
return $this->current;
}

if (!$this->strategy->isReadOperation($command)) {
$this->current = $this->getMaster();
}

return $this->current;
}









protected function assertConnectionRole(NodeConnectionInterface $connection, $role)
{
$role = strtolower($role);
$actualRole = $connection->executeCommand(RawCommand::create('ROLE'));

if ($role !== $actualRole[0]) {
throw new RoleException($connection, "Expected $role but got $actualRole[0] [$connection]");
}
}




public function getConnection(CommandInterface $command)
{
$connection = $this->getConnectionInternal($command);

if (!$connection->isConnected()) {

 
 $expectedRole = $this->strategy->isReadOperation($command) && $this->slaves ? 'slave' : 'master';
$this->assertConnectionRole($connection, $expectedRole);
}

return $connection;
}




public function getConnectionById($connectionId)
{
if ($connectionId === 'master') {
return $this->getMaster();
}

$this->getSlaves();

if (isset($this->slaves[$connectionId])) {
return $this->slaves[$connectionId];
}
}




public function switchTo($connection)
{
if (!$connection instanceof NodeConnectionInterface) {
$connection = $this->getConnectionById($connection);
}

if ($connection && $connection === $this->current) {
return;
}

if ($connection !== $this->master && !in_array($connection, $this->slaves, true)) {
throw new \InvalidArgumentException('Invalid connection or connection not found.');
}

$connection->connect();

if ($this->current) {
$this->current->disconnect();
}

$this->current = $connection;
}




public function switchToMaster()
{
$this->switchTo('master');
}




public function switchToSlave()
{
$connection = $this->pickSlave();
$this->switchTo($connection);
}




public function isConnected()
{
return $this->current ? $this->current->isConnected() : false;
}




public function connect()
{
if (!$this->current) {
if (!$this->current = $this->pickSlave()) {
$this->current = $this->getMaster();
}
}

$this->current->connect();
}




public function disconnect()
{
if ($this->master) {
$this->master->disconnect();
}

foreach ($this->slaves as $connection) {
$connection->disconnect();
}
}










private function retryCommandOnFailure(CommandInterface $command, $method)
{
$retries = 0;

SENTINEL_RETRY: {
try {
$response = $this->getConnection($command)->$method($command);
} catch (CommunicationException $exception) {
$this->wipeServerList();
$exception->getConnection()->disconnect();

if ($retries == $this->retryLimit) {
throw $exception;
}

usleep($this->retryWait * 1000);

++$retries;
goto SENTINEL_RETRY;
}
}

return $response;
}




public function writeRequest(CommandInterface $command)
{
$this->retryCommandOnFailure($command, __FUNCTION__);
}




public function readResponse(CommandInterface $command)
{
return $this->retryCommandOnFailure($command, __FUNCTION__);
}




public function executeCommand(CommandInterface $command)
{
return $this->retryCommandOnFailure($command, __FUNCTION__);
}






public function getReplicationStrategy()
{
return $this->strategy;
}




public function __sleep()
{
return array(
'master', 'slaves', 'service', 'sentinels', 'connectionFactory', 'strategy',
);
}
}
<?php










namespace Predis\Connection\Aggregate;

use Predis\ClientException;
use Predis\Cluster\RedisStrategy as RedisClusterStrategy;
use Predis\Cluster\StrategyInterface;
use Predis\Command\CommandInterface;
use Predis\Command\RawCommand;
use Predis\Connection\ConnectionException;
use Predis\Connection\FactoryInterface;
use Predis\Connection\NodeConnectionInterface;
use Predis\NotSupportedException;
use Predis\Response\ErrorInterface as ErrorResponseInterface;























class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
{
private $useClusterSlots = true;
private $pool = array();
private $slots = array();
private $slotsMap;
private $strategy;
private $connections;
private $retryLimit = 5;





public function __construct(
FactoryInterface $connections,
StrategyInterface $strategy = null
) {
$this->connections = $connections;
$this->strategy = $strategy ?: new RedisClusterStrategy();
}










public function setRetryLimit($retry)
{
$this->retryLimit = (int) $retry;
}




public function isConnected()
{
foreach ($this->pool as $connection) {
if ($connection->isConnected()) {
return true;
}
}

return false;
}




public function connect()
{
if ($connection = $this->getRandomConnection()) {
$connection->connect();
}
}




public function disconnect()
{
foreach ($this->pool as $connection) {
$connection->disconnect();
}
}




public function add(NodeConnectionInterface $connection)
{
$this->pool[(string) $connection] = $connection;
unset($this->slotsMap);
}




public function remove(NodeConnectionInterface $connection)
{
if (false !== $id = array_search($connection, $this->pool, true)) {
unset(
$this->pool[$id],
$this->slotsMap
);

$this->slots = array_diff($this->slots, array($connection));

return true;
}

return false;
}








public function removeById($connectionID)
{
if (isset($this->pool[$connectionID])) {
unset(
$this->pool[$connectionID],
$this->slotsMap
);

return true;
}

return false;
}












public function buildSlotsMap()
{
$this->slotsMap = array();

foreach ($this->pool as $connectionID => $connection) {
$parameters = $connection->getParameters();

if (!isset($parameters->slots)) {
continue;
}

foreach (explode(',', $parameters->slots) as $slotRange) {
$slots = explode('-', $slotRange, 2);

if (!isset($slots[1])) {
$slots[1] = $slots[0];
}

$this->setSlots($slots[0], $slots[1], $connectionID);
}
}

return $this->slotsMap;
}












private function queryClusterNodeForSlotsMap(NodeConnectionInterface $connection)
{
$retries = 0;
$command = RawCommand::create('CLUSTER', 'SLOTS');

RETRY_COMMAND: {
try {
$response = $connection->executeCommand($command);
} catch (ConnectionException $exception) {
$connection = $exception->getConnection();
$connection->disconnect();

$this->remove($connection);

if ($retries === $this->retryLimit) {
throw $exception;
}

if (!$connection = $this->getRandomConnection()) {
throw new ClientException('No connections left in the pool for `CLUSTER SLOTS`');
}

++$retries;
goto RETRY_COMMAND;
}
}

return $response;
}










public function askSlotsMap(NodeConnectionInterface $connection = null)
{
if (!$connection && !$connection = $this->getRandomConnection()) {
return array();
}

$this->resetSlotsMap();

$response = $this->queryClusterNodeForSlotsMap($connection);

foreach ($response as $slots) {

 
 list($start, $end, $master) = $slots;

if ($master[0] === '') {
$this->setSlots($start, $end, (string) $connection);
} else {
$this->setSlots($start, $end, "{$master[0]}:{$master[1]}");
}
}

return $this->slotsMap;
}




public function resetSlotsMap()
{
$this->slotsMap = array();
}








public function getSlotsMap()
{
if (!isset($this->slotsMap)) {
$this->slotsMap = array();
}

return $this->slotsMap;
}










public function setSlots($first, $last, $connection)
{
if ($first < 0x0000 || $first > 0x3FFF ||
$last < 0x0000 || $last > 0x3FFF ||
$last < $first
) {
throw new \OutOfBoundsException(
"Invalid slot range for $connection: [$first-$last]."
);
}

$slots = array_fill($first, $last - $first + 1, (string) $connection);
$this->slotsMap = $this->getSlotsMap() + $slots;
}










protected function guessNode($slot)
{
if (!$this->pool) {
throw new ClientException('No connections available in the pool');
}

if (!isset($this->slotsMap)) {
$this->buildSlotsMap();
}

if (isset($this->slotsMap[$slot])) {
return $this->slotsMap[$slot];
}

$count = count($this->pool);
$index = min((int) ($slot / (int) (16384 / $count)), $count - 1);
$nodes = array_keys($this->pool);

return $nodes[$index];
}








protected function createConnection($connectionID)
{
$separator = strrpos($connectionID, ':');

return $this->connections->create(array(
'host' => substr($connectionID, 0, $separator),
'port' => substr($connectionID, $separator + 1),
));
}




public function getConnection(CommandInterface $command)
{
$slot = $this->strategy->getSlot($command);

if (!isset($slot)) {
throw new NotSupportedException(
"Cannot use '{$command->getId()}' with redis-cluster."
);
}

if (isset($this->slots[$slot])) {
return $this->slots[$slot];
} else {
return $this->getConnectionBySlot($slot);
}
}










public function getConnectionBySlot($slot)
{
if ($slot < 0x0000 || $slot > 0x3FFF) {
throw new \OutOfBoundsException("Invalid slot [$slot].");
}

if (isset($this->slots[$slot])) {
return $this->slots[$slot];
}

$connectionID = $this->guessNode($slot);

if (!$connection = $this->getConnectionById($connectionID)) {
$connection = $this->createConnection($connectionID);
$this->pool[$connectionID] = $connection;
}

return $this->slots[$slot] = $connection;
}




public function getConnectionById($connectionID)
{
if (isset($this->pool[$connectionID])) {
return $this->pool[$connectionID];
}
}






protected function getRandomConnection()
{
if ($this->pool) {
return $this->pool[array_rand($this->pool)];
}
}








protected function move(NodeConnectionInterface $connection, $slot)
{
$this->pool[(string) $connection] = $connection;
$this->slots[(int) $slot] = $connection;
}









protected function onErrorResponse(CommandInterface $command, ErrorResponseInterface $error)
{
$details = explode(' ', $error->getMessage(), 2);

switch ($details[0]) {
case 'MOVED':
return $this->onMovedResponse($command, $details[1]);

case 'ASK':
return $this->onAskResponse($command, $details[1]);

default:
return $error;
}
}










protected function onMovedResponse(CommandInterface $command, $details)
{
list($slot, $connectionID) = explode(' ', $details, 2);

if (!$connection = $this->getConnectionById($connectionID)) {
$connection = $this->createConnection($connectionID);
}

if ($this->useClusterSlots) {
$this->askSlotsMap($connection);
}

$this->move($connection, $slot);
$response = $this->executeCommand($command);

return $response;
}










protected function onAskResponse(CommandInterface $command, $details)
{
list($slot, $connectionID) = explode(' ', $details, 2);

if (!$connection = $this->getConnectionById($connectionID)) {
$connection = $this->createConnection($connectionID);
}

$connection->executeCommand(RawCommand::create('ASKING'));
$response = $connection->executeCommand($command);

return $response;
}















private function retryCommandOnFailure(CommandInterface $command, $method)
{
$failure = false;

RETRY_COMMAND: {
try {
$response = $this->getConnection($command)->$method($command);
} catch (ConnectionException $exception) {
$connection = $exception->getConnection();
$connection->disconnect();

$this->remove($connection);

if ($failure) {
throw $exception;
} elseif ($this->useClusterSlots) {
$this->askSlotsMap();
}

$failure = true;

goto RETRY_COMMAND;
}
}

return $response;
}




public function writeRequest(CommandInterface $command)
{
$this->retryCommandOnFailure($command, __FUNCTION__);
}




public function readResponse(CommandInterface $command)
{
return $this->retryCommandOnFailure($command, __FUNCTION__);
}




public function executeCommand(CommandInterface $command)
{
$response = $this->retryCommandOnFailure($command, __FUNCTION__);

if ($response instanceof ErrorResponseInterface) {
return $this->onErrorResponse($command, $response);
}

return $response;
}





 public function count()
{
return count($this->pool);
}





 public function getIterator()
{
if ($this->useClusterSlots) {
$slotsmap = $this->getSlotsMap() ?: $this->askSlotsMap();
} else {
$slotsmap = $this->getSlotsMap() ?: $this->buildSlotsMap();
}

$connections = array();

foreach (array_unique($slotsmap) as $node) {
if (!$connection = $this->getConnectionById($node)) {
$this->add($connection = $this->createConnection($node));
}

$connections[] = $connection;
}

return new \ArrayIterator($connections);
}







public function getClusterStrategy()
{
return $this->strategy;
}







public function getConnectionFactory()
{
return $this->connections;
}














public function useClusterSlots($value)
{
$this->useClusterSlots = (bool) $value;
}
}
<?php










namespace Predis\Cluster;

use Predis\Cluster\Distributor\DistributorInterface;
use Predis\Command\CommandInterface;









interface StrategyInterface
{








public function getSlot(CommandInterface $command);









public function getSlotByKey($key);






public function getDistributor();
}
<?php










namespace Predis\Cluster;

use Predis\Cluster\Distributor\DistributorInterface;
use Predis\Cluster\Distributor\HashRing;






class PredisStrategy extends ClusterStrategy
{
protected $distributor;




public function __construct(DistributorInterface $distributor = null)
{
parent::__construct();

$this->distributor = $distributor ?: new HashRing();
}




public function getSlotByKey($key)
{
$key = $this->extractKeyTag($key);
$hash = $this->distributor->hash($key);
$slot = $this->distributor->getSlot($hash);

return $slot;
}




protected function checkSameSlotForKeys(array $keys)
{
if (!$count = count($keys)) {
return false;
}

$currentKey = $this->extractKeyTag($keys[0]);

for ($i = 1; $i < $count; ++$i) {
$nextKey = $this->extractKeyTag($keys[$i]);

if ($currentKey !== $nextKey) {
return false;
}

$currentKey = $nextKey;
}

return true;
}




public function getDistributor()
{
return $this->distributor;
}
}
<?php










namespace Predis\Cluster\Hash;







interface HashGeneratorInterface
{







public function hash($value);
}
<?php










namespace Predis\Cluster\Hash;






class CRC16 implements HashGeneratorInterface
{
private static $CCITT_16 = array(
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0,
);




public function hash($value)
{

 $crc = 0;
$CCITT_16 = self::$CCITT_16;

$value = (string) $value;
$strlen = strlen($value);

for ($i = 0; $i < $strlen; ++$i) {
$crc = (($crc << 8) ^ $CCITT_16[($crc >> 8) ^ ord($value[$i])]) & 0xFFFF;
}

return $crc;
}
}
<?php










namespace Predis\Cluster;

use Predis\Cluster\Hash\CRC16;
use Predis\Cluster\Hash\HashGeneratorInterface;
use Predis\NotSupportedException;







class RedisStrategy extends ClusterStrategy
{
protected $hashGenerator;




public function __construct(HashGeneratorInterface $hashGenerator = null)
{
parent::__construct();

$this->hashGenerator = $hashGenerator ?: new CRC16();
}




public function getSlotByKey($key)
{
$key = $this->extractKeyTag($key);
$slot = $this->hashGenerator->hash($key) & 0x3FFF;

return $slot;
}




public function getDistributor()
{
throw new NotSupportedException(
'This cluster strategy does not provide an external distributor'
);
}
}
<?php










namespace Predis\Cluster;

use Predis\Command\CommandInterface;
use Predis\Command\ScriptCommand;






abstract class ClusterStrategy implements StrategyInterface
{
protected $commands;




public function __construct()
{
$this->commands = $this->getDefaultCommands();
}






protected function getDefaultCommands()
{
$getKeyFromFirstArgument = array($this, 'getKeyFromFirstArgument');
$getKeyFromAllArguments = array($this, 'getKeyFromAllArguments');

return array(

'EXISTS' => $getKeyFromAllArguments,
'DEL' => $getKeyFromAllArguments,
'TYPE' => $getKeyFromFirstArgument,
'EXPIRE' => $getKeyFromFirstArgument,
'EXPIREAT' => $getKeyFromFirstArgument,
'PERSIST' => $getKeyFromFirstArgument,
'PEXPIRE' => $getKeyFromFirstArgument,
'PEXPIREAT' => $getKeyFromFirstArgument,
'TTL' => $getKeyFromFirstArgument,
'PTTL' => $getKeyFromFirstArgument,
'SORT' => array($this, 'getKeyFromSortCommand'),
'DUMP' => $getKeyFromFirstArgument,
'RESTORE' => $getKeyFromFirstArgument,


'APPEND' => $getKeyFromFirstArgument,
'DECR' => $getKeyFromFirstArgument,
'DECRBY' => $getKeyFromFirstArgument,
'GET' => $getKeyFromFirstArgument,
'GETBIT' => $getKeyFromFirstArgument,
'MGET' => $getKeyFromAllArguments,
'SET' => $getKeyFromFirstArgument,
'GETRANGE' => $getKeyFromFirstArgument,
'GETSET' => $getKeyFromFirstArgument,
'INCR' => $getKeyFromFirstArgument,
'INCRBY' => $getKeyFromFirstArgument,
'INCRBYFLOAT' => $getKeyFromFirstArgument,
'SETBIT' => $getKeyFromFirstArgument,
'SETEX' => $getKeyFromFirstArgument,
'MSET' => array($this, 'getKeyFromInterleavedArguments'),
'MSETNX' => array($this, 'getKeyFromInterleavedArguments'),
'SETNX' => $getKeyFromFirstArgument,
'SETRANGE' => $getKeyFromFirstArgument,
'STRLEN' => $getKeyFromFirstArgument,
'SUBSTR' => $getKeyFromFirstArgument,
'BITOP' => array($this, 'getKeyFromBitOp'),
'BITCOUNT' => $getKeyFromFirstArgument,
'BITFIELD' => $getKeyFromFirstArgument,


'LINSERT' => $getKeyFromFirstArgument,
'LINDEX' => $getKeyFromFirstArgument,
'LLEN' => $getKeyFromFirstArgument,
'LPOP' => $getKeyFromFirstArgument,
'RPOP' => $getKeyFromFirstArgument,
'RPOPLPUSH' => $getKeyFromAllArguments,
'BLPOP' => array($this, 'getKeyFromBlockingListCommands'),
'BRPOP' => array($this, 'getKeyFromBlockingListCommands'),
'BRPOPLPUSH' => array($this, 'getKeyFromBlockingListCommands'),
'LPUSH' => $getKeyFromFirstArgument,
'LPUSHX' => $getKeyFromFirstArgument,
'RPUSH' => $getKeyFromFirstArgument,
'RPUSHX' => $getKeyFromFirstArgument,
'LRANGE' => $getKeyFromFirstArgument,
'LREM' => $getKeyFromFirstArgument,
'LSET' => $getKeyFromFirstArgument,
'LTRIM' => $getKeyFromFirstArgument,


'SADD' => $getKeyFromFirstArgument,
'SCARD' => $getKeyFromFirstArgument,
'SDIFF' => $getKeyFromAllArguments,
'SDIFFSTORE' => $getKeyFromAllArguments,
'SINTER' => $getKeyFromAllArguments,
'SINTERSTORE' => $getKeyFromAllArguments,
'SUNION' => $getKeyFromAllArguments,
'SUNIONSTORE' => $getKeyFromAllArguments,
'SISMEMBER' => $getKeyFromFirstArgument,
'SMEMBERS' => $getKeyFromFirstArgument,
'SSCAN' => $getKeyFromFirstArgument,
'SPOP' => $getKeyFromFirstArgument,
'SRANDMEMBER' => $getKeyFromFirstArgument,
'SREM' => $getKeyFromFirstArgument,


'ZADD' => $getKeyFromFirstArgument,
'ZCARD' => $getKeyFromFirstArgument,
'ZCOUNT' => $getKeyFromFirstArgument,
'ZINCRBY' => $getKeyFromFirstArgument,
'ZINTERSTORE' => array($this, 'getKeyFromZsetAggregationCommands'),
'ZRANGE' => $getKeyFromFirstArgument,
'ZRANGEBYSCORE' => $getKeyFromFirstArgument,
'ZRANK' => $getKeyFromFirstArgument,
'ZREM' => $getKeyFromFirstArgument,
'ZREMRANGEBYRANK' => $getKeyFromFirstArgument,
'ZREMRANGEBYSCORE' => $getKeyFromFirstArgument,
'ZREVRANGE' => $getKeyFromFirstArgument,
'ZREVRANGEBYSCORE' => $getKeyFromFirstArgument,
'ZREVRANK' => $getKeyFromFirstArgument,
'ZSCORE' => $getKeyFromFirstArgument,
'ZUNIONSTORE' => array($this, 'getKeyFromZsetAggregationCommands'),
'ZSCAN' => $getKeyFromFirstArgument,
'ZLEXCOUNT' => $getKeyFromFirstArgument,
'ZRANGEBYLEX' => $getKeyFromFirstArgument,
'ZREMRANGEBYLEX' => $getKeyFromFirstArgument,
'ZREVRANGEBYLEX' => $getKeyFromFirstArgument,


'HDEL' => $getKeyFromFirstArgument,
'HEXISTS' => $getKeyFromFirstArgument,
'HGET' => $getKeyFromFirstArgument,
'HGETALL' => $getKeyFromFirstArgument,
'HMGET' => $getKeyFromFirstArgument,
'HMSET' => $getKeyFromFirstArgument,
'HINCRBY' => $getKeyFromFirstArgument,
'HINCRBYFLOAT' => $getKeyFromFirstArgument,
'HKEYS' => $getKeyFromFirstArgument,
'HLEN' => $getKeyFromFirstArgument,
'HSET' => $getKeyFromFirstArgument,
'HSETNX' => $getKeyFromFirstArgument,
'HVALS' => $getKeyFromFirstArgument,
'HSCAN' => $getKeyFromFirstArgument,
'HSTRLEN' => $getKeyFromFirstArgument,


'PFADD' => $getKeyFromFirstArgument,
'PFCOUNT' => $getKeyFromAllArguments,
'PFMERGE' => $getKeyFromAllArguments,


'EVAL' => array($this, 'getKeyFromScriptingCommands'),
'EVALSHA' => array($this, 'getKeyFromScriptingCommands'),


'GEOADD' => $getKeyFromFirstArgument,
'GEOHASH' => $getKeyFromFirstArgument,
'GEOPOS' => $getKeyFromFirstArgument,
'GEODIST' => $getKeyFromFirstArgument,
'GEORADIUS' => array($this, 'getKeyFromGeoradiusCommands'),
'GEORADIUSBYMEMBER' => array($this, 'getKeyFromGeoradiusCommands'),
);
}






public function getSupportedCommands()
{
return array_keys($this->commands);
}















public function setCommandHandler($commandID, $callback = null)
{
$commandID = strtoupper($commandID);

if (!isset($callback)) {
unset($this->commands[$commandID]);

return;
}

if (!is_callable($callback)) {
throw new \InvalidArgumentException(
'The argument must be a callable object or NULL.'
);
}

$this->commands[$commandID] = $callback;
}








protected function getKeyFromFirstArgument(CommandInterface $command)
{
return $command->getArgument(0);
}









protected function getKeyFromAllArguments(CommandInterface $command)
{
$arguments = $command->getArguments();

if ($this->checkSameSlotForKeys($arguments)) {
return $arguments[0];
}
}









protected function getKeyFromInterleavedArguments(CommandInterface $command)
{
$arguments = $command->getArguments();
$keys = array();

for ($i = 0; $i < count($arguments); $i += 2) {
$keys[] = $arguments[$i];
}

if ($this->checkSameSlotForKeys($keys)) {
return $arguments[0];
}
}








protected function getKeyFromSortCommand(CommandInterface $command)
{
$arguments = $command->getArguments();
$firstKey = $arguments[0];

if (1 === $argc = count($arguments)) {
return $firstKey;
}

$keys = array($firstKey);

for ($i = 1; $i < $argc; ++$i) {
if (strtoupper($arguments[$i]) === 'STORE') {
$keys[] = $arguments[++$i];
}
}

if ($this->checkSameSlotForKeys($keys)) {
return $firstKey;
}
}








protected function getKeyFromBlockingListCommands(CommandInterface $command)
{
$arguments = $command->getArguments();

if ($this->checkSameSlotForKeys(array_slice($arguments, 0, count($arguments) - 1))) {
return $arguments[0];
}
}








protected function getKeyFromBitOp(CommandInterface $command)
{
$arguments = $command->getArguments();

if ($this->checkSameSlotForKeys(array_slice($arguments, 1, count($arguments)))) {
return $arguments[1];
}
}








protected function getKeyFromGeoradiusCommands(CommandInterface $command)
{
$arguments = $command->getArguments();
$argc = count($arguments);
$startIndex = $command->getId() === 'GEORADIUS' ? 5 : 4;

if ($argc > $startIndex) {
$keys = array($arguments[0]);

for ($i = $startIndex; $i < $argc; ++$i) {
$argument = strtoupper($arguments[$i]);
if ($argument === 'STORE' || $argument === 'STOREDIST') {
$keys[] = $arguments[++$i];
}
}

if ($this->checkSameSlotForKeys($keys)) {
return $arguments[0];
} else {
return;
}
}

return $arguments[0];
}








protected function getKeyFromZsetAggregationCommands(CommandInterface $command)
{
$arguments = $command->getArguments();
$keys = array_merge(array($arguments[0]), array_slice($arguments, 2, $arguments[1]));

if ($this->checkSameSlotForKeys($keys)) {
return $arguments[0];
}
}








protected function getKeyFromScriptingCommands(CommandInterface $command)
{
if ($command instanceof ScriptCommand) {
$keys = $command->getKeys();
} else {
$keys = array_slice($args = $command->getArguments(), 2, $args[1]);
}

if ($keys && $this->checkSameSlotForKeys($keys)) {
return $keys[0];
}
}




public function getSlot(CommandInterface $command)
{
$slot = $command->getSlot();

if (!isset($slot) && isset($this->commands[$cmdID = $command->getId()])) {
$key = call_user_func($this->commands[$cmdID], $command);

if (isset($key)) {
$slot = $this->getSlotByKey($key);
$command->setSlot($slot);
}
}

return $slot;
}








protected function checkSameSlotForKeys(array $keys)
{
if (!$count = count($keys)) {
return false;
}

$currentSlot = $this->getSlotByKey($keys[0]);

for ($i = 1; $i < $count; ++$i) {
$nextSlot = $this->getSlotByKey($keys[$i]);

if ($currentSlot !== $nextSlot) {
return false;
}

$currentSlot = $nextSlot;
}

return true;
}









protected function extractKeyTag($key)
{
if (false !== $start = strpos($key, '{')) {
if (false !== ($end = strpos($key, '}', $start)) && $end !== ++$start) {
$key = substr($key, $start, $end - $start);
}
}

return $key;
}
}
<?php










namespace Predis\Cluster\Distributor;

use Predis\Cluster\Hash\HashGeneratorInterface;









class HashRing implements DistributorInterface, HashGeneratorInterface
{
const DEFAULT_REPLICAS = 128;
const DEFAULT_WEIGHT = 100;

private $ring;
private $ringKeys;
private $ringKeysCount;
private $replicas;
private $nodeHashCallback;
private $nodes = array();





public function __construct($replicas = self::DEFAULT_REPLICAS, $nodeHashCallback = null)
{
$this->replicas = $replicas;
$this->nodeHashCallback = $nodeHashCallback;
}







public function add($node, $weight = null)
{

 
 $this->nodes[] = array(
'object' => $node,
'weight' => (int) $weight ?: $this::DEFAULT_WEIGHT,
);

$this->reset();
}




public function remove($node)
{

 
 
 
 for ($i = 0; $i < count($this->nodes); ++$i) {
if ($this->nodes[$i]['object'] === $node) {
array_splice($this->nodes, $i, 1);
$this->reset();

break;
}
}
}




private function reset()
{
unset(
$this->ring,
$this->ringKeys,
$this->ringKeysCount
);
}






private function isInitialized()
{
return isset($this->ringKeys);
}






private function computeTotalWeight()
{
$totalWeight = 0;

foreach ($this->nodes as $node) {
$totalWeight += $node['weight'];
}

return $totalWeight;
}




private function initialize()
{
if ($this->isInitialized()) {
return;
}

if (!$this->nodes) {
throw new EmptyRingException('Cannot initialize an empty hashring.');
}

$this->ring = array();
$totalWeight = $this->computeTotalWeight();
$nodesCount = count($this->nodes);

foreach ($this->nodes as $node) {
$weightRatio = $node['weight'] / $totalWeight;
$this->addNodeToRing($this->ring, $node, $nodesCount, $this->replicas, $weightRatio);
}

ksort($this->ring, SORT_NUMERIC);
$this->ringKeys = array_keys($this->ring);
$this->ringKeysCount = count($this->ringKeys);
}










protected function addNodeToRing(&$ring, $node, $totalNodes, $replicas, $weightRatio)
{
$nodeObject = $node['object'];
$nodeHash = $this->getNodeHash($nodeObject);
$replicas = (int) round($weightRatio * $totalNodes * $replicas);

for ($i = 0; $i < $replicas; ++$i) {
$key = $this->hash("$nodeHash:$i");
$ring[$key] = $nodeObject;
}
}




protected function getNodeHash($nodeObject)
{
if (!isset($this->nodeHashCallback)) {
return (string) $nodeObject;
}

return call_user_func($this->nodeHashCallback, $nodeObject);
}




public function hash($value)
{
return crc32($value);
}




public function getByHash($hash)
{
return $this->ring[$this->getSlot($hash)];
}




public function getBySlot($slot)
{
$this->initialize();

if (isset($this->ring[$slot])) {
return $this->ring[$slot];
}
}




public function getSlot($hash)
{
$this->initialize();

$ringKeys = $this->ringKeys;
$upper = $this->ringKeysCount - 1;
$lower = 0;

while ($lower <= $upper) {
$index = ($lower + $upper) >> 1;
$item = $ringKeys[$index];

if ($item > $hash) {
$upper = $index - 1;
} elseif ($item < $hash) {
$lower = $index + 1;
} else {
return $item;
}
}

return $ringKeys[$this->wrapAroundStrategy($upper, $lower, $this->ringKeysCount)];
}




public function get($value)
{
$hash = $this->hash($value);
$node = $this->getByHash($hash);

return $node;
}










protected function wrapAroundStrategy($upper, $lower, $ringKeysCount)
{

 
 return $upper >= 0 ? $upper : $ringKeysCount - 1;
}




public function getHashGenerator()
{
return $this;
}
}
<?php










namespace Predis\Cluster\Distributor;






class EmptyRingException extends \Exception
{
}
<?php










namespace Predis\Cluster\Distributor;

use Predis\Cluster\Hash\HashGeneratorInterface;







interface DistributorInterface
{






public function add($node, $weight = null);






public function remove($node);









public function getSlot($hash);








public function getBySlot($slot);








public function getByHash($hash);








public function get($value);






public function getHashGenerator();
}
<?php










namespace Predis\Cluster\Distributor;









class KetamaRing extends HashRing
{
const DEFAULT_REPLICAS = 160;




public function __construct($nodeHashCallback = null)
{
parent::__construct($this::DEFAULT_REPLICAS, $nodeHashCallback);
}




protected function addNodeToRing(&$ring, $node, $totalNodes, $replicas, $weightRatio)
{
$nodeObject = $node['object'];
$nodeHash = $this->getNodeHash($nodeObject);
$replicas = (int) floor($weightRatio * $totalNodes * ($replicas / 4));

for ($i = 0; $i < $replicas; ++$i) {
$unpackedDigest = unpack('V4', md5("$nodeHash-$i", true));

foreach ($unpackedDigest as $key) {
$ring[$key] = $nodeObject;
}
}
}




public function hash($value)
{
$hash = unpack('V', md5($value, true));

return $hash[1];
}




protected function wrapAroundStrategy($upper, $lower, $ringKeysCount)
{

 
 return $lower < $ringKeysCount ? $lower : 0;
}
}
<?php










namespace Predis\Protocol;

use Predis\Command\CommandInterface;
use Predis\Connection\CompositeConnectionInterface;







interface ProtocolProcessorInterface
{






public function write(CompositeConnectionInterface $connection, CommandInterface $command);








public function read(CompositeConnectionInterface $connection);
}
<?php










namespace Predis\Protocol;

use Predis\CommunicationException;







class ProtocolException extends CommunicationException
{
}
<?php










namespace Predis\Protocol\Text;

use Predis\Command\CommandInterface;
use Predis\Connection\CompositeConnectionInterface;
use Predis\Protocol\ProtocolProcessorInterface;
use Predis\Protocol\RequestSerializerInterface;
use Predis\Protocol\ResponseReaderInterface;









class CompositeProtocolProcessor implements ProtocolProcessorInterface
{



protected $serializer;




protected $reader;





public function __construct(
RequestSerializerInterface $serializer = null,
ResponseReaderInterface $reader = null
) {
$this->setRequestSerializer($serializer ?: new RequestSerializer());
$this->setResponseReader($reader ?: new ResponseReader());
}




public function write(CompositeConnectionInterface $connection, CommandInterface $command)
{
$connection->writeBuffer($this->serializer->serialize($command));
}




public function read(CompositeConnectionInterface $connection)
{
return $this->reader->read($connection);
}






public function setRequestSerializer(RequestSerializerInterface $serializer)
{
$this->serializer = $serializer;
}






public function getRequestSerializer()
{
return $this->serializer;
}






public function setResponseReader(ResponseReaderInterface $reader)
{
$this->reader = $reader;
}






public function getResponseReader()
{
return $this->reader;
}
}
<?php










namespace Predis\Protocol\Text;

use Predis\Command\CommandInterface;
use Predis\CommunicationException;
use Predis\Connection\CompositeConnectionInterface;
use Predis\Protocol\ProtocolException;
use Predis\Protocol\ProtocolProcessorInterface;
use Predis\Response\Error as ErrorResponse;
use Predis\Response\Iterator\MultiBulk as MultiBulkIterator;
use Predis\Response\Status as StatusResponse;








class ProtocolProcessor implements ProtocolProcessorInterface
{
protected $mbiterable;
protected $serializer;




public function __construct()
{
$this->mbiterable = false;
$this->serializer = new RequestSerializer();
}




public function write(CompositeConnectionInterface $connection, CommandInterface $command)
{
$request = $this->serializer->serialize($command);
$connection->writeBuffer($request);
}




public function read(CompositeConnectionInterface $connection)
{
$chunk = $connection->readLine();
$prefix = $chunk[0];
$payload = substr($chunk, 1);

switch ($prefix) {
case '+':
return new StatusResponse($payload);

case '$':
$size = (int) $payload;
if ($size === -1) {
return;
}

return substr($connection->readBuffer($size + 2), 0, -2);

case '*':
$count = (int) $payload;

if ($count === -1) {
return;
}
if ($this->mbiterable) {
return new MultiBulkIterator($connection, $count);
}

$multibulk = array();

for ($i = 0; $i < $count; ++$i) {
$multibulk[$i] = $this->read($connection);
}

return $multibulk;

case ':':
$integer = (int) $payload;
return $integer == $payload ? $integer : $payload;

case '-':
return new ErrorResponse($payload);

default:
CommunicationException::handle(new ProtocolException(
$connection, "Unknown response prefix: '$prefix'."
));

return;
}
}












public function useIterableMultibulk($value)
{
$this->mbiterable = (bool) $value;
}
}
<?php










namespace Predis\Protocol\Text;

use Predis\CommunicationException;
use Predis\Connection\CompositeConnectionInterface;
use Predis\Protocol\ProtocolException;
use Predis\Protocol\ResponseReaderInterface;








class ResponseReader implements ResponseReaderInterface
{
protected $handlers;




public function __construct()
{
$this->handlers = $this->getDefaultHandlers();
}






protected function getDefaultHandlers()
{
return array(
'+' => new Handler\StatusResponse(),
'-' => new Handler\ErrorResponse(),
':' => new Handler\IntegerResponse(),
'$' => new Handler\BulkResponse(),
'*' => new Handler\MultiBulkResponse(),
);
}







public function setHandler($prefix, Handler\ResponseHandlerInterface $handler)
{
$this->handlers[$prefix] = $handler;
}








public function getHandler($prefix)
{
if (isset($this->handlers[$prefix])) {
return $this->handlers[$prefix];
}

return;
}




public function read(CompositeConnectionInterface $connection)
{
$header = $connection->readLine();

if ($header === '') {
$this->onProtocolError($connection, 'Unexpected empty reponse header.');
}

$prefix = $header[0];

if (!isset($this->handlers[$prefix])) {
$this->onProtocolError($connection, "Unknown response prefix: '$prefix'.");
}

$payload = $this->handlers[$prefix]->handle($connection, substr($header, 1));

return $payload;
}








protected function onProtocolError(CompositeConnectionInterface $connection, $message)
{
CommunicationException::handle(
new ProtocolException($connection, $message)
);
}
}
<?php










namespace Predis\Protocol\Text\Handler;

use Predis\CommunicationException;
use Predis\Connection\CompositeConnectionInterface;
use Predis\Protocol\ProtocolException;









class MultiBulkResponse implements ResponseHandlerInterface
{



public function handle(CompositeConnectionInterface $connection, $payload)
{
$length = (int) $payload;

if ("$length" !== $payload) {
CommunicationException::handle(new ProtocolException(
$connection, "Cannot parse '$payload' as a valid length of a multi-bulk response."
));
}

if ($length === -1) {
return;
}

$list = array();

if ($length > 0) {
$handlersCache = array();
$reader = $connection->getProtocol()->getResponseReader();

for ($i = 0; $i < $length; ++$i) {
$header = $connection->readLine();
$prefix = $header[0];

if (isset($handlersCache[$prefix])) {
$handler = $handlersCache[$prefix];
} else {
$handler = $reader->getHandler($prefix);
$handlersCache[$prefix] = $handler;
}

$list[$i] = $handler->handle($connection, substr($header, 1));
}
}

return $list;
}
}
<?php










namespace Predis\Protocol\Text\Handler;

use Predis\Connection\CompositeConnectionInterface;






interface ResponseHandlerInterface
{









public function handle(CompositeConnectionInterface $connection, $payload);
}
<?php










namespace Predis\Protocol\Text\Handler;

use Predis\CommunicationException;
use Predis\Connection\CompositeConnectionInterface;
use Predis\Protocol\ProtocolException;









class BulkResponse implements ResponseHandlerInterface
{



public function handle(CompositeConnectionInterface $connection, $payload)
{
$length = (int) $payload;

if ("$length" !== $payload) {
CommunicationException::handle(new ProtocolException(
$connection, "Cannot parse '$payload' as a valid length for a bulk response."
));
}

if ($length >= 0) {
return substr($connection->readBuffer($length + 2), 0, -2);
}

if ($length == -1) {
return;
}

CommunicationException::handle(new ProtocolException(
$connection, "Value '$payload' is not a valid length for a bulk response."
));

return;
}
}
<?php










namespace Predis\Protocol\Text\Handler;

use Predis\Connection\CompositeConnectionInterface;
use Predis\Response\Error;









class ErrorResponse implements ResponseHandlerInterface
{



public function handle(CompositeConnectionInterface $connection, $payload)
{
return new Error($payload);
}
}
<?php










namespace Predis\Protocol\Text\Handler;

use Predis\CommunicationException;
use Predis\Connection\CompositeConnectionInterface;
use Predis\Protocol\ProtocolException;









class IntegerResponse implements ResponseHandlerInterface
{



public function handle(CompositeConnectionInterface $connection, $payload)
{
if (is_numeric($payload)) {
$integer = (int) $payload;
return $integer == $payload ? $integer : $payload;
}

if ($payload !== 'nil') {
CommunicationException::handle(new ProtocolException(
$connection, "Cannot parse '$payload' as a valid numeric response."
));
}

return;
}
}
<?php










namespace Predis\Protocol\Text\Handler;

use Predis\CommunicationException;
use Predis\Connection\CompositeConnectionInterface;
use Predis\Protocol\ProtocolException;
use Predis\Response\Iterator\MultiBulk as MultiBulkIterator;












class StreamableMultiBulkResponse implements ResponseHandlerInterface
{



public function handle(CompositeConnectionInterface $connection, $payload)
{
$length = (int) $payload;

if ("$length" != $payload) {
CommunicationException::handle(new ProtocolException(
$connection, "Cannot parse '$payload' as a valid length for a multi-bulk response."
));
}

return new MultiBulkIterator($connection, $length);
}
}
<?php










namespace Predis\Protocol\Text\Handler;

use Predis\Connection\CompositeConnectionInterface;
use Predis\Response\Status;










class StatusResponse implements ResponseHandlerInterface
{



public function handle(CompositeConnectionInterface $connection, $payload)
{
return Status::get($payload);
}
}
<?php










namespace Predis\Protocol\Text;

use Predis\Command\CommandInterface;
use Predis\Protocol\RequestSerializerInterface;








class RequestSerializer implements RequestSerializerInterface
{



public function serialize(CommandInterface $command)
{
$commandID = $command->getId();
$arguments = $command->getArguments();

$cmdlen = strlen($commandID);
$reqlen = count($arguments) + 1;

$buffer = "*{$reqlen}\r\n\${$cmdlen}\r\n{$commandID}\r\n";

foreach ($arguments as $argument) {
$arglen = strlen($argument);
$buffer .= "\${$arglen}\r\n{$argument}\r\n";
}

return $buffer;
}
}
<?php










namespace Predis\Protocol;

use Predis\Command\CommandInterface;






interface RequestSerializerInterface
{







public function serialize(CommandInterface $command);
}
<?php










namespace Predis\Protocol;

use Predis\Connection\CompositeConnectionInterface;







interface ResponseReaderInterface
{







public function read(CompositeConnectionInterface $connection);
}
<?php










namespace Predis;







class Autoloader
{
private $directory;
private $prefix;
private $prefixLength;




public function __construct($baseDirectory = __DIR__)
{
$this->directory = $baseDirectory;
$this->prefix = __NAMESPACE__.'\\';
$this->prefixLength = strlen($this->prefix);
}






public static function register($prepend = false)
{
spl_autoload_register(array(new self(), 'autoload'), true, $prepend);
}






public function autoload($className)
{
if (0 === strpos($className, $this->prefix)) {
$parts = explode('\\', substr($className, $this->prefixLength));
$filepath = $this->directory.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $parts).'.php';

if (is_file($filepath)) {
require $filepath;
}
}
}
}
<?php










namespace Predis\Response;

use Predis\PredisException;






class ServerException extends PredisException implements ErrorInterface
{





public function getErrorType()
{
list($errorType) = explode(' ', $this->getMessage(), 2);

return $errorType;
}






public function toErrorResponse()
{
return new Error($this->getMessage());
}
}
<?php










namespace Predis\Response;






interface ResponseInterface
{
}
<?php










namespace Predis\Response\Iterator;










class MultiBulkTuple extends MultiBulk implements \OuterIterator
{
private $iterator;




public function __construct(MultiBulk $iterator)
{
$this->checkPreconditions($iterator);

$this->size = count($iterator) / 2;
$this->iterator = $iterator;
$this->position = $iterator->getPosition();
$this->current = $this->size > 0 ? $this->getValue() : null;
}









protected function checkPreconditions(MultiBulk $iterator)
{
if ($iterator->getPosition() !== 0) {
throw new \InvalidArgumentException(
'Cannot initialize a tuple iterator using an already initiated iterator.'
);
}

if (($size = count($iterator)) % 2 !== 0) {
throw new \UnexpectedValueException('Invalid response size for a tuple iterator.');
}
}





 public function getInnerIterator()
{
return $this->iterator;
}




public function __destruct()
{
$this->iterator->drop(true);
}




protected function getValue()
{
$k = $this->iterator->current();
$this->iterator->next();

$v = $this->iterator->current();
$this->iterator->next();

return array($k, $v);
}
}
<?php










namespace Predis\Response\Iterator;

use Predis\Response\ResponseInterface;













abstract class MultiBulkIterator implements \Iterator, \Countable, ResponseInterface
{
protected $current;
protected $position;
protected $size;





 public function rewind()
{

 }





 public function current()
{
return $this->current;
}





 public function key()
{
return $this->position;
}





 public function next()
{
if (++$this->position < $this->size) {
$this->current = $this->getValue();
}
}





 public function valid()
{
return $this->position < $this->size;
}











 public function count()
{
return $this->size;
}






public function getPosition()
{
return $this->position;
}




abstract protected function getValue();
}
<?php










namespace Predis\Response\Iterator;

use Predis\Connection\NodeConnectionInterface;






class MultiBulk extends MultiBulkIterator
{
private $connection;





public function __construct(NodeConnectionInterface $connection, $size)
{
$this->connection = $connection;
$this->size = $size;
$this->position = 0;
$this->current = $size > 0 ? $this->getValue() : null;
}






public function __destruct()
{
$this->drop(true);
}








public function drop($disconnect = false)
{
if ($disconnect) {
if ($this->valid()) {
$this->position = $this->size;
$this->connection->disconnect();
}
} else {
while ($this->valid()) {
$this->next();
}
}
}






protected function getValue()
{
return $this->connection->read();
}
}
<?php










namespace Predis\Response;







interface ErrorInterface extends ResponseInterface
{





public function getMessage();






public function getErrorType();
}
<?php










namespace Predis\Response;






class Status implements ResponseInterface
{
private static $OK;
private static $QUEUED;

private $payload;




public function __construct($payload)
{
$this->payload = $payload;
}






public function __toString()
{
return $this->payload;
}






public function getPayload()
{
return $this->payload;
}











public static function get($payload)
{
switch ($payload) {
case 'OK':
case 'QUEUED':
if (isset(self::$$payload)) {
return self::$$payload;
}

return self::$$payload = new self($payload);

default:
return new self($payload);
}
}
}
<?php










namespace Predis\Response;







class Error implements ErrorInterface
{
private $message;




public function __construct($message)
{
$this->message = $message;
}




public function getMessage()
{
return $this->message;
}




public function getErrorType()
{
list($errorType) = explode(' ', $this->getMessage(), 2);

return $errorType;
}






public function __toString()
{
return $this->getMessage();
}
}
<?php










namespace Predis\Command;






class ConnectionEcho extends Command
{



public function getId()
{
return 'ECHO';
}
}
<?php










namespace Predis\Command;






class ZSetRangeByScore extends ZSetRange
{



public function getId()
{
return 'ZRANGEBYSCORE';
}




protected function prepareOptions($options)
{
$opts = array_change_key_case($options, CASE_UPPER);
$finalizedOpts = array();

if (isset($opts['LIMIT']) && is_array($opts['LIMIT'])) {
$limit = array_change_key_case($opts['LIMIT'], CASE_UPPER);

$finalizedOpts[] = 'LIMIT';
$finalizedOpts[] = isset($limit['OFFSET']) ? $limit['OFFSET'] : $limit[0];
$finalizedOpts[] = isset($limit['COUNT']) ? $limit['COUNT'] : $limit[1];
}

return array_merge($finalizedOpts, parent::prepareOptions($options));
}




protected function withScores()
{
$arguments = $this->getArguments();

for ($i = 3; $i < count($arguments); ++$i) {
switch (strtoupper($arguments[$i])) {
case 'WITHSCORES':
return true;

case 'LIMIT':
$i += 2;
break;
}
}

return false;
}
}
<?php










namespace Predis\Command;






class HashLength extends Command
{



public function getId()
{
return 'HLEN';
}
}
<?php










namespace Predis\Command;






class ZSetCardinality extends Command
{



public function getId()
{
return 'ZCARD';
}
}
<?php










namespace Predis\Command;






class StringBitPos extends Command
{



public function getId()
{
return 'BITPOS';
}
}
<?php










namespace Predis\Command;






class ZSetReverseRank extends Command
{



public function getId()
{
return 'ZREVRANK';
}
}
<?php










namespace Predis\Command;






class ListPushHead extends ListPushTail
{



public function getId()
{
return 'LPUSH';
}
}
<?php










namespace Predis\Command;






class HashIncrementByFloat extends Command
{



public function getId()
{
return 'HINCRBYFLOAT';
}
}
<?php










namespace Predis\Command;






class HashKeys extends Command
{



public function getId()
{
return 'HKEYS';
}
}
<?php










namespace Predis\Command;






class ZSetUnionStore extends Command
{



public function getId()
{
return 'ZUNIONSTORE';
}




protected function filterArguments(array $arguments)
{
$options = array();
$argc = count($arguments);

if ($argc > 2 && is_array($arguments[$argc - 1])) {
$options = $this->prepareOptions(array_pop($arguments));
}

if (is_array($arguments[1])) {
$arguments = array_merge(
array($arguments[0], count($arguments[1])),
$arguments[1]
);
}

return array_merge($arguments, $options);
}








private function prepareOptions($options)
{
$opts = array_change_key_case($options, CASE_UPPER);
$finalizedOpts = array();

if (isset($opts['WEIGHTS']) && is_array($opts['WEIGHTS'])) {
$finalizedOpts[] = 'WEIGHTS';

foreach ($opts['WEIGHTS'] as $weight) {
$finalizedOpts[] = $weight;
}
}

if (isset($opts['AGGREGATE'])) {
$finalizedOpts[] = 'AGGREGATE';
$finalizedOpts[] = $opts['AGGREGATE'];
}

return $finalizedOpts;
}
}
<?php










namespace Predis\Command;






class StringSetExpire extends Command
{



public function getId()
{
return 'SETEX';
}
}
<?php










namespace Predis\Command;






class ListPushTail extends Command
{



public function getId()
{
return 'RPUSH';
}




protected function filterArguments(array $arguments)
{
return self::normalizeVariadic($arguments);
}
}
<?php










namespace Predis\Command;






class KeyExpireAt extends Command
{



public function getId()
{
return 'EXPIREAT';
}
}
<?php










namespace Predis\Command;






class HashIncrementBy extends Command
{



public function getId()
{
return 'HINCRBY';
}
}
<?php










namespace Predis\Command;






class SetMove extends Command
{



public function getId()
{
return 'SMOVE';
}
}
<?php










namespace Predis\Command;






class ListPopFirstBlocking extends Command
{



public function getId()
{
return 'BLPOP';
}




protected function filterArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[0])) {
list($arguments, $timeout) = $arguments;
array_push($arguments, $timeout);
}

return $arguments;
}
}
<?php










namespace Predis\Command;






class ConnectionSelect extends Command
{



public function getId()
{
return 'SELECT';
}
}
<?php










namespace Predis\Command;






class HashScan extends Command
{



public function getId()
{
return 'HSCAN';
}




protected function filterArguments(array $arguments)
{
if (count($arguments) === 3 && is_array($arguments[2])) {
$options = $this->prepareOptions(array_pop($arguments));
$arguments = array_merge($arguments, $options);
}

return $arguments;
}








protected function prepareOptions($options)
{
$options = array_change_key_case($options, CASE_UPPER);
$normalized = array();

if (!empty($options['MATCH'])) {
$normalized[] = 'MATCH';
$normalized[] = $options['MATCH'];
}

if (!empty($options['COUNT'])) {
$normalized[] = 'COUNT';
$normalized[] = $options['COUNT'];
}

return $normalized;
}




public function parseResponse($data)
{
if (is_array($data)) {
$fields = $data[1];
$result = array();

for ($i = 0; $i < count($fields); ++$i) {
$result[$fields[$i]] = $fields[++$i];
}

$data[1] = $result;
}

return $data;
}
}
<?php










namespace Predis\Command;






class PubSubPubsub extends Command
{



public function getId()
{
return 'PUBSUB';
}




public function parseResponse($data)
{
switch (strtolower($this->getArgument(0))) {
case 'numsub':
return self::processNumsub($data);

default:
return $data;
}
}








protected static function processNumsub(array $channels)
{
$processed = array();
$count = count($channels);

for ($i = 0; $i < $count; ++$i) {
$processed[$channels[$i]] = $channels[++$i];
}

return $processed;
}
}
<?php










namespace Predis\Command;






class KeyRandom extends Command
{



public function getId()
{
return 'RANDOMKEY';
}




public function parseResponse($data)
{
return $data !== '' ? $data : null;
}
}
<?php










namespace Predis\Command;






class ServerObject extends Command
{



public function getId()
{
return 'OBJECT';
}
}
<?php










namespace Predis\Command;






class StringBitCount extends Command
{



public function getId()
{
return 'BITCOUNT';
}
}
<?php










namespace Predis\Command;






class ListPopLastPushHead extends Command
{



public function getId()
{
return 'RPOPLPUSH';
}
}
<?php










namespace Predis\Command;









abstract class ScriptCommand extends ServerEvalSHA
{





abstract public function getScript();










protected function getKeysCount()
{
return 0;
}






public function getKeys()
{
return array_slice($this->getArguments(), 2, $this->getKeysCount());
}




protected function filterArguments(array $arguments)
{
if (($numkeys = $this->getKeysCount()) && $numkeys < 0) {
$numkeys = count($arguments) + $numkeys;
}

return array_merge(array(sha1($this->getScript()), (int) $numkeys), $arguments);
}




public function getEvalArguments()
{
$arguments = $this->getArguments();
$arguments[0] = $this->getScript();

return $arguments;
}
}
<?php










namespace Predis\Command;






class StringSetMultiplePreserve extends StringSetMultiple
{



public function getId()
{
return 'MSETNX';
}
}
<?php










namespace Predis\Command;






class ServerFlushAll extends Command
{



public function getId()
{
return 'FLUSHALL';
}
}
<?php










namespace Predis\Command;






class KeyDump extends Command
{



public function getId()
{
return 'DUMP';
}
}
<?php










namespace Predis\Command;






class ServerBackgroundRewriteAOF extends Command
{



public function getId()
{
return 'BGREWRITEAOF';
}




public function parseResponse($data)
{
return $data == 'Background append only file rewriting started';
}
}
<?php










namespace Predis\Command;






class ListIndex extends Command
{



public function getId()
{
return 'LINDEX';
}
}
<?php










namespace Predis\Command;






class ServerSave extends Command
{



public function getId()
{
return 'SAVE';
}
}
<?php










namespace Predis\Command;






class ServerFlushDatabase extends Command
{



public function getId()
{
return 'FLUSHDB';
}
}
<?php










namespace Predis\Command;






class ConnectionAuth extends Command
{



public function getId()
{
return 'AUTH';
}
}
<?php










namespace Predis\Command;






class HashSet extends Command
{



public function getId()
{
return 'HSET';
}
}
<?php










namespace Predis\Command;






class PubSubSubscribe extends Command
{



public function getId()
{
return 'SUBSCRIBE';
}




protected function filterArguments(array $arguments)
{
return self::normalizeArguments($arguments);
}
}
<?php










namespace Predis\Command;






class KeyRename extends Command
{



public function getId()
{
return 'RENAME';
}
}
<?php










namespace Predis\Command;






class ServerScript extends Command
{



public function getId()
{
return 'SCRIPT';
}
}
<?php










namespace Predis\Command;






class ListRemove extends Command
{



public function getId()
{
return 'LREM';
}
}
<?php










namespace Predis\Command;






class SetMembers extends Command
{



public function getId()
{
return 'SMEMBERS';
}
}
<?php










namespace Predis\Command;






class StringStrlen extends Command
{



public function getId()
{
return 'STRLEN';
}
}
<?php










namespace Predis\Command;






class ServerLastSave extends Command
{



public function getId()
{
return 'LASTSAVE';
}
}
<?php










namespace Predis\Command;






class StringGetBit extends Command
{



public function getId()
{
return 'GETBIT';
}
}
<?php










namespace Predis\Command;






class HashExists extends Command
{



public function getId()
{
return 'HEXISTS';
}
}
<?php










namespace Predis\Command;






class KeyPreciseTimeToLive extends KeyTimeToLive
{



public function getId()
{
return 'PTTL';
}
}
<?php










namespace Predis\Command;






class StringDecrement extends Command
{



public function getId()
{
return 'DECR';
}
}
<?php










namespace Predis\Command;






class SetIntersectionStore extends Command
{



public function getId()
{
return 'SINTERSTORE';
}




protected function filterArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[1])) {
return array_merge(array($arguments[0]), $arguments[1]);
}

return $arguments;
}
}
<?php










namespace Predis\Command;






class KeyScan extends Command
{



public function getId()
{
return 'SCAN';
}




protected function filterArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[1])) {
$options = $this->prepareOptions(array_pop($arguments));
$arguments = array_merge($arguments, $options);
}

return $arguments;
}








protected function prepareOptions($options)
{
$options = array_change_key_case($options, CASE_UPPER);
$normalized = array();

if (!empty($options['MATCH'])) {
$normalized[] = 'MATCH';
$normalized[] = $options['MATCH'];
}

if (!empty($options['COUNT'])) {
$normalized[] = 'COUNT';
$normalized[] = $options['COUNT'];
}

return $normalized;
}
}
<?php










namespace Predis\Command;






class ZSetCount extends Command
{



public function getId()
{
return 'ZCOUNT';
}
}
<?php










namespace Predis\Command;






class HashSetMultiple extends Command
{



public function getId()
{
return 'HMSET';
}




protected function filterArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[1])) {
$flattenedKVs = array($arguments[0]);
$args = $arguments[1];

foreach ($args as $k => $v) {
$flattenedKVs[] = $k;
$flattenedKVs[] = $v;
}

return $flattenedKVs;
}

return $arguments;
}
}
<?php










namespace Predis\Command;






class SetPop extends Command
{



public function getId()
{
return 'SPOP';
}
}
<?php










namespace Predis\Command;






class HashSetPreserve extends Command
{



public function getId()
{
return 'HSETNX';
}
}
<?php










namespace Predis\Command;






class ZSetAdd extends Command
{



public function getId()
{
return 'ZADD';
}




protected function filterArguments(array $arguments)
{
if (is_array(end($arguments))) {
foreach (array_pop($arguments) as $member => $score) {
$arguments[] = $score;
$arguments[] = $member;
}
}

return $arguments;
}
}
<?php










namespace Predis\Command;






class KeySort extends Command
{



public function getId()
{
return 'SORT';
}




protected function filterArguments(array $arguments)
{
if (count($arguments) === 1) {
return $arguments;
}

$query = array($arguments[0]);
$sortParams = array_change_key_case($arguments[1], CASE_UPPER);

if (isset($sortParams['BY'])) {
$query[] = 'BY';
$query[] = $sortParams['BY'];
}

if (isset($sortParams['GET'])) {
$getargs = $sortParams['GET'];

if (is_array($getargs)) {
foreach ($getargs as $getarg) {
$query[] = 'GET';
$query[] = $getarg;
}
} else {
$query[] = 'GET';
$query[] = $getargs;
}
}

if (isset($sortParams['LIMIT']) &&
is_array($sortParams['LIMIT']) &&
count($sortParams['LIMIT']) == 2) {
$query[] = 'LIMIT';
$query[] = $sortParams['LIMIT'][0];
$query[] = $sortParams['LIMIT'][1];
}

if (isset($sortParams['SORT'])) {
$query[] = strtoupper($sortParams['SORT']);
}

if (isset($sortParams['ALPHA']) && $sortParams['ALPHA'] == true) {
$query[] = 'ALPHA';
}

if (isset($sortParams['STORE'])) {
$query[] = 'STORE';
$query[] = $sortParams['STORE'];
}

return $query;
}
}
<?php










namespace Predis\Command;






class ListPopLastBlocking extends ListPopFirstBlocking
{



public function getId()
{
return 'BRPOP';
}
}
<?php










namespace Predis\Command;






class SetDifferenceStore extends SetIntersectionStore
{



public function getId()
{
return 'SDIFFSTORE';
}
}
<?php










namespace Predis\Command;






class ServerSlaveOf extends Command
{



public function getId()
{
return 'SLAVEOF';
}




protected function filterArguments(array $arguments)
{
if (count($arguments) === 0 || $arguments[0] === 'NO ONE') {
return array('NO', 'ONE');
}

return $arguments;
}
}
<?php










namespace Predis\Command;






class PubSubUnsubscribe extends Command
{



public function getId()
{
return 'UNSUBSCRIBE';
}




protected function filterArguments(array $arguments)
{
return self::normalizeArguments($arguments);
}
}
<?php










namespace Predis\Command;






class StringBitField extends Command
{



public function getId()
{
return 'BITFIELD';
}
}
<?php










namespace Predis\Command;






class ServerInfoV26x extends ServerInfo
{



public function parseResponse($data)
{
if ($data === '') {
return array();
}

$info = array();

$current = null;
$infoLines = preg_split('/\r?\n/', $data);

if (isset($infoLines[0]) && $infoLines[0][0] !== '#') {
return parent::parseResponse($data);
}

foreach ($infoLines as $row) {
if ($row === '') {
continue;
}

if (preg_match('/^# (\w+)$/', $row, $matches)) {
$info[$matches[1]] = array();
$current = &$info[$matches[1]];
continue;
}

list($k, $v) = $this->parseRow($row);
$current[$k] = $v;
}

return $info;
}
}
<?php










namespace Predis\Command;






class ServerCommand extends Command
{



public function getId()
{
return 'COMMAND';
}
}
<?php










namespace Predis\Command;






class ListPushTailX extends Command
{



public function getId()
{
return 'RPUSHX';
}
}
<?php










namespace Predis\Command;






class ListPopLast extends Command
{



public function getId()
{
return 'RPOP';
}
}
<?php










namespace Predis\Command;






class ZSetRemoveRangeByRank extends Command
{



public function getId()
{
return 'ZREMRANGEBYRANK';
}
}
<?php










namespace Predis\Command;






class SetIsMember extends Command
{



public function getId()
{
return 'SISMEMBER';
}
}
<?php










namespace Predis\Command;






class KeyTimeToLive extends Command
{



public function getId()
{
return 'TTL';
}
}
<?php










namespace Predis\Command;






class TransactionMulti extends Command
{



public function getId()
{
return 'MULTI';
}
}
<?php










namespace Predis\Command;






class TransactionWatch extends Command
{



public function getId()
{
return 'WATCH';
}




protected function filterArguments(array $arguments)
{
if (isset($arguments[0]) && is_array($arguments[0])) {
return $arguments[0];
}

return $arguments;
}
}
<?php










namespace Predis\Command;






class ZSetRangeByLex extends ZSetRange
{



public function getId()
{
return 'ZRANGEBYLEX';
}




protected function prepareOptions($options)
{
$opts = array_change_key_case($options, CASE_UPPER);
$finalizedOpts = array();

if (isset($opts['LIMIT']) && is_array($opts['LIMIT'])) {
$limit = array_change_key_case($opts['LIMIT'], CASE_UPPER);

$finalizedOpts[] = 'LIMIT';
$finalizedOpts[] = isset($limit['OFFSET']) ? $limit['OFFSET'] : $limit[0];
$finalizedOpts[] = isset($limit['COUNT']) ? $limit['COUNT'] : $limit[1];
}

return $finalizedOpts;
}




protected function withScores()
{
return false;
}
}
<?php










namespace Predis\Command;






class ListPopFirst extends Command
{



public function getId()
{
return 'LPOP';
}
}
<?php










namespace Predis\Command;






class HashGetMultiple extends Command
{



public function getId()
{
return 'HMGET';
}




protected function filterArguments(array $arguments)
{
return self::normalizeVariadic($arguments);
}
}
<?php










namespace Predis\Command;






class StringDecrementBy extends Command
{



public function getId()
{
return 'DECRBY';
}
}
<?php










namespace Predis\Command;






class HashDelete extends Command
{



public function getId()
{
return 'HDEL';
}




protected function filterArguments(array $arguments)
{
return self::normalizeVariadic($arguments);
}
}
<?php










namespace Predis\Command;






class StringIncrement extends Command
{



public function getId()
{
return 'INCR';
}
}
<?php










namespace Predis\Command;






class SetCardinality extends Command
{



public function getId()
{
return 'SCARD';
}
}
<?php










namespace Predis\Command;






class ZSetScan extends Command
{



public function getId()
{
return 'ZSCAN';
}




protected function filterArguments(array $arguments)
{
if (count($arguments) === 3 && is_array($arguments[2])) {
$options = $this->prepareOptions(array_pop($arguments));
$arguments = array_merge($arguments, $options);
}

return $arguments;
}








protected function prepareOptions($options)
{
$options = array_change_key_case($options, CASE_UPPER);
$normalized = array();

if (!empty($options['MATCH'])) {
$normalized[] = 'MATCH';
$normalized[] = $options['MATCH'];
}

if (!empty($options['COUNT'])) {
$normalized[] = 'COUNT';
$normalized[] = $options['COUNT'];
}

return $normalized;
}




public function parseResponse($data)
{
if (is_array($data)) {
$members = $data[1];
$result = array();

for ($i = 0; $i < count($members); ++$i) {
$result[$members[$i]] = (float) $members[++$i];
}

$data[1] = $result;
}

return $data;
}
}
<?php










namespace Predis\Command;






class KeyPreciseExpire extends KeyExpire
{



public function getId()
{
return 'PEXPIRE';
}
}
<?php










namespace Predis\Command;






class ListTrim extends Command
{



public function getId()
{
return 'LTRIM';
}
}
<?php










namespace Predis\Command;






class StringIncrementByFloat extends Command
{



public function getId()
{
return 'INCRBYFLOAT';
}
}
<?php










namespace Predis\Command;






class ServerInfo extends Command
{



public function getId()
{
return 'INFO';
}




public function parseResponse($data)
{
$info = array();
$infoLines = preg_split('/\r?\n/', $data);

foreach ($infoLines as $row) {
if (strpos($row, ':') === false) {
continue;
}

list($k, $v) = $this->parseRow($row);
$info[$k] = $v;
}

return $info;
}








protected function parseRow($row)
{
list($k, $v) = explode(':', $row, 2);

if (preg_match('/^db\d+$/', $k)) {
$v = $this->parseDatabaseStats($v);
}

return array($k, $v);
}








protected function parseDatabaseStats($str)
{
$db = array();

foreach (explode(',', $str) as $dbvar) {
list($dbvk, $dbvv) = explode('=', $dbvar);
$db[trim($dbvk)] = $dbvv;
}

return $db;
}








protected function parseAllocationStats($str)
{
$stats = array();

foreach (explode(',', $str) as $kv) {
@list($size, $objects, $extra) = explode('=', $kv);


 if (isset($extra)) {
$size = ">=$objects";
$objects = $extra;
}

$stats[$size] = $objects;
}

return $stats;
}
}
<?php










namespace Predis\Command;






class GeospatialGeoDist extends Command
{



public function getId()
{
return 'GEODIST';
}
}
<?php










namespace Predis\Command;






class HashStringLength extends Command
{



public function getId()
{
return 'HSTRLEN';
}
}
<?php










namespace Predis\Command;






class HyperLogLogCount extends Command
{



public function getId()
{
return 'PFCOUNT';
}




protected function filterArguments(array $arguments)
{
return self::normalizeArguments($arguments);
}
}
<?php










namespace Predis\Command;






class SetRandomMember extends Command
{



public function getId()
{
return 'SRANDMEMBER';
}
}
<?php










namespace Predis\Command;






class KeyPreciseExpireAt extends KeyExpireAt
{



public function getId()
{
return 'PEXPIREAT';
}
}
<?php










namespace Predis\Command;






class HyperLogLogMerge extends Command
{



public function getId()
{
return 'PFMERGE';
}




protected function filterArguments(array $arguments)
{
return self::normalizeArguments($arguments);
}
}
<?php










namespace Predis\Command;






class KeyKeys extends Command
{



public function getId()
{
return 'KEYS';
}
}
<?php










namespace Predis\Command;






class ConnectionPing extends Command
{



public function getId()
{
return 'PING';
}
}
<?php










namespace Predis\Command;






interface CommandInterface
{






public function getId();






public function setSlot($slot);






public function getSlot();






public function setArguments(array $arguments);






public function setRawArguments(array $arguments);






public function getArguments();








public function getArgument($index);








public function parseResponse($data);
}
<?php










namespace Predis\Command;






class ServerEval extends Command
{



public function getId()
{
return 'EVAL';
}






public function getScriptHash()
{
return sha1($this->getArgument(0));
}
}
<?php










namespace Predis\Command;






class ListLength extends Command
{



public function getId()
{
return 'LLEN';
}
}
<?php










namespace Predis\Command;






class SetDifference extends SetIntersection
{



public function getId()
{
return 'SDIFF';
}
}
<?php










namespace Predis\Command;






class ServerBackgroundSave extends Command
{



public function getId()
{
return 'BGSAVE';
}




public function parseResponse($data)
{
return $data === 'Background saving started' ? true : $data;
}
}
<?php










namespace Predis\Command;






class StringSetBit extends Command
{



public function getId()
{
return 'SETBIT';
}
}
<?php










namespace Predis\Command;






class ServerSlowlog extends Command
{



public function getId()
{
return 'SLOWLOG';
}




public function parseResponse($data)
{
if (is_array($data)) {
$log = array();

foreach ($data as $index => $entry) {
$log[$index] = array(
'id' => $entry[0],
'timestamp' => $entry[1],
'duration' => $entry[2],
'command' => $entry[3],
);
}

return $log;
}

return $data;
}
}
<?php










namespace Predis\Command;






class GeospatialGeoAdd extends Command
{



public function getId()
{
return 'GEOADD';
}




protected function filterArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[1])) {
foreach (array_pop($arguments) as $item) {
$arguments = array_merge($arguments, $item);
}
}

return $arguments;
}
}
<?php










namespace Predis\Command;






class GeospatialGeoPos extends Command
{



public function getId()
{
return 'GEOPOS';
}




protected function filterArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[1])) {
$members = array_pop($arguments);
$arguments = array_merge($arguments, $members);
}

return $arguments;
}
}
<?php










namespace Predis\Command;






class ZSetReverseRangeByLex extends ZSetRangeByLex
{



public function getId()
{
return 'ZREVRANGEBYLEX';
}
}
<?php










namespace Predis\Command;






class ZSetReverseRange extends ZSetRange
{



public function getId()
{
return 'ZREVRANGE';
}
}
<?php










namespace Predis\Command;






class TransactionExec extends Command
{



public function getId()
{
return 'EXEC';
}
}
<?php










namespace Predis\Command;






class KeyMove extends Command
{



public function getId()
{
return 'MOVE';
}
}
<?php










namespace Predis\Command;






class SetIntersection extends Command
{



public function getId()
{
return 'SINTER';
}




protected function filterArguments(array $arguments)
{
return self::normalizeArguments($arguments);
}
}
<?php










namespace Predis\Command;






class KeyRenamePreserve extends KeyRename
{



public function getId()
{
return 'RENAMENX';
}
}
<?php










namespace Predis\Command;






interface PrefixableCommandInterface extends CommandInterface
{





public function prefixKeys($prefix);
}
<?php










namespace Predis\Command;






class ZSetRank extends Command
{



public function getId()
{
return 'ZRANK';
}
}
<?php










namespace Predis\Command;






class ServerShutdown extends Command
{



public function getId()
{
return 'SHUTDOWN';
}
}
<?php










namespace Predis\Command;






class StringBitOp extends Command
{



public function getId()
{
return 'BITOP';
}




protected function filterArguments(array $arguments)
{
if (count($arguments) === 3 && is_array($arguments[2])) {
list($operation, $destination) = $arguments;
$arguments = $arguments[2];
array_unshift($arguments, $operation, $destination);
}

return $arguments;
}
}
<?php










namespace Predis\Command;






class KeyExists extends Command
{



public function getId()
{
return 'EXISTS';
}
}
<?php










namespace Predis\Command;






class GeospatialGeoRadiusByMember extends GeospatialGeoRadius
{



public function getId()
{
return 'GEORADIUSBYMEMBER';
}
}
<?php










namespace Predis\Command;






class ZSetLexCount extends Command
{



public function getId()
{
return 'ZLEXCOUNT';
}
}
<?php










namespace Predis\Command;






class KeyDelete extends Command
{



public function getId()
{
return 'DEL';
}




protected function filterArguments(array $arguments)
{
return self::normalizeArguments($arguments);
}
}
<?php










namespace Predis\Command;






class SetRemove extends Command
{



public function getId()
{
return 'SREM';
}




protected function filterArguments(array $arguments)
{
return self::normalizeVariadic($arguments);
}
}
<?php










namespace Predis\Command;






class ZSetScore extends Command
{



public function getId()
{
return 'ZSCORE';
}
}
<?php










namespace Predis\Command;






class HashGetAll extends Command
{



public function getId()
{
return 'HGETALL';
}




public function parseResponse($data)
{
$result = array();

for ($i = 0; $i < count($data); ++$i) {
$result[$data[$i]] = $data[++$i];
}

return $result;
}
}
<?php










namespace Predis\Command;









class ServerConfig extends Command
{



public function getId()
{
return 'CONFIG';
}




public function parseResponse($data)
{
if (is_array($data)) {
$result = array();

for ($i = 0; $i < count($data); ++$i) {
$result[$data[$i]] = $data[++$i];
}

return $result;
}

return $data;
}
}
<?php










namespace Predis\Command;






class ServerSentinel extends Command
{



public function getId()
{
return 'SENTINEL';
}




public function parseResponse($data)
{
$argument = $this->getArgument(0);
$argument = is_null($argument) ? null : strtolower($argument);

switch ($argument) {
case 'masters':
case 'slaves':
return self::processMastersOrSlaves($data);

default:
return $data;
}
}








protected static function processMastersOrSlaves(array $servers)
{
foreach ($servers as $idx => $node) {
$processed = array();
$count = count($node);

for ($i = 0; $i < $count; ++$i) {
$processed[$node[$i]] = $node[++$i];
}

$servers[$idx] = $processed;
}

return $servers;
}
}
<?php










namespace Predis\Command;






class ServerEvalSHA extends ServerEval
{



public function getId()
{
return 'EVALSHA';
}






public function getScriptHash()
{
return $this->getArgument(0);
}
}
<?php










namespace Predis\Command;






class TransactionUnwatch extends Command
{



public function getId()
{
return 'UNWATCH';
}
}
<?php










namespace Predis\Command;









class ServerClient extends Command
{



public function getId()
{
return 'CLIENT';
}




public function parseResponse($data)
{
$args = array_change_key_case($this->getArguments(), CASE_UPPER);

switch (strtoupper($args[0])) {
case 'LIST':
return $this->parseClientList($data);
case 'KILL':
case 'GETNAME':
case 'SETNAME':
default:
return $data;
}
}








protected function parseClientList($data)
{
$clients = array();

foreach (explode("\n", $data, -1) as $clientData) {
$client = array();

foreach (explode(' ', $clientData) as $kv) {
@list($k, $v) = explode('=', $kv);
$client[$k] = $v;
}

$clients[] = $client;
}

return $clients;
}
}
<?php










namespace Predis\Command;






class ServerTime extends Command
{



public function getId()
{
return 'TIME';
}
}
<?php










namespace Predis\Command;






class ServerMonitor extends Command
{



public function getId()
{
return 'MONITOR';
}
}
<?php










namespace Predis\Command;






class KeyPersist extends Command
{



public function getId()
{
return 'PERSIST';
}
}
<?php










namespace Predis\Command;






class ConnectionQuit extends Command
{



public function getId()
{
return 'QUIT';
}
}
<?php










namespace Predis\Command;






class HashValues extends Command
{



public function getId()
{
return 'HVALS';
}
}
<?php










namespace Predis\Command;






class ZSetRemove extends Command
{



public function getId()
{
return 'ZREM';
}




protected function filterArguments(array $arguments)
{
return self::normalizeVariadic($arguments);
}
}
<?php










namespace Predis\Command;






class ListRange extends Command
{



public function getId()
{
return 'LRANGE';
}
}
<?php










namespace Predis\Command;






class GeospatialGeoHash extends Command
{



public function getId()
{
return 'GEOHASH';
}




protected function filterArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[1])) {
$members = array_pop($arguments);
$arguments = array_merge($arguments, $members);
}

return $arguments;
}
}
<?php










namespace Predis\Command;






class ZSetRemoveRangeByScore extends Command
{



public function getId()
{
return 'ZREMRANGEBYSCORE';
}
}
<?php










namespace Predis\Command;











class RawCommand implements CommandInterface
{
private $slot;
private $commandID;
private $arguments;






public function __construct(array $arguments)
{
if (!$arguments) {
throw new \InvalidArgumentException(
'The arguments array must contain at least the command ID.'
);
}

$this->commandID = strtoupper(array_shift($arguments));
$this->arguments = $arguments;
}









public static function create($commandID )
{
$arguments = func_get_args();
$command = new self($arguments);

return $command;
}




public function getId()
{
return $this->commandID;
}




public function setArguments(array $arguments)
{
$this->arguments = $arguments;
unset($this->slot);
}




public function setRawArguments(array $arguments)
{
$this->setArguments($arguments);
}




public function getArguments()
{
return $this->arguments;
}




public function getArgument($index)
{
if (isset($this->arguments[$index])) {
return $this->arguments[$index];
}
}




public function setSlot($slot)
{
$this->slot = $slot;
}




public function getSlot()
{
if (isset($this->slot)) {
return $this->slot;
}
}




public function parseResponse($data)
{
return $data;
}
}
<?php










namespace Predis\Command;






class StringSetPreserve extends Command
{



public function getId()
{
return 'SETNX';
}
}
<?php










namespace Predis\Command;






class SetUnion extends SetIntersection
{



public function getId()
{
return 'SUNION';
}
}
<?php










namespace Predis\Command;






class TransactionDiscard extends Command
{



public function getId()
{
return 'DISCARD';
}
}
<?php










namespace Predis\Command;






class StringSubstr extends Command
{



public function getId()
{
return 'SUBSTR';
}
}
<?php










namespace Predis\Command;






class KeyMigrate extends Command
{



public function getId()
{
return 'MIGRATE';
}




protected function filterArguments(array $arguments)
{
if (is_array(end($arguments))) {
foreach (array_pop($arguments) as $modifier => $value) {
$modifier = strtoupper($modifier);

if ($modifier === 'COPY' && $value == true) {
$arguments[] = $modifier;
}

if ($modifier === 'REPLACE' && $value == true) {
$arguments[] = $modifier;
}
}
}

return $arguments;
}
}
<?php










namespace Predis\Command;






class ZSetRange extends Command
{



public function getId()
{
return 'ZRANGE';
}




protected function filterArguments(array $arguments)
{
if (count($arguments) === 4) {
$lastType = gettype($arguments[3]);

if ($lastType === 'string' && strtoupper($arguments[3]) === 'WITHSCORES') {

 $arguments[3] = array('WITHSCORES' => true);
$lastType = 'array';
}

if ($lastType === 'array') {
$options = $this->prepareOptions(array_pop($arguments));

return array_merge($arguments, $options);
}
}

return $arguments;
}








protected function prepareOptions($options)
{
$opts = array_change_key_case($options, CASE_UPPER);
$finalizedOpts = array();

if (!empty($opts['WITHSCORES'])) {
$finalizedOpts[] = 'WITHSCORES';
}

return $finalizedOpts;
}






protected function withScores()
{
$arguments = $this->getArguments();

if (count($arguments) < 4) {
return false;
}

return strtoupper($arguments[3]) === 'WITHSCORES';
}




public function parseResponse($data)
{
if ($this->withScores()) {
$result = array();

for ($i = 0; $i < count($data); ++$i) {
$result[$data[$i]] = $data[++$i];
}

return $result;
}

return $data;
}
}
<?php










namespace Predis\Command;






class KeyType extends Command
{



public function getId()
{
return 'TYPE';
}
}
<?php










namespace Predis\Command;






abstract class Command implements CommandInterface
{
private $slot;
private $arguments = array();








protected function filterArguments(array $arguments)
{
return $arguments;
}




public function setArguments(array $arguments)
{
$this->arguments = $this->filterArguments($arguments);
unset($this->slot);
}




public function setRawArguments(array $arguments)
{
$this->arguments = $arguments;
unset($this->slot);
}




public function getArguments()
{
return $this->arguments;
}




public function getArgument($index)
{
if (isset($this->arguments[$index])) {
return $this->arguments[$index];
}
}




public function setSlot($slot)
{
$this->slot = $slot;
}




public function getSlot()
{
if (isset($this->slot)) {
return $this->slot;
}
}




public function parseResponse($data)
{
return $data;
}








public static function normalizeArguments(array $arguments)
{
if (count($arguments) === 1 && isset($arguments[0]) && is_array($arguments[0])) {
return $arguments[0];
}

return $arguments;
}








public static function normalizeVariadic(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[1])) {
return array_merge(array($arguments[0]), $arguments[1]);
}

return $arguments;
}
}
<?php










namespace Predis\Command;






class StringPreciseSetExpire extends StringSetExpire
{



public function getId()
{
return 'PSETEX';
}
}
<?php










namespace Predis\Command;






class ListPopLastPushHeadBlocking extends Command
{



public function getId()
{
return 'BRPOPLPUSH';
}
}
<?php










namespace Predis\Command;






class SetScan extends Command
{



public function getId()
{
return 'SSCAN';
}




protected function filterArguments(array $arguments)
{
if (count($arguments) === 3 && is_array($arguments[2])) {
$options = $this->prepareOptions(array_pop($arguments));
$arguments = array_merge($arguments, $options);
}

return $arguments;
}








protected function prepareOptions($options)
{
$options = array_change_key_case($options, CASE_UPPER);
$normalized = array();

if (!empty($options['MATCH'])) {
$normalized[] = 'MATCH';
$normalized[] = $options['MATCH'];
}

if (!empty($options['COUNT'])) {
$normalized[] = 'COUNT';
$normalized[] = $options['COUNT'];
}

return $normalized;
}
}
<?php










namespace Predis\Command;






class ListInsert extends Command
{



public function getId()
{
return 'LINSERT';
}
}
<?php










namespace Predis\Command;






class KeyRestore extends Command
{



public function getId()
{
return 'RESTORE';
}
}
<?php










namespace Predis\Command;






class HyperLogLogAdd extends Command
{



public function getId()
{
return 'PFADD';
}




protected function filterArguments(array $arguments)
{
return self::normalizeVariadic($arguments);
}
}
<?php










namespace Predis\Command;






class ZSetRemoveRangeByLex extends Command
{



public function getId()
{
return 'ZREMRANGEBYLEX';
}
}
<?php










namespace Predis\Command;






class StringIncrementBy extends Command
{



public function getId()
{
return 'INCRBY';
}
}
<?php










namespace Predis\Command;






class ZSetReverseRangeByScore extends ZSetRangeByScore
{



public function getId()
{
return 'ZREVRANGEBYSCORE';
}
}
<?php










namespace Predis\Command;






class ListPushHeadX extends Command
{



public function getId()
{
return 'LPUSHX';
}
}
<?php










namespace Predis\Command;






class PubSubUnsubscribeByPattern extends PubSubUnsubscribe
{



public function getId()
{
return 'PUNSUBSCRIBE';
}
}
<?php










namespace Predis\Command;






class StringGetRange extends Command
{



public function getId()
{
return 'GETRANGE';
}
}
<?php










namespace Predis\Command;






class PubSubSubscribeByPattern extends PubSubSubscribe
{



public function getId()
{
return 'PSUBSCRIBE';
}
}
<?php










namespace Predis\Command;






class SetUnionStore extends SetIntersectionStore
{



public function getId()
{
return 'SUNIONSTORE';
}
}
<?php










namespace Predis\Command;






class ServerDatabaseSize extends Command
{



public function getId()
{
return 'DBSIZE';
}
}
<?php










namespace Predis\Command;






class PubSubPublish extends Command
{



public function getId()
{
return 'PUBLISH';
}
}
<?php










namespace Predis\Command;






class StringGetMultiple extends Command
{



public function getId()
{
return 'MGET';
}




protected function filterArguments(array $arguments)
{
return self::normalizeArguments($arguments);
}
}
<?php










namespace Predis\Command;






class ListSet extends Command
{



public function getId()
{
return 'LSET';
}
}
<?php










namespace Predis\Command;






class StringGetSet extends Command
{



public function getId()
{
return 'GETSET';
}
}
<?php










namespace Predis\Command;






class StringAppend extends Command
{



public function getId()
{
return 'APPEND';
}
}
<?php










namespace Predis\Command;






class ZSetIntersectionStore extends ZSetUnionStore
{



public function getId()
{
return 'ZINTERSTORE';
}
}
<?php










namespace Predis\Command;






class KeyExpire extends Command
{



public function getId()
{
return 'EXPIRE';
}
}
<?php










namespace Predis\Command;






class StringGet extends Command
{



public function getId()
{
return 'GET';
}
}
<?php










namespace Predis\Command;






class StringSet extends Command
{



public function getId()
{
return 'SET';
}
}
<?php










namespace Predis\Command;






class StringSetMultiple extends Command
{



public function getId()
{
return 'MSET';
}




protected function filterArguments(array $arguments)
{
if (count($arguments) === 1 && is_array($arguments[0])) {
$flattenedKVs = array();
$args = $arguments[0];

foreach ($args as $k => $v) {
$flattenedKVs[] = $k;
$flattenedKVs[] = $v;
}

return $flattenedKVs;
}

return $arguments;
}
}
<?php










namespace Predis\Command;






class GeospatialGeoRadius extends Command
{



public function getId()
{
return 'GEORADIUS';
}




protected function filterArguments(array $arguments)
{
if ($arguments && is_array(end($arguments))) {
$options = array_change_key_case(array_pop($arguments), CASE_UPPER);

if (isset($options['WITHCOORD']) && $options['WITHCOORD'] == true) {
$arguments[] = 'WITHCOORD';
}

if (isset($options['WITHDIST']) && $options['WITHDIST'] == true) {
$arguments[] = 'WITHDIST';
}

if (isset($options['WITHHASH']) && $options['WITHHASH'] == true) {
$arguments[] = 'WITHHASH';
}

if (isset($options['COUNT'])) {
$arguments[] = 'COUNT';
$arguments[] = $options['COUNT'];
}

if (isset($options['SORT'])) {
$arguments[] = strtoupper($options['SORT']);
}

if (isset($options['STORE'])) {
$arguments[] = 'STORE';
$arguments[] = $options['STORE'];
}

if (isset($options['STOREDIST'])) {
$arguments[] = 'STOREDIST';
$arguments[] = $options['STOREDIST'];
}
}

return $arguments;
}
}
<?php










namespace Predis\Command;






class StringSetRange extends Command
{



public function getId()
{
return 'SETRANGE';
}
}
<?php










namespace Predis\Command;






class SetAdd extends Command
{



public function getId()
{
return 'SADD';
}




protected function filterArguments(array $arguments)
{
return self::normalizeVariadic($arguments);
}
}
<?php










namespace Predis\Command;






class ZSetIncrementBy extends Command
{



public function getId()
{
return 'ZINCRBY';
}
}
<?php










namespace Predis\Command;






class HashGet extends Command
{



public function getId()
{
return 'HGET';
}
}
<?php










namespace Predis\Command\Processor;

use Predis\Command\CommandInterface;






interface ProcessorInterface
{





public function process(CommandInterface $command);
}
<?php










namespace Predis\Command\Processor;

use Predis\Command\CommandInterface;
use Predis\Command\PrefixableCommandInterface;







class KeyPrefixProcessor implements ProcessorInterface
{
private $prefix;
private $commands;




public function __construct($prefix)
{
$this->prefix = $prefix;
$this->commands = array(

'EXISTS' => 'static::all',
'DEL' => 'static::all',
'TYPE' => 'static::first',
'KEYS' => 'static::first',
'RENAME' => 'static::all',
'RENAMENX' => 'static::all',
'EXPIRE' => 'static::first',
'EXPIREAT' => 'static::first',
'TTL' => 'static::first',
'MOVE' => 'static::first',
'SORT' => 'static::sort',
'DUMP' => 'static::first',
'RESTORE' => 'static::first',
'SET' => 'static::first',
'SETNX' => 'static::first',
'MSET' => 'static::interleaved',
'MSETNX' => 'static::interleaved',
'GET' => 'static::first',
'MGET' => 'static::all',
'GETSET' => 'static::first',
'INCR' => 'static::first',
'INCRBY' => 'static::first',
'DECR' => 'static::first',
'DECRBY' => 'static::first',
'RPUSH' => 'static::first',
'LPUSH' => 'static::first',
'LLEN' => 'static::first',
'LRANGE' => 'static::first',
'LTRIM' => 'static::first',
'LINDEX' => 'static::first',
'LSET' => 'static::first',
'LREM' => 'static::first',
'LPOP' => 'static::first',
'RPOP' => 'static::first',
'RPOPLPUSH' => 'static::all',
'SADD' => 'static::first',
'SREM' => 'static::first',
'SPOP' => 'static::first',
'SMOVE' => 'static::skipLast',
'SCARD' => 'static::first',
'SISMEMBER' => 'static::first',
'SINTER' => 'static::all',
'SINTERSTORE' => 'static::all',
'SUNION' => 'static::all',
'SUNIONSTORE' => 'static::all',
'SDIFF' => 'static::all',
'SDIFFSTORE' => 'static::all',
'SMEMBERS' => 'static::first',
'SRANDMEMBER' => 'static::first',
'ZADD' => 'static::first',
'ZINCRBY' => 'static::first',
'ZREM' => 'static::first',
'ZRANGE' => 'static::first',
'ZREVRANGE' => 'static::first',
'ZRANGEBYSCORE' => 'static::first',
'ZCARD' => 'static::first',
'ZSCORE' => 'static::first',
'ZREMRANGEBYSCORE' => 'static::first',

'SETEX' => 'static::first',
'APPEND' => 'static::first',
'SUBSTR' => 'static::first',
'BLPOP' => 'static::skipLast',
'BRPOP' => 'static::skipLast',
'ZUNIONSTORE' => 'static::zsetStore',
'ZINTERSTORE' => 'static::zsetStore',
'ZCOUNT' => 'static::first',
'ZRANK' => 'static::first',
'ZREVRANK' => 'static::first',
'ZREMRANGEBYRANK' => 'static::first',
'HSET' => 'static::first',
'HSETNX' => 'static::first',
'HMSET' => 'static::first',
'HINCRBY' => 'static::first',
'HGET' => 'static::first',
'HMGET' => 'static::first',
'HDEL' => 'static::first',
'HEXISTS' => 'static::first',
'HLEN' => 'static::first',
'HKEYS' => 'static::first',
'HVALS' => 'static::first',
'HGETALL' => 'static::first',
'SUBSCRIBE' => 'static::all',
'UNSUBSCRIBE' => 'static::all',
'PSUBSCRIBE' => 'static::all',
'PUNSUBSCRIBE' => 'static::all',
'PUBLISH' => 'static::first',

'PERSIST' => 'static::first',
'STRLEN' => 'static::first',
'SETRANGE' => 'static::first',
'GETRANGE' => 'static::first',
'SETBIT' => 'static::first',
'GETBIT' => 'static::first',
'RPUSHX' => 'static::first',
'LPUSHX' => 'static::first',
'LINSERT' => 'static::first',
'BRPOPLPUSH' => 'static::skipLast',
'ZREVRANGEBYSCORE' => 'static::first',
'WATCH' => 'static::all',

'PTTL' => 'static::first',
'PEXPIRE' => 'static::first',
'PEXPIREAT' => 'static::first',
'PSETEX' => 'static::first',
'INCRBYFLOAT' => 'static::first',
'BITOP' => 'static::skipFirst',
'BITCOUNT' => 'static::first',
'HINCRBYFLOAT' => 'static::first',
'EVAL' => 'static::evalKeys',
'EVALSHA' => 'static::evalKeys',
'MIGRATE' => 'static::migrate',

'SSCAN' => 'static::first',
'ZSCAN' => 'static::first',
'HSCAN' => 'static::first',
'PFADD' => 'static::first',
'PFCOUNT' => 'static::all',
'PFMERGE' => 'static::all',
'ZLEXCOUNT' => 'static::first',
'ZRANGEBYLEX' => 'static::first',
'ZREMRANGEBYLEX' => 'static::first',
'ZREVRANGEBYLEX' => 'static::first',
'BITPOS' => 'static::first',

'HSTRLEN' => 'static::first',
'BITFIELD' => 'static::first',
'GEOADD' => 'static::first',
'GEOHASH' => 'static::first',
'GEOPOS' => 'static::first',
'GEODIST' => 'static::first',
'GEORADIUS' => 'static::georadius',
'GEORADIUSBYMEMBER' => 'static::georadius',
);
}






public function setPrefix($prefix)
{
$this->prefix = $prefix;
}






public function getPrefix()
{
return $this->prefix;
}




public function process(CommandInterface $command)
{
if ($command instanceof PrefixableCommandInterface) {
$command->prefixKeys($this->prefix);
} elseif (isset($this->commands[$commandID = strtoupper($command->getId())])) {
call_user_func($this->commands[$commandID], $command, $this->prefix);
}
}

















public function setCommandHandler($commandID, $callback = null)
{
$commandID = strtoupper($commandID);

if (!isset($callback)) {
unset($this->commands[$commandID]);

return;
}

if (!is_callable($callback)) {
throw new \InvalidArgumentException(
'Callback must be a valid callable object or NULL'
);
}

$this->commands[$commandID] = $callback;
}




public function __toString()
{
return $this->getPrefix();
}







public static function first(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
$arguments[0] = "$prefix{$arguments[0]}";
$command->setRawArguments($arguments);
}
}







public static function all(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
foreach ($arguments as &$key) {
$key = "$prefix$key";
}

$command->setRawArguments($arguments);
}
}







public static function interleaved(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
$length = count($arguments);

for ($i = 0; $i < $length; $i += 2) {
$arguments[$i] = "$prefix{$arguments[$i]}";
}

$command->setRawArguments($arguments);
}
}







public static function skipFirst(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
$length = count($arguments);

for ($i = 1; $i < $length; ++$i) {
$arguments[$i] = "$prefix{$arguments[$i]}";
}

$command->setRawArguments($arguments);
}
}







public static function skipLast(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
$length = count($arguments);

for ($i = 0; $i < $length - 1; ++$i) {
$arguments[$i] = "$prefix{$arguments[$i]}";
}

$command->setRawArguments($arguments);
}
}







public static function sort(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
$arguments[0] = "$prefix{$arguments[0]}";

if (($count = count($arguments)) > 1) {
for ($i = 1; $i < $count; ++$i) {
switch (strtoupper($arguments[$i])) {
case 'BY':
case 'STORE':
$arguments[$i] = "$prefix{$arguments[++$i]}";
break;

case 'GET':
$value = $arguments[++$i];
if ($value !== '#') {
$arguments[$i] = "$prefix$value";
}
break;

case 'LIMIT';
$i += 2;
break;
}
}
}

$command->setRawArguments($arguments);
}
}







public static function evalKeys(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
for ($i = 2; $i < $arguments[1] + 2; ++$i) {
$arguments[$i] = "$prefix{$arguments[$i]}";
}

$command->setRawArguments($arguments);
}
}







public static function zsetStore(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
$arguments[0] = "$prefix{$arguments[0]}";
$length = ((int) $arguments[1]) + 2;

for ($i = 2; $i < $length; ++$i) {
$arguments[$i] = "$prefix{$arguments[$i]}";
}

$command->setRawArguments($arguments);
}
}







public static function migrate(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
$arguments[2] = "$prefix{$arguments[2]}";
$command->setRawArguments($arguments);
}
}







public static function georadius(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
$arguments[0] = "$prefix{$arguments[0]}";
$startIndex = $command->getId() === 'GEORADIUS' ? 5 : 4;

if (($count = count($arguments)) > $startIndex) {
for ($i = $startIndex; $i < $count; ++$i) {
switch (strtoupper($arguments[$i])) {
case 'STORE':
case 'STOREDIST':
$arguments[$i] = "$prefix{$arguments[++$i]}";
break;

}
}
}

$command->setRawArguments($arguments);
}
}
}
<?php










namespace Predis\Command\Processor;

use Predis\Command\CommandInterface;






class ProcessorChain implements \ArrayAccess, ProcessorInterface
{
private $processors = array();




public function __construct($processors = array())
{
foreach ($processors as $processor) {
$this->add($processor);
}
}




public function add(ProcessorInterface $processor)
{
$this->processors[] = $processor;
}




public function remove(ProcessorInterface $processor)
{
if (false !== $index = array_search($processor, $this->processors, true)) {
unset($this[$index]);
}
}




public function process(CommandInterface $command)
{
for ($i = 0; $i < $count = count($this->processors); ++$i) {
$this->processors[$i]->process($command);
}
}




public function getProcessors()
{
return $this->processors;
}






public function getIterator()
{
return new \ArrayIterator($this->processors);
}






public function count()
{
return count($this->processors);
}





 public function offsetExists($index)
{
return isset($this->processors[$index]);
}





 public function offsetGet($index)
{
return $this->processors[$index];
}





 public function offsetSet($index, $processor)
{
if (!$processor instanceof ProcessorInterface) {
throw new \InvalidArgumentException(
'A processor chain accepts only instances of '.
"'Predis\Command\Processor\ProcessorInterface'."
);
}

$this->processors[$index] = $processor;
}





 public function offsetUnset($index)
{
unset($this->processors[$index]);
$this->processors = array_values($this->processors);
}
}
<?php










namespace Predis\Collection\Iterator;

use Predis\ClientInterface;









class Keyspace extends CursorBasedIterator
{



public function __construct(ClientInterface $client, $match = null, $count = null)
{
$this->requiredCommand($client, 'SCAN');

parent::__construct($client, $match, $count);
}




protected function executeCommand()
{
return $this->client->scan($this->cursor, $this->getScanOptions());
}
}
<?php










namespace Predis\Collection\Iterator;

use Predis\ClientInterface;









class HashKey extends CursorBasedIterator
{
protected $key;




public function __construct(ClientInterface $client, $key, $match = null, $count = null)
{
$this->requiredCommand($client, 'HSCAN');

parent::__construct($client, $match, $count);

$this->key = $key;
}




protected function executeCommand()
{
return $this->client->hscan($this->key, $this->cursor, $this->getScanOptions());
}




protected function extractNext()
{
$this->position = key($this->elements);
$this->current = current($this->elements);

unset($this->elements[$this->position]);
}
}
<?php










namespace Predis\Collection\Iterator;

use Predis\ClientInterface;
use Predis\NotSupportedException;















class ListKey implements \Iterator
{
protected $client;
protected $count;
protected $key;

protected $valid;
protected $fetchmore;
protected $elements;
protected $position;
protected $current;








public function __construct(ClientInterface $client, $key, $count = 10)
{
$this->requiredCommand($client, 'LRANGE');

if ((false === $count = filter_var($count, FILTER_VALIDATE_INT)) || $count < 0) {
throw new \InvalidArgumentException('The $count argument must be a positive integer.');
}

$this->client = $client;
$this->key = $key;
$this->count = $count;

$this->reset();
}










protected function requiredCommand(ClientInterface $client, $commandID)
{
if (!$client->getProfile()->supportsCommand($commandID)) {
throw new NotSupportedException("The current profile does not support '$commandID'.");
}
}




protected function reset()
{
$this->valid = true;
$this->fetchmore = true;
$this->elements = array();
$this->position = -1;
$this->current = null;
}







protected function executeCommand()
{
return $this->client->lrange($this->key, $this->position + 1, $this->position + $this->count);
}





protected function fetch()
{
$elements = $this->executeCommand();

if (count($elements) < $this->count) {
$this->fetchmore = false;
}

$this->elements = $elements;
}




protected function extractNext()
{
++$this->position;
$this->current = array_shift($this->elements);
}





 public function rewind()
{
$this->reset();
$this->next();
}





 public function current()
{
return $this->current;
}





 public function key()
{
return $this->position;
}





 public function next()
{
if (!$this->elements && $this->fetchmore) {
$this->fetch();
}

if ($this->elements) {
$this->extractNext();
} else {
$this->valid = false;
}
}





 public function valid()
{
return $this->valid;
}
}
<?php










namespace Predis\Collection\Iterator;

use Predis\ClientInterface;









class SortedSetKey extends CursorBasedIterator
{
protected $key;




public function __construct(ClientInterface $client, $key, $match = null, $count = null)
{
$this->requiredCommand($client, 'ZSCAN');

parent::__construct($client, $match, $count);

$this->key = $key;
}




protected function executeCommand()
{
return $this->client->zscan($this->key, $this->cursor, $this->getScanOptions());
}




protected function extractNext()
{
$this->position = key($this->elements);
$this->current = current($this->elements);

unset($this->elements[$this->position]);
}
}
<?php










namespace Predis\Collection\Iterator;

use Predis\ClientInterface;
use Predis\NotSupportedException;














abstract class CursorBasedIterator implements \Iterator
{
protected $client;
protected $match;
protected $count;

protected $valid;
protected $fetchmore;
protected $elements;
protected $cursor;
protected $position;
protected $current;






public function __construct(ClientInterface $client, $match = null, $count = null)
{
$this->client = $client;
$this->match = $match;
$this->count = $count;

$this->reset();
}










protected function requiredCommand(ClientInterface $client, $commandID)
{
if (!$client->getProfile()->supportsCommand($commandID)) {
throw new NotSupportedException("The current profile does not support '$commandID'.");
}
}




protected function reset()
{
$this->valid = true;
$this->fetchmore = true;
$this->elements = array();
$this->cursor = 0;
$this->position = -1;
$this->current = null;
}






protected function getScanOptions()
{
$options = array();

if (strlen(strval($this->match)) > 0) {
$options['MATCH'] = $this->match;
}

if ($this->count > 0) {
$options['COUNT'] = $this->count;
}

return $options;
}







abstract protected function executeCommand();





protected function fetch()
{
list($cursor, $elements) = $this->executeCommand();

if (!$cursor) {
$this->fetchmore = false;
}

$this->cursor = $cursor;
$this->elements = $elements;
}




protected function extractNext()
{
++$this->position;
$this->current = array_shift($this->elements);
}





 public function rewind()
{
$this->reset();
$this->next();
}





 public function current()
{
return $this->current;
}





 public function key()
{
return $this->position;
}





 public function next()
{
tryFetch: {
if (!$this->elements && $this->fetchmore) {
$this->fetch();
}

if ($this->elements) {
$this->extractNext();
} elseif ($this->cursor) {
goto tryFetch;
} else {
$this->valid = false;
}
}
}





 public function valid()
{
return $this->valid;
}
}
<?php










namespace Predis\Collection\Iterator;

use Predis\ClientInterface;









class SetKey extends CursorBasedIterator
{
protected $key;




public function __construct(ClientInterface $client, $key, $match = null, $count = null)
{
$this->requiredCommand($client, 'SSCAN');

parent::__construct($client, $match, $count);

$this->key = $key;
}




protected function executeCommand()
{
return $this->client->sscan($this->key, $this->cursor, $this->getScanOptions());
}
}
<?php










namespace Predis;

use Predis\Connection\NodeConnectionInterface;






abstract class CommunicationException extends PredisException
{
private $connection;







public function __construct(
NodeConnectionInterface $connection,
$message = null,
$code = null,
\Exception $innerException = null
) {
parent::__construct(
is_null($message) ? '' : $message,
is_null($code) ? 0 : $code,
$innerException
);

$this->connection = $connection;
}






public function getConnection()
{
return $this->connection;
}






public function shouldResetConnection()
{
return true;
}








public static function handle(CommunicationException $exception)
{
if ($exception->shouldResetConnection()) {
$connection = $exception->getConnection();

if ($connection->isConnected()) {
$connection->disconnect();
}
}

throw $exception;
}
}
<?php










namespace Predis;






class ClientException extends PredisException
{
}
<?php










require __DIR__.'/src/Autoloader.php';

Predis\Autoloader::register();
<?php










require __DIR__.'/shared.php';








use Predis\Command\ScriptCommand;
use Predis\Connection\Aggregate\MasterSlaveReplication;
use Predis\Replication\ReplicationStrategy;






class HashMultipleGetAll extends ScriptCommand
{
const BODY = <<<LUA
local hashes = {}
for _, key in pairs(KEYS) do
    table.insert(hashes, key)
    table.insert(hashes, redis.call('hgetall', key))
end
return hashes
LUA;

public function getScript()
{
return self::BODY;
}
}



$parameters = array(
'tcp://127.0.0.1:6379/?alias=master',
'tcp://127.0.0.1:6380/?alias=slave',
);

$options = array(
'profile' => function ($options, $option) {
$profile = $options->getDefault($option);
$profile->defineCommand('hmgetall', 'HashMultipleGetAll');

return $profile;
},
'replication' => function () {
$strategy = new ReplicationStrategy();
$strategy->setScriptReadOnly(HashMultipleGetAll::BODY);

$replication = new MasterSlaveReplication($strategy);

return $replication;
},
);



$client = new Predis\Client($parameters, $options);





$hashes = $client->hmgetall('metavars', 'servers');

$replication = $client->getConnection();
$stillOnSlave = $replication->getCurrent() === $replication->getConnectionById('slave');

echo 'Is still on slave? ', $stillOnSlave ? 'YES!' : 'NO!', PHP_EOL;
var_export($hashes);
<?php










require __DIR__.'/shared.php';






$client = new Predis\Client($single_server, array('prefix' => 'nrk:'));

$client->mset(array('foo' => 'bar', 'lol' => 'wut'));
var_export($client->mget('foo', 'lol'));







var_export($client->keys('*'));






<?php










require __DIR__.'/shared.php';





use Predis\Cluster\Distributor\DistributorInterface;
use Predis\Cluster\Hash\HashGeneratorInterface;
use Predis\Cluster\PredisStrategy;
use Predis\Connection\Aggregate\PredisCluster;

class NaiveDistributor implements DistributorInterface, HashGeneratorInterface
{
private $nodes;
private $nodesCount;

public function __construct()
{
$this->nodes = array();
$this->nodesCount = 0;
}

public function add($node, $weight = null)
{
$this->nodes[] = $node;
++$this->nodesCount;
}

public function remove($node)
{
$this->nodes = array_filter($this->nodes, function ($n) use ($node) {
return $n !== $node;
});

$this->nodesCount = count($this->nodes);
}

public function getSlot($hash)
{
return $this->nodesCount > 1 ? abs($hash % $this->nodesCount) : 0;
}

public function getBySlot($slot)
{
return isset($this->nodes[$slot]) ? $this->nodes[$slot] : null;
}

public function getByHash($hash)
{
if (!$this->nodesCount) {
throw new RuntimeException('No connections.');
}

$slot = $this->getSlot($hash);
$node = $this->getBySlot($slot);

return $node;
}

public function get($value)
{
$hash = $this->hash($value);
$node = $this->getByHash($hash);

return $node;
}

public function hash($value)
{
return crc32($value);
}

public function getHashGenerator()
{
return $this;
}
}

$options = array(
'cluster' => function () {
$distributor = new NaiveDistributor();
$strategy = new PredisStrategy($distributor);
$cluster = new PredisCluster($strategy);

return $cluster;
},
);

$client = new Predis\Client($multiple_servers, $options);

for ($i = 0; $i < 100; ++$i) {
$client->set("key:$i", str_pad($i, 4, '0', 0));
$client->get("key:$i");
}

$server1 = $client->getClientFor('first')->info();
$server2 = $client->getClientFor('second')->info();

if (isset($server1['Keyspace'], $server2['Keyspace'])) {
$server1 = $server1['Keyspace'];
$server2 = $server2['Keyspace'];
}

printf("Server '%s' has %d keys while server '%s' has %d keys.\n",
'first', $server1['db15']['keys'], 'second', $server2['db15']['keys']
);
<?php










require __DIR__.'/shared.php';














function zpop($client, $key)
{
$element = null;
$options = array(
'cas' => true, 
 'watch' => $key, 
 'retry' => 3, 
 
 );

$client->transaction($options, function ($tx) use ($key, &$element) {
@list($element) = $tx->zrange($key, 0, 0);

if (isset($element)) {
$tx->multi(); 
 $tx->zrem($key, $element);
}
});

return $element;
}

$client = new Predis\Client($single_server);
$zpopped = zpop($client, 'zset');

echo isset($zpopped) ? "ZPOPed $zpopped" : 'Nothing to ZPOP!', PHP_EOL;
<?php










if (PHP_SAPI !== 'cli') {
die("Example scripts are meant to be executed locally via CLI.");
}

require __DIR__.'/../autoload.php';

function redis_version($info)
{
if (isset($info['Server']['redis_version'])) {
return $info['Server']['redis_version'];
} elseif (isset($info['redis_version'])) {
return $info['redis_version'];
} else {
return 'unknown version';
}
}

$single_server = array(
'host' => '127.0.0.1',
'port' => 6379,
'database' => 15,
);

$multiple_servers = array(
array(
'host' => '127.0.0.1',
'port' => 6379,
'database' => 15,
'alias' => 'first',
),
array(
'host' => '127.0.0.1',
'port' => 6380,
'database' => 15,
'alias' => 'second',
),
);
<?php










require __DIR__.'/shared.php';






use Predis\Command\CommandInterface;
use Predis\Connection\StreamConnection;

class SimpleDebuggableConnection extends StreamConnection
{
private $tstart = 0;
private $debugBuffer = array();

public function connect()
{
$this->tstart = microtime(true);

parent::connect();
}

private function storeDebug(CommandInterface $command, $direction)
{
$firtsArg = $command->getArgument(0);
$timestamp = round(microtime(true) - $this->tstart, 4);

$debug = $command->getId();
$debug .= isset($firtsArg) ? " $firtsArg " : ' ';
$debug .= "$direction $this";
$debug .= " [{$timestamp}s]";

$this->debugBuffer[] = $debug;
}

public function writeRequest(CommandInterface $command)
{
parent::writeRequest($command);

$this->storeDebug($command, '->');
}

public function readResponse(CommandInterface $command)
{
$response = parent::readResponse($command);
$this->storeDebug($command, '<-');

return $response;
}

public function getDebugBuffer()
{
return $this->debugBuffer;
}
}

$options = array(
'connections' => array(
'tcp' => 'SimpleDebuggableConnection',
),
);

$client = new Predis\Client($single_server, $options);
$client->set('foo', 'bar');
$client->get('foo');
$client->info();

var_export($client->getConnection()->getDebugBuffer());













<?php










require __DIR__.'/shared.php';

use Predis\Collection\Iterator;


















$client = new Predis\Client($single_server, array('profile' => '2.8'));


$client->del('predis:set', 'predis:zset', 'predis:hash');
for ($i = 0; $i < 5; ++$i) {
$client->sadd('predis:set', "member:$i");
$client->zadd('predis:zset', -$i, "member:$i");
$client->hset('predis:hash', "field:$i", "value:$i");
}


echo 'Scan the keyspace matching only our prefixed keys:', PHP_EOL;
foreach (new Iterator\Keyspace($client, 'predis:*') as $key) {
echo " - $key", PHP_EOL;
}









echo 'Scan members of `predis:set`:', PHP_EOL;
foreach (new Iterator\SetKey($client, 'predis:set') as $member) {
echo " - $member", PHP_EOL;
}











echo 'Scan members and ranks of `predis:zset`:', PHP_EOL;
foreach (new Iterator\SortedSetKey($client, 'predis:zset') as $member => $rank) {
echo " - $member [rank: $rank]", PHP_EOL;
}











echo 'Scan fields and values of `predis:hash`:', PHP_EOL;
foreach (new Iterator\HashKey($client, 'predis:hash') as $field => $value) {
echo " - $field => $value", PHP_EOL;
}









<?php










require __DIR__.'/shared.php';





$client = new Predis\Client($single_server);

$responses = $client->pipeline(function ($pipe) {
$pipe->flushdb();
$pipe->incrby('counter', 10);
$pipe->incrby('counter', 30);
$pipe->exists('counter');
$pipe->get('counter');
$pipe->mget('does_not_exist', 'counter');
});

var_export($responses);
















<?php










require __DIR__.'/shared.php';







$client = new Predis\Client($single_server + array('read_write_timeout' => 0));


$timestamp = new DateTime();

foreach (($monitor = $client->monitor()) as $event) {
$timestamp->setTimestamp((int) $event->timestamp);


 
 if ($event->command === 'ECHO' && $event->arguments === '"QUIT_MONITOR"') {
echo 'Exiting the monitor loop...', PHP_EOL;
$monitor->stop();
break;
}

echo "* Received {$event->command} on DB {$event->database} at {$timestamp->format(DateTime::W3C)}", PHP_EOL;
if (isset($event->arguments)) {
echo "    Arguments: {$event->arguments}", PHP_EOL;
}
}


$version = redis_version($client->info());
echo "Goodbye from Redis $version!", PHP_EOL;
<?php










require __DIR__.'/shared.php';















$sentinels = array(
'tcp://127.0.0.1:5380?timeout=0.100',
'tcp://127.0.0.1:5381?timeout=0.100',
'tcp://127.0.0.1:5382?timeout=0.100',
);

$client = new Predis\Client($sentinels, array(
'replication' => 'sentinel',
'service' => 'mymaster',
));


$exists = $client->exists('foo') ? 'yes' : 'no';
$current = $client->getConnection()->getCurrent()->getParameters();
echo "Does 'foo' exist on {$current->alias}? $exists.", PHP_EOL;


$client->set('foo', 'bar');
$current = $client->getConnection()->getCurrent()->getParameters();
echo "Now 'foo' has been set to 'bar' on {$current->alias}!", PHP_EOL;


$bar = $client->get('foo');
$current = $client->getConnection()->getCurrent()->getParameters();
echo "We fetched 'foo' from {$current->alias} and its value is '$bar'.", PHP_EOL;






<?php










require __DIR__.'/shared.php';













$client = new Predis\Client($single_server + array('read_write_timeout' => 0));


$pubsub = $client->pubSubLoop();


$dispatcher = new Predis\PubSub\DispatcherLoop($pubsub);


class EventsListener implements Countable
{
private $events;

public function __construct()
{
$this->events = array();
}

public function count()
{
return count($this->events);
}

public function getEvents()
{
return $this->events;
}

public function __invoke($payload)
{
$this->events[] = $payload;
}
}


$dispatcher->attachCallback('events', ($events = new EventsListener()));


$dispatcher->attachCallback('control', function ($payload) use ($dispatcher) {
if ($payload === 'terminate_dispatcher') {
$dispatcher->stop();
}
});



$dispatcher->run();


echo "We received {$events->count()} messages!", PHP_EOL;


$version = redis_version($client->info());
echo "Goodbye from Redis $version!", PHP_EOL;
<?php










require __DIR__.'/shared.php';











$parameters = array(
'tcp://127.0.0.1:6379?database=15&alias=master',
'tcp://127.0.0.1:6380?database=15&alias=slave',
);

$options = array('replication' => true);

$client = new Predis\Client($parameters, $options);


$exists = $client->exists('foo') ? 'yes' : 'no';
$current = $client->getConnection()->getCurrent()->getParameters();
echo "Does 'foo' exist on {$current->alias}? $exists.", PHP_EOL;


$client->set('foo', 'bar');
$current = $client->getConnection()->getCurrent()->getParameters();
echo "Now 'foo' has been set to 'bar' on {$current->alias}!", PHP_EOL;


$bar = $client->get('foo');
$current = $client->getConnection()->getCurrent()->getParameters();
echo "We fetched 'foo' from {$current->alias} and its value is '$bar'.", PHP_EOL;






<?php










require __DIR__.'/shared.php';









use Predis\Command\ScriptCommand;

class IncrementExistingKeysBy extends ScriptCommand
{
public function getKeysCount()
{

 
 return -1;
}

public function getScript()
{
return <<<LUA
local cmd, insert = redis.call, table.insert
local increment, results = ARGV[1], { }

for idx, key in ipairs(KEYS) do
  if cmd('exists', key) == 1 then
    insert(results, idx, cmd('incrby', key, increment))
  else
    insert(results, idx, false)
  end
end

return results
LUA;
}
}

$client = new Predis\Client($single_server, array(
'profile' => function ($options) {
$profile = $options->getDefault('profile');
$profile->defineCommand('increxby', 'IncrementExistingKeysBy');

return $profile;
},
));

$client->mset('foo', 10, 'foobar', 100);

var_export($client->increxby('foo', 'foofoo', 'foobar', 50));








<?php










require __DIR__.'/shared.php';





$client = new Predis\Client($single_server + array('read_write_timeout' => 0));


$pubsub = $client->pubSubLoop();


$pubsub->subscribe('control_channel', 'notifications');





foreach ($pubsub as $message) {
switch ($message->kind) {
case 'subscribe':
echo "Subscribed to {$message->channel}", PHP_EOL;
break;

case 'message':
if ($message->channel == 'control_channel') {
if ($message->payload == 'quit_loop') {
echo 'Aborting pubsub loop...', PHP_EOL;
$pubsub->unsubscribe();
} else {
echo "Received an unrecognized command: {$message->payload}.", PHP_EOL;
}
} else {
echo "Received the following message from {$message->channel}:",
PHP_EOL, "  {$message->payload}", PHP_EOL, PHP_EOL;
}
break;
}
}




unset($pubsub);


$version = redis_version($client->info());
echo "Goodbye from Redis $version!", PHP_EOL;
<?php










require __DIR__.'/shared.php';

$client = new Predis\Client($single_server);


$client->set('library', 'predis');
$response = $client->get('library');

var_export($response); echo PHP_EOL;





$mkv = array(
'uid:0001' => '1st user',
'uid:0002' => '2nd user',
'uid:0003' => '3rd user',
);

$client->mset($mkv);
$response = $client->mget(array_keys($mkv));

var_export($response); echo PHP_EOL;











$response = $client->executeRaw(array(
'MGET', 'uid:0001', 'uid:0002', 'uid:0003',
));

var_export($response); echo PHP_EOL;






<?php










require __DIR__.'/shared.php';














if (!interface_exists('SessionHandlerInterface')) {
die('ATTENTION: the session handler implemented by Predis requires PHP >= 5.4.0 '.
"or a polyfill for SessionHandlerInterface provided by an external package.\n");
}



$client = new Predis\Client($single_server, array('prefix' => 'sessions:'));


$handler = new Predis\Session\Handler($client, array('gc_maxlifetime' => 5));


$handler->register();


session_id('example_session_id');

session_start();

if (isset($_SESSION['foo'])) {
echo "Session has `foo` set to {$_SESSION['foo']}", PHP_EOL;
} else {
$_SESSION['foo'] = $value = mt_rand();
echo "Empty session, `foo` has been set with $value", PHP_EOL;
}
<?php

namespace DeepCopy\TypeMatcher;

class TypeMatcher
{



private $type;




public function __construct($type)
{
$this->type = $type;
}






public function matches($element)
{
return is_object($element) ? is_a($element, $this->type) : gettype($element) === $this->type;
}
}
<?php

namespace DeepCopy;

use function function_exists;

if (false === function_exists('DeepCopy\deep_copy')) {








function deep_copy($value, $useCloneMethod = false)
{
return (new DeepCopy($useCloneMethod))->copy($value);
}
}
<?php

namespace DeepCopy\Matcher\Doctrine;

use DeepCopy\Matcher\Matcher;
use Doctrine\Common\Persistence\Proxy;




class DoctrineProxyMatcher implements Matcher
{





public function matches($object, $property)
{
return $object instanceof Proxy;
}
}
<?php

namespace DeepCopy\Matcher;




class PropertyNameMatcher implements Matcher
{



private $property;




public function __construct($property)
{
$this->property = $property;
}






public function matches($object, $property)
{
return $property == $this->property;
}
}
<?php

namespace DeepCopy\Matcher;




class PropertyMatcher implements Matcher
{



private $class;




private $property;





public function __construct($class, $property)
{
$this->class = $class;
$this->property = $property;
}






public function matches($object, $property)
{
return ($object instanceof $this->class) && $property == $this->property;
}
}
<?php

namespace DeepCopy\Matcher;

interface Matcher
{






public function matches($object, $property);
}
<?php

namespace DeepCopy\Matcher;

use DeepCopy\Reflection\ReflectionHelper;
use ReflectionException;









class PropertyTypeMatcher implements Matcher
{



private $propertyType;




public function __construct($propertyType)
{
$this->propertyType = $propertyType;
}




public function matches($object, $property)
{
try {
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
} catch (ReflectionException $exception) {
return false;
}

$reflectionProperty->setAccessible(true);


 if (method_exists($reflectionProperty, 'isInitialized') && !$reflectionProperty->isInitialized($object)) {

 return false;
}

return $reflectionProperty->getValue($object) instanceof $this->propertyType;
}
}
<?php

namespace DeepCopy\Reflection;

use DeepCopy\Exception\PropertyException;
use ReflectionClass;
use ReflectionException;
use ReflectionObject;
use ReflectionProperty;

class ReflectionHelper
{












public static function getProperties(ReflectionClass $ref)
{
$props = $ref->getProperties();
$propsArr = array();

foreach ($props as $prop) {
$propertyName = $prop->getName();
$propsArr[$propertyName] = $prop;
}

if ($parentClass = $ref->getParentClass()) {
$parentPropsArr = self::getProperties($parentClass);
foreach ($propsArr as $key => $property) {
$parentPropsArr[$key] = $property;
}

return $parentPropsArr;
}

return $propsArr;
}












public static function getProperty($object, $name)
{
$reflection = is_object($object) ? new ReflectionObject($object) : new ReflectionClass($object);

if ($reflection->hasProperty($name)) {
return $reflection->getProperty($name);
}

if ($parentClass = $reflection->getParentClass()) {
return self::getProperty($parentClass->getName(), $name);
}

throw new PropertyException(
sprintf(
'The class "%s" doesn\'t have a property with the given name: "%s".',
is_object($object) ? get_class($object) : $object,
$name
)
);
}
}
<?php

namespace DeepCopy;

use ArrayObject;
use DateInterval;
use DateTimeInterface;
use DateTimeZone;
use DeepCopy\Exception\CloneException;
use DeepCopy\Filter\Filter;
use DeepCopy\Matcher\Matcher;
use DeepCopy\Reflection\ReflectionHelper;
use DeepCopy\TypeFilter\Date\DateIntervalFilter;
use DeepCopy\TypeFilter\Spl\ArrayObjectFilter;
use DeepCopy\TypeFilter\Spl\SplDoublyLinkedListFilter;
use DeepCopy\TypeFilter\TypeFilter;
use DeepCopy\TypeMatcher\TypeMatcher;
use ReflectionObject;
use ReflectionProperty;
use SplDoublyLinkedList;




class DeepCopy
{



private $hashMap = [];






private $filters = [];






private $typeFilters = [];




private $skipUncloneable = false;




private $useCloneMethod;





public function __construct($useCloneMethod = false)
{
$this->useCloneMethod = $useCloneMethod;

$this->addTypeFilter(new ArrayObjectFilter($this), new TypeMatcher(ArrayObject::class));
$this->addTypeFilter(new DateIntervalFilter(), new TypeMatcher(DateInterval::class));
$this->addTypeFilter(new SplDoublyLinkedListFilter($this), new TypeMatcher(SplDoublyLinkedList::class));
}








public function skipUncloneable($skipUncloneable = true)
{
$this->skipUncloneable = $skipUncloneable;

return $this;
}








public function copy($object)
{
$this->hashMap = [];

return $this->recursiveCopy($object);
}

public function addFilter(Filter $filter, Matcher $matcher)
{
$this->filters[] = [
'matcher' => $matcher,
'filter' => $filter,
];
}

public function prependFilter(Filter $filter, Matcher $matcher)
{
array_unshift($this->filters, [
'matcher' => $matcher,
'filter' => $filter,
]);
}

public function addTypeFilter(TypeFilter $filter, TypeMatcher $matcher)
{
$this->typeFilters[] = [
'matcher' => $matcher,
'filter' => $filter,
];
}

private function recursiveCopy($var)
{

 if ($filter = $this->getFirstMatchedTypeFilter($this->typeFilters, $var)) {
return $filter->apply($var);
}


 if (is_resource($var)) {
return $var;
}


 if (is_array($var)) {
return $this->copyArray($var);
}


 if (! is_object($var)) {
return $var;
}


 return $this->copyObject($var);
}






private function copyArray(array $array)
{
foreach ($array as $key => $value) {
$array[$key] = $this->recursiveCopy($value);
}

return $array;
}










private function copyObject($object)
{
$objectHash = spl_object_hash($object);

if (isset($this->hashMap[$objectHash])) {
return $this->hashMap[$objectHash];
}

$reflectedObject = new ReflectionObject($object);
$isCloneable = $reflectedObject->isCloneable();

if (false === $isCloneable) {
if ($this->skipUncloneable) {
$this->hashMap[$objectHash] = $object;

return $object;
}

throw new CloneException(
sprintf(
'The class "%s" is not cloneable.',
$reflectedObject->getName()
)
);
}

$newObject = clone $object;
$this->hashMap[$objectHash] = $newObject;

if ($this->useCloneMethod && $reflectedObject->hasMethod('__clone')) {
return $newObject;
}

if ($newObject instanceof DateTimeInterface || $newObject instanceof DateTimeZone) {
return $newObject;
}

foreach (ReflectionHelper::getProperties($reflectedObject) as $property) {
$this->copyObjectProperty($newObject, $property);
}

return $newObject;
}

private function copyObjectProperty($object, ReflectionProperty $property)
{

 if ($property->isStatic()) {
return;
}


 foreach ($this->filters as $item) {

$matcher = $item['matcher'];

$filter = $item['filter'];

if ($matcher->matches($object, $property->getName())) {
$filter->apply(
$object,
$property->getName(),
function ($object) {
return $this->recursiveCopy($object);
}
);


 return;
}
}

$property->setAccessible(true);


 if (method_exists($property, 'isInitialized') && !$property->isInitialized($object)) {
return;
}

$propertyValue = $property->getValue($object);


 $property->setValue($object, $this->recursiveCopy($propertyValue));
}










private function getFirstMatchedTypeFilter(array $filterRecords, $var)
{
$matched = $this->first(
$filterRecords,
function (array $record) use ($var) {

$matcher = $record['matcher'];

return $matcher->matches($var);
}
);

return isset($matched) ? $matched['filter'] : null;
}










private function first(array $elements, callable $predicate)
{
foreach ($elements as $element) {
if (call_user_func($predicate, $element)) {
return $element;
}
}

return null;
}
}
<?php

namespace DeepCopy\TypeFilter;

interface TypeFilter
{





public function apply($element);
}
<?php

namespace DeepCopy\TypeFilter\Date;

use DateInterval;
use DeepCopy\TypeFilter\TypeFilter;






class DateIntervalFilter implements TypeFilter
{








public function apply($element)
{
$copy = new DateInterval('P0D');

foreach ($element as $propertyName => $propertyValue) {
$copy->{$propertyName} = $propertyValue;
}

return $copy;
}
}
<?php

namespace DeepCopy\TypeFilter;




class ShallowCopyFilter implements TypeFilter
{



public function apply($element)
{
return clone $element;
}
}
<?php

namespace DeepCopy\TypeFilter;




class ReplaceFilter implements TypeFilter
{



protected $callback;




public function __construct(callable $callable)
{
$this->callback = $callable;
}




public function apply($element)
{
return call_user_func($this->callback, $element);
}
}
<?php

namespace DeepCopy\TypeFilter\Spl;




class SplDoublyLinkedList extends SplDoublyLinkedListFilter
{
}
<?php

namespace DeepCopy\TypeFilter\Spl;

use Closure;
use DeepCopy\DeepCopy;
use DeepCopy\TypeFilter\TypeFilter;
use SplDoublyLinkedList;




class SplDoublyLinkedListFilter implements TypeFilter
{
private $copier;

public function __construct(DeepCopy $copier)
{
$this->copier = $copier;
}




public function apply($element)
{
$newElement = clone $element;

$copy = $this->createCopyClosure();

return $copy($newElement);
}

private function createCopyClosure()
{
$copier = $this->copier;

$copy = function (SplDoublyLinkedList $list) use ($copier) {

 for ($i = 1; $i <= $list->count(); $i++) {
$copy = $copier->recursiveCopy($list->shift());

$list->push($copy);
}

return $list;
};

return Closure::bind($copy, null, DeepCopy::class);
}
}
<?php
namespace DeepCopy\TypeFilter\Spl;

use DeepCopy\DeepCopy;
use DeepCopy\TypeFilter\TypeFilter;





final class ArrayObjectFilter implements TypeFilter
{



private $copier;

public function __construct(DeepCopy $copier)
{
$this->copier = $copier;
}




public function apply($arrayObject)
{
$clone = clone $arrayObject;
foreach ($arrayObject->getArrayCopy() as $k => $v) {
$clone->offsetSet($k, $this->copier->copy($v));
}

return $clone;
}
}

<?php

namespace DeepCopy\Filter;

class KeepFilter implements Filter
{





public function apply($object, $property, $objectCopier)
{

 }
}
<?php

namespace DeepCopy\Filter\Doctrine;

use DeepCopy\Filter\Filter;




class DoctrineProxyFilter implements Filter
{






public function apply($object, $property, $objectCopier)
{
$object->__load();
}
}
<?php

namespace DeepCopy\Filter\Doctrine;

use DeepCopy\Filter\Filter;
use DeepCopy\Reflection\ReflectionHelper;




class DoctrineCollectionFilter implements Filter
{





public function apply($object, $property, $objectCopier)
{
$reflectionProperty = ReflectionHelper::getProperty($object, $property);

$reflectionProperty->setAccessible(true);
$oldCollection = $reflectionProperty->getValue($object);

$newCollection = $oldCollection->map(
function ($item) use ($objectCopier) {
return $objectCopier($item);
}
);

$reflectionProperty->setValue($object, $newCollection);
}
}
<?php

namespace DeepCopy\Filter\Doctrine;

use DeepCopy\Filter\Filter;
use DeepCopy\Reflection\ReflectionHelper;
use Doctrine\Common\Collections\ArrayCollection;




class DoctrineEmptyCollectionFilter implements Filter
{







public function apply($object, $property, $objectCopier)
{
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
$reflectionProperty->setAccessible(true);

$reflectionProperty->setValue($object, new ArrayCollection());
}
} <?php

namespace DeepCopy\Filter;

use DeepCopy\Reflection\ReflectionHelper;




class SetNullFilter implements Filter
{





public function apply($object, $property, $objectCopier)
{
$reflectionProperty = ReflectionHelper::getProperty($object, $property);

$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue($object, null);
}
}
<?php

namespace DeepCopy\Filter;

use DeepCopy\Reflection\ReflectionHelper;




class ReplaceFilter implements Filter
{



protected $callback;




public function __construct(callable $callable)
{
$this->callback = $callable;
}






public function apply($object, $property, $objectCopier)
{
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
$reflectionProperty->setAccessible(true);

$value = call_user_func($this->callback, $reflectionProperty->getValue($object));

$reflectionProperty->setValue($object, $value);
}
}
<?php

namespace DeepCopy\Filter;




interface Filter
{







public function apply($object, $property, $objectCopier);
}
<?php

namespace DeepCopy\Exception;

use UnexpectedValueException;

class CloneException extends UnexpectedValueException
{
} <?php

namespace DeepCopy\Exception;

use ReflectionException;

class PropertyException extends ReflectionException
{
}
<?php










use Symfony\Polyfill\Intl\Normalizer as p;

if (\PHP_VERSION_ID >= 80000) {
return require __DIR__.'/bootstrap80.php';
}

if (!function_exists('normalizer_is_normalized')) {
function normalizer_is_normalized($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::isNormalized($string, $form); }
}
if (!function_exists('normalizer_normalize')) {
function normalizer_normalize($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::normalize($string, $form); }
}
<?php










use Symfony\Polyfill\Intl\Normalizer as p;

if (!function_exists('normalizer_is_normalized')) {
function normalizer_is_normalized(?string $string, ?int $form = p\Normalizer::FORM_C): bool { return p\Normalizer::isNormalized((string) $string, (int) $form); }
}
if (!function_exists('normalizer_normalize')) {
function normalizer_normalize(?string $string, ?int $form = p\Normalizer::FORM_C): string|false { return p\Normalizer::normalize((string) $string, (int) $form); }
}
<?php










namespace Symfony\Polyfill\Intl\Normalizer;











class Normalizer
{
public const FORM_D = \Normalizer::FORM_D;
public const FORM_KD = \Normalizer::FORM_KD;
public const FORM_C = \Normalizer::FORM_C;
public const FORM_KC = \Normalizer::FORM_KC;
public const NFD = \Normalizer::NFD;
public const NFKD = \Normalizer::NFKD;
public const NFC = \Normalizer::NFC;
public const NFKC = \Normalizer::NFKC;

private static $C;
private static $D;
private static $KD;
private static $cC;
private static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
private static $ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";

public static function isNormalized(string $s, int $form = self::FORM_C)
{
if (!\in_array($form, [self::NFD, self::NFKD, self::NFC, self::NFKC])) {
return false;
}
if (!isset($s[strspn($s, self::$ASCII)])) {
return true;
}
if (self::NFC == $form && preg_match('//u', $s) && !preg_match('/[^\x00-\x{2FF}]/u', $s)) {
return true;
}

return self::normalize($s, $form) === $s;
}

public static function normalize(string $s, int $form = self::FORM_C)
{
if (!preg_match('//u', $s)) {
return false;
}

switch ($form) {
case self::NFC: $C = true; $K = false; break;
case self::NFD: $C = false; $K = false; break;
case self::NFKC: $C = true; $K = true; break;
case self::NFKD: $C = false; $K = true; break;
default:
if (\defined('Normalizer::NONE') && \Normalizer::NONE == $form) {
return $s;
}

if (80000 > \PHP_VERSION_ID) {
return false;
}

throw new \ValueError('normalizer_normalize(): Argument #2 ($form) must be a a valid normalization form');
}

if ('' === $s) {
return '';
}

if ($K && null === self::$KD) {
self::$KD = self::getData('compatibilityDecomposition');
}

if (null === self::$D) {
self::$D = self::getData('canonicalDecomposition');
self::$cC = self::getData('combiningClass');
}

if (null !== $mbEncoding = (2  & (int) ini_get('mbstring.func_overload')) ? mb_internal_encoding() : null) {
mb_internal_encoding('8bit');
}

$r = self::decompose($s, $K);

if ($C) {
if (null === self::$C) {
self::$C = self::getData('canonicalComposition');
}

$r = self::recompose($r);
}
if (null !== $mbEncoding) {
mb_internal_encoding($mbEncoding);
}

return $r;
}

private static function recompose($s)
{
$ASCII = self::$ASCII;
$compMap = self::$C;
$combClass = self::$cC;
$ulenMask = self::$ulenMask;

$result = $tail = '';

$i = $s[0] < "\x80" ? 1 : $ulenMask[$s[0] & "\xF0"];
$len = \strlen($s);

$lastUchr = substr($s, 0, $i);
$lastUcls = isset($combClass[$lastUchr]) ? 256 : 0;

while ($i < $len) {
if ($s[$i] < "\x80") {


if ($tail) {
$lastUchr .= $tail;
$tail = '';
}

if ($j = strspn($s, $ASCII, $i + 1)) {
$lastUchr .= substr($s, $i, $j);
$i += $j;
}

$result .= $lastUchr;
$lastUchr = $s[$i];
$lastUcls = 0;
++$i;
continue;
}

$ulen = $ulenMask[$s[$i] & "\xF0"];
$uchr = substr($s, $i, $ulen);

if ($lastUchr < "\xE1\x84\x80" || "\xE1\x84\x92" < $lastUchr
|| $uchr < "\xE1\x85\xA1" || "\xE1\x85\xB5" < $uchr
|| $lastUcls) {


$ucls = $combClass[$uchr] ?? 0;

if (isset($compMap[$lastUchr.$uchr]) && (!$lastUcls || $lastUcls < $ucls)) {
$lastUchr = $compMap[$lastUchr.$uchr];
} elseif ($lastUcls = $ucls) {
$tail .= $uchr;
} else {
if ($tail) {
$lastUchr .= $tail;
$tail = '';
}

$result .= $lastUchr;
$lastUchr = $uchr;
}
} else {


$L = \ord($lastUchr[2]) - 0x80;
$V = \ord($uchr[2]) - 0xA1;
$T = 0;

$uchr = substr($s, $i + $ulen, 3);

if ("\xE1\x86\xA7" <= $uchr && $uchr <= "\xE1\x87\x82") {
$T = \ord($uchr[2]) - 0xA7;
0 > $T && $T += 0x40;
$ulen += 3;
}

$L = 0xAC00 + ($L * 21 + $V) * 28 + $T;
$lastUchr = \chr(0xE0 | $L >> 12).\chr(0x80 | $L >> 6 & 0x3F).\chr(0x80 | $L & 0x3F);
}

$i += $ulen;
}

return $result.$lastUchr.$tail;
}

private static function decompose($s, $c)
{
$result = '';

$ASCII = self::$ASCII;
$decompMap = self::$D;
$combClass = self::$cC;
$ulenMask = self::$ulenMask;
if ($c) {
$compatMap = self::$KD;
}

$c = [];
$i = 0;
$len = \strlen($s);

while ($i < $len) {
if ($s[$i] < "\x80") {


if ($c) {
ksort($c);
$result .= implode('', $c);
$c = [];
}

$j = 1 + strspn($s, $ASCII, $i + 1);
$result .= substr($s, $i, $j);
$i += $j;
continue;
}

$ulen = $ulenMask[$s[$i] & "\xF0"];
$uchr = substr($s, $i, $ulen);
$i += $ulen;

if ($uchr < "\xEA\xB0\x80" || "\xED\x9E\xA3" < $uchr) {


if ($uchr !== $j = $compatMap[$uchr] ?? ($decompMap[$uchr] ?? $uchr)) {
$uchr = $j;

$j = \strlen($uchr);
$ulen = $uchr[0] < "\x80" ? 1 : $ulenMask[$uchr[0] & "\xF0"];

if ($ulen != $j) {


$j -= $ulen;
$i -= $j;

if (0 > $i) {
$s = str_repeat(' ', -$i).$s;
$len -= $i;
$i = 0;
}

while ($j--) {
$s[$i + $j] = $uchr[$ulen + $j];
}

$uchr = substr($uchr, 0, $ulen);
}
}
if (isset($combClass[$uchr])) {


if (!isset($c[$combClass[$uchr]])) {
$c[$combClass[$uchr]] = '';
}
$c[$combClass[$uchr]] .= $uchr;
continue;
}
} else {


$uchr = unpack('C*', $uchr);
$j = (($uchr[1] - 224) << 12) + (($uchr[2] - 128) << 6) + $uchr[3] - 0xAC80;

$uchr = "\xE1\x84".\chr(0x80 + (int) ($j / 588))
."\xE1\x85".\chr(0xA1 + (int) (($j % 588) / 28));

if ($j %= 28) {
$uchr .= $j < 25
? ("\xE1\x86".\chr(0xA7 + $j))
: ("\xE1\x87".\chr(0x67 + $j));
}
}
if ($c) {
ksort($c);
$result .= implode('', $c);
$c = [];
}

$result .= $uchr;
}

if ($c) {
ksort($c);
$result .= implode('', $c);
}

return $result;
}

private static function getData($file)
{
if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
return require $file;
}

return false;
}
}
<?php

return array (
'̀' => 230,
'́' => 230,
'̂' => 230,
'̃' => 230,
'̄' => 230,
'̅' => 230,
'̆' => 230,
'̇' => 230,
'̈' => 230,
'̉' => 230,
'̊' => 230,
'̋' => 230,
'̌' => 230,
'̍' => 230,
'̎' => 230,
'̏' => 230,
'̐' => 230,
'̑' => 230,
'̒' => 230,
'̓' => 230,
'̔' => 230,
'̕' => 232,
'̖' => 220,
'̗' => 220,
'̘' => 220,
'̙' => 220,
'̚' => 232,
'̛' => 216,
'̜' => 220,
'̝' => 220,
'̞' => 220,
'̟' => 220,
'̠' => 220,
'̡' => 202,
'̢' => 202,
'̣' => 220,
'̤' => 220,
'̥' => 220,
'̦' => 220,
'̧' => 202,
'̨' => 202,
'̩' => 220,
'̪' => 220,
'̫' => 220,
'̬' => 220,
'̭' => 220,
'̮' => 220,
'̯' => 220,
'̰' => 220,
'̱' => 220,
'̲' => 220,
'̳' => 220,
'̴' => 1,
'̵' => 1,
'̶' => 1,
'̷' => 1,
'̸' => 1,
'̹' => 220,
'̺' => 220,
'̻' => 220,
'̼' => 220,
'̽' => 230,
'̾' => 230,
'̿' => 230,
'̀' => 230,
'́' => 230,
'͂' => 230,
'̓' => 230,
'̈́' => 230,
'ͅ' => 240,
'͆' => 230,
'͇' => 220,
'͈' => 220,
'͉' => 220,
'͊' => 230,
'͋' => 230,
'͌' => 230,
'͍' => 220,
'͎' => 220,
'͐' => 230,
'͑' => 230,
'͒' => 230,
'͓' => 220,
'͔' => 220,
'͕' => 220,
'͖' => 220,
'͗' => 230,
'͘' => 232,
'͙' => 220,
'͚' => 220,
'͛' => 230,
'͜' => 233,
'͝' => 234,
'͞' => 234,
'͟' => 233,
'͠' => 234,
'͡' => 234,
'͢' => 233,
'ͣ' => 230,
'ͤ' => 230,
'ͥ' => 230,
'ͦ' => 230,
'ͧ' => 230,
'ͨ' => 230,
'ͩ' => 230,
'ͪ' => 230,
'ͫ' => 230,
'ͬ' => 230,
'ͭ' => 230,
'ͮ' => 230,
'ͯ' => 230,
'҃' => 230,
'҄' => 230,
'҅' => 230,
'҆' => 230,
'҇' => 230,
'֑' => 220,
'֒' => 230,
'֓' => 230,
'֔' => 230,
'֕' => 230,
'֖' => 220,
'֗' => 230,
'֘' => 230,
'֙' => 230,
'֚' => 222,
'֛' => 220,
'֜' => 230,
'֝' => 230,
'֞' => 230,
'֟' => 230,
'֠' => 230,
'֡' => 230,
'֢' => 220,
'֣' => 220,
'֤' => 220,
'֥' => 220,
'֦' => 220,
'֧' => 220,
'֨' => 230,
'֩' => 230,
'֪' => 220,
'֫' => 230,
'֬' => 230,
'֭' => 222,
'֮' => 228,
'֯' => 230,
'ְ' => 10,
'ֱ' => 11,
'ֲ' => 12,
'ֳ' => 13,
'ִ' => 14,
'ֵ' => 15,
'ֶ' => 16,
'ַ' => 17,
'ָ' => 18,
'ֹ' => 19,
'ֺ' => 19,
'ֻ' => 20,
'ּ' => 21,
'ֽ' => 22,
'ֿ' => 23,
'ׁ' => 24,
'ׂ' => 25,
'ׄ' => 230,
'ׅ' => 220,
'ׇ' => 18,
'ؐ' => 230,
'ؑ' => 230,
'ؒ' => 230,
'ؓ' => 230,
'ؔ' => 230,
'ؕ' => 230,
'ؖ' => 230,
'ؗ' => 230,
'ؘ' => 30,
'ؙ' => 31,
'ؚ' => 32,
'ً' => 27,
'ٌ' => 28,
'ٍ' => 29,
'َ' => 30,
'ُ' => 31,
'ِ' => 32,
'ّ' => 33,
'ْ' => 34,
'ٓ' => 230,
'ٔ' => 230,
'ٕ' => 220,
'ٖ' => 220,
'ٗ' => 230,
'٘' => 230,
'ٙ' => 230,
'ٚ' => 230,
'ٛ' => 230,
'ٜ' => 220,
'ٝ' => 230,
'ٞ' => 230,
'ٟ' => 220,
'ٰ' => 35,
'ۖ' => 230,
'ۗ' => 230,
'ۘ' => 230,
'ۙ' => 230,
'ۚ' => 230,
'ۛ' => 230,
'ۜ' => 230,
'۟' => 230,
'۠' => 230,
'ۡ' => 230,
'ۢ' => 230,
'ۣ' => 220,
'ۤ' => 230,
'ۧ' => 230,
'ۨ' => 230,
'۪' => 220,
'۫' => 230,
'۬' => 230,
'ۭ' => 220,
'ܑ' => 36,
'ܰ' => 230,
'ܱ' => 220,
'ܲ' => 230,
'ܳ' => 230,
'ܴ' => 220,
'ܵ' => 230,
'ܶ' => 230,
'ܷ' => 220,
'ܸ' => 220,
'ܹ' => 220,
'ܺ' => 230,
'ܻ' => 220,
'ܼ' => 220,
'ܽ' => 230,
'ܾ' => 220,
'ܿ' => 230,
'݀' => 230,
'݁' => 230,
'݂' => 220,
'݃' => 230,
'݄' => 220,
'݅' => 230,
'݆' => 220,
'݇' => 230,
'݈' => 220,
'݉' => 230,
'݊' => 230,
'߫' => 230,
'߬' => 230,
'߭' => 230,
'߮' => 230,
'߯' => 230,
'߰' => 230,
'߱' => 230,
'߲' => 220,
'߳' => 230,
'߽' => 220,
'ࠖ' => 230,
'ࠗ' => 230,
'࠘' => 230,
'࠙' => 230,
'ࠛ' => 230,
'ࠜ' => 230,
'ࠝ' => 230,
'ࠞ' => 230,
'ࠟ' => 230,
'ࠠ' => 230,
'ࠡ' => 230,
'ࠢ' => 230,
'ࠣ' => 230,
'ࠥ' => 230,
'ࠦ' => 230,
'ࠧ' => 230,
'ࠩ' => 230,
'ࠪ' => 230,
'ࠫ' => 230,
'ࠬ' => 230,
'࠭' => 230,
'࡙' => 220,
'࡚' => 220,
'࡛' => 220,
'࣓' => 220,
'ࣔ' => 230,
'ࣕ' => 230,
'ࣖ' => 230,
'ࣗ' => 230,
'ࣘ' => 230,
'ࣙ' => 230,
'ࣚ' => 230,
'ࣛ' => 230,
'ࣜ' => 230,
'ࣝ' => 230,
'ࣞ' => 230,
'ࣟ' => 230,
'࣠' => 230,
'࣡' => 230,
'ࣣ' => 220,
'ࣤ' => 230,
'ࣥ' => 230,
'ࣦ' => 220,
'ࣧ' => 230,
'ࣨ' => 230,
'ࣩ' => 220,
'࣪' => 230,
'࣫' => 230,
'࣬' => 230,
'࣭' => 220,
'࣮' => 220,
'࣯' => 220,
'ࣰ' => 27,
'ࣱ' => 28,
'ࣲ' => 29,
'ࣳ' => 230,
'ࣴ' => 230,
'ࣵ' => 230,
'ࣶ' => 220,
'ࣷ' => 230,
'ࣸ' => 230,
'ࣹ' => 220,
'ࣺ' => 220,
'ࣻ' => 230,
'ࣼ' => 230,
'ࣽ' => 230,
'ࣾ' => 230,
'ࣿ' => 230,
'़' => 7,
'्' => 9,
'॑' => 230,
'॒' => 220,
'॓' => 230,
'॔' => 230,
'়' => 7,
'্' => 9,
'৾' => 230,
'਼' => 7,
'੍' => 9,
'઼' => 7,
'્' => 9,
'଼' => 7,
'୍' => 9,
'்' => 9,
'్' => 9,
'ౕ' => 84,
'ౖ' => 91,
'಼' => 7,
'್' => 9,
'഻' => 9,
'഼' => 9,
'്' => 9,
'්' => 9,
'ุ' => 103,
'ู' => 103,
'ฺ' => 9,
'่' => 107,
'้' => 107,
'๊' => 107,
'๋' => 107,
'ຸ' => 118,
'ູ' => 118,
'຺' => 9,
'່' => 122,
'້' => 122,
'໊' => 122,
'໋' => 122,
'༘' => 220,
'༙' => 220,
'༵' => 220,
'༷' => 220,
'༹' => 216,
'ཱ' => 129,
'ི' => 130,
'ུ' => 132,
'ེ' => 130,
'ཻ' => 130,
'ོ' => 130,
'ཽ' => 130,
'ྀ' => 130,
'ྂ' => 230,
'ྃ' => 230,
'྄' => 9,
'྆' => 230,
'྇' => 230,
'࿆' => 220,
'့' => 7,
'္' => 9,
'်' => 9,
'ႍ' => 220,
'፝' => 230,
'፞' => 230,
'፟' => 230,
'᜔' => 9,
'᜴' => 9,
'្' => 9,
'៝' => 230,
'ᢩ' => 228,
'᤹' => 222,
'᤺' => 230,
'᤻' => 220,
'ᨗ' => 230,
'ᨘ' => 220,
'᩠' => 9,
'᩵' => 230,
'᩶' => 230,
'᩷' => 230,
'᩸' => 230,
'᩹' => 230,
'᩺' => 230,
'᩻' => 230,
'᩼' => 230,
'᩿' => 220,
'᪰' => 230,
'᪱' => 230,
'᪲' => 230,
'᪳' => 230,
'᪴' => 230,
'᪵' => 220,
'᪶' => 220,
'᪷' => 220,
'᪸' => 220,
'᪹' => 220,
'᪺' => 220,
'᪻' => 230,
'᪼' => 230,
'᪽' => 220,
'ᪿ' => 220,
'ᫀ' => 220,
'᬴' => 7,
'᭄' => 9,
'᭫' => 230,
'᭬' => 220,
'᭭' => 230,
'᭮' => 230,
'᭯' => 230,
'᭰' => 230,
'᭱' => 230,
'᭲' => 230,
'᭳' => 230,
'᮪' => 9,
'᮫' => 9,
'᯦' => 7,
'᯲' => 9,
'᯳' => 9,
'᰷' => 7,
'᳐' => 230,
'᳑' => 230,
'᳒' => 230,
'᳔' => 1,
'᳕' => 220,
'᳖' => 220,
'᳗' => 220,
'᳘' => 220,
'᳙' => 220,
'᳚' => 230,
'᳛' => 230,
'᳜' => 220,
'᳝' => 220,
'᳞' => 220,
'᳟' => 220,
'᳠' => 230,
'᳢' => 1,
'᳣' => 1,
'᳤' => 1,
'᳥' => 1,
'᳦' => 1,
'᳧' => 1,
'᳨' => 1,
'᳭' => 220,
'᳴' => 230,
'᳸' => 230,
'᳹' => 230,
'᷀' => 230,
'᷁' => 230,
'᷂' => 220,
'᷃' => 230,
'᷄' => 230,
'᷅' => 230,
'᷆' => 230,
'᷇' => 230,
'᷈' => 230,
'᷉' => 230,
'᷊' => 220,
'᷋' => 230,
'᷌' => 230,
'᷍' => 234,
'᷎' => 214,
'᷏' => 220,
'᷐' => 202,
'᷑' => 230,
'᷒' => 230,
'ᷓ' => 230,
'ᷔ' => 230,
'ᷕ' => 230,
'ᷖ' => 230,
'ᷗ' => 230,
'ᷘ' => 230,
'ᷙ' => 230,
'ᷚ' => 230,
'ᷛ' => 230,
'ᷜ' => 230,
'ᷝ' => 230,
'ᷞ' => 230,
'ᷟ' => 230,
'ᷠ' => 230,
'ᷡ' => 230,
'ᷢ' => 230,
'ᷣ' => 230,
'ᷤ' => 230,
'ᷥ' => 230,
'ᷦ' => 230,
'ᷧ' => 230,
'ᷨ' => 230,
'ᷩ' => 230,
'ᷪ' => 230,
'ᷫ' => 230,
'ᷬ' => 230,
'ᷭ' => 230,
'ᷮ' => 230,
'ᷯ' => 230,
'ᷰ' => 230,
'ᷱ' => 230,
'ᷲ' => 230,
'ᷳ' => 230,
'ᷴ' => 230,
'᷵' => 230,
'᷶' => 232,
'᷷' => 228,
'᷸' => 228,
'᷹' => 220,
'᷻' => 230,
'᷼' => 233,
'᷽' => 220,
'᷾' => 230,
'᷿' => 220,
'⃐' => 230,
'⃑' => 230,
'⃒' => 1,
'⃓' => 1,
'⃔' => 230,
'⃕' => 230,
'⃖' => 230,
'⃗' => 230,
'⃘' => 1,
'⃙' => 1,
'⃚' => 1,
'⃛' => 230,
'⃜' => 230,
'⃡' => 230,
'⃥' => 1,
'⃦' => 1,
'⃧' => 230,
'⃨' => 220,
'⃩' => 230,
'⃪' => 1,
'⃫' => 1,
'⃬' => 220,
'⃭' => 220,
'⃮' => 220,
'⃯' => 220,
'⃰' => 230,
'⳯' => 230,
'⳰' => 230,
'⳱' => 230,
'⵿' => 9,
'ⷠ' => 230,
'ⷡ' => 230,
'ⷢ' => 230,
'ⷣ' => 230,
'ⷤ' => 230,
'ⷥ' => 230,
'ⷦ' => 230,
'ⷧ' => 230,
'ⷨ' => 230,
'ⷩ' => 230,
'ⷪ' => 230,
'ⷫ' => 230,
'ⷬ' => 230,
'ⷭ' => 230,
'ⷮ' => 230,
'ⷯ' => 230,
'ⷰ' => 230,
'ⷱ' => 230,
'ⷲ' => 230,
'ⷳ' => 230,
'ⷴ' => 230,
'ⷵ' => 230,
'ⷶ' => 230,
'ⷷ' => 230,
'ⷸ' => 230,
'ⷹ' => 230,
'ⷺ' => 230,
'ⷻ' => 230,
'ⷼ' => 230,
'ⷽ' => 230,
'ⷾ' => 230,
'ⷿ' => 230,
'〪' => 218,
'〫' => 228,
'〬' => 232,
'〭' => 222,
'〮' => 224,
'〯' => 224,
'゙' => 8,
'゚' => 8,
'꙯' => 230,
'ꙴ' => 230,
'ꙵ' => 230,
'ꙶ' => 230,
'ꙷ' => 230,
'ꙸ' => 230,
'ꙹ' => 230,
'ꙺ' => 230,
'ꙻ' => 230,
'꙼' => 230,
'꙽' => 230,
'ꚞ' => 230,
'ꚟ' => 230,
'꛰' => 230,
'꛱' => 230,
'꠆' => 9,
'꠬' => 9,
'꣄' => 9,
'꣠' => 230,
'꣡' => 230,
'꣢' => 230,
'꣣' => 230,
'꣤' => 230,
'꣥' => 230,
'꣦' => 230,
'꣧' => 230,
'꣨' => 230,
'꣩' => 230,
'꣪' => 230,
'꣫' => 230,
'꣬' => 230,
'꣭' => 230,
'꣮' => 230,
'꣯' => 230,
'꣰' => 230,
'꣱' => 230,
'꤫' => 220,
'꤬' => 220,
'꤭' => 220,
'꥓' => 9,
'꦳' => 7,
'꧀' => 9,
'ꪰ' => 230,
'ꪲ' => 230,
'ꪳ' => 230,
'ꪴ' => 220,
'ꪷ' => 230,
'ꪸ' => 230,
'ꪾ' => 230,
'꪿' => 230,
'꫁' => 230,
'꫶' => 9,
'꯭' => 9,
'ﬞ' => 26,
'︠' => 230,
'︡' => 230,
'︢' => 230,
'︣' => 230,
'︤' => 230,
'︥' => 230,
'︦' => 230,
'︧' => 220,
'︨' => 220,
'︩' => 220,
'︪' => 220,
'︫' => 220,
'︬' => 220,
'︭' => 220,
'︮' => 230,
'︯' => 230,
'𐇽' => 220,
'𐋠' => 220,
'𐍶' => 230,
'𐍷' => 230,
'𐍸' => 230,
'𐍹' => 230,
'𐍺' => 230,
'𐨍' => 220,
'𐨏' => 230,
'𐨸' => 230,
'𐨹' => 1,
'𐨺' => 220,
'𐨿' => 9,
'𐫥' => 230,
'𐫦' => 220,
'𐴤' => 230,
'𐴥' => 230,
'𐴦' => 230,
'𐴧' => 230,
'𐺫' => 230,
'𐺬' => 230,
'𐽆' => 220,
'𐽇' => 220,
'𐽈' => 230,
'𐽉' => 230,
'𐽊' => 230,
'𐽋' => 220,
'𐽌' => 230,
'𐽍' => 220,
'𐽎' => 220,
'𐽏' => 220,
'𐽐' => 220,
'𑁆' => 9,
'𑁿' => 9,
'𑂹' => 9,
'𑂺' => 7,
'𑄀' => 230,
'𑄁' => 230,
'𑄂' => 230,
'𑄳' => 9,
'𑄴' => 9,
'𑅳' => 7,
'𑇀' => 9,
'𑇊' => 7,
'𑈵' => 9,
'𑈶' => 7,
'𑋩' => 7,
'𑋪' => 9,
'𑌻' => 7,
'𑌼' => 7,
'𑍍' => 9,
'𑍦' => 230,
'𑍧' => 230,
'𑍨' => 230,
'𑍩' => 230,
'𑍪' => 230,
'𑍫' => 230,
'𑍬' => 230,
'𑍰' => 230,
'𑍱' => 230,
'𑍲' => 230,
'𑍳' => 230,
'𑍴' => 230,
'𑑂' => 9,
'𑑆' => 7,
'𑑞' => 230,
'𑓂' => 9,
'𑓃' => 7,
'𑖿' => 9,
'𑗀' => 7,
'𑘿' => 9,
'𑚶' => 9,
'𑚷' => 7,
'𑜫' => 9,
'𑠹' => 9,
'𑠺' => 7,
'𑤽' => 9,
'𑤾' => 9,
'𑥃' => 7,
'𑧠' => 9,
'𑨴' => 9,
'𑩇' => 9,
'𑪙' => 9,
'𑰿' => 9,
'𑵂' => 7,
'𑵄' => 9,
'𑵅' => 9,
'𑶗' => 9,
'𖫰' => 1,
'𖫱' => 1,
'𖫲' => 1,
'𖫳' => 1,
'𖫴' => 1,
'𖬰' => 230,
'𖬱' => 230,
'𖬲' => 230,
'𖬳' => 230,
'𖬴' => 230,
'𖬵' => 230,
'𖬶' => 230,
'𖿰' => 6,
'𖿱' => 6,
'𛲞' => 1,
'𝅥' => 216,
'𝅦' => 216,
'𝅧' => 1,
'𝅨' => 1,
'𝅩' => 1,
'𝅭' => 226,
'𝅮' => 216,
'𝅯' => 216,
'𝅰' => 216,
'𝅱' => 216,
'𝅲' => 216,
'𝅻' => 220,
'𝅼' => 220,
'𝅽' => 220,
'𝅾' => 220,
'𝅿' => 220,
'𝆀' => 220,
'𝆁' => 220,
'𝆂' => 220,
'𝆅' => 230,
'𝆆' => 230,
'𝆇' => 230,
'𝆈' => 230,
'𝆉' => 230,
'𝆊' => 220,
'𝆋' => 220,
'𝆪' => 230,
'𝆫' => 230,
'𝆬' => 230,
'𝆭' => 230,
'𝉂' => 230,
'𝉃' => 230,
'𝉄' => 230,
'𞀀' => 230,
'𞀁' => 230,
'𞀂' => 230,
'𞀃' => 230,
'𞀄' => 230,
'𞀅' => 230,
'𞀆' => 230,
'𞀈' => 230,
'𞀉' => 230,
'𞀊' => 230,
'𞀋' => 230,
'𞀌' => 230,
'𞀍' => 230,
'𞀎' => 230,
'𞀏' => 230,
'𞀐' => 230,
'𞀑' => 230,
'𞀒' => 230,
'𞀓' => 230,
'𞀔' => 230,
'𞀕' => 230,
'𞀖' => 230,
'𞀗' => 230,
'𞀘' => 230,
'𞀛' => 230,
'𞀜' => 230,
'𞀝' => 230,
'𞀞' => 230,
'𞀟' => 230,
'𞀠' => 230,
'𞀡' => 230,
'𞀣' => 230,
'𞀤' => 230,
'𞀦' => 230,
'𞀧' => 230,
'𞀨' => 230,
'𞀩' => 230,
'𞀪' => 230,
'𞄰' => 230,
'𞄱' => 230,
'𞄲' => 230,
'𞄳' => 230,
'𞄴' => 230,
'𞄵' => 230,
'𞄶' => 230,
'𞋬' => 230,
'𞋭' => 230,
'𞋮' => 230,
'𞋯' => 230,
'𞣐' => 220,
'𞣑' => 220,
'𞣒' => 220,
'𞣓' => 220,
'𞣔' => 220,
'𞣕' => 220,
'𞣖' => 220,
'𞥄' => 230,
'𞥅' => 230,
'𞥆' => 230,
'𞥇' => 230,
'𞥈' => 230,
'𞥉' => 230,
'𞥊' => 7,
);
<?php

return array (
' ' => ' ',
'¨' => ' ̈',
'ª' => 'a',
'¯' => ' ̄',
'²' => '2',
'³' => '3',
'´' => ' ́',
'µ' => 'μ',
'¸' => ' ̧',
'¹' => '1',
'º' => 'o',
'¼' => '1⁄4',
'½' => '1⁄2',
'¾' => '3⁄4',
'Ĳ' => 'IJ',
'ĳ' => 'ij',
'Ŀ' => 'L·',
'ŀ' => 'l·',
'ŉ' => 'ʼn',
'ſ' => 's',
'Ǆ' => 'DŽ',
'ǅ' => 'Dž',
'ǆ' => 'dž',
'Ǉ' => 'LJ',
'ǈ' => 'Lj',
'ǉ' => 'lj',
'Ǌ' => 'NJ',
'ǋ' => 'Nj',
'ǌ' => 'nj',
'Ǳ' => 'DZ',
'ǲ' => 'Dz',
'ǳ' => 'dz',
'ʰ' => 'h',
'ʱ' => 'ɦ',
'ʲ' => 'j',
'ʳ' => 'r',
'ʴ' => 'ɹ',
'ʵ' => 'ɻ',
'ʶ' => 'ʁ',
'ʷ' => 'w',
'ʸ' => 'y',
'˘' => ' ̆',
'˙' => ' ̇',
'˚' => ' ̊',
'˛' => ' ̨',
'˜' => ' ̃',
'˝' => ' ̋',
'ˠ' => 'ɣ',
'ˡ' => 'l',
'ˢ' => 's',
'ˣ' => 'x',
'ˤ' => 'ʕ',
'ͺ' => ' ͅ',
'΄' => ' ́',
'΅' => ' ̈́',
'ϐ' => 'β',
'ϑ' => 'θ',
'ϒ' => 'Υ',
'ϓ' => 'Ύ',
'ϔ' => 'Ϋ',
'ϕ' => 'φ',
'ϖ' => 'π',
'ϰ' => 'κ',
'ϱ' => 'ρ',
'ϲ' => 'ς',
'ϴ' => 'Θ',
'ϵ' => 'ε',
'Ϲ' => 'Σ',
'և' => 'եւ',
'ٵ' => 'اٴ',
'ٶ' => 'وٴ',
'ٷ' => 'ۇٴ',
'ٸ' => 'يٴ',
'ำ' => 'ํา',
'ຳ' => 'ໍາ',
'ໜ' => 'ຫນ',
'ໝ' => 'ຫມ',
'༌' => '་',
'ཷ' => 'ྲཱྀ',
'ཹ' => 'ླཱྀ',
'ჼ' => 'ნ',
'ᴬ' => 'A',
'ᴭ' => 'Æ',
'ᴮ' => 'B',
'ᴰ' => 'D',
'ᴱ' => 'E',
'ᴲ' => 'Ǝ',
'ᴳ' => 'G',
'ᴴ' => 'H',
'ᴵ' => 'I',
'ᴶ' => 'J',
'ᴷ' => 'K',
'ᴸ' => 'L',
'ᴹ' => 'M',
'ᴺ' => 'N',
'ᴼ' => 'O',
'ᴽ' => 'Ȣ',
'ᴾ' => 'P',
'ᴿ' => 'R',
'ᵀ' => 'T',
'ᵁ' => 'U',
'ᵂ' => 'W',
'ᵃ' => 'a',
'ᵄ' => 'ɐ',
'ᵅ' => 'ɑ',
'ᵆ' => 'ᴂ',
'ᵇ' => 'b',
'ᵈ' => 'd',
'ᵉ' => 'e',
'ᵊ' => 'ə',
'ᵋ' => 'ɛ',
'ᵌ' => 'ɜ',
'ᵍ' => 'g',
'ᵏ' => 'k',
'ᵐ' => 'm',
'ᵑ' => 'ŋ',
'ᵒ' => 'o',
'ᵓ' => 'ɔ',
'ᵔ' => 'ᴖ',
'ᵕ' => 'ᴗ',
'ᵖ' => 'p',
'ᵗ' => 't',
'ᵘ' => 'u',
'ᵙ' => 'ᴝ',
'ᵚ' => 'ɯ',
'ᵛ' => 'v',
'ᵜ' => 'ᴥ',
'ᵝ' => 'β',
'ᵞ' => 'γ',
'ᵟ' => 'δ',
'ᵠ' => 'φ',
'ᵡ' => 'χ',
'ᵢ' => 'i',
'ᵣ' => 'r',
'ᵤ' => 'u',
'ᵥ' => 'v',
'ᵦ' => 'β',
'ᵧ' => 'γ',
'ᵨ' => 'ρ',
'ᵩ' => 'φ',
'ᵪ' => 'χ',
'ᵸ' => 'н',
'ᶛ' => 'ɒ',
'ᶜ' => 'c',
'ᶝ' => 'ɕ',
'ᶞ' => 'ð',
'ᶟ' => 'ɜ',
'ᶠ' => 'f',
'ᶡ' => 'ɟ',
'ᶢ' => 'ɡ',
'ᶣ' => 'ɥ',
'ᶤ' => 'ɨ',
'ᶥ' => 'ɩ',
'ᶦ' => 'ɪ',
'ᶧ' => 'ᵻ',
'ᶨ' => 'ʝ',
'ᶩ' => 'ɭ',
'ᶪ' => 'ᶅ',
'ᶫ' => 'ʟ',
'ᶬ' => 'ɱ',
'ᶭ' => 'ɰ',
'ᶮ' => 'ɲ',
'ᶯ' => 'ɳ',
'ᶰ' => 'ɴ',
'ᶱ' => 'ɵ',
'ᶲ' => 'ɸ',
'ᶳ' => 'ʂ',
'ᶴ' => 'ʃ',
'ᶵ' => 'ƫ',
'ᶶ' => 'ʉ',
'ᶷ' => 'ʊ',
'ᶸ' => 'ᴜ',
'ᶹ' => 'ʋ',
'ᶺ' => 'ʌ',
'ᶻ' => 'z',
'ᶼ' => 'ʐ',
'ᶽ' => 'ʑ',
'ᶾ' => 'ʒ',
'ᶿ' => 'θ',
'ẚ' => 'aʾ',
'ẛ' => 'ṡ',
'᾽' => ' ̓',
'᾿' => ' ̓',
'῀' => ' ͂',
'῁' => ' ̈͂',
'῍' => ' ̓̀',
'῎' => ' ̓́',
'῏' => ' ̓͂',
'῝' => ' ̔̀',
'῞' => ' ̔́',
'῟' => ' ̔͂',
'῭' => ' ̈̀',
'΅' => ' ̈́',
'´' => ' ́',
'῾' => ' ̔',
' ' => ' ',
' ' => ' ',
' ' => ' ',
' ' => ' ',
' ' => ' ',
' ' => ' ',
' ' => ' ',
' ' => ' ',
' ' => ' ',
' ' => ' ',
' ' => ' ',
'‑' => '‐',
'‗' => ' ̳',
'․' => '.',
'‥' => '..',
'…' => '...',
' ' => ' ',
'″' => '′′',
'‴' => '′′′',
'‶' => '‵‵',
'‷' => '‵‵‵',
'‼' => '!!',
'‾' => ' ̅',
'⁇' => '??',
'⁈' => '?!',
'⁉' => '!?',
'⁗' => '′′′′',
' ' => ' ',
'⁰' => '0',
'ⁱ' => 'i',
'⁴' => '4',
'⁵' => '5',
'⁶' => '6',
'⁷' => '7',
'⁸' => '8',
'⁹' => '9',
'⁺' => '+',
'⁻' => '−',
'⁼' => '=',
'⁽' => '(',
'⁾' => ')',
'ⁿ' => 'n',
'₀' => '0',
'₁' => '1',
'₂' => '2',
'₃' => '3',
'₄' => '4',
'₅' => '5',
'₆' => '6',
'₇' => '7',
'₈' => '8',
'₉' => '9',
'₊' => '+',
'₋' => '−',
'₌' => '=',
'₍' => '(',
'₎' => ')',
'ₐ' => 'a',
'ₑ' => 'e',
'ₒ' => 'o',
'ₓ' => 'x',
'ₔ' => 'ə',
'ₕ' => 'h',
'ₖ' => 'k',
'ₗ' => 'l',
'ₘ' => 'm',
'ₙ' => 'n',
'ₚ' => 'p',
'ₛ' => 's',
'ₜ' => 't',
'₨' => 'Rs',
'℀' => 'a/c',
'℁' => 'a/s',
'ℂ' => 'C',
'℃' => '°C',
'℅' => 'c/o',
'℆' => 'c/u',
'ℇ' => 'Ɛ',
'℉' => '°F',
'ℊ' => 'g',
'ℋ' => 'H',
'ℌ' => 'H',
'ℍ' => 'H',
'ℎ' => 'h',
'ℏ' => 'ħ',
'ℐ' => 'I',
'ℑ' => 'I',
'ℒ' => 'L',
'ℓ' => 'l',
'ℕ' => 'N',
'№' => 'No',
'ℙ' => 'P',
'ℚ' => 'Q',
'ℛ' => 'R',
'ℜ' => 'R',
'ℝ' => 'R',
'℠' => 'SM',
'℡' => 'TEL',
'™' => 'TM',
'ℤ' => 'Z',
'ℨ' => 'Z',
'ℬ' => 'B',
'ℭ' => 'C',
'ℯ' => 'e',
'ℰ' => 'E',
'ℱ' => 'F',
'ℳ' => 'M',
'ℴ' => 'o',
'ℵ' => 'א',
'ℶ' => 'ב',
'ℷ' => 'ג',
'ℸ' => 'ד',
'ℹ' => 'i',
'℻' => 'FAX',
'ℼ' => 'π',
'ℽ' => 'γ',
'ℾ' => 'Γ',
'ℿ' => 'Π',
'⅀' => '∑',
'ⅅ' => 'D',
'ⅆ' => 'd',
'ⅇ' => 'e',
'ⅈ' => 'i',
'ⅉ' => 'j',
'⅐' => '1⁄7',
'⅑' => '1⁄9',
'⅒' => '1⁄10',
'⅓' => '1⁄3',
'⅔' => '2⁄3',
'⅕' => '1⁄5',
'⅖' => '2⁄5',
'⅗' => '3⁄5',
'⅘' => '4⁄5',
'⅙' => '1⁄6',
'⅚' => '5⁄6',
'⅛' => '1⁄8',
'⅜' => '3⁄8',
'⅝' => '5⁄8',
'⅞' => '7⁄8',
'⅟' => '1⁄',
'Ⅰ' => 'I',
'Ⅱ' => 'II',
'Ⅲ' => 'III',
'Ⅳ' => 'IV',
'Ⅴ' => 'V',
'Ⅵ' => 'VI',
'Ⅶ' => 'VII',
'Ⅷ' => 'VIII',
'Ⅸ' => 'IX',
'Ⅹ' => 'X',
'Ⅺ' => 'XI',
'Ⅻ' => 'XII',
'Ⅼ' => 'L',
'Ⅽ' => 'C',
'Ⅾ' => 'D',
'Ⅿ' => 'M',
'ⅰ' => 'i',
'ⅱ' => 'ii',
'ⅲ' => 'iii',
'ⅳ' => 'iv',
'ⅴ' => 'v',
'ⅵ' => 'vi',
'ⅶ' => 'vii',
'ⅷ' => 'viii',
'ⅸ' => 'ix',
'ⅹ' => 'x',
'ⅺ' => 'xi',
'ⅻ' => 'xii',
'ⅼ' => 'l',
'ⅽ' => 'c',
'ⅾ' => 'd',
'ⅿ' => 'm',
'↉' => '0⁄3',
'∬' => '∫∫',
'∭' => '∫∫∫',
'∯' => '∮∮',
'∰' => '∮∮∮',
'①' => '1',
'②' => '2',
'③' => '3',
'④' => '4',
'⑤' => '5',
'⑥' => '6',
'⑦' => '7',
'⑧' => '8',
'⑨' => '9',
'⑩' => '10',
'⑪' => '11',
'⑫' => '12',
'⑬' => '13',
'⑭' => '14',
'⑮' => '15',
'⑯' => '16',
'⑰' => '17',
'⑱' => '18',
'⑲' => '19',
'⑳' => '20',
'⑴' => '(1)',
'⑵' => '(2)',
'⑶' => '(3)',
'⑷' => '(4)',
'⑸' => '(5)',
'⑹' => '(6)',
'⑺' => '(7)',
'⑻' => '(8)',
'⑼' => '(9)',
'⑽' => '(10)',
'⑾' => '(11)',
'⑿' => '(12)',
'⒀' => '(13)',
'⒁' => '(14)',
'⒂' => '(15)',
'⒃' => '(16)',
'⒄' => '(17)',
'⒅' => '(18)',
'⒆' => '(19)',
'⒇' => '(20)',
'⒈' => '1.',
'⒉' => '2.',
'⒊' => '3.',
'⒋' => '4.',
'⒌' => '5.',
'⒍' => '6.',
'⒎' => '7.',
'⒏' => '8.',
'⒐' => '9.',
'⒑' => '10.',
'⒒' => '11.',
'⒓' => '12.',
'⒔' => '13.',
'⒕' => '14.',
'⒖' => '15.',
'⒗' => '16.',
'⒘' => '17.',
'⒙' => '18.',
'⒚' => '19.',
'⒛' => '20.',
'⒜' => '(a)',
'⒝' => '(b)',
'⒞' => '(c)',
'⒟' => '(d)',
'⒠' => '(e)',
'⒡' => '(f)',
'⒢' => '(g)',
'⒣' => '(h)',
'⒤' => '(i)',
'⒥' => '(j)',
'⒦' => '(k)',
'⒧' => '(l)',
'⒨' => '(m)',
'⒩' => '(n)',
'⒪' => '(o)',
'⒫' => '(p)',
'⒬' => '(q)',
'⒭' => '(r)',
'⒮' => '(s)',
'⒯' => '(t)',
'⒰' => '(u)',
'⒱' => '(v)',
'⒲' => '(w)',
'⒳' => '(x)',
'⒴' => '(y)',
'⒵' => '(z)',
'Ⓐ' => 'A',
'Ⓑ' => 'B',
'Ⓒ' => 'C',
'Ⓓ' => 'D',
'Ⓔ' => 'E',
'Ⓕ' => 'F',
'Ⓖ' => 'G',
'Ⓗ' => 'H',
'Ⓘ' => 'I',
'Ⓙ' => 'J',
'Ⓚ' => 'K',
'Ⓛ' => 'L',
'Ⓜ' => 'M',
'Ⓝ' => 'N',
'Ⓞ' => 'O',
'Ⓟ' => 'P',
'Ⓠ' => 'Q',
'Ⓡ' => 'R',
'Ⓢ' => 'S',
'Ⓣ' => 'T',
'Ⓤ' => 'U',
'Ⓥ' => 'V',
'Ⓦ' => 'W',
'Ⓧ' => 'X',
'Ⓨ' => 'Y',
'Ⓩ' => 'Z',
'ⓐ' => 'a',
'ⓑ' => 'b',
'ⓒ' => 'c',
'ⓓ' => 'd',
'ⓔ' => 'e',
'ⓕ' => 'f',
'ⓖ' => 'g',
'ⓗ' => 'h',
'ⓘ' => 'i',
'ⓙ' => 'j',
'ⓚ' => 'k',
'ⓛ' => 'l',
'ⓜ' => 'm',
'ⓝ' => 'n',
'ⓞ' => 'o',
'ⓟ' => 'p',
'ⓠ' => 'q',
'ⓡ' => 'r',
'ⓢ' => 's',
'ⓣ' => 't',
'ⓤ' => 'u',
'ⓥ' => 'v',
'ⓦ' => 'w',
'ⓧ' => 'x',
'ⓨ' => 'y',
'ⓩ' => 'z',
'⓪' => '0',
'⨌' => '∫∫∫∫',
'⩴' => '::=',
'⩵' => '==',
'⩶' => '===',
'ⱼ' => 'j',
'ⱽ' => 'V',
'ⵯ' => 'ⵡ',
'⺟' => '母',
'⻳' => '龟',
'⼀' => '一',
'⼁' => '丨',
'⼂' => '丶',
'⼃' => '丿',
'⼄' => '乙',
'⼅' => '亅',
'⼆' => '二',
'⼇' => '亠',
'⼈' => '人',
'⼉' => '儿',
'⼊' => '入',
'⼋' => '八',
'⼌' => '冂',
'⼍' => '冖',
'⼎' => '冫',
'⼏' => '几',
'⼐' => '凵',
'⼑' => '刀',
'⼒' => '力',
'⼓' => '勹',
'⼔' => '匕',
'⼕' => '匚',
'⼖' => '匸',
'⼗' => '十',
'⼘' => '卜',
'⼙' => '卩',
'⼚' => '厂',
'⼛' => '厶',
'⼜' => '又',
'⼝' => '口',
'⼞' => '囗',
'⼟' => '土',
'⼠' => '士',
'⼡' => '夂',
'⼢' => '夊',
'⼣' => '夕',
'⼤' => '大',
'⼥' => '女',
'⼦' => '子',
'⼧' => '宀',
'⼨' => '寸',
'⼩' => '小',
'⼪' => '尢',
'⼫' => '尸',
'⼬' => '屮',
'⼭' => '山',
'⼮' => '巛',
'⼯' => '工',
'⼰' => '己',
'⼱' => '巾',
'⼲' => '干',
'⼳' => '幺',
'⼴' => '广',
'⼵' => '廴',
'⼶' => '廾',
'⼷' => '弋',
'⼸' => '弓',
'⼹' => '彐',
'⼺' => '彡',
'⼻' => '彳',
'⼼' => '心',
'⼽' => '戈',
'⼾' => '戶',
'⼿' => '手',
'⽀' => '支',
'⽁' => '攴',
'⽂' => '文',
'⽃' => '斗',
'⽄' => '斤',
'⽅' => '方',
'⽆' => '无',
'⽇' => '日',
'⽈' => '曰',
'⽉' => '月',
'⽊' => '木',
'⽋' => '欠',
'⽌' => '止',
'⽍' => '歹',
'⽎' => '殳',
'⽏' => '毋',
'⽐' => '比',
'⽑' => '毛',
'⽒' => '氏',
'⽓' => '气',
'⽔' => '水',
'⽕' => '火',
'⽖' => '爪',
'⽗' => '父',
'⽘' => '爻',
'⽙' => '爿',
'⽚' => '片',
'⽛' => '牙',
'⽜' => '牛',
'⽝' => '犬',
'⽞' => '玄',
'⽟' => '玉',
'⽠' => '瓜',
'⽡' => '瓦',
'⽢' => '甘',
'⽣' => '生',
'⽤' => '用',
'⽥' => '田',
'⽦' => '疋',
'⽧' => '疒',
'⽨' => '癶',
'⽩' => '白',
'⽪' => '皮',
'⽫' => '皿',
'⽬' => '目',
'⽭' => '矛',
'⽮' => '矢',
'⽯' => '石',
'⽰' => '示',
'⽱' => '禸',
'⽲' => '禾',
'⽳' => '穴',
'⽴' => '立',
'⽵' => '竹',
'⽶' => '米',
'⽷' => '糸',
'⽸' => '缶',
'⽹' => '网',
'⽺' => '羊',
'⽻' => '羽',
'⽼' => '老',
'⽽' => '而',
'⽾' => '耒',
'⽿' => '耳',
'⾀' => '聿',
'⾁' => '肉',
'⾂' => '臣',
'⾃' => '自',
'⾄' => '至',
'⾅' => '臼',
'⾆' => '舌',
'⾇' => '舛',
'⾈' => '舟',
'⾉' => '艮',
'⾊' => '色',
'⾋' => '艸',
'⾌' => '虍',
'⾍' => '虫',
'⾎' => '血',
'⾏' => '行',
'⾐' => '衣',
'⾑' => '襾',
'⾒' => '見',
'⾓' => '角',
'⾔' => '言',
'⾕' => '谷',
'⾖' => '豆',
'⾗' => '豕',
'⾘' => '豸',
'⾙' => '貝',
'⾚' => '赤',
'⾛' => '走',
'⾜' => '足',
'⾝' => '身',
'⾞' => '車',
'⾟' => '辛',
'⾠' => '辰',
'⾡' => '辵',
'⾢' => '邑',
'⾣' => '酉',
'⾤' => '釆',
'⾥' => '里',
'⾦' => '金',
'⾧' => '長',
'⾨' => '門',
'⾩' => '阜',
'⾪' => '隶',
'⾫' => '隹',
'⾬' => '雨',
'⾭' => '靑',
'⾮' => '非',
'⾯' => '面',
'⾰' => '革',
'⾱' => '韋',
'⾲' => '韭',
'⾳' => '音',
'⾴' => '頁',
'⾵' => '風',
'⾶' => '飛',
'⾷' => '食',
'⾸' => '首',
'⾹' => '香',
'⾺' => '馬',
'⾻' => '骨',
'⾼' => '高',
'⾽' => '髟',
'⾾' => '鬥',
'⾿' => '鬯',
'⿀' => '鬲',
'⿁' => '鬼',
'⿂' => '魚',
'⿃' => '鳥',
'⿄' => '鹵',
'⿅' => '鹿',
'⿆' => '麥',
'⿇' => '麻',
'⿈' => '黃',
'⿉' => '黍',
'⿊' => '黑',
'⿋' => '黹',
'⿌' => '黽',
'⿍' => '鼎',
'⿎' => '鼓',
'⿏' => '鼠',
'⿐' => '鼻',
'⿑' => '齊',
'⿒' => '齒',
'⿓' => '龍',
'⿔' => '龜',
'⿕' => '龠',
'　' => ' ',
'〶' => '〒',
'〸' => '十',
'〹' => '卄',
'〺' => '卅',
'゛' => ' ゙',
'゜' => ' ゚',
'ゟ' => 'より',
'ヿ' => 'コト',
'ㄱ' => 'ᄀ',
'ㄲ' => 'ᄁ',
'ㄳ' => 'ᆪ',
'ㄴ' => 'ᄂ',
'ㄵ' => 'ᆬ',
'ㄶ' => 'ᆭ',
'ㄷ' => 'ᄃ',
'ㄸ' => 'ᄄ',
'ㄹ' => 'ᄅ',
'ㄺ' => 'ᆰ',
'ㄻ' => 'ᆱ',
'ㄼ' => 'ᆲ',
'ㄽ' => 'ᆳ',
'ㄾ' => 'ᆴ',
'ㄿ' => 'ᆵ',
'ㅀ' => 'ᄚ',
'ㅁ' => 'ᄆ',
'ㅂ' => 'ᄇ',
'ㅃ' => 'ᄈ',
'ㅄ' => 'ᄡ',
'ㅅ' => 'ᄉ',
'ㅆ' => 'ᄊ',
'ㅇ' => 'ᄋ',
'ㅈ' => 'ᄌ',
'ㅉ' => 'ᄍ',
'ㅊ' => 'ᄎ',
'ㅋ' => 'ᄏ',
'ㅌ' => 'ᄐ',
'ㅍ' => 'ᄑ',
'ㅎ' => 'ᄒ',
'ㅏ' => 'ᅡ',
'ㅐ' => 'ᅢ',
'ㅑ' => 'ᅣ',
'ㅒ' => 'ᅤ',
'ㅓ' => 'ᅥ',
'ㅔ' => 'ᅦ',
'ㅕ' => 'ᅧ',
'ㅖ' => 'ᅨ',
'ㅗ' => 'ᅩ',
'ㅘ' => 'ᅪ',
'ㅙ' => 'ᅫ',
'ㅚ' => 'ᅬ',
'ㅛ' => 'ᅭ',
'ㅜ' => 'ᅮ',
'ㅝ' => 'ᅯ',
'ㅞ' => 'ᅰ',
'ㅟ' => 'ᅱ',
'ㅠ' => 'ᅲ',
'ㅡ' => 'ᅳ',
'ㅢ' => 'ᅴ',
'ㅣ' => 'ᅵ',
'ㅤ' => 'ᅠ',
'ㅥ' => 'ᄔ',
'ㅦ' => 'ᄕ',
'ㅧ' => 'ᇇ',
'ㅨ' => 'ᇈ',
'ㅩ' => 'ᇌ',
'ㅪ' => 'ᇎ',
'ㅫ' => 'ᇓ',
'ㅬ' => 'ᇗ',
'ㅭ' => 'ᇙ',
'ㅮ' => 'ᄜ',
'ㅯ' => 'ᇝ',
'ㅰ' => 'ᇟ',
'ㅱ' => 'ᄝ',
'ㅲ' => 'ᄞ',
'ㅳ' => 'ᄠ',
'ㅴ' => 'ᄢ',
'ㅵ' => 'ᄣ',
'ㅶ' => 'ᄧ',
'ㅷ' => 'ᄩ',
'ㅸ' => 'ᄫ',
'ㅹ' => 'ᄬ',
'ㅺ' => 'ᄭ',
'ㅻ' => 'ᄮ',
'ㅼ' => 'ᄯ',
'ㅽ' => 'ᄲ',
'ㅾ' => 'ᄶ',
'ㅿ' => 'ᅀ',
'ㆀ' => 'ᅇ',
'ㆁ' => 'ᅌ',
'ㆂ' => 'ᇱ',
'ㆃ' => 'ᇲ',
'ㆄ' => 'ᅗ',
'ㆅ' => 'ᅘ',
'ㆆ' => 'ᅙ',
'ㆇ' => 'ᆄ',
'ㆈ' => 'ᆅ',
'ㆉ' => 'ᆈ',
'ㆊ' => 'ᆑ',
'ㆋ' => 'ᆒ',
'ㆌ' => 'ᆔ',
'ㆍ' => 'ᆞ',
'ㆎ' => 'ᆡ',
'㆒' => '一',
'㆓' => '二',
'㆔' => '三',
'㆕' => '四',
'㆖' => '上',
'㆗' => '中',
'㆘' => '下',
'㆙' => '甲',
'㆚' => '乙',
'㆛' => '丙',
'㆜' => '丁',
'㆝' => '天',
'㆞' => '地',
'㆟' => '人',
'㈀' => '(ᄀ)',
'㈁' => '(ᄂ)',
'㈂' => '(ᄃ)',
'㈃' => '(ᄅ)',
'㈄' => '(ᄆ)',
'㈅' => '(ᄇ)',
'㈆' => '(ᄉ)',
'㈇' => '(ᄋ)',
'㈈' => '(ᄌ)',
'㈉' => '(ᄎ)',
'㈊' => '(ᄏ)',
'㈋' => '(ᄐ)',
'㈌' => '(ᄑ)',
'㈍' => '(ᄒ)',
'㈎' => '(가)',
'㈏' => '(나)',
'㈐' => '(다)',
'㈑' => '(라)',
'㈒' => '(마)',
'㈓' => '(바)',
'㈔' => '(사)',
'㈕' => '(아)',
'㈖' => '(자)',
'㈗' => '(차)',
'㈘' => '(카)',
'㈙' => '(타)',
'㈚' => '(파)',
'㈛' => '(하)',
'㈜' => '(주)',
'㈝' => '(오전)',
'㈞' => '(오후)',
'㈠' => '(一)',
'㈡' => '(二)',
'㈢' => '(三)',
'㈣' => '(四)',
'㈤' => '(五)',
'㈥' => '(六)',
'㈦' => '(七)',
'㈧' => '(八)',
'㈨' => '(九)',
'㈩' => '(十)',
'㈪' => '(月)',
'㈫' => '(火)',
'㈬' => '(水)',
'㈭' => '(木)',
'㈮' => '(金)',
'㈯' => '(土)',
'㈰' => '(日)',
'㈱' => '(株)',
'㈲' => '(有)',
'㈳' => '(社)',
'㈴' => '(名)',
'㈵' => '(特)',
'㈶' => '(財)',
'㈷' => '(祝)',
'㈸' => '(労)',
'㈹' => '(代)',
'㈺' => '(呼)',
'㈻' => '(学)',
'㈼' => '(監)',
'㈽' => '(企)',
'㈾' => '(資)',
'㈿' => '(協)',
'㉀' => '(祭)',
'㉁' => '(休)',
'㉂' => '(自)',
'㉃' => '(至)',
'㉄' => '問',
'㉅' => '幼',
'㉆' => '文',
'㉇' => '箏',
'㉐' => 'PTE',
'㉑' => '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',
'㋀' => '1月',
'㋁' => '2月',
'㋂' => '3月',
'㋃' => '4月',
'㋄' => '5月',
'㋅' => '6月',
'㋆' => '7月',
'㋇' => '8月',
'㋈' => '9月',
'㋉' => '10月',
'㋊' => '11月',
'㋋' => '12月',
'㋌' => 'Hg',
'㋍' => 'erg',
'㋎' => 'eV',
'㋏' => 'LTD',
'㋐' => 'ア',
'㋑' => 'イ',
'㋒' => 'ウ',
'㋓' => 'エ',
'㋔' => 'オ',
'㋕' => 'カ',
'㋖' => 'キ',
'㋗' => 'ク',
'㋘' => 'ケ',
'㋙' => 'コ',
'㋚' => 'サ',
'㋛' => 'シ',
'㋜' => 'ス',
'㋝' => 'セ',
'㋞' => 'ソ',
'㋟' => 'タ',
'㋠' => 'チ',
'㋡' => 'ツ',
'㋢' => 'テ',
'㋣' => 'ト',
'㋤' => 'ナ',
'㋥' => 'ニ',
'㋦' => 'ヌ',
'㋧' => 'ネ',
'㋨' => 'ノ',
'㋩' => 'ハ',
'㋪' => 'ヒ',
'㋫' => 'フ',
'㋬' => 'ヘ',
'㋭' => 'ホ',
'㋮' => 'マ',
'㋯' => 'ミ',
'㋰' => 'ム',
'㋱' => 'メ',
'㋲' => 'モ',
'㋳' => 'ヤ',
'㋴' => 'ユ',
'㋵' => 'ヨ',
'㋶' => 'ラ',
'㋷' => 'リ',
'㋸' => 'ル',
'㋹' => 'レ',
'㋺' => 'ロ',
'㋻' => 'ワ',
'㋼' => 'ヰ',
'㋽' => 'ヱ',
'㋾' => 'ヲ',
'㋿' => '令和',
'㌀' => 'アパート',
'㌁' => 'アルファ',
'㌂' => 'アンペア',
'㌃' => 'アール',
'㌄' => 'イニング',
'㌅' => 'インチ',
'㌆' => 'ウォン',
'㌇' => 'エスクード',
'㌈' => 'エーカー',
'㌉' => 'オンス',
'㌊' => 'オーム',
'㌋' => 'カイリ',
'㌌' => 'カラット',
'㌍' => 'カロリー',
'㌎' => 'ガロン',
'㌏' => 'ガンマ',
'㌐' => 'ギガ',
'㌑' => 'ギニー',
'㌒' => 'キュリー',
'㌓' => 'ギルダー',
'㌔' => 'キロ',
'㌕' => 'キログラム',
'㌖' => 'キロメートル',
'㌗' => 'キロワット',
'㌘' => 'グラム',
'㌙' => 'グラムトン',
'㌚' => 'クルゼイロ',
'㌛' => 'クローネ',
'㌜' => 'ケース',
'㌝' => 'コルナ',
'㌞' => 'コーポ',
'㌟' => 'サイクル',
'㌠' => 'サンチーム',
'㌡' => 'シリング',
'㌢' => 'センチ',
'㌣' => 'セント',
'㌤' => 'ダース',
'㌥' => 'デシ',
'㌦' => 'ドル',
'㌧' => 'トン',
'㌨' => 'ナノ',
'㌩' => 'ノット',
'㌪' => 'ハイツ',
'㌫' => 'パーセント',
'㌬' => 'パーツ',
'㌭' => 'バーレル',
'㌮' => 'ピアストル',
'㌯' => 'ピクル',
'㌰' => 'ピコ',
'㌱' => 'ビル',
'㌲' => 'ファラッド',
'㌳' => 'フィート',
'㌴' => 'ブッシェル',
'㌵' => 'フラン',
'㌶' => 'ヘクタール',
'㌷' => 'ペソ',
'㌸' => 'ペニヒ',
'㌹' => 'ヘルツ',
'㌺' => 'ペンス',
'㌻' => 'ページ',
'㌼' => 'ベータ',
'㌽' => 'ポイント',
'㌾' => 'ボルト',
'㌿' => 'ホン',
'㍀' => 'ポンド',
'㍁' => 'ホール',
'㍂' => 'ホーン',
'㍃' => 'マイクロ',
'㍄' => 'マイル',
'㍅' => 'マッハ',
'㍆' => 'マルク',
'㍇' => 'マンション',
'㍈' => 'ミクロン',
'㍉' => 'ミリ',
'㍊' => 'ミリバール',
'㍋' => 'メガ',
'㍌' => 'メガトン',
'㍍' => 'メートル',
'㍎' => 'ヤード',
'㍏' => 'ヤール',
'㍐' => 'ユアン',
'㍑' => 'リットル',
'㍒' => 'リラ',
'㍓' => 'ルピー',
'㍔' => 'ルーブル',
'㍕' => 'レム',
'㍖' => 'レントゲン',
'㍗' => 'ワット',
'㍘' => '0点',
'㍙' => '1点',
'㍚' => '2点',
'㍛' => '3点',
'㍜' => '4点',
'㍝' => '5点',
'㍞' => '6点',
'㍟' => '7点',
'㍠' => '8点',
'㍡' => '9点',
'㍢' => '10点',
'㍣' => '11点',
'㍤' => '12点',
'㍥' => '13点',
'㍦' => '14点',
'㍧' => '15点',
'㍨' => '16点',
'㍩' => '17点',
'㍪' => '18点',
'㍫' => '19点',
'㍬' => '20点',
'㍭' => '21点',
'㍮' => '22点',
'㍯' => '23点',
'㍰' => '24点',
'㍱' => 'hPa',
'㍲' => 'da',
'㍳' => 'AU',
'㍴' => 'bar',
'㍵' => 'oV',
'㍶' => 'pc',
'㍷' => 'dm',
'㍸' => 'dm2',
'㍹' => 'dm3',
'㍺' => 'IU',
'㍻' => '平成',
'㍼' => '昭和',
'㍽' => '大正',
'㍾' => '明治',
'㍿' => '株式会社',
'㎀' => 'pA',
'㎁' => 'nA',
'㎂' => 'μA',
'㎃' => 'mA',
'㎄' => 'kA',
'㎅' => 'KB',
'㎆' => 'MB',
'㎇' => 'GB',
'㎈' => 'cal',
'㎉' => 'kcal',
'㎊' => 'pF',
'㎋' => 'nF',
'㎌' => 'μF',
'㎍' => 'μg',
'㎎' => 'mg',
'㎏' => 'kg',
'㎐' => 'Hz',
'㎑' => 'kHz',
'㎒' => 'MHz',
'㎓' => 'GHz',
'㎔' => 'THz',
'㎕' => 'μl',
'㎖' => 'ml',
'㎗' => 'dl',
'㎘' => 'kl',
'㎙' => 'fm',
'㎚' => 'nm',
'㎛' => 'μm',
'㎜' => 'mm',
'㎝' => 'cm',
'㎞' => 'km',
'㎟' => 'mm2',
'㎠' => 'cm2',
'㎡' => 'm2',
'㎢' => 'km2',
'㎣' => 'mm3',
'㎤' => 'cm3',
'㎥' => 'm3',
'㎦' => 'km3',
'㎧' => 'm∕s',
'㎨' => 'm∕s2',
'㎩' => 'Pa',
'㎪' => 'kPa',
'㎫' => 'MPa',
'㎬' => 'GPa',
'㎭' => 'rad',
'㎮' => 'rad∕s',
'㎯' => 'rad∕s2',
'㎰' => 'ps',
'㎱' => 'ns',
'㎲' => 'μs',
'㎳' => 'ms',
'㎴' => 'pV',
'㎵' => 'nV',
'㎶' => 'μV',
'㎷' => 'mV',
'㎸' => 'kV',
'㎹' => 'MV',
'㎺' => 'pW',
'㎻' => 'nW',
'㎼' => 'μW',
'㎽' => 'mW',
'㎾' => 'kW',
'㎿' => 'MW',
'㏀' => 'kΩ',
'㏁' => 'MΩ',
'㏂' => 'a.m.',
'㏃' => 'Bq',
'㏄' => 'cc',
'㏅' => 'cd',
'㏆' => 'C∕kg',
'㏇' => 'Co.',
'㏈' => 'dB',
'㏉' => 'Gy',
'㏊' => 'ha',
'㏋' => 'HP',
'㏌' => 'in',
'㏍' => 'KK',
'㏎' => 'KM',
'㏏' => 'kt',
'㏐' => 'lm',
'㏑' => 'ln',
'㏒' => 'log',
'㏓' => 'lx',
'㏔' => 'mb',
'㏕' => 'mil',
'㏖' => 'mol',
'㏗' => 'PH',
'㏘' => 'p.m.',
'㏙' => 'PPM',
'㏚' => 'PR',
'㏛' => 'sr',
'㏜' => 'Sv',
'㏝' => 'Wb',
'㏞' => 'V∕m',
'㏟' => 'A∕m',
'㏠' => '1日',
'㏡' => '2日',
'㏢' => '3日',
'㏣' => '4日',
'㏤' => '5日',
'㏥' => '6日',
'㏦' => '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日',
'㏿' => 'gal',
'ꚜ' => 'ъ',
'ꚝ' => 'ь',
'ꝰ' => 'ꝯ',
'ꟸ' => 'Ħ',
'ꟹ' => 'œ',
'ꭜ' => 'ꜧ',
'ꭝ' => 'ꬷ',
'ꭞ' => 'ɫ',
'ꭟ' => 'ꭒ',
'ꭩ' => 'ʍ',
'ﬀ' => 'ff',
'ﬁ' => 'fi',
'ﬂ' => 'fl',
'ﬃ' => 'ffi',
'ﬄ' => 'ffl',
'ﬅ' => 'st',
'ﬆ' => 'st',
'ﬓ' => 'մն',
'ﬔ' => 'մե',
'ﬕ' => 'մի',
'ﬖ' => 'վն',
'ﬗ' => 'մխ',
'ﬠ' => 'ע',
'ﬡ' => 'א',
'ﬢ' => 'ד',
'ﬣ' => 'ה',
'ﬤ' => 'כ',
'ﬥ' => 'ל',
'ﬦ' => 'ם',
'ﬧ' => 'ר',
'ﬨ' => 'ת',
'﬩' => '+',
'ﭏ' => 'אל',
'ﭐ' => 'ٱ',
'ﭑ' => 'ٱ',
'ﭒ' => 'ٻ',
'ﭓ' => 'ٻ',
'ﭔ' => 'ٻ',
'ﭕ' => 'ٻ',
'ﭖ' => 'پ',
'ﭗ' => 'پ',
'ﭘ' => 'پ',
'ﭙ' => 'پ',
'ﭚ' => 'ڀ',
'ﭛ' => 'ڀ',
'ﭜ' => 'ڀ',
'ﭝ' => 'ڀ',
'ﭞ' => 'ٺ',
'ﭟ' => 'ٺ',
'ﭠ' => 'ٺ',
'ﭡ' => 'ٺ',
'ﭢ' => 'ٿ',
'ﭣ' => 'ٿ',
'ﭤ' => 'ٿ',
'ﭥ' => 'ٿ',
'ﭦ' => 'ٹ',
'ﭧ' => 'ٹ',
'ﭨ' => 'ٹ',
'ﭩ' => 'ٹ',
'ﭪ' => 'ڤ',
'ﭫ' => 'ڤ',
'ﭬ' => 'ڤ',
'ﭭ' => 'ڤ',
'ﭮ' => 'ڦ',
'ﭯ' => 'ڦ',
'ﭰ' => 'ڦ',
'ﭱ' => 'ڦ',
'ﭲ' => 'ڄ',
'ﭳ' => 'ڄ',
'ﭴ' => 'ڄ',
'ﭵ' => 'ڄ',
'ﭶ' => 'ڃ',
'ﭷ' => 'ڃ',
'ﭸ' => 'ڃ',
'ﭹ' => 'ڃ',
'ﭺ' => 'چ',
'ﭻ' => 'چ',
'ﭼ' => 'چ',
'ﭽ' => 'چ',
'ﭾ' => 'ڇ',
'ﭿ' => 'ڇ',
'ﮀ' => 'ڇ',
'ﮁ' => 'ڇ',
'ﮂ' => 'ڍ',
'ﮃ' => 'ڍ',
'ﮄ' => 'ڌ',
'ﮅ' => 'ڌ',
'ﮆ' => 'ڎ',
'ﮇ' => 'ڎ',
'ﮈ' => 'ڈ',
'ﮉ' => 'ڈ',
'ﮊ' => 'ژ',
'ﮋ' => 'ژ',
'ﮌ' => 'ڑ',
'ﮍ' => 'ڑ',
'ﮎ' => 'ک',
'ﮏ' => 'ک',
'ﮐ' => 'ک',
'ﮑ' => 'ک',
'ﮒ' => 'گ',
'ﮓ' => 'گ',
'ﮔ' => 'گ',
'ﮕ' => 'گ',
'ﮖ' => 'ڳ',
'ﮗ' => 'ڳ',
'ﮘ' => 'ڳ',
'ﮙ' => 'ڳ',
'ﮚ' => 'ڱ',
'ﮛ' => 'ڱ',
'ﮜ' => 'ڱ',
'ﮝ' => 'ڱ',
'ﮞ' => 'ں',
'ﮟ' => 'ں',
'ﮠ' => 'ڻ',
'ﮡ' => 'ڻ',
'ﮢ' => 'ڻ',
'ﮣ' => 'ڻ',
'ﮤ' => 'ۀ',
'ﮥ' => 'ۀ',
'ﮦ' => 'ہ',
'ﮧ' => 'ہ',
'ﮨ' => 'ہ',
'ﮩ' => 'ہ',
'ﮪ' => 'ھ',
'ﮫ' => 'ھ',
'ﮬ' => 'ھ',
'ﮭ' => 'ھ',
'ﮮ' => 'ے',
'ﮯ' => 'ے',
'ﮰ' => 'ۓ',
'ﮱ' => 'ۓ',
'ﯓ' => 'ڭ',
'ﯔ' => 'ڭ',
'ﯕ' => 'ڭ',
'ﯖ' => 'ڭ',
'ﯗ' => 'ۇ',
'ﯘ' => 'ۇ',
'ﯙ' => 'ۆ',
'ﯚ' => 'ۆ',
'ﯛ' => 'ۈ',
'ﯜ' => 'ۈ',
'ﯝ' => 'ۇٴ',
'ﯞ' => 'ۋ',
'ﯟ' => 'ۋ',
'ﯠ' => 'ۅ',
'ﯡ' => 'ۅ',
'ﯢ' => 'ۉ',
'ﯣ' => 'ۉ',
'ﯤ' => 'ې',
'ﯥ' => 'ې',
'ﯦ' => 'ې',
'ﯧ' => 'ې',
'ﯨ' => 'ى',
'ﯩ' => 'ى',
'ﯪ' => 'ئا',
'ﯫ' => 'ئا',
'ﯬ' => 'ئە',
'ﯭ' => 'ئە',
'ﯮ' => 'ئو',
'ﯯ' => 'ئو',
'ﯰ' => 'ئۇ',
'ﯱ' => 'ئۇ',
'ﯲ' => 'ئۆ',
'ﯳ' => 'ئۆ',
'ﯴ' => 'ئۈ',
'ﯵ' => 'ئۈ',
'ﯶ' => 'ئې',
'ﯷ' => 'ئې',
'ﯸ' => 'ئې',
'ﯹ' => 'ئى',
'ﯺ' => 'ئى',
'ﯻ' => 'ئى',
'ﯼ' => 'ی',
'ﯽ' => 'ی',
'ﯾ' => 'ی',
'ﯿ' => 'ی',
'ﰀ' => 'ئج',
'ﰁ' => 'ئح',
'ﰂ' => 'ئم',
'ﰃ' => 'ئى',
'ﰄ' => 'ئي',
'ﰅ' => 'بج',
'ﰆ' => 'بح',
'ﰇ' => 'بخ',
'ﰈ' => 'بم',
'ﰉ' => 'بى',
'ﰊ' => 'بي',
'ﰋ' => 'تج',
'ﰌ' => 'تح',
'ﰍ' => 'تخ',
'ﰎ' => 'تم',
'ﰏ' => 'تى',
'ﰐ' => 'تي',
'ﰑ' => 'ثج',
'ﰒ' => 'ثم',
'ﰓ' => 'ثى',
'ﰔ' => 'ثي',
'ﰕ' => 'جح',
'ﰖ' => 'جم',
'ﰗ' => 'حج',
'ﰘ' => 'حم',
'ﰙ' => 'خج',
'ﰚ' => 'خح',
'ﰛ' => 'خم',
'ﰜ' => 'سج',
'ﰝ' => 'سح',
'ﰞ' => 'سخ',
'ﰟ' => 'سم',
'ﰠ' => 'صح',
'ﰡ' => 'صم',
'ﰢ' => 'ضج',
'ﰣ' => 'ضح',
'ﰤ' => 'ضخ',
'ﰥ' => 'ضم',
'ﰦ' => 'طح',
'ﰧ' => 'طم',
'ﰨ' => 'ظم',
'ﰩ' => 'عج',
'ﰪ' => 'عم',
'ﰫ' => 'غج',
'ﰬ' => 'غم',
'ﰭ' => 'فج',
'ﰮ' => 'فح',
'ﰯ' => 'فخ',
'ﰰ' => 'فم',
'ﰱ' => 'فى',
'ﰲ' => 'في',
'ﰳ' => 'قح',
'ﰴ' => 'قم',
'ﰵ' => 'قى',
'ﰶ' => 'قي',
'ﰷ' => 'كا',
'ﰸ' => 'كج',
'ﰹ' => 'كح',
'ﰺ' => 'كخ',
'ﰻ' => 'كل',
'ﰼ' => 'كم',
'ﰽ' => 'كى',
'ﰾ' => 'كي',
'ﰿ' => 'لج',
'ﱀ' => 'لح',
'ﱁ' => 'لخ',
'ﱂ' => 'لم',
'ﱃ' => 'لى',
'ﱄ' => 'لي',
'ﱅ' => 'مج',
'ﱆ' => 'مح',
'ﱇ' => 'مخ',
'ﱈ' => 'مم',
'ﱉ' => 'مى',
'ﱊ' => 'مي',
'ﱋ' => 'نج',
'ﱌ' => 'نح',
'ﱍ' => 'نخ',
'ﱎ' => 'نم',
'ﱏ' => 'نى',
'ﱐ' => 'ني',
'ﱑ' => 'هج',
'ﱒ' => 'هم',
'ﱓ' => 'هى',
'ﱔ' => 'هي',
'ﱕ' => 'يج',
'ﱖ' => 'يح',
'ﱗ' => 'يخ',
'ﱘ' => 'يم',
'ﱙ' => 'يى',
'ﱚ' => 'يي',
'ﱛ' => 'ذٰ',
'ﱜ' => 'رٰ',
'ﱝ' => 'ىٰ',
'ﱞ' => ' ٌّ',
'ﱟ' => ' ٍّ',
'ﱠ' => ' َّ',
'ﱡ' => ' ُّ',
'ﱢ' => ' ِّ',
'ﱣ' => ' ّٰ',
'ﱤ' => 'ئر',
'ﱥ' => 'ئز',
'ﱦ' => 'ئم',
'ﱧ' => 'ئن',
'ﱨ' => 'ئى',
'ﱩ' => 'ئي',
'ﱪ' => 'بر',
'ﱫ' => 'بز',
'ﱬ' => 'بم',
'ﱭ' => 'بن',
'ﱮ' => 'بى',
'ﱯ' => 'بي',
'ﱰ' => 'تر',
'ﱱ' => 'تز',
'ﱲ' => 'تم',
'ﱳ' => 'تن',
'ﱴ' => 'تى',
'ﱵ' => 'تي',
'ﱶ' => 'ثر',
'ﱷ' => 'ثز',
'ﱸ' => 'ثم',
'ﱹ' => 'ثن',
'ﱺ' => 'ثى',
'ﱻ' => 'ثي',
'ﱼ' => 'فى',
'ﱽ' => 'في',
'ﱾ' => 'قى',
'ﱿ' => 'قي',
'ﲀ' => 'كا',
'ﲁ' => 'كل',
'ﲂ' => 'كم',
'ﲃ' => 'كى',
'ﲄ' => 'كي',
'ﲅ' => 'لم',
'ﲆ' => 'لى',
'ﲇ' => 'لي',
'ﲈ' => 'ما',
'ﲉ' => 'مم',
'ﲊ' => 'نر',
'ﲋ' => 'نز',
'ﲌ' => 'نم',
'ﲍ' => 'نن',
'ﲎ' => 'نى',
'ﲏ' => 'ني',
'ﲐ' => 'ىٰ',
'ﲑ' => 'ير',
'ﲒ' => 'يز',
'ﲓ' => 'يم',
'ﲔ' => 'ين',
'ﲕ' => 'يى',
'ﲖ' => 'يي',
'ﲗ' => 'ئج',
'ﲘ' => 'ئح',
'ﲙ' => 'ئخ',
'ﲚ' => 'ئم',
'ﲛ' => 'ئه',
'ﲜ' => 'بج',
'ﲝ' => 'بح',
'ﲞ' => 'بخ',
'ﲟ' => 'بم',
'ﲠ' => 'به',
'ﲡ' => 'تج',
'ﲢ' => 'تح',
'ﲣ' => 'تخ',
'ﲤ' => 'تم',
'ﲥ' => 'ته',
'ﲦ' => 'ثم',
'ﲧ' => 'جح',
'ﲨ' => 'جم',
'ﲩ' => 'حج',
'ﲪ' => 'حم',
'ﲫ' => 'خج',
'ﲬ' => 'خم',
'ﲭ' => 'سج',
'ﲮ' => 'سح',
'ﲯ' => 'سخ',
'ﲰ' => 'سم',
'ﲱ' => 'صح',
'ﲲ' => 'صخ',
'ﲳ' => 'صم',
'ﲴ' => 'ضج',
'ﲵ' => 'ضح',
'ﲶ' => 'ضخ',
'ﲷ' => 'ضم',
'ﲸ' => 'طح',
'ﲹ' => 'ظم',
'ﲺ' => 'عج',
'ﲻ' => 'عم',
'ﲼ' => 'غج',
'ﲽ' => 'غم',
'ﲾ' => 'فج',
'ﲿ' => 'فح',
'ﳀ' => 'فخ',
'ﳁ' => 'فم',
'ﳂ' => 'قح',
'ﳃ' => 'قم',
'ﳄ' => 'كج',
'ﳅ' => 'كح',
'ﳆ' => 'كخ',
'ﳇ' => 'كل',
'ﳈ' => 'كم',
'ﳉ' => 'لج',
'ﳊ' => 'لح',
'ﳋ' => 'لخ',
'ﳌ' => 'لم',
'ﳍ' => 'له',
'ﳎ' => 'مج',
'ﳏ' => 'مح',
'ﳐ' => 'مخ',
'ﳑ' => 'مم',
'ﳒ' => 'نج',
'ﳓ' => 'نح',
'ﳔ' => 'نخ',
'ﳕ' => 'نم',
'ﳖ' => 'نه',
'ﳗ' => 'هج',
'ﳘ' => 'هم',
'ﳙ' => 'هٰ',
'ﳚ' => 'يج',
'ﳛ' => 'يح',
'ﳜ' => 'يخ',
'ﳝ' => 'يم',
'ﳞ' => 'يه',
'ﳟ' => 'ئم',
'ﳠ' => 'ئه',
'ﳡ' => 'بم',
'ﳢ' => 'به',
'ﳣ' => 'تم',
'ﳤ' => 'ته',
'ﳥ' => 'ثم',
'ﳦ' => 'ثه',
'ﳧ' => 'سم',
'ﳨ' => 'سه',
'ﳩ' => 'شم',
'ﳪ' => 'شه',
'ﳫ' => 'كل',
'ﳬ' => 'كم',
'ﳭ' => 'لم',
'ﳮ' => 'نم',
'ﳯ' => 'نه',
'ﳰ' => 'يم',
'ﳱ' => 'يه',
'ﳲ' => 'ـَّ',
'ﳳ' => 'ـُّ',
'ﳴ' => 'ـِّ',
'ﳵ' => 'طى',
'ﳶ' => 'طي',
'ﳷ' => 'عى',
'ﳸ' => 'عي',
'ﳹ' => 'غى',
'ﳺ' => 'غي',
'ﳻ' => 'سى',
'ﳼ' => 'سي',
'ﳽ' => 'شى',
'ﳾ' => 'شي',
'ﳿ' => 'حى',
'ﴀ' => 'حي',
'ﴁ' => 'جى',
'ﴂ' => 'جي',
'ﴃ' => 'خى',
'ﴄ' => 'خي',
'ﴅ' => 'صى',
'ﴆ' => 'صي',
'ﴇ' => 'ضى',
'ﴈ' => 'ضي',
'ﴉ' => 'شج',
'ﴊ' => 'شح',
'ﴋ' => 'شخ',
'ﴌ' => 'شم',
'ﴍ' => 'شر',
'ﴎ' => 'سر',
'ﴏ' => 'صر',
'ﴐ' => 'ضر',
'ﴑ' => 'طى',
'ﴒ' => 'طي',
'ﴓ' => 'عى',
'ﴔ' => 'عي',
'ﴕ' => 'غى',
'ﴖ' => 'غي',
'ﴗ' => 'سى',
'ﴘ' => 'سي',
'ﴙ' => 'شى',
'ﴚ' => 'شي',
'ﴛ' => 'حى',
'ﴜ' => 'حي',
'ﴝ' => 'جى',
'ﴞ' => 'جي',
'ﴟ' => 'خى',
'ﴠ' => 'خي',
'ﴡ' => 'صى',
'ﴢ' => 'صي',
'ﴣ' => 'ضى',
'ﴤ' => 'ضي',
'ﴥ' => 'شج',
'ﴦ' => 'شح',
'ﴧ' => 'شخ',
'ﴨ' => 'شم',
'ﴩ' => 'شر',
'ﴪ' => 'سر',
'ﴫ' => 'صر',
'ﴬ' => 'ضر',
'ﴭ' => 'شج',
'ﴮ' => 'شح',
'ﴯ' => 'شخ',
'ﴰ' => 'شم',
'ﴱ' => 'سه',
'ﴲ' => 'شه',
'ﴳ' => 'طم',
'ﴴ' => 'سج',
'ﴵ' => 'سح',
'ﴶ' => 'سخ',
'ﴷ' => 'شج',
'ﴸ' => 'شح',
'ﴹ' => 'شخ',
'ﴺ' => 'طم',
'ﴻ' => 'ظم',
'ﴼ' => 'اً',
'ﴽ' => 'اً',
'ﵐ' => 'تجم',
'ﵑ' => 'تحج',
'ﵒ' => 'تحج',
'ﵓ' => 'تحم',
'ﵔ' => 'تخم',
'ﵕ' => 'تمج',
'ﵖ' => 'تمح',
'ﵗ' => 'تمخ',
'ﵘ' => 'جمح',
'ﵙ' => 'جمح',
'ﵚ' => 'حمي',
'ﵛ' => 'حمى',
'ﵜ' => 'سحج',
'ﵝ' => 'سجح',
'ﵞ' => 'سجى',
'ﵟ' => 'سمح',
'ﵠ' => 'سمح',
'ﵡ' => 'سمج',
'ﵢ' => 'سمم',
'ﵣ' => 'سمم',
'ﵤ' => 'صحح',
'ﵥ' => 'صحح',
'ﵦ' => 'صمم',
'ﵧ' => 'شحم',
'ﵨ' => 'شحم',
'ﵩ' => 'شجي',
'ﵪ' => 'شمخ',
'ﵫ' => 'شمخ',
'ﵬ' => 'شمم',
'ﵭ' => 'شمم',
'ﵮ' => 'ضحى',
'ﵯ' => 'ضخم',
'ﵰ' => 'ضخم',
'ﵱ' => 'طمح',
'ﵲ' => 'طمح',
'ﵳ' => 'طمم',
'ﵴ' => 'طمي',
'ﵵ' => 'عجم',
'ﵶ' => 'عمم',
'ﵷ' => 'عمم',
'ﵸ' => 'عمى',
'ﵹ' => 'غمم',
'ﵺ' => 'غمي',
'ﵻ' => 'غمى',
'ﵼ' => 'فخم',
'ﵽ' => 'فخم',
'ﵾ' => 'قمح',
'ﵿ' => 'قمم',
'ﶀ' => 'لحم',
'ﶁ' => 'لحي',
'ﶂ' => 'لحى',
'ﶃ' => 'لجج',
'ﶄ' => 'لجج',
'ﶅ' => 'لخم',
'ﶆ' => 'لخم',
'ﶇ' => 'لمح',
'ﶈ' => 'لمح',
'ﶉ' => 'محج',
'ﶊ' => 'محم',
'ﶋ' => 'محي',
'ﶌ' => 'مجح',
'ﶍ' => 'مجم',
'ﶎ' => 'مخج',
'ﶏ' => 'مخم',
'ﶒ' => 'مجخ',
'ﶓ' => 'همج',
'ﶔ' => 'همم',
'ﶕ' => 'نحم',
'ﶖ' => 'نحى',
'ﶗ' => 'نجم',
'ﶘ' => 'نجم',
'ﶙ' => 'نجى',
'ﶚ' => 'نمي',
'ﶛ' => 'نمى',
'ﶜ' => 'يمم',
'ﶝ' => 'يمم',
'ﶞ' => 'بخي',
'ﶟ' => 'تجي',
'ﶠ' => 'تجى',
'ﶡ' => 'تخي',
'ﶢ' => 'تخى',
'ﶣ' => 'تمي',
'ﶤ' => 'تمى',
'ﶥ' => 'جمي',
'ﶦ' => 'جحى',
'ﶧ' => 'جمى',
'ﶨ' => 'سخى',
'ﶩ' => 'صحي',
'ﶪ' => 'شحي',
'ﶫ' => 'ضحي',
'ﶬ' => 'لجي',
'ﶭ' => 'لمي',
'ﶮ' => 'يحي',
'ﶯ' => 'يجي',
'ﶰ' => 'يمي',
'ﶱ' => 'ممي',
'ﶲ' => 'قمي',
'ﶳ' => 'نحي',
'ﶴ' => 'قمح',
'ﶵ' => 'لحم',
'ﶶ' => 'عمي',
'ﶷ' => 'كمي',
'ﶸ' => 'نجح',
'ﶹ' => 'مخي',
'ﶺ' => 'لجم',
'ﶻ' => 'كمم',
'ﶼ' => 'لجم',
'ﶽ' => 'نجح',
'ﶾ' => 'جحي',
'ﶿ' => 'حجي',
'ﷀ' => 'مجي',
'ﷁ' => 'فمي',
'ﷂ' => 'بحي',
'ﷃ' => 'كمم',
'ﷄ' => 'عجم',
'ﷅ' => 'صمم',
'ﷆ' => 'سخي',
'ﷇ' => 'نجي',
'ﷰ' => 'صلے',
'ﷱ' => 'قلے',
'ﷲ' => 'الله',
'ﷳ' => 'اكبر',
'ﷴ' => 'محمد',
'ﷵ' => 'صلعم',
'ﷶ' => 'رسول',
'ﷷ' => 'عليه',
'ﷸ' => 'وسلم',
'ﷹ' => 'صلى',
'ﷺ' => 'صلى الله عليه وسلم',
'ﷻ' => 'جل جلاله',
'﷼' => 'ریال',
'︐' => ',',
'︑' => '、',
'︒' => '。',
'︓' => ':',
'︔' => ';',
'︕' => '!',
'︖' => '?',
'︗' => '〖',
'︘' => '〗',
'︙' => '...',
'︰' => '..',
'︱' => '—',
'︲' => '–',
'︳' => '_',
'︴' => '_',
'︵' => '(',
'︶' => ')',
'︷' => '{',
'︸' => '}',
'︹' => '〔',
'︺' => '〕',
'︻' => '【',
'︼' => '】',
'︽' => '《',
'︾' => '》',
'︿' => '〈',
'﹀' => '〉',
'﹁' => '「',
'﹂' => '」',
'﹃' => '『',
'﹄' => '』',
'﹇' => '[',
'﹈' => ']',
'﹉' => ' ̅',
'﹊' => ' ̅',
'﹋' => ' ̅',
'﹌' => ' ̅',
'﹍' => '_',
'﹎' => '_',
'﹏' => '_',
'﹐' => ',',
'﹑' => '、',
'﹒' => '.',
'﹔' => ';',
'﹕' => ':',
'﹖' => '?',
'﹗' => '!',
'﹘' => '—',
'﹙' => '(',
'﹚' => ')',
'﹛' => '{',
'﹜' => '}',
'﹝' => '〔',
'﹞' => '〕',
'﹟' => '#',
'﹠' => '&',
'﹡' => '*',
'﹢' => '+',
'﹣' => '-',
'﹤' => '<',
'﹥' => '>',
'﹦' => '=',
'﹨' => '\\',
'﹩' => '$',
'﹪' => '%',
'﹫' => '@',
'ﹰ' => ' ً',
'ﹱ' => 'ـً',
'ﹲ' => ' ٌ',
'ﹴ' => ' ٍ',
'ﹶ' => ' َ',
'ﹷ' => 'ـَ',
'ﹸ' => ' ُ',
'ﹹ' => 'ـُ',
'ﹺ' => ' ِ',
'ﹻ' => 'ـِ',
'ﹼ' => ' ّ',
'ﹽ' => 'ـّ',
'ﹾ' => ' ْ',
'ﹿ' => 'ـْ',
'ﺀ' => 'ء',
'ﺁ' => 'آ',
'ﺂ' => 'آ',
'ﺃ' => 'أ',
'ﺄ' => 'أ',
'ﺅ' => 'ؤ',
'ﺆ' => 'ؤ',
'ﺇ' => 'إ',
'ﺈ' => 'إ',
'ﺉ' => 'ئ',
'ﺊ' => 'ئ',
'ﺋ' => 'ئ',
'ﺌ' => 'ئ',
'ﺍ' => 'ا',
'ﺎ' => 'ا',
'ﺏ' => 'ب',
'ﺐ' => 'ب',
'ﺑ' => 'ب',
'ﺒ' => 'ب',
'ﺓ' => 'ة',
'ﺔ' => 'ة',
'ﺕ' => 'ت',
'ﺖ' => 'ت',
'ﺗ' => 'ت',
'ﺘ' => 'ت',
'ﺙ' => 'ث',
'ﺚ' => 'ث',
'ﺛ' => 'ث',
'ﺜ' => 'ث',
'ﺝ' => 'ج',
'ﺞ' => 'ج',
'ﺟ' => 'ج',
'ﺠ' => 'ج',
'ﺡ' => 'ح',
'ﺢ' => 'ح',
'ﺣ' => 'ح',
'ﺤ' => 'ح',
'ﺥ' => 'خ',
'ﺦ' => 'خ',
'ﺧ' => 'خ',
'ﺨ' => 'خ',
'ﺩ' => 'د',
'ﺪ' => 'د',
'ﺫ' => 'ذ',
'ﺬ' => 'ذ',
'ﺭ' => 'ر',
'ﺮ' => 'ر',
'ﺯ' => 'ز',
'ﺰ' => 'ز',
'ﺱ' => 'س',
'ﺲ' => 'س',
'ﺳ' => 'س',
'ﺴ' => 'س',
'ﺵ' => 'ش',
'ﺶ' => 'ش',
'ﺷ' => 'ش',
'ﺸ' => 'ش',
'ﺹ' => 'ص',
'ﺺ' => 'ص',
'ﺻ' => 'ص',
'ﺼ' => 'ص',
'ﺽ' => 'ض',
'ﺾ' => 'ض',
'ﺿ' => 'ض',
'ﻀ' => 'ض',
'ﻁ' => 'ط',
'ﻂ' => 'ط',
'ﻃ' => 'ط',
'ﻄ' => 'ط',
'ﻅ' => 'ظ',
'ﻆ' => 'ظ',
'ﻇ' => 'ظ',
'ﻈ' => 'ظ',
'ﻉ' => 'ع',
'ﻊ' => 'ع',
'ﻋ' => 'ع',
'ﻌ' => 'ع',
'ﻍ' => 'غ',
'ﻎ' => 'غ',
'ﻏ' => 'غ',
'ﻐ' => 'غ',
'ﻑ' => 'ف',
'ﻒ' => 'ف',
'ﻓ' => 'ف',
'ﻔ' => 'ف',
'ﻕ' => 'ق',
'ﻖ' => 'ق',
'ﻗ' => 'ق',
'ﻘ' => 'ق',
'ﻙ' => 'ك',
'ﻚ' => 'ك',
'ﻛ' => 'ك',
'ﻜ' => 'ك',
'ﻝ' => 'ل',
'ﻞ' => 'ل',
'ﻟ' => 'ل',
'ﻠ' => 'ل',
'ﻡ' => 'م',
'ﻢ' => 'م',
'ﻣ' => 'م',
'ﻤ' => 'م',
'ﻥ' => 'ن',
'ﻦ' => 'ن',
'ﻧ' => 'ن',
'ﻨ' => 'ن',
'ﻩ' => 'ه',
'ﻪ' => 'ه',
'ﻫ' => 'ه',
'ﻬ' => 'ه',
'ﻭ' => 'و',
'ﻮ' => 'و',
'ﻯ' => 'ى',
'ﻰ' => 'ى',
'ﻱ' => 'ي',
'ﻲ' => 'ي',
'ﻳ' => 'ي',
'ﻴ' => 'ي',
'ﻵ' => 'لآ',
'ﻶ' => 'لآ',
'ﻷ' => 'لأ',
'ﻸ' => 'لأ',
'ﻹ' => 'لإ',
'ﻺ' => 'لإ',
'ﻻ' => 'لا',
'ﻼ' => 'لا',
'！' => '!',
'＂' => '"',
'＃' => '#',
'＄' => '$',
'％' => '%',
'＆' => '&',
'＇' => '\'',
'（' => '(',
'）' => ')',
'＊' => '*',
'＋' => '+',
'，' => ',',
'－' => '-',
'．' => '.',
'／' => '/',
'０' => '0',
'１' => '1',
'２' => '2',
'３' => '3',
'４' => '4',
'５' => '5',
'６' => '6',
'７' => '7',
'８' => '8',
'９' => '9',
'：' => ':',
'；' => ';',
'＜' => '<',
'＝' => '=',
'＞' => '>',
'？' => '?',
'＠' => '@',
'Ａ' => 'A',
'Ｂ' => 'B',
'Ｃ' => 'C',
'Ｄ' => 'D',
'Ｅ' => 'E',
'Ｆ' => 'F',
'Ｇ' => 'G',
'Ｈ' => 'H',
'Ｉ' => 'I',
'Ｊ' => 'J',
'Ｋ' => 'K',
'Ｌ' => 'L',
'Ｍ' => 'M',
'Ｎ' => 'N',
'Ｏ' => 'O',
'Ｐ' => 'P',
'Ｑ' => 'Q',
'Ｒ' => 'R',
'Ｓ' => 'S',
'Ｔ' => 'T',
'Ｕ' => 'U',
'Ｖ' => 'V',
'Ｗ' => 'W',
'Ｘ' => 'X',
'Ｙ' => 'Y',
'Ｚ' => 'Z',
'［' => '[',
'＼' => '\\',
'］' => ']',
'＾' => '^',
'＿' => '_',
'｀' => '`',
'ａ' => 'a',
'ｂ' => 'b',
'ｃ' => 'c',
'ｄ' => 'd',
'ｅ' => 'e',
'ｆ' => 'f',
'ｇ' => 'g',
'ｈ' => 'h',
'ｉ' => 'i',
'ｊ' => 'j',
'ｋ' => 'k',
'ｌ' => 'l',
'ｍ' => 'm',
'ｎ' => 'n',
'ｏ' => 'o',
'ｐ' => 'p',
'ｑ' => 'q',
'ｒ' => 'r',
'ｓ' => 's',
'ｔ' => 't',
'ｕ' => 'u',
'ｖ' => 'v',
'ｗ' => 'w',
'ｘ' => 'x',
'ｙ' => 'y',
'ｚ' => 'z',
'｛' => '{',
'｜' => '|',
'｝' => '}',
'～' => '~',
'｟' => '⦅',
'｠' => '⦆',
'｡' => '。',
'｢' => '「',
'｣' => '」',
'､' => '、',
'･' => '・',
'ｦ' => 'ヲ',
'ｧ' => 'ァ',
'ｨ' => 'ィ',
'ｩ' => 'ゥ',
'ｪ' => 'ェ',
'ｫ' => 'ォ',
'ｬ' => 'ャ',
'ｭ' => 'ュ',
'ｮ' => 'ョ',
'ｯ' => 'ッ',
'ｰ' => 'ー',
'ｱ' => 'ア',
'ｲ' => 'イ',
'ｳ' => 'ウ',
'ｴ' => 'エ',
'ｵ' => 'オ',
'ｶ' => 'カ',
'ｷ' => 'キ',
'ｸ' => 'ク',
'ｹ' => 'ケ',
'ｺ' => 'コ',
'ｻ' => 'サ',
'ｼ' => 'シ',
'ｽ' => 'ス',
'ｾ' => 'セ',
'ｿ' => 'ソ',
'ﾀ' => 'タ',
'ﾁ' => 'チ',
'ﾂ' => 'ツ',
'ﾃ' => 'テ',
'ﾄ' => 'ト',
'ﾅ' => 'ナ',
'ﾆ' => 'ニ',
'ﾇ' => 'ヌ',
'ﾈ' => 'ネ',
'ﾉ' => 'ノ',
'ﾊ' => 'ハ',
'ﾋ' => 'ヒ',
'ﾌ' => 'フ',
'ﾍ' => 'ヘ',
'ﾎ' => 'ホ',
'ﾏ' => 'マ',
'ﾐ' => 'ミ',
'ﾑ' => 'ム',
'ﾒ' => 'メ',
'ﾓ' => 'モ',
'ﾔ' => 'ヤ',
'ﾕ' => 'ユ',
'ﾖ' => 'ヨ',
'ﾗ' => 'ラ',
'ﾘ' => 'リ',
'ﾙ' => 'ル',
'ﾚ' => 'レ',
'ﾛ' => 'ロ',
'ﾜ' => 'ワ',
'ﾝ' => 'ン',
'ﾞ' => '゙',
'ﾟ' => '゚',
'ﾠ' => 'ᅠ',
'ﾡ' => 'ᄀ',
'ﾢ' => 'ᄁ',
'ﾣ' => 'ᆪ',
'ﾤ' => 'ᄂ',
'ﾥ' => 'ᆬ',
'ﾦ' => 'ᆭ',
'ﾧ' => 'ᄃ',
'ﾨ' => 'ᄄ',
'ﾩ' => 'ᄅ',
'ﾪ' => 'ᆰ',
'ﾫ' => 'ᆱ',
'ﾬ' => 'ᆲ',
'ﾭ' => 'ᆳ',
'ﾮ' => 'ᆴ',
'ﾯ' => 'ᆵ',
'ﾰ' => 'ᄚ',
'ﾱ' => 'ᄆ',
'ﾲ' => 'ᄇ',
'ﾳ' => 'ᄈ',
'ﾴ' => 'ᄡ',
'ﾵ' => 'ᄉ',
'ﾶ' => 'ᄊ',
'ﾷ' => 'ᄋ',
'ﾸ' => 'ᄌ',
'ﾹ' => 'ᄍ',
'ﾺ' => 'ᄎ',
'ﾻ' => 'ᄏ',
'ﾼ' => 'ᄐ',
'ﾽ' => 'ᄑ',
'ﾾ' => 'ᄒ',
'ￂ' => 'ᅡ',
'ￃ' => 'ᅢ',
'ￄ' => 'ᅣ',
'ￅ' => 'ᅤ',
'ￆ' => 'ᅥ',
'ￇ' => 'ᅦ',
'ￊ' => 'ᅧ',
'ￋ' => 'ᅨ',
'ￌ' => 'ᅩ',
'ￍ' => 'ᅪ',
'ￎ' => 'ᅫ',
'ￏ' => 'ᅬ',
'ￒ' => 'ᅭ',
'ￓ' => 'ᅮ',
'ￔ' => 'ᅯ',
'ￕ' => 'ᅰ',
'ￖ' => 'ᅱ',
'ￗ' => 'ᅲ',
'ￚ' => 'ᅳ',
'ￛ' => 'ᅴ',
'ￜ' => 'ᅵ',
'￠' => '¢',
'￡' => '£',
'￢' => '¬',
'￣' => ' ̄',
'￤' => '¦',
'￥' => '¥',
'￦' => '₩',
'￨' => '│',
'￩' => '←',
'￪' => '↑',
'￫' => '→',
'￬' => '↓',
'￭' => '■',
'￮' => '○',
'𝐀' => 'A',
'𝐁' => 'B',
'𝐂' => 'C',
'𝐃' => 'D',
'𝐄' => 'E',
'𝐅' => 'F',
'𝐆' => 'G',
'𝐇' => 'H',
'𝐈' => 'I',
'𝐉' => 'J',
'𝐊' => 'K',
'𝐋' => 'L',
'𝐌' => 'M',
'𝐍' => 'N',
'𝐎' => 'O',
'𝐏' => 'P',
'𝐐' => 'Q',
'𝐑' => 'R',
'𝐒' => 'S',
'𝐓' => 'T',
'𝐔' => 'U',
'𝐕' => 'V',
'𝐖' => 'W',
'𝐗' => 'X',
'𝐘' => 'Y',
'𝐙' => 'Z',
'𝐚' => 'a',
'𝐛' => 'b',
'𝐜' => 'c',
'𝐝' => 'd',
'𝐞' => 'e',
'𝐟' => 'f',
'𝐠' => 'g',
'𝐡' => 'h',
'𝐢' => 'i',
'𝐣' => 'j',
'𝐤' => 'k',
'𝐥' => 'l',
'𝐦' => 'm',
'𝐧' => 'n',
'𝐨' => 'o',
'𝐩' => 'p',
'𝐪' => 'q',
'𝐫' => 'r',
'𝐬' => 's',
'𝐭' => 't',
'𝐮' => 'u',
'𝐯' => 'v',
'𝐰' => 'w',
'𝐱' => 'x',
'𝐲' => 'y',
'𝐳' => 'z',
'𝐴' => 'A',
'𝐵' => 'B',
'𝐶' => 'C',
'𝐷' => 'D',
'𝐸' => 'E',
'𝐹' => 'F',
'𝐺' => 'G',
'𝐻' => 'H',
'𝐼' => 'I',
'𝐽' => 'J',
'𝐾' => 'K',
'𝐿' => 'L',
'𝑀' => 'M',
'𝑁' => 'N',
'𝑂' => 'O',
'𝑃' => 'P',
'𝑄' => 'Q',
'𝑅' => 'R',
'𝑆' => 'S',
'𝑇' => 'T',
'𝑈' => 'U',
'𝑉' => 'V',
'𝑊' => 'W',
'𝑋' => 'X',
'𝑌' => 'Y',
'𝑍' => 'Z',
'𝑎' => 'a',
'𝑏' => 'b',
'𝑐' => 'c',
'𝑑' => 'd',
'𝑒' => 'e',
'𝑓' => 'f',
'𝑔' => 'g',
'𝑖' => 'i',
'𝑗' => 'j',
'𝑘' => 'k',
'𝑙' => 'l',
'𝑚' => 'm',
'𝑛' => 'n',
'𝑜' => 'o',
'𝑝' => 'p',
'𝑞' => 'q',
'𝑟' => 'r',
'𝑠' => 's',
'𝑡' => 't',
'𝑢' => 'u',
'𝑣' => 'v',
'𝑤' => 'w',
'𝑥' => 'x',
'𝑦' => 'y',
'𝑧' => 'z',
'𝑨' => 'A',
'𝑩' => 'B',
'𝑪' => 'C',
'𝑫' => 'D',
'𝑬' => 'E',
'𝑭' => 'F',
'𝑮' => 'G',
'𝑯' => 'H',
'𝑰' => 'I',
'𝑱' => 'J',
'𝑲' => 'K',
'𝑳' => 'L',
'𝑴' => 'M',
'𝑵' => 'N',
'𝑶' => 'O',
'𝑷' => 'P',
'𝑸' => 'Q',
'𝑹' => 'R',
'𝑺' => 'S',
'𝑻' => 'T',
'𝑼' => 'U',
'𝑽' => 'V',
'𝑾' => 'W',
'𝑿' => 'X',
'𝒀' => 'Y',
'𝒁' => 'Z',
'𝒂' => 'a',
'𝒃' => 'b',
'𝒄' => 'c',
'𝒅' => 'd',
'𝒆' => 'e',
'𝒇' => 'f',
'𝒈' => 'g',
'𝒉' => 'h',
'𝒊' => 'i',
'𝒋' => 'j',
'𝒌' => 'k',
'𝒍' => 'l',
'𝒎' => 'm',
'𝒏' => 'n',
'𝒐' => 'o',
'𝒑' => 'p',
'𝒒' => 'q',
'𝒓' => 'r',
'𝒔' => 's',
'𝒕' => 't',
'𝒖' => 'u',
'𝒗' => 'v',
'𝒘' => 'w',
'𝒙' => 'x',
'𝒚' => 'y',
'𝒛' => 'z',
'𝒜' => 'A',
'𝒞' => 'C',
'𝒟' => 'D',
'𝒢' => 'G',
'𝒥' => 'J',
'𝒦' => 'K',
'𝒩' => 'N',
'𝒪' => 'O',
'𝒫' => 'P',
'𝒬' => 'Q',
'𝒮' => 'S',
'𝒯' => 'T',
'𝒰' => 'U',
'𝒱' => 'V',
'𝒲' => 'W',
'𝒳' => 'X',
'𝒴' => 'Y',
'𝒵' => 'Z',
'𝒶' => 'a',
'𝒷' => 'b',
'𝒸' => 'c',
'𝒹' => 'd',
'𝒻' => 'f',
'𝒽' => 'h',
'𝒾' => 'i',
'𝒿' => 'j',
'𝓀' => 'k',
'𝓁' => 'l',
'𝓂' => 'm',
'𝓃' => 'n',
'𝓅' => 'p',
'𝓆' => 'q',
'𝓇' => 'r',
'𝓈' => 's',
'𝓉' => 't',
'𝓊' => 'u',
'𝓋' => 'v',
'𝓌' => 'w',
'𝓍' => 'x',
'𝓎' => 'y',
'𝓏' => 'z',
'𝓐' => 'A',
'𝓑' => 'B',
'𝓒' => 'C',
'𝓓' => 'D',
'𝓔' => 'E',
'𝓕' => 'F',
'𝓖' => 'G',
'𝓗' => 'H',
'𝓘' => 'I',
'𝓙' => 'J',
'𝓚' => 'K',
'𝓛' => 'L',
'𝓜' => 'M',
'𝓝' => 'N',
'𝓞' => 'O',
'𝓟' => 'P',
'𝓠' => 'Q',
'𝓡' => 'R',
'𝓢' => 'S',
'𝓣' => 'T',
'𝓤' => 'U',
'𝓥' => 'V',
'𝓦' => 'W',
'𝓧' => 'X',
'𝓨' => 'Y',
'𝓩' => 'Z',
'𝓪' => 'a',
'𝓫' => 'b',
'𝓬' => 'c',
'𝓭' => 'd',
'𝓮' => 'e',
'𝓯' => 'f',
'𝓰' => 'g',
'𝓱' => 'h',
'𝓲' => 'i',
'𝓳' => 'j',
'𝓴' => 'k',
'𝓵' => 'l',
'𝓶' => 'm',
'𝓷' => 'n',
'𝓸' => 'o',
'𝓹' => 'p',
'𝓺' => 'q',
'𝓻' => 'r',
'𝓼' => 's',
'𝓽' => 't',
'𝓾' => 'u',
'𝓿' => 'v',
'𝔀' => 'w',
'𝔁' => 'x',
'𝔂' => 'y',
'𝔃' => 'z',
'𝔄' => 'A',
'𝔅' => 'B',
'𝔇' => 'D',
'𝔈' => 'E',
'𝔉' => 'F',
'𝔊' => 'G',
'𝔍' => 'J',
'𝔎' => 'K',
'𝔏' => 'L',
'𝔐' => 'M',
'𝔑' => 'N',
'𝔒' => 'O',
'𝔓' => 'P',
'𝔔' => 'Q',
'𝔖' => 'S',
'𝔗' => 'T',
'𝔘' => 'U',
'𝔙' => 'V',
'𝔚' => 'W',
'𝔛' => 'X',
'𝔜' => 'Y',
'𝔞' => 'a',
'𝔟' => 'b',
'𝔠' => 'c',
'𝔡' => 'd',
'𝔢' => 'e',
'𝔣' => 'f',
'𝔤' => 'g',
'𝔥' => 'h',
'𝔦' => 'i',
'𝔧' => 'j',
'𝔨' => 'k',
'𝔩' => 'l',
'𝔪' => 'm',
'𝔫' => 'n',
'𝔬' => 'o',
'𝔭' => 'p',
'𝔮' => 'q',
'𝔯' => 'r',
'𝔰' => 's',
'𝔱' => 't',
'𝔲' => 'u',
'𝔳' => 'v',
'𝔴' => 'w',
'𝔵' => 'x',
'𝔶' => 'y',
'𝔷' => 'z',
'𝔸' => 'A',
'𝔹' => 'B',
'𝔻' => 'D',
'𝔼' => 'E',
'𝔽' => 'F',
'𝔾' => 'G',
'𝕀' => 'I',
'𝕁' => 'J',
'𝕂' => 'K',
'𝕃' => 'L',
'𝕄' => 'M',
'𝕆' => 'O',
'𝕊' => 'S',
'𝕋' => 'T',
'𝕌' => 'U',
'𝕍' => 'V',
'𝕎' => 'W',
'𝕏' => 'X',
'𝕐' => 'Y',
'𝕒' => 'a',
'𝕓' => 'b',
'𝕔' => 'c',
'𝕕' => 'd',
'𝕖' => 'e',
'𝕗' => 'f',
'𝕘' => 'g',
'𝕙' => 'h',
'𝕚' => 'i',
'𝕛' => 'j',
'𝕜' => 'k',
'𝕝' => 'l',
'𝕞' => 'm',
'𝕟' => 'n',
'𝕠' => 'o',
'𝕡' => 'p',
'𝕢' => 'q',
'𝕣' => 'r',
'𝕤' => 's',
'𝕥' => 't',
'𝕦' => 'u',
'𝕧' => 'v',
'𝕨' => 'w',
'𝕩' => 'x',
'𝕪' => 'y',
'𝕫' => 'z',
'𝕬' => 'A',
'𝕭' => 'B',
'𝕮' => 'C',
'𝕯' => 'D',
'𝕰' => 'E',
'𝕱' => 'F',
'𝕲' => 'G',
'𝕳' => 'H',
'𝕴' => 'I',
'𝕵' => 'J',
'𝕶' => 'K',
'𝕷' => 'L',
'𝕸' => 'M',
'𝕹' => 'N',
'𝕺' => 'O',
'𝕻' => 'P',
'𝕼' => 'Q',
'𝕽' => 'R',
'𝕾' => 'S',
'𝕿' => 'T',
'𝖀' => 'U',
'𝖁' => 'V',
'𝖂' => 'W',
'𝖃' => 'X',
'𝖄' => 'Y',
'𝖅' => 'Z',
'𝖆' => 'a',
'𝖇' => 'b',
'𝖈' => 'c',
'𝖉' => 'd',
'𝖊' => 'e',
'𝖋' => 'f',
'𝖌' => 'g',
'𝖍' => 'h',
'𝖎' => 'i',
'𝖏' => 'j',
'𝖐' => 'k',
'𝖑' => 'l',
'𝖒' => 'm',
'𝖓' => 'n',
'𝖔' => 'o',
'𝖕' => 'p',
'𝖖' => 'q',
'𝖗' => 'r',
'𝖘' => 's',
'𝖙' => 't',
'𝖚' => 'u',
'𝖛' => 'v',
'𝖜' => 'w',
'𝖝' => 'x',
'𝖞' => 'y',
'𝖟' => 'z',
'𝖠' => 'A',
'𝖡' => 'B',
'𝖢' => 'C',
'𝖣' => 'D',
'𝖤' => 'E',
'𝖥' => 'F',
'𝖦' => 'G',
'𝖧' => 'H',
'𝖨' => 'I',
'𝖩' => 'J',
'𝖪' => 'K',
'𝖫' => 'L',
'𝖬' => 'M',
'𝖭' => 'N',
'𝖮' => 'O',
'𝖯' => 'P',
'𝖰' => 'Q',
'𝖱' => 'R',
'𝖲' => 'S',
'𝖳' => 'T',
'𝖴' => 'U',
'𝖵' => 'V',
'𝖶' => 'W',
'𝖷' => 'X',
'𝖸' => 'Y',
'𝖹' => 'Z',
'𝖺' => 'a',
'𝖻' => 'b',
'𝖼' => 'c',
'𝖽' => 'd',
'𝖾' => 'e',
'𝖿' => 'f',
'𝗀' => 'g',
'𝗁' => 'h',
'𝗂' => 'i',
'𝗃' => 'j',
'𝗄' => 'k',
'𝗅' => 'l',
'𝗆' => 'm',
'𝗇' => 'n',
'𝗈' => 'o',
'𝗉' => 'p',
'𝗊' => 'q',
'𝗋' => 'r',
'𝗌' => 's',
'𝗍' => 't',
'𝗎' => 'u',
'𝗏' => 'v',
'𝗐' => 'w',
'𝗑' => 'x',
'𝗒' => 'y',
'𝗓' => 'z',
'𝗔' => 'A',
'𝗕' => 'B',
'𝗖' => 'C',
'𝗗' => 'D',
'𝗘' => 'E',
'𝗙' => 'F',
'𝗚' => 'G',
'𝗛' => 'H',
'𝗜' => 'I',
'𝗝' => 'J',
'𝗞' => 'K',
'𝗟' => 'L',
'𝗠' => 'M',
'𝗡' => 'N',
'𝗢' => 'O',
'𝗣' => 'P',
'𝗤' => 'Q',
'𝗥' => 'R',
'𝗦' => 'S',
'𝗧' => 'T',
'𝗨' => 'U',
'𝗩' => 'V',
'𝗪' => 'W',
'𝗫' => 'X',
'𝗬' => 'Y',
'𝗭' => 'Z',
'𝗮' => 'a',
'𝗯' => 'b',
'𝗰' => 'c',
'𝗱' => 'd',
'𝗲' => 'e',
'𝗳' => 'f',
'𝗴' => 'g',
'𝗵' => 'h',
'𝗶' => 'i',
'𝗷' => 'j',
'𝗸' => 'k',
'𝗹' => 'l',
'𝗺' => 'm',
'𝗻' => 'n',
'𝗼' => 'o',
'𝗽' => 'p',
'𝗾' => 'q',
'𝗿' => 'r',
'𝘀' => 's',
'𝘁' => 't',
'𝘂' => 'u',
'𝘃' => 'v',
'𝘄' => 'w',
'𝘅' => 'x',
'𝘆' => 'y',
'𝘇' => 'z',
'𝘈' => 'A',
'𝘉' => 'B',
'𝘊' => 'C',
'𝘋' => 'D',
'𝘌' => 'E',
'𝘍' => 'F',
'𝘎' => 'G',
'𝘏' => 'H',
'𝘐' => 'I',
'𝘑' => 'J',
'𝘒' => 'K',
'𝘓' => 'L',
'𝘔' => 'M',
'𝘕' => 'N',
'𝘖' => 'O',
'𝘗' => 'P',
'𝘘' => 'Q',
'𝘙' => 'R',
'𝘚' => 'S',
'𝘛' => 'T',
'𝘜' => 'U',
'𝘝' => 'V',
'𝘞' => 'W',
'𝘟' => 'X',
'𝘠' => 'Y',
'𝘡' => 'Z',
'𝘢' => 'a',
'𝘣' => 'b',
'𝘤' => 'c',
'𝘥' => 'd',
'𝘦' => 'e',
'𝘧' => 'f',
'𝘨' => 'g',
'𝘩' => 'h',
'𝘪' => 'i',
'𝘫' => 'j',
'𝘬' => 'k',
'𝘭' => 'l',
'𝘮' => 'm',
'𝘯' => 'n',
'𝘰' => 'o',
'𝘱' => 'p',
'𝘲' => 'q',
'𝘳' => 'r',
'𝘴' => 's',
'𝘵' => 't',
'𝘶' => 'u',
'𝘷' => 'v',
'𝘸' => 'w',
'𝘹' => 'x',
'𝘺' => 'y',
'𝘻' => 'z',
'𝘼' => 'A',
'𝘽' => 'B',
'𝘾' => 'C',
'𝘿' => 'D',
'𝙀' => 'E',
'𝙁' => 'F',
'𝙂' => 'G',
'𝙃' => 'H',
'𝙄' => 'I',
'𝙅' => 'J',
'𝙆' => 'K',
'𝙇' => 'L',
'𝙈' => 'M',
'𝙉' => 'N',
'𝙊' => 'O',
'𝙋' => 'P',
'𝙌' => 'Q',
'𝙍' => 'R',
'𝙎' => 'S',
'𝙏' => 'T',
'𝙐' => 'U',
'𝙑' => 'V',
'𝙒' => 'W',
'𝙓' => 'X',
'𝙔' => 'Y',
'𝙕' => 'Z',
'𝙖' => 'a',
'𝙗' => 'b',
'𝙘' => 'c',
'𝙙' => 'd',
'𝙚' => 'e',
'𝙛' => 'f',
'𝙜' => 'g',
'𝙝' => 'h',
'𝙞' => 'i',
'𝙟' => 'j',
'𝙠' => 'k',
'𝙡' => 'l',
'𝙢' => 'm',
'𝙣' => 'n',
'𝙤' => 'o',
'𝙥' => 'p',
'𝙦' => 'q',
'𝙧' => 'r',
'𝙨' => 's',
'𝙩' => 't',
'𝙪' => 'u',
'𝙫' => 'v',
'𝙬' => 'w',
'𝙭' => 'x',
'𝙮' => 'y',
'𝙯' => 'z',
'𝙰' => 'A',
'𝙱' => 'B',
'𝙲' => 'C',
'𝙳' => 'D',
'𝙴' => 'E',
'𝙵' => 'F',
'𝙶' => 'G',
'𝙷' => 'H',
'𝙸' => 'I',
'𝙹' => 'J',
'𝙺' => 'K',
'𝙻' => 'L',
'𝙼' => 'M',
'𝙽' => 'N',
'𝙾' => 'O',
'𝙿' => 'P',
'𝚀' => 'Q',
'𝚁' => 'R',
'𝚂' => 'S',
'𝚃' => 'T',
'𝚄' => 'U',
'𝚅' => 'V',
'𝚆' => 'W',
'𝚇' => 'X',
'𝚈' => 'Y',
'𝚉' => 'Z',
'𝚊' => 'a',
'𝚋' => 'b',
'𝚌' => 'c',
'𝚍' => 'd',
'𝚎' => 'e',
'𝚏' => 'f',
'𝚐' => 'g',
'𝚑' => 'h',
'𝚒' => 'i',
'𝚓' => 'j',
'𝚔' => 'k',
'𝚕' => 'l',
'𝚖' => 'm',
'𝚗' => 'n',
'𝚘' => 'o',
'𝚙' => 'p',
'𝚚' => 'q',
'𝚛' => 'r',
'𝚜' => 's',
'𝚝' => 't',
'𝚞' => 'u',
'𝚟' => 'v',
'𝚠' => 'w',
'𝚡' => 'x',
'𝚢' => 'y',
'𝚣' => 'z',
'𝚤' => 'ı',
'𝚥' => 'ȷ',
'𝚨' => 'Α',
'𝚩' => 'Β',
'𝚪' => 'Γ',
'𝚫' => 'Δ',
'𝚬' => 'Ε',
'𝚭' => 'Ζ',
'𝚮' => 'Η',
'𝚯' => 'Θ',
'𝚰' => 'Ι',
'𝚱' => 'Κ',
'𝚲' => 'Λ',
'𝚳' => 'Μ',
'𝚴' => 'Ν',
'𝚵' => 'Ξ',
'𝚶' => 'Ο',
'𝚷' => 'Π',
'𝚸' => 'Ρ',
'𝚹' => 'Θ',
'𝚺' => 'Σ',
'𝚻' => 'Τ',
'𝚼' => 'Υ',
'𝚽' => 'Φ',
'𝚾' => 'Χ',
'𝚿' => 'Ψ',
'𝛀' => 'Ω',
'𝛁' => '∇',
'𝛂' => 'α',
'𝛃' => 'β',
'𝛄' => 'γ',
'𝛅' => 'δ',
'𝛆' => 'ε',
'𝛇' => 'ζ',
'𝛈' => 'η',
'𝛉' => 'θ',
'𝛊' => 'ι',
'𝛋' => 'κ',
'𝛌' => 'λ',
'𝛍' => 'μ',
'𝛎' => 'ν',
'𝛏' => 'ξ',
'𝛐' => 'ο',
'𝛑' => 'π',
'𝛒' => 'ρ',
'𝛓' => 'ς',
'𝛔' => 'σ',
'𝛕' => 'τ',
'𝛖' => 'υ',
'𝛗' => 'φ',
'𝛘' => 'χ',
'𝛙' => 'ψ',
'𝛚' => 'ω',
'𝛛' => '∂',
'𝛜' => 'ε',
'𝛝' => 'θ',
'𝛞' => 'κ',
'𝛟' => 'φ',
'𝛠' => 'ρ',
'𝛡' => 'π',
'𝛢' => 'Α',
'𝛣' => 'Β',
'𝛤' => 'Γ',
'𝛥' => 'Δ',
'𝛦' => 'Ε',
'𝛧' => 'Ζ',
'𝛨' => 'Η',
'𝛩' => 'Θ',
'𝛪' => 'Ι',
'𝛫' => 'Κ',
'𝛬' => 'Λ',
'𝛭' => 'Μ',
'𝛮' => 'Ν',
'𝛯' => 'Ξ',
'𝛰' => 'Ο',
'𝛱' => 'Π',
'𝛲' => 'Ρ',
'𝛳' => 'Θ',
'𝛴' => 'Σ',
'𝛵' => 'Τ',
'𝛶' => 'Υ',
'𝛷' => 'Φ',
'𝛸' => 'Χ',
'𝛹' => 'Ψ',
'𝛺' => 'Ω',
'𝛻' => '∇',
'𝛼' => 'α',
'𝛽' => 'β',
'𝛾' => 'γ',
'𝛿' => 'δ',
'𝜀' => 'ε',
'𝜁' => 'ζ',
'𝜂' => 'η',
'𝜃' => 'θ',
'𝜄' => 'ι',
'𝜅' => 'κ',
'𝜆' => 'λ',
'𝜇' => 'μ',
'𝜈' => 'ν',
'𝜉' => 'ξ',
'𝜊' => 'ο',
'𝜋' => 'π',
'𝜌' => 'ρ',
'𝜍' => 'ς',
'𝜎' => 'σ',
'𝜏' => 'τ',
'𝜐' => 'υ',
'𝜑' => 'φ',
'𝜒' => 'χ',
'𝜓' => 'ψ',
'𝜔' => 'ω',
'𝜕' => '∂',
'𝜖' => 'ε',
'𝜗' => 'θ',
'𝜘' => 'κ',
'𝜙' => 'φ',
'𝜚' => 'ρ',
'𝜛' => 'π',
'𝜜' => 'Α',
'𝜝' => 'Β',
'𝜞' => 'Γ',
'𝜟' => 'Δ',
'𝜠' => 'Ε',
'𝜡' => 'Ζ',
'𝜢' => 'Η',
'𝜣' => 'Θ',
'𝜤' => 'Ι',
'𝜥' => 'Κ',
'𝜦' => 'Λ',
'𝜧' => 'Μ',
'𝜨' => 'Ν',
'𝜩' => 'Ξ',
'𝜪' => 'Ο',
'𝜫' => 'Π',
'𝜬' => 'Ρ',
'𝜭' => 'Θ',
'𝜮' => 'Σ',
'𝜯' => 'Τ',
'𝜰' => 'Υ',
'𝜱' => 'Φ',
'𝜲' => 'Χ',
'𝜳' => 'Ψ',
'𝜴' => 'Ω',
'𝜵' => '∇',
'𝜶' => 'α',
'𝜷' => 'β',
'𝜸' => 'γ',
'𝜹' => 'δ',
'𝜺' => 'ε',
'𝜻' => 'ζ',
'𝜼' => 'η',
'𝜽' => 'θ',
'𝜾' => 'ι',
'𝜿' => 'κ',
'𝝀' => 'λ',
'𝝁' => 'μ',
'𝝂' => 'ν',
'𝝃' => 'ξ',
'𝝄' => 'ο',
'𝝅' => 'π',
'𝝆' => 'ρ',
'𝝇' => 'ς',
'𝝈' => 'σ',
'𝝉' => 'τ',
'𝝊' => 'υ',
'𝝋' => 'φ',
'𝝌' => 'χ',
'𝝍' => 'ψ',
'𝝎' => 'ω',
'𝝏' => '∂',
'𝝐' => 'ε',
'𝝑' => 'θ',
'𝝒' => 'κ',
'𝝓' => 'φ',
'𝝔' => 'ρ',
'𝝕' => 'π',
'𝝖' => 'Α',
'𝝗' => 'Β',
'𝝘' => 'Γ',
'𝝙' => 'Δ',
'𝝚' => 'Ε',
'𝝛' => 'Ζ',
'𝝜' => 'Η',
'𝝝' => 'Θ',
'𝝞' => 'Ι',
'𝝟' => 'Κ',
'𝝠' => 'Λ',
'𝝡' => 'Μ',
'𝝢' => 'Ν',
'𝝣' => 'Ξ',
'𝝤' => 'Ο',
'𝝥' => 'Π',
'𝝦' => 'Ρ',
'𝝧' => 'Θ',
'𝝨' => 'Σ',
'𝝩' => 'Τ',
'𝝪' => 'Υ',
'𝝫' => 'Φ',
'𝝬' => 'Χ',
'𝝭' => 'Ψ',
'𝝮' => 'Ω',
'𝝯' => '∇',
'𝝰' => 'α',
'𝝱' => 'β',
'𝝲' => 'γ',
'𝝳' => 'δ',
'𝝴' => 'ε',
'𝝵' => 'ζ',
'𝝶' => 'η',
'𝝷' => 'θ',
'𝝸' => 'ι',
'𝝹' => 'κ',
'𝝺' => 'λ',
'𝝻' => 'μ',
'𝝼' => 'ν',
'𝝽' => 'ξ',
'𝝾' => 'ο',
'𝝿' => 'π',
'𝞀' => 'ρ',
'𝞁' => 'ς',
'𝞂' => 'σ',
'𝞃' => 'τ',
'𝞄' => 'υ',
'𝞅' => 'φ',
'𝞆' => 'χ',
'𝞇' => 'ψ',
'𝞈' => 'ω',
'𝞉' => '∂',
'𝞊' => 'ε',
'𝞋' => 'θ',
'𝞌' => 'κ',
'𝞍' => 'φ',
'𝞎' => 'ρ',
'𝞏' => 'π',
'𝞐' => 'Α',
'𝞑' => 'Β',
'𝞒' => 'Γ',
'𝞓' => 'Δ',
'𝞔' => 'Ε',
'𝞕' => 'Ζ',
'𝞖' => 'Η',
'𝞗' => 'Θ',
'𝞘' => 'Ι',
'𝞙' => 'Κ',
'𝞚' => 'Λ',
'𝞛' => 'Μ',
'𝞜' => 'Ν',
'𝞝' => 'Ξ',
'𝞞' => 'Ο',
'𝞟' => 'Π',
'𝞠' => 'Ρ',
'𝞡' => 'Θ',
'𝞢' => 'Σ',
'𝞣' => 'Τ',
'𝞤' => 'Υ',
'𝞥' => 'Φ',
'𝞦' => 'Χ',
'𝞧' => 'Ψ',
'𝞨' => 'Ω',
'𝞩' => '∇',
'𝞪' => 'α',
'𝞫' => 'β',
'𝞬' => 'γ',
'𝞭' => 'δ',
'𝞮' => 'ε',
'𝞯' => 'ζ',
'𝞰' => 'η',
'𝞱' => 'θ',
'𝞲' => 'ι',
'𝞳' => 'κ',
'𝞴' => 'λ',
'𝞵' => 'μ',
'𝞶' => 'ν',
'𝞷' => 'ξ',
'𝞸' => 'ο',
'𝞹' => 'π',
'𝞺' => 'ρ',
'𝞻' => 'ς',
'𝞼' => 'σ',
'𝞽' => 'τ',
'𝞾' => 'υ',
'𝞿' => 'φ',
'𝟀' => 'χ',
'𝟁' => 'ψ',
'𝟂' => 'ω',
'𝟃' => '∂',
'𝟄' => 'ε',
'𝟅' => 'θ',
'𝟆' => 'κ',
'𝟇' => 'φ',
'𝟈' => 'ρ',
'𝟉' => 'π',
'𝟊' => 'Ϝ',
'𝟋' => 'ϝ',
'𝟎' => '0',
'𝟏' => '1',
'𝟐' => '2',
'𝟑' => '3',
'𝟒' => '4',
'𝟓' => '5',
'𝟔' => '6',
'𝟕' => '7',
'𝟖' => '8',
'𝟗' => '9',
'𝟘' => '0',
'𝟙' => '1',
'𝟚' => '2',
'𝟛' => '3',
'𝟜' => '4',
'𝟝' => '5',
'𝟞' => '6',
'𝟟' => '7',
'𝟠' => '8',
'𝟡' => '9',
'𝟢' => '0',
'𝟣' => '1',
'𝟤' => '2',
'𝟥' => '3',
'𝟦' => '4',
'𝟧' => '5',
'𝟨' => '6',
'𝟩' => '7',
'𝟪' => '8',
'𝟫' => '9',
'𝟬' => '0',
'𝟭' => '1',
'𝟮' => '2',
'𝟯' => '3',
'𝟰' => '4',
'𝟱' => '5',
'𝟲' => '6',
'𝟳' => '7',
'𝟴' => '8',
'𝟵' => '9',
'𝟶' => '0',
'𝟷' => '1',
'𝟸' => '2',
'𝟹' => '3',
'𝟺' => '4',
'𝟻' => '5',
'𝟼' => '6',
'𝟽' => '7',
'𝟾' => '8',
'𝟿' => '9',
'𞸀' => 'ا',
'𞸁' => 'ب',
'𞸂' => 'ج',
'𞸃' => 'د',
'𞸅' => 'و',
'𞸆' => 'ز',
'𞸇' => 'ح',
'𞸈' => 'ط',
'𞸉' => 'ي',
'𞸊' => 'ك',
'𞸋' => 'ل',
'𞸌' => 'م',
'𞸍' => 'ن',
'𞸎' => 'س',
'𞸏' => 'ع',
'𞸐' => 'ف',
'𞸑' => 'ص',
'𞸒' => 'ق',
'𞸓' => 'ر',
'𞸔' => 'ش',
'𞸕' => 'ت',
'𞸖' => 'ث',
'𞸗' => 'خ',
'𞸘' => 'ذ',
'𞸙' => 'ض',
'𞸚' => 'ظ',
'𞸛' => 'غ',
'𞸜' => 'ٮ',
'𞸝' => 'ں',
'𞸞' => 'ڡ',
'𞸟' => 'ٯ',
'𞸡' => 'ب',
'𞸢' => 'ج',
'𞸤' => 'ه',
'𞸧' => 'ح',
'𞸩' => 'ي',
'𞸪' => 'ك',
'𞸫' => 'ل',
'𞸬' => 'م',
'𞸭' => 'ن',
'𞸮' => 'س',
'𞸯' => 'ع',
'𞸰' => 'ف',
'𞸱' => 'ص',
'𞸲' => 'ق',
'𞸴' => 'ش',
'𞸵' => 'ت',
'𞸶' => 'ث',
'𞸷' => 'خ',
'𞸹' => 'ض',
'𞸻' => 'غ',
'𞹂' => 'ج',
'𞹇' => 'ح',
'𞹉' => 'ي',
'𞹋' => 'ل',
'𞹍' => 'ن',
'𞹎' => 'س',
'𞹏' => 'ع',
'𞹑' => 'ص',
'𞹒' => 'ق',
'𞹔' => 'ش',
'𞹗' => 'خ',
'𞹙' => 'ض',
'𞹛' => 'غ',
'𞹝' => 'ں',
'𞹟' => 'ٯ',
'𞹡' => 'ب',
'𞹢' => 'ج',
'𞹤' => 'ه',
'𞹧' => 'ح',
'𞹨' => 'ط',
'𞹩' => 'ي',
'𞹪' => 'ك',
'𞹬' => 'م',
'𞹭' => 'ن',
'𞹮' => 'س',
'𞹯' => 'ع',
'𞹰' => 'ف',
'𞹱' => 'ص',
'𞹲' => 'ق',
'𞹴' => 'ش',
'𞹵' => 'ت',
'𞹶' => 'ث',
'𞹷' => 'خ',
'𞹹' => 'ض',
'𞹺' => 'ظ',
'𞹻' => 'غ',
'𞹼' => 'ٮ',
'𞹾' => 'ڡ',
'𞺀' => 'ا',
'𞺁' => 'ب',
'𞺂' => 'ج',
'𞺃' => 'د',
'𞺄' => 'ه',
'𞺅' => 'و',
'𞺆' => 'ز',
'𞺇' => 'ح',
'𞺈' => 'ط',
'𞺉' => 'ي',
'𞺋' => 'ل',
'𞺌' => 'م',
'𞺍' => 'ن',
'𞺎' => 'س',
'𞺏' => 'ع',
'𞺐' => 'ف',
'𞺑' => 'ص',
'𞺒' => 'ق',
'𞺓' => 'ر',
'𞺔' => 'ش',
'𞺕' => 'ت',
'𞺖' => 'ث',
'𞺗' => 'خ',
'𞺘' => 'ذ',
'𞺙' => 'ض',
'𞺚' => 'ظ',
'𞺛' => 'غ',
'𞺡' => 'ب',
'𞺢' => 'ج',
'𞺣' => 'د',
'𞺥' => 'و',
'𞺦' => 'ز',
'𞺧' => 'ح',
'𞺨' => 'ط',
'𞺩' => 'ي',
'𞺫' => 'ل',
'𞺬' => 'م',
'𞺭' => 'ن',
'𞺮' => 'س',
'𞺯' => 'ع',
'𞺰' => 'ف',
'𞺱' => 'ص',
'𞺲' => 'ق',
'𞺳' => 'ر',
'𞺴' => 'ش',
'𞺵' => 'ت',
'𞺶' => 'ث',
'𞺷' => 'خ',
'𞺸' => 'ذ',
'𞺹' => 'ض',
'𞺺' => 'ظ',
'𞺻' => 'غ',
'🄀' => '0.',
'🄁' => '0,',
'🄂' => '1,',
'🄃' => '2,',
'🄄' => '3,',
'🄅' => '4,',
'🄆' => '5,',
'🄇' => '6,',
'🄈' => '7,',
'🄉' => '8,',
'🄊' => '9,',
'🄐' => '(A)',
'🄑' => '(B)',
'🄒' => '(C)',
'🄓' => '(D)',
'🄔' => '(E)',
'🄕' => '(F)',
'🄖' => '(G)',
'🄗' => '(H)',
'🄘' => '(I)',
'🄙' => '(J)',
'🄚' => '(K)',
'🄛' => '(L)',
'🄜' => '(M)',
'🄝' => '(N)',
'🄞' => '(O)',
'🄟' => '(P)',
'🄠' => '(Q)',
'🄡' => '(R)',
'🄢' => '(S)',
'🄣' => '(T)',
'🄤' => '(U)',
'🄥' => '(V)',
'🄦' => '(W)',
'🄧' => '(X)',
'🄨' => '(Y)',
'🄩' => '(Z)',
'🄪' => '〔S〕',
'🄫' => 'C',
'🄬' => 'R',
'🄭' => 'CD',
'🄮' => 'WZ',
'🄰' => 'A',
'🄱' => 'B',
'🄲' => 'C',
'🄳' => 'D',
'🄴' => 'E',
'🄵' => 'F',
'🄶' => 'G',
'🄷' => 'H',
'🄸' => 'I',
'🄹' => 'J',
'🄺' => 'K',
'🄻' => 'L',
'🄼' => 'M',
'🄽' => 'N',
'🄾' => 'O',
'🄿' => 'P',
'🅀' => 'Q',
'🅁' => 'R',
'🅂' => 'S',
'🅃' => 'T',
'🅄' => 'U',
'🅅' => 'V',
'🅆' => 'W',
'🅇' => 'X',
'🅈' => 'Y',
'🅉' => 'Z',
'🅊' => 'HV',
'🅋' => 'MV',
'🅌' => 'SD',
'🅍' => 'SS',
'🅎' => 'PPV',
'🅏' => 'WC',
'🅪' => 'MC',
'🅫' => 'MD',
'🅬' => 'MR',
'🆐' => 'DJ',
'🈀' => 'ほか',
'🈁' => 'ココ',
'🈂' => 'サ',
'🈐' => '手',
'🈑' => '字',
'🈒' => '双',
'🈓' => 'デ',
'🈔' => '二',
'🈕' => '多',
'🈖' => '解',
'🈗' => '天',
'🈘' => '交',
'🈙' => '映',
'🈚' => '無',
'🈛' => '料',
'🈜' => '前',
'🈝' => '後',
'🈞' => '再',
'🈟' => '新',
'🈠' => '初',
'🈡' => '終',
'🈢' => '生',
'🈣' => '販',
'🈤' => '声',
'🈥' => '吹',
'🈦' => '演',
'🈧' => '投',
'🈨' => '捕',
'🈩' => '一',
'🈪' => '三',
'🈫' => '遊',
'🈬' => '左',
'🈭' => '中',
'🈮' => '右',
'🈯' => '指',
'🈰' => '走',
'🈱' => '打',
'🈲' => '禁',
'🈳' => '空',
'🈴' => '合',
'🈵' => '満',
'🈶' => '有',
'🈷' => '月',
'🈸' => '申',
'🈹' => '割',
'🈺' => '営',
'🈻' => '配',
'🉀' => '〔本〕',
'🉁' => '〔三〕',
'🉂' => '〔二〕',
'🉃' => '〔安〕',
'🉄' => '〔点〕',
'🉅' => '〔打〕',
'🉆' => '〔盗〕',
'🉇' => '〔勝〕',
'🉈' => '〔敗〕',
'🉐' => '得',
'🉑' => '可',
'🯰' => '0',
'🯱' => '1',
'🯲' => '2',
'🯳' => '3',
'🯴' => '4',
'🯵' => '5',
'🯶' => '6',
'🯷' => '7',
'🯸' => '8',
'🯹' => '9',
);
<?php

return array (
'À' => 'À',
'Á' => 'Á',
'Â' => 'Â',
'Ã' => 'Ã',
'Ä' => 'Ä',
'Å' => 'Å',
'Ç' => 'Ç',
'È' => 'È',
'É' => 'É',
'Ê' => 'Ê',
'Ë' => 'Ë',
'Ì' => 'Ì',
'Í' => 'Í',
'Î' => 'Î',
'Ï' => 'Ï',
'Ñ' => 'Ñ',
'Ò' => 'Ò',
'Ó' => 'Ó',
'Ô' => 'Ô',
'Õ' => 'Õ',
'Ö' => 'Ö',
'Ù' => 'Ù',
'Ú' => 'Ú',
'Û' => 'Û',
'Ü' => 'Ü',
'Ý' => 'Ý',
'à' => 'à',
'á' => 'á',
'â' => 'â',
'ã' => 'ã',
'ä' => 'ä',
'å' => 'å',
'ç' => 'ç',
'è' => 'è',
'é' => 'é',
'ê' => 'ê',
'ë' => 'ë',
'ì' => 'ì',
'í' => 'í',
'î' => 'î',
'ï' => 'ï',
'ñ' => 'ñ',
'ò' => 'ò',
'ó' => 'ó',
'ô' => 'ô',
'õ' => 'õ',
'ö' => 'ö',
'ù' => 'ù',
'ú' => 'ú',
'û' => 'û',
'ü' => 'ü',
'ý' => 'ý',
'ÿ' => 'ÿ',
'Ā' => 'Ā',
'ā' => 'ā',
'Ă' => 'Ă',
'ă' => 'ă',
'Ą' => 'Ą',
'ą' => 'ą',
'Ć' => 'Ć',
'ć' => 'ć',
'Ĉ' => 'Ĉ',
'ĉ' => 'ĉ',
'Ċ' => 'Ċ',
'ċ' => 'ċ',
'Č' => 'Č',
'č' => 'č',
'Ď' => 'Ď',
'ď' => 'ď',
'Ē' => 'Ē',
'ē' => 'ē',
'Ĕ' => 'Ĕ',
'ĕ' => 'ĕ',
'Ė' => 'Ė',
'ė' => 'ė',
'Ę' => 'Ę',
'ę' => 'ę',
'Ě' => 'Ě',
'ě' => 'ě',
'Ĝ' => 'Ĝ',
'ĝ' => 'ĝ',
'Ğ' => 'Ğ',
'ğ' => 'ğ',
'Ġ' => 'Ġ',
'ġ' => 'ġ',
'Ģ' => 'Ģ',
'ģ' => 'ģ',
'Ĥ' => 'Ĥ',
'ĥ' => 'ĥ',
'Ĩ' => 'Ĩ',
'ĩ' => 'ĩ',
'Ī' => 'Ī',
'ī' => 'ī',
'Ĭ' => 'Ĭ',
'ĭ' => 'ĭ',
'Į' => 'Į',
'į' => 'į',
'İ' => 'İ',
'Ĵ' => 'Ĵ',
'ĵ' => 'ĵ',
'Ķ' => 'Ķ',
'ķ' => 'ķ',
'Ĺ' => 'Ĺ',
'ĺ' => 'ĺ',
'Ļ' => 'Ļ',
'ļ' => 'ļ',
'Ľ' => 'Ľ',
'ľ' => 'ľ',
'Ń' => 'Ń',
'ń' => 'ń',
'Ņ' => 'Ņ',
'ņ' => 'ņ',
'Ň' => 'Ň',
'ň' => 'ň',
'Ō' => 'Ō',
'ō' => 'ō',
'Ŏ' => 'Ŏ',
'ŏ' => 'ŏ',
'Ő' => 'Ő',
'ő' => 'ő',
'Ŕ' => 'Ŕ',
'ŕ' => 'ŕ',
'Ŗ' => 'Ŗ',
'ŗ' => 'ŗ',
'Ř' => 'Ř',
'ř' => 'ř',
'Ś' => 'Ś',
'ś' => 'ś',
'Ŝ' => 'Ŝ',
'ŝ' => 'ŝ',
'Ş' => 'Ş',
'ş' => 'ş',
'Š' => 'Š',
'š' => 'š',
'Ţ' => 'Ţ',
'ţ' => 'ţ',
'Ť' => 'Ť',
'ť' => 'ť',
'Ũ' => 'Ũ',
'ũ' => 'ũ',
'Ū' => 'Ū',
'ū' => 'ū',
'Ŭ' => 'Ŭ',
'ŭ' => 'ŭ',
'Ů' => 'Ů',
'ů' => 'ů',
'Ű' => 'Ű',
'ű' => 'ű',
'Ų' => 'Ų',
'ų' => 'ų',
'Ŵ' => 'Ŵ',
'ŵ' => 'ŵ',
'Ŷ' => 'Ŷ',
'ŷ' => 'ŷ',
'Ÿ' => 'Ÿ',
'Ź' => 'Ź',
'ź' => 'ź',
'Ż' => 'Ż',
'ż' => 'ż',
'Ž' => 'Ž',
'ž' => 'ž',
'Ơ' => 'Ơ',
'ơ' => 'ơ',
'Ư' => 'Ư',
'ư' => 'ư',
'Ǎ' => 'Ǎ',
'ǎ' => 'ǎ',
'Ǐ' => 'Ǐ',
'ǐ' => 'ǐ',
'Ǒ' => 'Ǒ',
'ǒ' => 'ǒ',
'Ǔ' => 'Ǔ',
'ǔ' => 'ǔ',
'Ǖ' => 'Ǖ',
'ǖ' => 'ǖ',
'Ǘ' => 'Ǘ',
'ǘ' => 'ǘ',
'Ǚ' => 'Ǚ',
'ǚ' => 'ǚ',
'Ǜ' => 'Ǜ',
'ǜ' => 'ǜ',
'Ǟ' => 'Ǟ',
'ǟ' => 'ǟ',
'Ǡ' => 'Ǡ',
'ǡ' => 'ǡ',
'Ǣ' => 'Ǣ',
'ǣ' => 'ǣ',
'Ǧ' => 'Ǧ',
'ǧ' => 'ǧ',
'Ǩ' => 'Ǩ',
'ǩ' => 'ǩ',
'Ǫ' => 'Ǫ',
'ǫ' => 'ǫ',
'Ǭ' => 'Ǭ',
'ǭ' => 'ǭ',
'Ǯ' => 'Ǯ',
'ǯ' => 'ǯ',
'ǰ' => 'ǰ',
'Ǵ' => 'Ǵ',
'ǵ' => 'ǵ',
'Ǹ' => 'Ǹ',
'ǹ' => 'ǹ',
'Ǻ' => 'Ǻ',
'ǻ' => 'ǻ',
'Ǽ' => 'Ǽ',
'ǽ' => 'ǽ',
'Ǿ' => 'Ǿ',
'ǿ' => 'ǿ',
'Ȁ' => 'Ȁ',
'ȁ' => 'ȁ',
'Ȃ' => 'Ȃ',
'ȃ' => 'ȃ',
'Ȅ' => 'Ȅ',
'ȅ' => 'ȅ',
'Ȇ' => 'Ȇ',
'ȇ' => 'ȇ',
'Ȉ' => 'Ȉ',
'ȉ' => 'ȉ',
'Ȋ' => 'Ȋ',
'ȋ' => 'ȋ',
'Ȍ' => 'Ȍ',
'ȍ' => 'ȍ',
'Ȏ' => 'Ȏ',
'ȏ' => 'ȏ',
'Ȑ' => 'Ȑ',
'ȑ' => 'ȑ',
'Ȓ' => 'Ȓ',
'ȓ' => 'ȓ',
'Ȕ' => 'Ȕ',
'ȕ' => 'ȕ',
'Ȗ' => 'Ȗ',
'ȗ' => 'ȗ',
'Ș' => 'Ș',
'ș' => 'ș',
'Ț' => 'Ț',
'ț' => 'ț',
'Ȟ' => 'Ȟ',
'ȟ' => 'ȟ',
'Ȧ' => 'Ȧ',
'ȧ' => 'ȧ',
'Ȩ' => 'Ȩ',
'ȩ' => 'ȩ',
'Ȫ' => 'Ȫ',
'ȫ' => 'ȫ',
'Ȭ' => 'Ȭ',
'ȭ' => 'ȭ',
'Ȯ' => 'Ȯ',
'ȯ' => 'ȯ',
'Ȱ' => 'Ȱ',
'ȱ' => 'ȱ',
'Ȳ' => 'Ȳ',
'ȳ' => 'ȳ',
'΅' => '΅',
'Ά' => 'Ά',
'Έ' => 'Έ',
'Ή' => 'Ή',
'Ί' => 'Ί',
'Ό' => 'Ό',
'Ύ' => 'Ύ',
'Ώ' => 'Ώ',
'ΐ' => 'ΐ',
'Ϊ' => 'Ϊ',
'Ϋ' => 'Ϋ',
'ά' => 'ά',
'έ' => 'έ',
'ή' => 'ή',
'ί' => 'ί',
'ΰ' => 'ΰ',
'ϊ' => 'ϊ',
'ϋ' => 'ϋ',
'ό' => 'ό',
'ύ' => 'ύ',
'ώ' => 'ώ',
'ϓ' => 'ϓ',
'ϔ' => 'ϔ',
'Ѐ' => 'Ѐ',
'Ё' => 'Ё',
'Ѓ' => 'Ѓ',
'Ї' => 'Ї',
'Ќ' => 'Ќ',
'Ѝ' => 'Ѝ',
'Ў' => 'Ў',
'Й' => 'Й',
'й' => 'й',
'ѐ' => 'ѐ',
'ё' => 'ё',
'ѓ' => 'ѓ',
'ї' => 'ї',
'ќ' => 'ќ',
'ѝ' => 'ѝ',
'ў' => 'ў',
'Ѷ' => 'Ѷ',
'ѷ' => 'ѷ',
'Ӂ' => 'Ӂ',
'ӂ' => 'ӂ',
'Ӑ' => 'Ӑ',
'ӑ' => 'ӑ',
'Ӓ' => 'Ӓ',
'ӓ' => 'ӓ',
'Ӗ' => 'Ӗ',
'ӗ' => 'ӗ',
'Ӛ' => 'Ӛ',
'ӛ' => 'ӛ',
'Ӝ' => 'Ӝ',
'ӝ' => 'ӝ',
'Ӟ' => 'Ӟ',
'ӟ' => 'ӟ',
'Ӣ' => 'Ӣ',
'ӣ' => 'ӣ',
'Ӥ' => 'Ӥ',
'ӥ' => 'ӥ',
'Ӧ' => 'Ӧ',
'ӧ' => 'ӧ',
'Ӫ' => 'Ӫ',
'ӫ' => 'ӫ',
'Ӭ' => 'Ӭ',
'ӭ' => 'ӭ',
'Ӯ' => 'Ӯ',
'ӯ' => 'ӯ',
'Ӱ' => 'Ӱ',
'ӱ' => 'ӱ',
'Ӳ' => 'Ӳ',
'ӳ' => 'ӳ',
'Ӵ' => 'Ӵ',
'ӵ' => 'ӵ',
'Ӹ' => 'Ӹ',
'ӹ' => 'ӹ',
'آ' => 'آ',
'أ' => 'أ',
'ؤ' => 'ؤ',
'إ' => 'إ',
'ئ' => 'ئ',
'ۀ' => 'ۀ',
'ۂ' => 'ۂ',
'ۓ' => 'ۓ',
'ऩ' => 'ऩ',
'ऱ' => 'ऱ',
'ऴ' => 'ऴ',
'ো' => 'ো',
'ৌ' => 'ৌ',
'ୈ' => 'ୈ',
'ୋ' => 'ୋ',
'ୌ' => 'ୌ',
'ஔ' => 'ஔ',
'ொ' => 'ொ',
'ோ' => 'ோ',
'ௌ' => 'ௌ',
'ై' => 'ై',
'ೀ' => 'ೀ',
'ೇ' => 'ೇ',
'ೈ' => 'ೈ',
'ೊ' => 'ೊ',
'ೋ' => 'ೋ',
'ൊ' => 'ൊ',
'ോ' => 'ോ',
'ൌ' => 'ൌ',
'ේ' => 'ේ',
'ො' => 'ො',
'ෝ' => 'ෝ',
'ෞ' => 'ෞ',
'ဦ' => 'ဦ',
'ᬆ' => 'ᬆ',
'ᬈ' => 'ᬈ',
'ᬊ' => 'ᬊ',
'ᬌ' => 'ᬌ',
'ᬎ' => 'ᬎ',
'ᬒ' => 'ᬒ',
'ᬻ' => 'ᬻ',
'ᬽ' => 'ᬽ',
'ᭀ' => 'ᭀ',
'ᭁ' => 'ᭁ',
'ᭃ' => 'ᭃ',
'Ḁ' => 'Ḁ',
'ḁ' => 'ḁ',
'Ḃ' => 'Ḃ',
'ḃ' => 'ḃ',
'Ḅ' => 'Ḅ',
'ḅ' => 'ḅ',
'Ḇ' => 'Ḇ',
'ḇ' => 'ḇ',
'Ḉ' => 'Ḉ',
'ḉ' => 'ḉ',
'Ḋ' => 'Ḋ',
'ḋ' => 'ḋ',
'Ḍ' => 'Ḍ',
'ḍ' => 'ḍ',
'Ḏ' => 'Ḏ',
'ḏ' => 'ḏ',
'Ḑ' => 'Ḑ',
'ḑ' => 'ḑ',
'Ḓ' => 'Ḓ',
'ḓ' => 'ḓ',
'Ḕ' => 'Ḕ',
'ḕ' => 'ḕ',
'Ḗ' => 'Ḗ',
'ḗ' => 'ḗ',
'Ḙ' => 'Ḙ',
'ḙ' => 'ḙ',
'Ḛ' => 'Ḛ',
'ḛ' => 'ḛ',
'Ḝ' => 'Ḝ',
'ḝ' => 'ḝ',
'Ḟ' => 'Ḟ',
'ḟ' => 'ḟ',
'Ḡ' => 'Ḡ',
'ḡ' => 'ḡ',
'Ḣ' => 'Ḣ',
'ḣ' => 'ḣ',
'Ḥ' => 'Ḥ',
'ḥ' => 'ḥ',
'Ḧ' => 'Ḧ',
'ḧ' => 'ḧ',
'Ḩ' => 'Ḩ',
'ḩ' => 'ḩ',
'Ḫ' => 'Ḫ',
'ḫ' => 'ḫ',
'Ḭ' => 'Ḭ',
'ḭ' => 'ḭ',
'Ḯ' => 'Ḯ',
'ḯ' => 'ḯ',
'Ḱ' => 'Ḱ',
'ḱ' => 'ḱ',
'Ḳ' => 'Ḳ',
'ḳ' => 'ḳ',
'Ḵ' => 'Ḵ',
'ḵ' => 'ḵ',
'Ḷ' => 'Ḷ',
'ḷ' => 'ḷ',
'Ḹ' => 'Ḹ',
'ḹ' => 'ḹ',
'Ḻ' => 'Ḻ',
'ḻ' => 'ḻ',
'Ḽ' => 'Ḽ',
'ḽ' => 'ḽ',
'Ḿ' => 'Ḿ',
'ḿ' => 'ḿ',
'Ṁ' => 'Ṁ',
'ṁ' => 'ṁ',
'Ṃ' => 'Ṃ',
'ṃ' => 'ṃ',
'Ṅ' => 'Ṅ',
'ṅ' => 'ṅ',
'Ṇ' => 'Ṇ',
'ṇ' => 'ṇ',
'Ṉ' => 'Ṉ',
'ṉ' => 'ṉ',
'Ṋ' => 'Ṋ',
'ṋ' => 'ṋ',
'Ṍ' => 'Ṍ',
'ṍ' => 'ṍ',
'Ṏ' => 'Ṏ',
'ṏ' => 'ṏ',
'Ṑ' => 'Ṑ',
'ṑ' => 'ṑ',
'Ṓ' => 'Ṓ',
'ṓ' => 'ṓ',
'Ṕ' => 'Ṕ',
'ṕ' => 'ṕ',
'Ṗ' => 'Ṗ',
'ṗ' => 'ṗ',
'Ṙ' => 'Ṙ',
'ṙ' => 'ṙ',
'Ṛ' => 'Ṛ',
'ṛ' => 'ṛ',
'Ṝ' => 'Ṝ',
'ṝ' => 'ṝ',
'Ṟ' => 'Ṟ',
'ṟ' => 'ṟ',
'Ṡ' => 'Ṡ',
'ṡ' => 'ṡ',
'Ṣ' => 'Ṣ',
'ṣ' => 'ṣ',
'Ṥ' => 'Ṥ',
'ṥ' => 'ṥ',
'Ṧ' => 'Ṧ',
'ṧ' => 'ṧ',
'Ṩ' => 'Ṩ',
'ṩ' => 'ṩ',
'Ṫ' => 'Ṫ',
'ṫ' => 'ṫ',
'Ṭ' => 'Ṭ',
'ṭ' => 'ṭ',
'Ṯ' => 'Ṯ',
'ṯ' => 'ṯ',
'Ṱ' => 'Ṱ',
'ṱ' => 'ṱ',
'Ṳ' => 'Ṳ',
'ṳ' => 'ṳ',
'Ṵ' => 'Ṵ',
'ṵ' => 'ṵ',
'Ṷ' => 'Ṷ',
'ṷ' => 'ṷ',
'Ṹ' => 'Ṹ',
'ṹ' => 'ṹ',
'Ṻ' => 'Ṻ',
'ṻ' => 'ṻ',
'Ṽ' => 'Ṽ',
'ṽ' => 'ṽ',
'Ṿ' => 'Ṿ',
'ṿ' => 'ṿ',
'Ẁ' => 'Ẁ',
'ẁ' => 'ẁ',
'Ẃ' => 'Ẃ',
'ẃ' => 'ẃ',
'Ẅ' => 'Ẅ',
'ẅ' => 'ẅ',
'Ẇ' => 'Ẇ',
'ẇ' => 'ẇ',
'Ẉ' => 'Ẉ',
'ẉ' => 'ẉ',
'Ẋ' => 'Ẋ',
'ẋ' => 'ẋ',
'Ẍ' => 'Ẍ',
'ẍ' => 'ẍ',
'Ẏ' => 'Ẏ',
'ẏ' => 'ẏ',
'Ẑ' => 'Ẑ',
'ẑ' => 'ẑ',
'Ẓ' => 'Ẓ',
'ẓ' => 'ẓ',
'Ẕ' => 'Ẕ',
'ẕ' => 'ẕ',
'ẖ' => 'ẖ',
'ẗ' => 'ẗ',
'ẘ' => 'ẘ',
'ẙ' => 'ẙ',
'ẛ' => 'ẛ',
'Ạ' => 'Ạ',
'ạ' => 'ạ',
'Ả' => 'Ả',
'ả' => 'ả',
'Ấ' => 'Ấ',
'ấ' => 'ấ',
'Ầ' => 'Ầ',
'ầ' => 'ầ',
'Ẩ' => 'Ẩ',
'ẩ' => 'ẩ',
'Ẫ' => 'Ẫ',
'ẫ' => 'ẫ',
'Ậ' => 'Ậ',
'ậ' => 'ậ',
'Ắ' => 'Ắ',
'ắ' => 'ắ',
'Ằ' => 'Ằ',
'ằ' => 'ằ',
'Ẳ' => 'Ẳ',
'ẳ' => 'ẳ',
'Ẵ' => 'Ẵ',
'ẵ' => 'ẵ',
'Ặ' => 'Ặ',
'ặ' => 'ặ',
'Ẹ' => 'Ẹ',
'ẹ' => 'ẹ',
'Ẻ' => 'Ẻ',
'ẻ' => 'ẻ',
'Ẽ' => 'Ẽ',
'ẽ' => 'ẽ',
'Ế' => 'Ế',
'ế' => 'ế',
'Ề' => 'Ề',
'ề' => 'ề',
'Ể' => 'Ể',
'ể' => 'ể',
'Ễ' => 'Ễ',
'ễ' => 'ễ',
'Ệ' => 'Ệ',
'ệ' => 'ệ',
'Ỉ' => 'Ỉ',
'ỉ' => 'ỉ',
'Ị' => 'Ị',
'ị' => 'ị',
'Ọ' => 'Ọ',
'ọ' => 'ọ',
'Ỏ' => 'Ỏ',
'ỏ' => 'ỏ',
'Ố' => 'Ố',
'ố' => 'ố',
'Ồ' => 'Ồ',
'ồ' => 'ồ',
'Ổ' => 'Ổ',
'ổ' => 'ổ',
'Ỗ' => 'Ỗ',
'ỗ' => 'ỗ',
'Ộ' => 'Ộ',
'ộ' => 'ộ',
'Ớ' => 'Ớ',
'ớ' => 'ớ',
'Ờ' => 'Ờ',
'ờ' => 'ờ',
'Ở' => 'Ở',
'ở' => 'ở',
'Ỡ' => 'Ỡ',
'ỡ' => 'ỡ',
'Ợ' => 'Ợ',
'ợ' => 'ợ',
'Ụ' => 'Ụ',
'ụ' => 'ụ',
'Ủ' => 'Ủ',
'ủ' => 'ủ',
'Ứ' => 'Ứ',
'ứ' => 'ứ',
'Ừ' => 'Ừ',
'ừ' => 'ừ',
'Ử' => 'Ử',
'ử' => 'ử',
'Ữ' => 'Ữ',
'ữ' => 'ữ',
'Ự' => 'Ự',
'ự' => 'ự',
'Ỳ' => 'Ỳ',
'ỳ' => 'ỳ',
'Ỵ' => 'Ỵ',
'ỵ' => 'ỵ',
'Ỷ' => 'Ỷ',
'ỷ' => 'ỷ',
'Ỹ' => 'Ỹ',
'ỹ' => 'ỹ',
'ἀ' => 'ἀ',
'ἁ' => 'ἁ',
'ἂ' => 'ἂ',
'ἃ' => 'ἃ',
'ἄ' => 'ἄ',
'ἅ' => 'ἅ',
'ἆ' => 'ἆ',
'ἇ' => 'ἇ',
'Ἀ' => 'Ἀ',
'Ἁ' => 'Ἁ',
'Ἂ' => 'Ἂ',
'Ἃ' => 'Ἃ',
'Ἄ' => 'Ἄ',
'Ἅ' => 'Ἅ',
'Ἆ' => 'Ἆ',
'Ἇ' => 'Ἇ',
'ἐ' => 'ἐ',
'ἑ' => 'ἑ',
'ἒ' => 'ἒ',
'ἓ' => 'ἓ',
'ἔ' => 'ἔ',
'ἕ' => 'ἕ',
'Ἐ' => 'Ἐ',
'Ἑ' => 'Ἑ',
'Ἒ' => 'Ἒ',
'Ἓ' => 'Ἓ',
'Ἔ' => 'Ἔ',
'Ἕ' => 'Ἕ',
'ἠ' => 'ἠ',
'ἡ' => 'ἡ',
'ἢ' => 'ἢ',
'ἣ' => 'ἣ',
'ἤ' => 'ἤ',
'ἥ' => 'ἥ',
'ἦ' => 'ἦ',
'ἧ' => 'ἧ',
'Ἠ' => 'Ἠ',
'Ἡ' => 'Ἡ',
'Ἢ' => 'Ἢ',
'Ἣ' => 'Ἣ',
'Ἤ' => 'Ἤ',
'Ἥ' => 'Ἥ',
'Ἦ' => 'Ἦ',
'Ἧ' => 'Ἧ',
'ἰ' => 'ἰ',
'ἱ' => 'ἱ',
'ἲ' => 'ἲ',
'ἳ' => 'ἳ',
'ἴ' => 'ἴ',
'ἵ' => 'ἵ',
'ἶ' => 'ἶ',
'ἷ' => 'ἷ',
'Ἰ' => 'Ἰ',
'Ἱ' => 'Ἱ',
'Ἲ' => 'Ἲ',
'Ἳ' => 'Ἳ',
'Ἴ' => 'Ἴ',
'Ἵ' => 'Ἵ',
'Ἶ' => 'Ἶ',
'Ἷ' => 'Ἷ',
'ὀ' => 'ὀ',
'ὁ' => 'ὁ',
'ὂ' => 'ὂ',
'ὃ' => 'ὃ',
'ὄ' => 'ὄ',
'ὅ' => 'ὅ',
'Ὀ' => 'Ὀ',
'Ὁ' => 'Ὁ',
'Ὂ' => 'Ὂ',
'Ὃ' => 'Ὃ',
'Ὄ' => 'Ὄ',
'Ὅ' => 'Ὅ',
'ὐ' => 'ὐ',
'ὑ' => 'ὑ',
'ὒ' => 'ὒ',
'ὓ' => 'ὓ',
'ὔ' => 'ὔ',
'ὕ' => 'ὕ',
'ὖ' => 'ὖ',
'ὗ' => 'ὗ',
'Ὑ' => 'Ὑ',
'Ὓ' => 'Ὓ',
'Ὕ' => 'Ὕ',
'Ὗ' => 'Ὗ',
'ὠ' => 'ὠ',
'ὡ' => 'ὡ',
'ὢ' => 'ὢ',
'ὣ' => 'ὣ',
'ὤ' => 'ὤ',
'ὥ' => 'ὥ',
'ὦ' => 'ὦ',
'ὧ' => 'ὧ',
'Ὠ' => 'Ὠ',
'Ὡ' => 'Ὡ',
'Ὢ' => 'Ὢ',
'Ὣ' => 'Ὣ',
'Ὤ' => 'Ὤ',
'Ὥ' => 'Ὥ',
'Ὦ' => 'Ὦ',
'Ὧ' => 'Ὧ',
'ὰ' => 'ὰ',
'ὲ' => 'ὲ',
'ὴ' => 'ὴ',
'ὶ' => 'ὶ',
'ὸ' => 'ὸ',
'ὺ' => 'ὺ',
'ὼ' => 'ὼ',
'ᾀ' => 'ᾀ',
'ᾁ' => 'ᾁ',
'ᾂ' => 'ᾂ',
'ᾃ' => 'ᾃ',
'ᾄ' => 'ᾄ',
'ᾅ' => 'ᾅ',
'ᾆ' => 'ᾆ',
'ᾇ' => 'ᾇ',
'ᾈ' => 'ᾈ',
'ᾉ' => 'ᾉ',
'ᾊ' => 'ᾊ',
'ᾋ' => 'ᾋ',
'ᾌ' => 'ᾌ',
'ᾍ' => 'ᾍ',
'ᾎ' => 'ᾎ',
'ᾏ' => 'ᾏ',
'ᾐ' => 'ᾐ',
'ᾑ' => 'ᾑ',
'ᾒ' => 'ᾒ',
'ᾓ' => 'ᾓ',
'ᾔ' => 'ᾔ',
'ᾕ' => 'ᾕ',
'ᾖ' => 'ᾖ',
'ᾗ' => 'ᾗ',
'ᾘ' => 'ᾘ',
'ᾙ' => 'ᾙ',
'ᾚ' => 'ᾚ',
'ᾛ' => 'ᾛ',
'ᾜ' => 'ᾜ',
'ᾝ' => 'ᾝ',
'ᾞ' => 'ᾞ',
'ᾟ' => 'ᾟ',
'ᾠ' => 'ᾠ',
'ᾡ' => 'ᾡ',
'ᾢ' => 'ᾢ',
'ᾣ' => 'ᾣ',
'ᾤ' => 'ᾤ',
'ᾥ' => 'ᾥ',
'ᾦ' => 'ᾦ',
'ᾧ' => 'ᾧ',
'ᾨ' => 'ᾨ',
'ᾩ' => 'ᾩ',
'ᾪ' => 'ᾪ',
'ᾫ' => 'ᾫ',
'ᾬ' => 'ᾬ',
'ᾭ' => 'ᾭ',
'ᾮ' => 'ᾮ',
'ᾯ' => 'ᾯ',
'ᾰ' => 'ᾰ',
'ᾱ' => 'ᾱ',
'ᾲ' => 'ᾲ',
'ᾳ' => 'ᾳ',
'ᾴ' => 'ᾴ',
'ᾶ' => 'ᾶ',
'ᾷ' => 'ᾷ',
'Ᾰ' => 'Ᾰ',
'Ᾱ' => 'Ᾱ',
'Ὰ' => 'Ὰ',
'ᾼ' => 'ᾼ',
'῁' => '῁',
'ῂ' => 'ῂ',
'ῃ' => 'ῃ',
'ῄ' => 'ῄ',
'ῆ' => 'ῆ',
'ῇ' => 'ῇ',
'Ὲ' => 'Ὲ',
'Ὴ' => 'Ὴ',
'ῌ' => 'ῌ',
'῍' => '῍',
'῎' => '῎',
'῏' => '῏',
'ῐ' => 'ῐ',
'ῑ' => 'ῑ',
'ῒ' => 'ῒ',
'ῖ' => 'ῖ',
'ῗ' => 'ῗ',
'Ῐ' => 'Ῐ',
'Ῑ' => 'Ῑ',
'Ὶ' => 'Ὶ',
'῝' => '῝',
'῞' => '῞',
'῟' => '῟',
'ῠ' => 'ῠ',
'ῡ' => 'ῡ',
'ῢ' => 'ῢ',
'ῤ' => 'ῤ',
'ῥ' => 'ῥ',
'ῦ' => 'ῦ',
'ῧ' => 'ῧ',
'Ῠ' => 'Ῠ',
'Ῡ' => 'Ῡ',
'Ὺ' => 'Ὺ',
'Ῥ' => 'Ῥ',
'῭' => '῭',
'ῲ' => 'ῲ',
'ῳ' => 'ῳ',
'ῴ' => 'ῴ',
'ῶ' => 'ῶ',
'ῷ' => 'ῷ',
'Ὸ' => 'Ὸ',
'Ὼ' => 'Ὼ',
'ῼ' => 'ῼ',
'↚' => '↚',
'↛' => '↛',
'↮' => '↮',
'⇍' => '⇍',
'⇎' => '⇎',
'⇏' => '⇏',
'∄' => '∄',
'∉' => '∉',
'∌' => '∌',
'∤' => '∤',
'∦' => '∦',
'≁' => '≁',
'≄' => '≄',
'≇' => '≇',
'≉' => '≉',
'≠' => '≠',
'≢' => '≢',
'≭' => '≭',
'≮' => '≮',
'≯' => '≯',
'≰' => '≰',
'≱' => '≱',
'≴' => '≴',
'≵' => '≵',
'≸' => '≸',
'≹' => '≹',
'⊀' => '⊀',
'⊁' => '⊁',
'⊄' => '⊄',
'⊅' => '⊅',
'⊈' => '⊈',
'⊉' => '⊉',
'⊬' => '⊬',
'⊭' => '⊭',
'⊮' => '⊮',
'⊯' => '⊯',
'⋠' => '⋠',
'⋡' => '⋡',
'⋢' => '⋢',
'⋣' => '⋣',
'⋪' => '⋪',
'⋫' => '⋫',
'⋬' => '⋬',
'⋭' => '⋭',
'が' => 'が',
'ぎ' => 'ぎ',
'ぐ' => 'ぐ',
'げ' => 'げ',
'ご' => 'ご',
'ざ' => 'ざ',
'じ' => 'じ',
'ず' => 'ず',
'ぜ' => 'ぜ',
'ぞ' => 'ぞ',
'だ' => 'だ',
'ぢ' => 'ぢ',
'づ' => 'づ',
'で' => 'で',
'ど' => 'ど',
'ば' => 'ば',
'ぱ' => 'ぱ',
'び' => 'び',
'ぴ' => 'ぴ',
'ぶ' => 'ぶ',
'ぷ' => 'ぷ',
'べ' => 'べ',
'ぺ' => 'ぺ',
'ぼ' => 'ぼ',
'ぽ' => 'ぽ',
'ゔ' => 'ゔ',
'ゞ' => 'ゞ',
'ガ' => 'ガ',
'ギ' => 'ギ',
'グ' => 'グ',
'ゲ' => 'ゲ',
'ゴ' => 'ゴ',
'ザ' => 'ザ',
'ジ' => 'ジ',
'ズ' => 'ズ',
'ゼ' => 'ゼ',
'ゾ' => 'ゾ',
'ダ' => 'ダ',
'ヂ' => 'ヂ',
'ヅ' => 'ヅ',
'デ' => 'デ',
'ド' => 'ド',
'バ' => 'バ',
'パ' => 'パ',
'ビ' => 'ビ',
'ピ' => 'ピ',
'ブ' => 'ブ',
'プ' => 'プ',
'ベ' => 'ベ',
'ペ' => 'ペ',
'ボ' => 'ボ',
'ポ' => 'ポ',
'ヴ' => 'ヴ',
'ヷ' => 'ヷ',
'ヸ' => 'ヸ',
'ヹ' => 'ヹ',
'ヺ' => 'ヺ',
'ヾ' => 'ヾ',
'𑂚' => '𑂚',
'𑂜' => '𑂜',
'𑂫' => '𑂫',
'𑄮' => '𑄮',
'𑄯' => '𑄯',
'𑍋' => '𑍋',
'𑍌' => '𑍌',
'𑒻' => '𑒻',
'𑒼' => '𑒼',
'𑒾' => '𑒾',
'𑖺' => '𑖺',
'𑖻' => '𑖻',
'𑤸' => '𑤸',
);
<?php

return array (
'À' => 'À',
'Á' => 'Á',
'Â' => 'Â',
'Ã' => 'Ã',
'Ä' => 'Ä',
'Å' => 'Å',
'Ç' => 'Ç',
'È' => 'È',
'É' => 'É',
'Ê' => 'Ê',
'Ë' => 'Ë',
'Ì' => 'Ì',
'Í' => 'Í',
'Î' => 'Î',
'Ï' => 'Ï',
'Ñ' => 'Ñ',
'Ò' => 'Ò',
'Ó' => 'Ó',
'Ô' => 'Ô',
'Õ' => 'Õ',
'Ö' => 'Ö',
'Ù' => 'Ù',
'Ú' => 'Ú',
'Û' => 'Û',
'Ü' => 'Ü',
'Ý' => 'Ý',
'à' => 'à',
'á' => 'á',
'â' => 'â',
'ã' => 'ã',
'ä' => 'ä',
'å' => 'å',
'ç' => 'ç',
'è' => 'è',
'é' => 'é',
'ê' => 'ê',
'ë' => 'ë',
'ì' => 'ì',
'í' => 'í',
'î' => 'î',
'ï' => 'ï',
'ñ' => 'ñ',
'ò' => 'ò',
'ó' => 'ó',
'ô' => 'ô',
'õ' => 'õ',
'ö' => 'ö',
'ù' => 'ù',
'ú' => 'ú',
'û' => 'û',
'ü' => 'ü',
'ý' => 'ý',
'ÿ' => 'ÿ',
'Ā' => 'Ā',
'ā' => 'ā',
'Ă' => 'Ă',
'ă' => 'ă',
'Ą' => 'Ą',
'ą' => 'ą',
'Ć' => 'Ć',
'ć' => 'ć',
'Ĉ' => 'Ĉ',
'ĉ' => 'ĉ',
'Ċ' => 'Ċ',
'ċ' => 'ċ',
'Č' => 'Č',
'č' => 'č',
'Ď' => 'Ď',
'ď' => 'ď',
'Ē' => 'Ē',
'ē' => 'ē',
'Ĕ' => 'Ĕ',
'ĕ' => 'ĕ',
'Ė' => 'Ė',
'ė' => 'ė',
'Ę' => 'Ę',
'ę' => 'ę',
'Ě' => 'Ě',
'ě' => 'ě',
'Ĝ' => 'Ĝ',
'ĝ' => 'ĝ',
'Ğ' => 'Ğ',
'ğ' => 'ğ',
'Ġ' => 'Ġ',
'ġ' => 'ġ',
'Ģ' => 'Ģ',
'ģ' => 'ģ',
'Ĥ' => 'Ĥ',
'ĥ' => 'ĥ',
'Ĩ' => 'Ĩ',
'ĩ' => 'ĩ',
'Ī' => 'Ī',
'ī' => 'ī',
'Ĭ' => 'Ĭ',
'ĭ' => 'ĭ',
'Į' => 'Į',
'į' => 'į',
'İ' => 'İ',
'Ĵ' => 'Ĵ',
'ĵ' => 'ĵ',
'Ķ' => 'Ķ',
'ķ' => 'ķ',
'Ĺ' => 'Ĺ',
'ĺ' => 'ĺ',
'Ļ' => 'Ļ',
'ļ' => 'ļ',
'Ľ' => 'Ľ',
'ľ' => 'ľ',
'Ń' => 'Ń',
'ń' => 'ń',
'Ņ' => 'Ņ',
'ņ' => 'ņ',
'Ň' => 'Ň',
'ň' => 'ň',
'Ō' => 'Ō',
'ō' => 'ō',
'Ŏ' => 'Ŏ',
'ŏ' => 'ŏ',
'Ő' => 'Ő',
'ő' => 'ő',
'Ŕ' => 'Ŕ',
'ŕ' => 'ŕ',
'Ŗ' => 'Ŗ',
'ŗ' => 'ŗ',
'Ř' => 'Ř',
'ř' => 'ř',
'Ś' => 'Ś',
'ś' => 'ś',
'Ŝ' => 'Ŝ',
'ŝ' => 'ŝ',
'Ş' => 'Ş',
'ş' => 'ş',
'Š' => 'Š',
'š' => 'š',
'Ţ' => 'Ţ',
'ţ' => 'ţ',
'Ť' => 'Ť',
'ť' => 'ť',
'Ũ' => 'Ũ',
'ũ' => 'ũ',
'Ū' => 'Ū',
'ū' => 'ū',
'Ŭ' => 'Ŭ',
'ŭ' => 'ŭ',
'Ů' => 'Ů',
'ů' => 'ů',
'Ű' => 'Ű',
'ű' => 'ű',
'Ų' => 'Ų',
'ų' => 'ų',
'Ŵ' => 'Ŵ',
'ŵ' => 'ŵ',
'Ŷ' => 'Ŷ',
'ŷ' => 'ŷ',
'Ÿ' => 'Ÿ',
'Ź' => 'Ź',
'ź' => 'ź',
'Ż' => 'Ż',
'ż' => 'ż',
'Ž' => 'Ž',
'ž' => 'ž',
'Ơ' => 'Ơ',
'ơ' => 'ơ',
'Ư' => 'Ư',
'ư' => 'ư',
'Ǎ' => 'Ǎ',
'ǎ' => 'ǎ',
'Ǐ' => 'Ǐ',
'ǐ' => 'ǐ',
'Ǒ' => 'Ǒ',
'ǒ' => 'ǒ',
'Ǔ' => 'Ǔ',
'ǔ' => 'ǔ',
'Ǖ' => 'Ǖ',
'ǖ' => 'ǖ',
'Ǘ' => 'Ǘ',
'ǘ' => 'ǘ',
'Ǚ' => 'Ǚ',
'ǚ' => 'ǚ',
'Ǜ' => 'Ǜ',
'ǜ' => 'ǜ',
'Ǟ' => 'Ǟ',
'ǟ' => 'ǟ',
'Ǡ' => 'Ǡ',
'ǡ' => 'ǡ',
'Ǣ' => 'Ǣ',
'ǣ' => 'ǣ',
'Ǧ' => 'Ǧ',
'ǧ' => 'ǧ',
'Ǩ' => 'Ǩ',
'ǩ' => 'ǩ',
'Ǫ' => 'Ǫ',
'ǫ' => 'ǫ',
'Ǭ' => 'Ǭ',
'ǭ' => 'ǭ',
'Ǯ' => 'Ǯ',
'ǯ' => 'ǯ',
'ǰ' => 'ǰ',
'Ǵ' => 'Ǵ',
'ǵ' => 'ǵ',
'Ǹ' => 'Ǹ',
'ǹ' => 'ǹ',
'Ǻ' => 'Ǻ',
'ǻ' => 'ǻ',
'Ǽ' => 'Ǽ',
'ǽ' => 'ǽ',
'Ǿ' => 'Ǿ',
'ǿ' => 'ǿ',
'Ȁ' => 'Ȁ',
'ȁ' => 'ȁ',
'Ȃ' => 'Ȃ',
'ȃ' => 'ȃ',
'Ȅ' => 'Ȅ',
'ȅ' => 'ȅ',
'Ȇ' => 'Ȇ',
'ȇ' => 'ȇ',
'Ȉ' => 'Ȉ',
'ȉ' => 'ȉ',
'Ȋ' => 'Ȋ',
'ȋ' => 'ȋ',
'Ȍ' => 'Ȍ',
'ȍ' => 'ȍ',
'Ȏ' => 'Ȏ',
'ȏ' => 'ȏ',
'Ȑ' => 'Ȑ',
'ȑ' => 'ȑ',
'Ȓ' => 'Ȓ',
'ȓ' => 'ȓ',
'Ȕ' => 'Ȕ',
'ȕ' => 'ȕ',
'Ȗ' => 'Ȗ',
'ȗ' => 'ȗ',
'Ș' => 'Ș',
'ș' => 'ș',
'Ț' => 'Ț',
'ț' => 'ț',
'Ȟ' => 'Ȟ',
'ȟ' => 'ȟ',
'Ȧ' => 'Ȧ',
'ȧ' => 'ȧ',
'Ȩ' => 'Ȩ',
'ȩ' => 'ȩ',
'Ȫ' => 'Ȫ',
'ȫ' => 'ȫ',
'Ȭ' => 'Ȭ',
'ȭ' => 'ȭ',
'Ȯ' => 'Ȯ',
'ȯ' => 'ȯ',
'Ȱ' => 'Ȱ',
'ȱ' => 'ȱ',
'Ȳ' => 'Ȳ',
'ȳ' => 'ȳ',
'̀' => '̀',
'́' => '́',
'̓' => '̓',
'̈́' => '̈́',
'ʹ' => 'ʹ',
';' => ';',
'΅' => '΅',
'Ά' => 'Ά',
'·' => '·',
'Έ' => 'Έ',
'Ή' => 'Ή',
'Ί' => 'Ί',
'Ό' => 'Ό',
'Ύ' => 'Ύ',
'Ώ' => 'Ώ',
'ΐ' => 'ΐ',
'Ϊ' => 'Ϊ',
'Ϋ' => 'Ϋ',
'ά' => 'ά',
'έ' => 'έ',
'ή' => 'ή',
'ί' => 'ί',
'ΰ' => 'ΰ',
'ϊ' => 'ϊ',
'ϋ' => 'ϋ',
'ό' => 'ό',
'ύ' => 'ύ',
'ώ' => 'ώ',
'ϓ' => 'ϓ',
'ϔ' => 'ϔ',
'Ѐ' => 'Ѐ',
'Ё' => 'Ё',
'Ѓ' => 'Ѓ',
'Ї' => 'Ї',
'Ќ' => 'Ќ',
'Ѝ' => 'Ѝ',
'Ў' => 'Ў',
'Й' => 'Й',
'й' => 'й',
'ѐ' => 'ѐ',
'ё' => 'ё',
'ѓ' => 'ѓ',
'ї' => 'ї',
'ќ' => 'ќ',
'ѝ' => 'ѝ',
'ў' => 'ў',
'Ѷ' => 'Ѷ',
'ѷ' => 'ѷ',
'Ӂ' => 'Ӂ',
'ӂ' => 'ӂ',
'Ӑ' => 'Ӑ',
'ӑ' => 'ӑ',
'Ӓ' => 'Ӓ',
'ӓ' => 'ӓ',
'Ӗ' => 'Ӗ',
'ӗ' => 'ӗ',
'Ӛ' => 'Ӛ',
'ӛ' => 'ӛ',
'Ӝ' => 'Ӝ',
'ӝ' => 'ӝ',
'Ӟ' => 'Ӟ',
'ӟ' => 'ӟ',
'Ӣ' => 'Ӣ',
'ӣ' => 'ӣ',
'Ӥ' => 'Ӥ',
'ӥ' => 'ӥ',
'Ӧ' => 'Ӧ',
'ӧ' => 'ӧ',
'Ӫ' => 'Ӫ',
'ӫ' => 'ӫ',
'Ӭ' => 'Ӭ',
'ӭ' => 'ӭ',
'Ӯ' => 'Ӯ',
'ӯ' => 'ӯ',
'Ӱ' => 'Ӱ',
'ӱ' => 'ӱ',
'Ӳ' => 'Ӳ',
'ӳ' => 'ӳ',
'Ӵ' => 'Ӵ',
'ӵ' => 'ӵ',
'Ӹ' => 'Ӹ',
'ӹ' => 'ӹ',
'آ' => 'آ',
'أ' => 'أ',
'ؤ' => 'ؤ',
'إ' => 'إ',
'ئ' => 'ئ',
'ۀ' => 'ۀ',
'ۂ' => 'ۂ',
'ۓ' => 'ۓ',
'ऩ' => 'ऩ',
'ऱ' => 'ऱ',
'ऴ' => 'ऴ',
'क़' => 'क़',
'ख़' => 'ख़',
'ग़' => 'ग़',
'ज़' => 'ज़',
'ड़' => 'ड़',
'ढ़' => 'ढ़',
'फ़' => 'फ़',
'य़' => 'य़',
'ো' => 'ো',
'ৌ' => 'ৌ',
'ড়' => 'ড়',
'ঢ়' => 'ঢ়',
'য়' => 'য়',
'ਲ਼' => 'ਲ਼',
'ਸ਼' => 'ਸ਼',
'ਖ਼' => 'ਖ਼',
'ਗ਼' => 'ਗ਼',
'ਜ਼' => 'ਜ਼',
'ਫ਼' => 'ਫ਼',
'ୈ' => 'ୈ',
'ୋ' => 'ୋ',
'ୌ' => 'ୌ',
'ଡ଼' => 'ଡ଼',
'ଢ଼' => 'ଢ଼',
'ஔ' => 'ஔ',
'ொ' => 'ொ',
'ோ' => 'ோ',
'ௌ' => 'ௌ',
'ై' => 'ై',
'ೀ' => 'ೀ',
'ೇ' => 'ೇ',
'ೈ' => 'ೈ',
'ೊ' => 'ೊ',
'ೋ' => 'ೋ',
'ൊ' => 'ൊ',
'ോ' => 'ോ',
'ൌ' => 'ൌ',
'ේ' => 'ේ',
'ො' => 'ො',
'ෝ' => 'ෝ',
'ෞ' => 'ෞ',
'གྷ' => 'གྷ',
'ཌྷ' => 'ཌྷ',
'དྷ' => 'དྷ',
'བྷ' => 'བྷ',
'ཛྷ' => 'ཛྷ',
'ཀྵ' => 'ཀྵ',
'ཱི' => 'ཱི',
'ཱུ' => 'ཱུ',
'ྲྀ' => 'ྲྀ',
'ླྀ' => 'ླྀ',
'ཱྀ' => 'ཱྀ',
'ྒྷ' => 'ྒྷ',
'ྜྷ' => 'ྜྷ',
'ྡྷ' => 'ྡྷ',
'ྦྷ' => 'ྦྷ',
'ྫྷ' => 'ྫྷ',
'ྐྵ' => 'ྐྵ',
'ဦ' => 'ဦ',
'ᬆ' => 'ᬆ',
'ᬈ' => 'ᬈ',
'ᬊ' => 'ᬊ',
'ᬌ' => 'ᬌ',
'ᬎ' => 'ᬎ',
'ᬒ' => 'ᬒ',
'ᬻ' => 'ᬻ',
'ᬽ' => 'ᬽ',
'ᭀ' => 'ᭀ',
'ᭁ' => 'ᭁ',
'ᭃ' => 'ᭃ',
'Ḁ' => 'Ḁ',
'ḁ' => 'ḁ',
'Ḃ' => 'Ḃ',
'ḃ' => 'ḃ',
'Ḅ' => 'Ḅ',
'ḅ' => 'ḅ',
'Ḇ' => 'Ḇ',
'ḇ' => 'ḇ',
'Ḉ' => 'Ḉ',
'ḉ' => 'ḉ',
'Ḋ' => 'Ḋ',
'ḋ' => 'ḋ',
'Ḍ' => 'Ḍ',
'ḍ' => 'ḍ',
'Ḏ' => 'Ḏ',
'ḏ' => 'ḏ',
'Ḑ' => 'Ḑ',
'ḑ' => 'ḑ',
'Ḓ' => 'Ḓ',
'ḓ' => 'ḓ',
'Ḕ' => 'Ḕ',
'ḕ' => 'ḕ',
'Ḗ' => 'Ḗ',
'ḗ' => 'ḗ',
'Ḙ' => 'Ḙ',
'ḙ' => 'ḙ',
'Ḛ' => 'Ḛ',
'ḛ' => 'ḛ',
'Ḝ' => 'Ḝ',
'ḝ' => 'ḝ',
'Ḟ' => 'Ḟ',
'ḟ' => 'ḟ',
'Ḡ' => 'Ḡ',
'ḡ' => 'ḡ',
'Ḣ' => 'Ḣ',
'ḣ' => 'ḣ',
'Ḥ' => 'Ḥ',
'ḥ' => 'ḥ',
'Ḧ' => 'Ḧ',
'ḧ' => 'ḧ',
'Ḩ' => 'Ḩ',
'ḩ' => 'ḩ',
'Ḫ' => 'Ḫ',
'ḫ' => 'ḫ',
'Ḭ' => 'Ḭ',
'ḭ' => 'ḭ',
'Ḯ' => 'Ḯ',
'ḯ' => 'ḯ',
'Ḱ' => 'Ḱ',
'ḱ' => 'ḱ',
'Ḳ' => 'Ḳ',
'ḳ' => 'ḳ',
'Ḵ' => 'Ḵ',
'ḵ' => 'ḵ',
'Ḷ' => 'Ḷ',
'ḷ' => 'ḷ',
'Ḹ' => 'Ḹ',
'ḹ' => 'ḹ',
'Ḻ' => 'Ḻ',
'ḻ' => 'ḻ',
'Ḽ' => 'Ḽ',
'ḽ' => 'ḽ',
'Ḿ' => 'Ḿ',
'ḿ' => 'ḿ',
'Ṁ' => 'Ṁ',
'ṁ' => 'ṁ',
'Ṃ' => 'Ṃ',
'ṃ' => 'ṃ',
'Ṅ' => 'Ṅ',
'ṅ' => 'ṅ',
'Ṇ' => 'Ṇ',
'ṇ' => 'ṇ',
'Ṉ' => 'Ṉ',
'ṉ' => 'ṉ',
'Ṋ' => 'Ṋ',
'ṋ' => 'ṋ',
'Ṍ' => 'Ṍ',
'ṍ' => 'ṍ',
'Ṏ' => 'Ṏ',
'ṏ' => 'ṏ',
'Ṑ' => 'Ṑ',
'ṑ' => 'ṑ',
'Ṓ' => 'Ṓ',
'ṓ' => 'ṓ',
'Ṕ' => 'Ṕ',
'ṕ' => 'ṕ',
'Ṗ' => 'Ṗ',
'ṗ' => 'ṗ',
'Ṙ' => 'Ṙ',
'ṙ' => 'ṙ',
'Ṛ' => 'Ṛ',
'ṛ' => 'ṛ',
'Ṝ' => 'Ṝ',
'ṝ' => 'ṝ',
'Ṟ' => 'Ṟ',
'ṟ' => 'ṟ',
'Ṡ' => 'Ṡ',
'ṡ' => 'ṡ',
'Ṣ' => 'Ṣ',
'ṣ' => 'ṣ',
'Ṥ' => 'Ṥ',
'ṥ' => 'ṥ',
'Ṧ' => 'Ṧ',
'ṧ' => 'ṧ',
'Ṩ' => 'Ṩ',
'ṩ' => 'ṩ',
'Ṫ' => 'Ṫ',
'ṫ' => 'ṫ',
'Ṭ' => 'Ṭ',
'ṭ' => 'ṭ',
'Ṯ' => 'Ṯ',
'ṯ' => 'ṯ',
'Ṱ' => 'Ṱ',
'ṱ' => 'ṱ',
'Ṳ' => 'Ṳ',
'ṳ' => 'ṳ',
'Ṵ' => 'Ṵ',
'ṵ' => 'ṵ',
'Ṷ' => 'Ṷ',
'ṷ' => 'ṷ',
'Ṹ' => 'Ṹ',
'ṹ' => 'ṹ',
'Ṻ' => 'Ṻ',
'ṻ' => 'ṻ',
'Ṽ' => 'Ṽ',
'ṽ' => 'ṽ',
'Ṿ' => 'Ṿ',
'ṿ' => 'ṿ',
'Ẁ' => 'Ẁ',
'ẁ' => 'ẁ',
'Ẃ' => 'Ẃ',
'ẃ' => 'ẃ',
'Ẅ' => 'Ẅ',
'ẅ' => 'ẅ',
'Ẇ' => 'Ẇ',
'ẇ' => 'ẇ',
'Ẉ' => 'Ẉ',
'ẉ' => 'ẉ',
'Ẋ' => 'Ẋ',
'ẋ' => 'ẋ',
'Ẍ' => 'Ẍ',
'ẍ' => 'ẍ',
'Ẏ' => 'Ẏ',
'ẏ' => 'ẏ',
'Ẑ' => 'Ẑ',
'ẑ' => 'ẑ',
'Ẓ' => 'Ẓ',
'ẓ' => 'ẓ',
'Ẕ' => 'Ẕ',
'ẕ' => 'ẕ',
'ẖ' => 'ẖ',
'ẗ' => 'ẗ',
'ẘ' => 'ẘ',
'ẙ' => 'ẙ',
'ẛ' => 'ẛ',
'Ạ' => 'Ạ',
'ạ' => 'ạ',
'Ả' => 'Ả',
'ả' => 'ả',
'Ấ' => 'Ấ',
'ấ' => 'ấ',
'Ầ' => 'Ầ',
'ầ' => 'ầ',
'Ẩ' => 'Ẩ',
'ẩ' => 'ẩ',
'Ẫ' => 'Ẫ',
'ẫ' => 'ẫ',
'Ậ' => 'Ậ',
'ậ' => 'ậ',
'Ắ' => 'Ắ',
'ắ' => 'ắ',
'Ằ' => 'Ằ',
'ằ' => 'ằ',
'Ẳ' => 'Ẳ',
'ẳ' => 'ẳ',
'Ẵ' => 'Ẵ',
'ẵ' => 'ẵ',
'Ặ' => 'Ặ',
'ặ' => 'ặ',
'Ẹ' => 'Ẹ',
'ẹ' => 'ẹ',
'Ẻ' => 'Ẻ',
'ẻ' => 'ẻ',
'Ẽ' => 'Ẽ',
'ẽ' => 'ẽ',
'Ế' => 'Ế',
'ế' => 'ế',
'Ề' => 'Ề',
'ề' => 'ề',
'Ể' => 'Ể',
'ể' => 'ể',
'Ễ' => 'Ễ',
'ễ' => 'ễ',
'Ệ' => 'Ệ',
'ệ' => 'ệ',
'Ỉ' => 'Ỉ',
'ỉ' => 'ỉ',
'Ị' => 'Ị',
'ị' => 'ị',
'Ọ' => 'Ọ',
'ọ' => 'ọ',
'Ỏ' => 'Ỏ',
'ỏ' => 'ỏ',
'Ố' => 'Ố',
'ố' => 'ố',
'Ồ' => 'Ồ',
'ồ' => 'ồ',
'Ổ' => 'Ổ',
'ổ' => 'ổ',
'Ỗ' => 'Ỗ',
'ỗ' => 'ỗ',
'Ộ' => 'Ộ',
'ộ' => 'ộ',
'Ớ' => 'Ớ',
'ớ' => 'ớ',
'Ờ' => 'Ờ',
'ờ' => 'ờ',
'Ở' => 'Ở',
'ở' => 'ở',
'Ỡ' => 'Ỡ',
'ỡ' => 'ỡ',
'Ợ' => 'Ợ',
'ợ' => 'ợ',
'Ụ' => 'Ụ',
'ụ' => 'ụ',
'Ủ' => 'Ủ',
'ủ' => 'ủ',
'Ứ' => 'Ứ',
'ứ' => 'ứ',
'Ừ' => 'Ừ',
'ừ' => 'ừ',
'Ử' => 'Ử',
'ử' => 'ử',
'Ữ' => 'Ữ',
'ữ' => 'ữ',
'Ự' => 'Ự',
'ự' => 'ự',
'Ỳ' => 'Ỳ',
'ỳ' => 'ỳ',
'Ỵ' => 'Ỵ',
'ỵ' => 'ỵ',
'Ỷ' => 'Ỷ',
'ỷ' => 'ỷ',
'Ỹ' => 'Ỹ',
'ỹ' => 'ỹ',
'ἀ' => 'ἀ',
'ἁ' => 'ἁ',
'ἂ' => 'ἂ',
'ἃ' => 'ἃ',
'ἄ' => 'ἄ',
'ἅ' => 'ἅ',
'ἆ' => 'ἆ',
'ἇ' => 'ἇ',
'Ἀ' => 'Ἀ',
'Ἁ' => 'Ἁ',
'Ἂ' => 'Ἂ',
'Ἃ' => 'Ἃ',
'Ἄ' => 'Ἄ',
'Ἅ' => 'Ἅ',
'Ἆ' => 'Ἆ',
'Ἇ' => 'Ἇ',
'ἐ' => 'ἐ',
'ἑ' => 'ἑ',
'ἒ' => 'ἒ',
'ἓ' => 'ἓ',
'ἔ' => 'ἔ',
'ἕ' => 'ἕ',
'Ἐ' => 'Ἐ',
'Ἑ' => 'Ἑ',
'Ἒ' => 'Ἒ',
'Ἓ' => 'Ἓ',
'Ἔ' => 'Ἔ',
'Ἕ' => 'Ἕ',
'ἠ' => 'ἠ',
'ἡ' => 'ἡ',
'ἢ' => 'ἢ',
'ἣ' => 'ἣ',
'ἤ' => 'ἤ',
'ἥ' => 'ἥ',
'ἦ' => 'ἦ',
'ἧ' => 'ἧ',
'Ἠ' => 'Ἠ',
'Ἡ' => 'Ἡ',
'Ἢ' => 'Ἢ',
'Ἣ' => 'Ἣ',
'Ἤ' => 'Ἤ',
'Ἥ' => 'Ἥ',
'Ἦ' => 'Ἦ',
'Ἧ' => 'Ἧ',
'ἰ' => 'ἰ',
'ἱ' => 'ἱ',
'ἲ' => 'ἲ',
'ἳ' => 'ἳ',
'ἴ' => 'ἴ',
'ἵ' => 'ἵ',
'ἶ' => 'ἶ',
'ἷ' => 'ἷ',
'Ἰ' => 'Ἰ',
'Ἱ' => 'Ἱ',
'Ἲ' => 'Ἲ',
'Ἳ' => 'Ἳ',
'Ἴ' => 'Ἴ',
'Ἵ' => 'Ἵ',
'Ἶ' => 'Ἶ',
'Ἷ' => 'Ἷ',
'ὀ' => 'ὀ',
'ὁ' => 'ὁ',
'ὂ' => 'ὂ',
'ὃ' => 'ὃ',
'ὄ' => 'ὄ',
'ὅ' => 'ὅ',
'Ὀ' => 'Ὀ',
'Ὁ' => 'Ὁ',
'Ὂ' => 'Ὂ',
'Ὃ' => 'Ὃ',
'Ὄ' => 'Ὄ',
'Ὅ' => 'Ὅ',
'ὐ' => 'ὐ',
'ὑ' => 'ὑ',
'ὒ' => 'ὒ',
'ὓ' => 'ὓ',
'ὔ' => 'ὔ',
'ὕ' => 'ὕ',
'ὖ' => 'ὖ',
'ὗ' => 'ὗ',
'Ὑ' => 'Ὑ',
'Ὓ' => 'Ὓ',
'Ὕ' => 'Ὕ',
'Ὗ' => 'Ὗ',
'ὠ' => 'ὠ',
'ὡ' => 'ὡ',
'ὢ' => 'ὢ',
'ὣ' => 'ὣ',
'ὤ' => 'ὤ',
'ὥ' => 'ὥ',
'ὦ' => 'ὦ',
'ὧ' => 'ὧ',
'Ὠ' => 'Ὠ',
'Ὡ' => 'Ὡ',
'Ὢ' => 'Ὢ',
'Ὣ' => 'Ὣ',
'Ὤ' => 'Ὤ',
'Ὥ' => 'Ὥ',
'Ὦ' => 'Ὦ',
'Ὧ' => 'Ὧ',
'ὰ' => 'ὰ',
'ά' => 'ά',
'ὲ' => 'ὲ',
'έ' => 'έ',
'ὴ' => 'ὴ',
'ή' => 'ή',
'ὶ' => 'ὶ',
'ί' => 'ί',
'ὸ' => 'ὸ',
'ό' => 'ό',
'ὺ' => 'ὺ',
'ύ' => 'ύ',
'ὼ' => 'ὼ',
'ώ' => 'ώ',
'ᾀ' => 'ᾀ',
'ᾁ' => 'ᾁ',
'ᾂ' => 'ᾂ',
'ᾃ' => 'ᾃ',
'ᾄ' => 'ᾄ',
'ᾅ' => 'ᾅ',
'ᾆ' => 'ᾆ',
'ᾇ' => 'ᾇ',
'ᾈ' => 'ᾈ',
'ᾉ' => 'ᾉ',
'ᾊ' => 'ᾊ',
'ᾋ' => 'ᾋ',
'ᾌ' => 'ᾌ',
'ᾍ' => 'ᾍ',
'ᾎ' => 'ᾎ',
'ᾏ' => 'ᾏ',
'ᾐ' => 'ᾐ',
'ᾑ' => 'ᾑ',
'ᾒ' => 'ᾒ',
'ᾓ' => 'ᾓ',
'ᾔ' => 'ᾔ',
'ᾕ' => 'ᾕ',
'ᾖ' => 'ᾖ',
'ᾗ' => 'ᾗ',
'ᾘ' => 'ᾘ',
'ᾙ' => 'ᾙ',
'ᾚ' => 'ᾚ',
'ᾛ' => 'ᾛ',
'ᾜ' => 'ᾜ',
'ᾝ' => 'ᾝ',
'ᾞ' => 'ᾞ',
'ᾟ' => 'ᾟ',
'ᾠ' => 'ᾠ',
'ᾡ' => 'ᾡ',
'ᾢ' => 'ᾢ',
'ᾣ' => 'ᾣ',
'ᾤ' => 'ᾤ',
'ᾥ' => 'ᾥ',
'ᾦ' => 'ᾦ',
'ᾧ' => 'ᾧ',
'ᾨ' => 'ᾨ',
'ᾩ' => 'ᾩ',
'ᾪ' => 'ᾪ',
'ᾫ' => 'ᾫ',
'ᾬ' => 'ᾬ',
'ᾭ' => 'ᾭ',
'ᾮ' => 'ᾮ',
'ᾯ' => 'ᾯ',
'ᾰ' => 'ᾰ',
'ᾱ' => 'ᾱ',
'ᾲ' => 'ᾲ',
'ᾳ' => 'ᾳ',
'ᾴ' => 'ᾴ',
'ᾶ' => 'ᾶ',
'ᾷ' => 'ᾷ',
'Ᾰ' => 'Ᾰ',
'Ᾱ' => 'Ᾱ',
'Ὰ' => 'Ὰ',
'Ά' => 'Ά',
'ᾼ' => 'ᾼ',
'ι' => 'ι',
'῁' => '῁',
'ῂ' => 'ῂ',
'ῃ' => 'ῃ',
'ῄ' => 'ῄ',
'ῆ' => 'ῆ',
'ῇ' => 'ῇ',
'Ὲ' => 'Ὲ',
'Έ' => 'Έ',
'Ὴ' => 'Ὴ',
'Ή' => 'Ή',
'ῌ' => 'ῌ',
'῍' => '῍',
'῎' => '῎',
'῏' => '῏',
'ῐ' => 'ῐ',
'ῑ' => 'ῑ',
'ῒ' => 'ῒ',
'ΐ' => 'ΐ',
'ῖ' => 'ῖ',
'ῗ' => 'ῗ',
'Ῐ' => 'Ῐ',
'Ῑ' => 'Ῑ',
'Ὶ' => 'Ὶ',
'Ί' => 'Ί',
'῝' => '῝',
'῞' => '῞',
'῟' => '῟',
'ῠ' => 'ῠ',
'ῡ' => 'ῡ',
'ῢ' => 'ῢ',
'ΰ' => 'ΰ',
'ῤ' => 'ῤ',
'ῥ' => 'ῥ',
'ῦ' => 'ῦ',
'ῧ' => 'ῧ',
'Ῠ' => 'Ῠ',
'Ῡ' => 'Ῡ',
'Ὺ' => 'Ὺ',
'Ύ' => 'Ύ',
'Ῥ' => 'Ῥ',
'῭' => '῭',
'΅' => '΅',
'`' => '`',
'ῲ' => 'ῲ',
'ῳ' => 'ῳ',
'ῴ' => 'ῴ',
'ῶ' => 'ῶ',
'ῷ' => 'ῷ',
'Ὸ' => 'Ὸ',
'Ό' => 'Ό',
'Ὼ' => 'Ὼ',
'Ώ' => 'Ώ',
'ῼ' => 'ῼ',
'´' => '´',
' ' => ' ',
' ' => ' ',
'Ω' => 'Ω',
'K' => 'K',
'Å' => 'Å',
'↚' => '↚',
'↛' => '↛',
'↮' => '↮',
'⇍' => '⇍',
'⇎' => '⇎',
'⇏' => '⇏',
'∄' => '∄',
'∉' => '∉',
'∌' => '∌',
'∤' => '∤',
'∦' => '∦',
'≁' => '≁',
'≄' => '≄',
'≇' => '≇',
'≉' => '≉',
'≠' => '≠',
'≢' => '≢',
'≭' => '≭',
'≮' => '≮',
'≯' => '≯',
'≰' => '≰',
'≱' => '≱',
'≴' => '≴',
'≵' => '≵',
'≸' => '≸',
'≹' => '≹',
'⊀' => '⊀',
'⊁' => '⊁',
'⊄' => '⊄',
'⊅' => '⊅',
'⊈' => '⊈',
'⊉' => '⊉',
'⊬' => '⊬',
'⊭' => '⊭',
'⊮' => '⊮',
'⊯' => '⊯',
'⋠' => '⋠',
'⋡' => '⋡',
'⋢' => '⋢',
'⋣' => '⋣',
'⋪' => '⋪',
'⋫' => '⋫',
'⋬' => '⋬',
'⋭' => '⋭',
'〈' => '〈',
'〉' => '〉',
'⫝̸' => '⫝̸',
'が' => 'が',
'ぎ' => 'ぎ',
'ぐ' => 'ぐ',
'げ' => 'げ',
'ご' => 'ご',
'ざ' => 'ざ',
'じ' => 'じ',
'ず' => 'ず',
'ぜ' => 'ぜ',
'ぞ' => 'ぞ',
'だ' => 'だ',
'ぢ' => 'ぢ',
'づ' => 'づ',
'で' => 'で',
'ど' => 'ど',
'ば' => 'ば',
'ぱ' => 'ぱ',
'び' => 'び',
'ぴ' => 'ぴ',
'ぶ' => 'ぶ',
'ぷ' => 'ぷ',
'べ' => 'べ',
'ぺ' => 'ぺ',
'ぼ' => 'ぼ',
'ぽ' => 'ぽ',
'ゔ' => 'ゔ',
'ゞ' => 'ゞ',
'ガ' => 'ガ',
'ギ' => 'ギ',
'グ' => 'グ',
'ゲ' => 'ゲ',
'ゴ' => 'ゴ',
'ザ' => 'ザ',
'ジ' => 'ジ',
'ズ' => 'ズ',
'ゼ' => 'ゼ',
'ゾ' => 'ゾ',
'ダ' => 'ダ',
'ヂ' => 'ヂ',
'ヅ' => 'ヅ',
'デ' => 'デ',
'ド' => 'ド',
'バ' => 'バ',
'パ' => 'パ',
'ビ' => 'ビ',
'ピ' => 'ピ',
'ブ' => 'ブ',
'プ' => 'プ',
'ベ' => 'ベ',
'ペ' => 'ペ',
'ボ' => 'ボ',
'ポ' => 'ポ',
'ヴ' => 'ヴ',
'ヷ' => 'ヷ',
'ヸ' => 'ヸ',
'ヹ' => 'ヹ',
'ヺ' => 'ヺ',
'ヾ' => 'ヾ',
'豈' => '豈',
'更' => '更',
'車' => '車',
'賈' => '賈',
'滑' => '滑',
'串' => '串',
'句' => '句',
'龜' => '龜',
'龜' => '龜',
'契' => '契',
'金' => '金',
'喇' => '喇',
'奈' => '奈',
'懶' => '懶',
'癩' => '癩',
'羅' => '羅',
'蘿' => '蘿',
'螺' => '螺',
'裸' => '裸',
'邏' => '邏',
'樂' => '樂',
'洛' => '洛',
'烙' => '烙',
'珞' => '珞',
'落' => '落',
'酪' => '酪',
'駱' => '駱',
'亂' => '亂',
'卵' => '卵',
'欄' => '欄',
'爛' => '爛',
'蘭' => '蘭',
'鸞' => '鸞',
'嵐' => '嵐',
'濫' => '濫',
'藍' => '藍',
'襤' => '襤',
'拉' => '拉',
'臘' => '臘',
'蠟' => '蠟',
'廊' => '廊',
'朗' => '朗',
'浪' => '浪',
'狼' => '狼',
'郎' => '郎',
'來' => '來',
'冷' => '冷',
'勞' => '勞',
'擄' => '擄',
'櫓' => '櫓',
'爐' => '爐',
'盧' => '盧',
'老' => '老',
'蘆' => '蘆',
'虜' => '虜',
'路' => '路',
'露' => '露',
'魯' => '魯',
'鷺' => '鷺',
'碌' => '碌',
'祿' => '祿',
'綠' => '綠',
'菉' => '菉',
'錄' => '錄',
'鹿' => '鹿',
'論' => '論',
'壟' => '壟',
'弄' => '弄',
'籠' => '籠',
'聾' => '聾',
'牢' => '牢',
'磊' => '磊',
'賂' => '賂',
'雷' => '雷',
'壘' => '壘',
'屢' => '屢',
'樓' => '樓',
'淚' => '淚',
'漏' => '漏',
'累' => '累',
'縷' => '縷',
'陋' => '陋',
'勒' => '勒',
'肋' => '肋',
'凜' => '凜',
'凌' => '凌',
'稜' => '稜',
'綾' => '綾',
'菱' => '菱',
'陵' => '陵',
'讀' => '讀',
'拏' => '拏',
'樂' => '樂',
'諾' => '諾',
'丹' => '丹',
'寧' => '寧',
'怒' => '怒',
'率' => '率',
'異' => '異',
'北' => '北',
'磻' => '磻',
'便' => '便',
'復' => '復',
'不' => '不',
'泌' => '泌',
'數' => '數',
'索' => '索',
'參' => '參',
'塞' => '塞',
'省' => '省',
'葉' => '葉',
'說' => '說',
'殺' => '殺',
'辰' => '辰',
'沈' => '沈',
'拾' => '拾',
'若' => '若',
'掠' => '掠',
'略' => '略',
'亮' => '亮',
'兩' => '兩',
'凉' => '凉',
'梁' => '梁',
'糧' => '糧',
'良' => '良',
'諒' => '諒',
'量' => '量',
'勵' => '勵',
'呂' => '呂',
'女' => '女',
'廬' => '廬',
'旅' => '旅',
'濾' => '濾',
'礪' => '礪',
'閭' => '閭',
'驪' => '驪',
'麗' => '麗',
'黎' => '黎',
'力' => '力',
'曆' => '曆',
'歷' => '歷',
'轢' => '轢',
'年' => '年',
'憐' => '憐',
'戀' => '戀',
'撚' => '撚',
'漣' => '漣',
'煉' => '煉',
'璉' => '璉',
'秊' => '秊',
'練' => '練',
'聯' => '聯',
'輦' => '輦',
'蓮' => '蓮',
'連' => '連',
'鍊' => '鍊',
'列' => '列',
'劣' => '劣',
'咽' => '咽',
'烈' => '烈',
'裂' => '裂',
'說' => '說',
'廉' => '廉',
'念' => '念',
'捻' => '捻',
'殮' => '殮',
'簾' => '簾',
'獵' => '獵',
'令' => '令',
'囹' => '囹',
'寧' => '寧',
'嶺' => '嶺',
'怜' => '怜',
'玲' => '玲',
'瑩' => '瑩',
'羚' => '羚',
'聆' => '聆',
'鈴' => '鈴',
'零' => '零',
'靈' => '靈',
'領' => '領',
'例' => '例',
'禮' => '禮',
'醴' => '醴',
'隸' => '隸',
'惡' => '惡',
'了' => '了',
'僚' => '僚',
'寮' => '寮',
'尿' => '尿',
'料' => '料',
'樂' => '樂',
'燎' => '燎',
'療' => '療',
'蓼' => '蓼',
'遼' => '遼',
'龍' => '龍',
'暈' => '暈',
'阮' => '阮',
'劉' => '劉',
'杻' => '杻',
'柳' => '柳',
'流' => '流',
'溜' => '溜',
'琉' => '琉',
'留' => '留',
'硫' => '硫',
'紐' => '紐',
'類' => '類',
'六' => '六',
'戮' => '戮',
'陸' => '陸',
'倫' => '倫',
'崙' => '崙',
'淪' => '淪',
'輪' => '輪',
'律' => '律',
'慄' => '慄',
'栗' => '栗',
'率' => '率',
'隆' => '隆',
'利' => '利',
'吏' => '吏',
'履' => '履',
'易' => '易',
'李' => '李',
'梨' => '梨',
'泥' => '泥',
'理' => '理',
'痢' => '痢',
'罹' => '罹',
'裏' => '裏',
'裡' => '裡',
'里' => '里',
'離' => '離',
'匿' => '匿',
'溺' => '溺',
'吝' => '吝',
'燐' => '燐',
'璘' => '璘',
'藺' => '藺',
'隣' => '隣',
'鱗' => '鱗',
'麟' => '麟',
'林' => '林',
'淋' => '淋',
'臨' => '臨',
'立' => '立',
'笠' => '笠',
'粒' => '粒',
'狀' => '狀',
'炙' => '炙',
'識' => '識',
'什' => '什',
'茶' => '茶',
'刺' => '刺',
'切' => '切',
'度' => '度',
'拓' => '拓',
'糖' => '糖',
'宅' => '宅',
'洞' => '洞',
'暴' => '暴',
'輻' => '輻',
'行' => '行',
'降' => '降',
'見' => '見',
'廓' => '廓',
'兀' => '兀',
'嗀' => '嗀',
'塚' => '塚',
'晴' => '晴',
'凞' => '凞',
'猪' => '猪',
'益' => '益',
'礼' => '礼',
'神' => '神',
'祥' => '祥',
'福' => '福',
'靖' => '靖',
'精' => '精',
'羽' => '羽',
'蘒' => '蘒',
'諸' => '諸',
'逸' => '逸',
'都' => '都',
'飯' => '飯',
'飼' => '飼',
'館' => '館',
'鶴' => '鶴',
'郞' => '郞',
'隷' => '隷',
'侮' => '侮',
'僧' => '僧',
'免' => '免',
'勉' => '勉',
'勤' => '勤',
'卑' => '卑',
'喝' => '喝',
'嘆' => '嘆',
'器' => '器',
'塀' => '塀',
'墨' => '墨',
'層' => '層',
'屮' => '屮',
'悔' => '悔',
'慨' => '慨',
'憎' => '憎',
'懲' => '懲',
'敏' => '敏',
'既' => '既',
'暑' => '暑',
'梅' => '梅',
'海' => '海',
'渚' => '渚',
'漢' => '漢',
'煮' => '煮',
'爫' => '爫',
'琢' => '琢',
'碑' => '碑',
'社' => '社',
'祉' => '祉',
'祈' => '祈',
'祐' => '祐',
'祖' => '祖',
'祝' => '祝',
'禍' => '禍',
'禎' => '禎',
'穀' => '穀',
'突' => '突',
'節' => '節',
'練' => '練',
'縉' => '縉',
'繁' => '繁',
'署' => '署',
'者' => '者',
'臭' => '臭',
'艹' => '艹',
'艹' => '艹',
'著' => '著',
'褐' => '褐',
'視' => '視',
'謁' => '謁',
'謹' => '謹',
'賓' => '賓',
'贈' => '贈',
'辶' => '辶',
'逸' => '逸',
'難' => '難',
'響' => '響',
'頻' => '頻',
'恵' => '恵',
'𤋮' => '𤋮',
'舘' => '舘',
'並' => '並',
'况' => '况',
'全' => '全',
'侀' => '侀',
'充' => '充',
'冀' => '冀',
'勇' => '勇',
'勺' => '勺',
'喝' => '喝',
'啕' => '啕',
'喙' => '喙',
'嗢' => '嗢',
'塚' => '塚',
'墳' => '墳',
'奄' => '奄',
'奔' => '奔',
'婢' => '婢',
'嬨' => '嬨',
'廒' => '廒',
'廙' => '廙',
'彩' => '彩',
'徭' => '徭',
'惘' => '惘',
'慎' => '慎',
'愈' => '愈',
'憎' => '憎',
'慠' => '慠',
'懲' => '懲',
'戴' => '戴',
'揄' => '揄',
'搜' => '搜',
'摒' => '摒',
'敖' => '敖',
'晴' => '晴',
'朗' => '朗',
'望' => '望',
'杖' => '杖',
'歹' => '歹',
'殺' => '殺',
'流' => '流',
'滛' => '滛',
'滋' => '滋',
'漢' => '漢',
'瀞' => '瀞',
'煮' => '煮',
'瞧' => '瞧',
'爵' => '爵',
'犯' => '犯',
'猪' => '猪',
'瑱' => '瑱',
'甆' => '甆',
'画' => '画',
'瘝' => '瘝',
'瘟' => '瘟',
'益' => '益',
'盛' => '盛',
'直' => '直',
'睊' => '睊',
'着' => '着',
'磌' => '磌',
'窱' => '窱',
'節' => '節',
'类' => '类',
'絛' => '絛',
'練' => '練',
'缾' => '缾',
'者' => '者',
'荒' => '荒',
'華' => '華',
'蝹' => '蝹',
'襁' => '襁',
'覆' => '覆',
'視' => '視',
'調' => '調',
'諸' => '諸',
'請' => '請',
'謁' => '謁',
'諾' => '諾',
'諭' => '諭',
'謹' => '謹',
'變' => '變',
'贈' => '贈',
'輸' => '輸',
'遲' => '遲',
'醙' => '醙',
'鉶' => '鉶',
'陼' => '陼',
'難' => '難',
'靖' => '靖',
'韛' => '韛',
'響' => '響',
'頋' => '頋',
'頻' => '頻',
'鬒' => '鬒',
'龜' => '龜',
'𢡊' => '𢡊',
'𢡄' => '𢡄',
'𣏕' => '𣏕',
'㮝' => '㮝',
'䀘' => '䀘',
'䀹' => '䀹',
'𥉉' => '𥉉',
'𥳐' => '𥳐',
'𧻓' => '𧻓',
'齃' => '齃',
'龎' => '龎',
'יִ' => 'יִ',
'ײַ' => 'ײַ',
'שׁ' => 'שׁ',
'שׂ' => 'שׂ',
'שּׁ' => 'שּׁ',
'שּׂ' => 'שּׂ',
'אַ' => 'אַ',
'אָ' => 'אָ',
'אּ' => 'אּ',
'בּ' => 'בּ',
'גּ' => 'גּ',
'דּ' => 'דּ',
'הּ' => 'הּ',
'וּ' => 'וּ',
'זּ' => 'זּ',
'טּ' => 'טּ',
'יּ' => 'יּ',
'ךּ' => 'ךּ',
'כּ' => 'כּ',
'לּ' => 'לּ',
'מּ' => 'מּ',
'נּ' => 'נּ',
'סּ' => 'סּ',
'ףּ' => 'ףּ',
'פּ' => 'פּ',
'צּ' => 'צּ',
'קּ' => 'קּ',
'רּ' => 'רּ',
'שּ' => 'שּ',
'תּ' => 'תּ',
'וֹ' => 'וֹ',
'בֿ' => 'בֿ',
'כֿ' => 'כֿ',
'פֿ' => 'פֿ',
'𑂚' => '𑂚',
'𑂜' => '𑂜',
'𑂫' => '𑂫',
'𑄮' => '𑄮',
'𑄯' => '𑄯',
'𑍋' => '𑍋',
'𑍌' => '𑍌',
'𑒻' => '𑒻',
'𑒼' => '𑒼',
'𑒾' => '𑒾',
'𑖺' => '𑖺',
'𑖻' => '𑖻',
'𑤸' => '𑤸',
'𝅗𝅥' => '𝅗𝅥',
'𝅘𝅥' => '𝅘𝅥',
'𝅘𝅥𝅮' => '𝅘𝅥𝅮',
'𝅘𝅥𝅯' => '𝅘𝅥𝅯',
'𝅘𝅥𝅰' => '𝅘𝅥𝅰',
'𝅘𝅥𝅱' => '𝅘𝅥𝅱',
'𝅘𝅥𝅲' => '𝅘𝅥𝅲',
'𝆹𝅥' => '𝆹𝅥',
'𝆺𝅥' => '𝆺𝅥',
'𝆹𝅥𝅮' => '𝆹𝅥𝅮',
'𝆺𝅥𝅮' => '𝆺𝅥𝅮',
'𝆹𝅥𝅯' => '𝆹𝅥𝅯',
'𝆺𝅥𝅯' => '𝆺𝅥𝅯',
'丽' => '丽',
'丸' => '丸',
'乁' => '乁',
'𠄢' => '𠄢',
'你' => '你',
'侮' => '侮',
'侻' => '侻',
'倂' => '倂',
'偺' => '偺',
'備' => '備',
'僧' => '僧',
'像' => '像',
'㒞' => '㒞',
'𠘺' => '𠘺',
'免' => '免',
'兔' => '兔',
'兤' => '兤',
'具' => '具',
'𠔜' => '𠔜',
'㒹' => '㒹',
'內' => '內',
'再' => '再',
'𠕋' => '𠕋',
'冗' => '冗',
'冤' => '冤',
'仌' => '仌',
'冬' => '冬',
'况' => '况',
'𩇟' => '𩇟',
'凵' => '凵',
'刃' => '刃',
'㓟' => '㓟',
'刻' => '刻',
'剆' => '剆',
'割' => '割',
'剷' => '剷',
'㔕' => '㔕',
'勇' => '勇',
'勉' => '勉',
'勤' => '勤',
'勺' => '勺',
'包' => '包',
'匆' => '匆',
'北' => '北',
'卉' => '卉',
'卑' => '卑',
'博' => '博',
'即' => '即',
'卽' => '卽',
'卿' => '卿',
'卿' => '卿',
'卿' => '卿',
'𠨬' => '𠨬',
'灰' => '灰',
'及' => '及',
'叟' => '叟',
'𠭣' => '𠭣',
'叫' => '叫',
'叱' => '叱',
'吆' => '吆',
'咞' => '咞',
'吸' => '吸',
'呈' => '呈',
'周' => '周',
'咢' => '咢',
'哶' => '哶',
'唐' => '唐',
'啓' => '啓',
'啣' => '啣',
'善' => '善',
'善' => '善',
'喙' => '喙',
'喫' => '喫',
'喳' => '喳',
'嗂' => '嗂',
'圖' => '圖',
'嘆' => '嘆',
'圗' => '圗',
'噑' => '噑',
'噴' => '噴',
'切' => '切',
'壮' => '壮',
'城' => '城',
'埴' => '埴',
'堍' => '堍',
'型' => '型',
'堲' => '堲',
'報' => '報',
'墬' => '墬',
'𡓤' => '𡓤',
'売' => '売',
'壷' => '壷',
'夆' => '夆',
'多' => '多',
'夢' => '夢',
'奢' => '奢',
'𡚨' => '𡚨',
'𡛪' => '𡛪',
'姬' => '姬',
'娛' => '娛',
'娧' => '娧',
'姘' => '姘',
'婦' => '婦',
'㛮' => '㛮',
'㛼' => '㛼',
'嬈' => '嬈',
'嬾' => '嬾',
'嬾' => '嬾',
'𡧈' => '𡧈',
'寃' => '寃',
'寘' => '寘',
'寧' => '寧',
'寳' => '寳',
'𡬘' => '𡬘',
'寿' => '寿',
'将' => '将',
'当' => '当',
'尢' => '尢',
'㞁' => '㞁',
'屠' => '屠',
'屮' => '屮',
'峀' => '峀',
'岍' => '岍',
'𡷤' => '𡷤',
'嵃' => '嵃',
'𡷦' => '𡷦',
'嵮' => '嵮',
'嵫' => '嵫',
'嵼' => '嵼',
'巡' => '巡',
'巢' => '巢',
'㠯' => '㠯',
'巽' => '巽',
'帨' => '帨',
'帽' => '帽',
'幩' => '幩',
'㡢' => '㡢',
'𢆃' => '𢆃',
'㡼' => '㡼',
'庰' => '庰',
'庳' => '庳',
'庶' => '庶',
'廊' => '廊',
'𪎒' => '𪎒',
'廾' => '廾',
'𢌱' => '𢌱',
'𢌱' => '𢌱',
'舁' => '舁',
'弢' => '弢',
'弢' => '弢',
'㣇' => '㣇',
'𣊸' => '𣊸',
'𦇚' => '𦇚',
'形' => '形',
'彫' => '彫',
'㣣' => '㣣',
'徚' => '徚',
'忍' => '忍',
'志' => '志',
'忹' => '忹',
'悁' => '悁',
'㤺' => '㤺',
'㤜' => '㤜',
'悔' => '悔',
'𢛔' => '𢛔',
'惇' => '惇',
'慈' => '慈',
'慌' => '慌',
'慎' => '慎',
'慌' => '慌',
'慺' => '慺',
'憎' => '憎',
'憲' => '憲',
'憤' => '憤',
'憯' => '憯',
'懞' => '懞',
'懲' => '懲',
'懶' => '懶',
'成' => '成',
'戛' => '戛',
'扝' => '扝',
'抱' => '抱',
'拔' => '拔',
'捐' => '捐',
'𢬌' => '𢬌',
'挽' => '挽',
'拼' => '拼',
'捨' => '捨',
'掃' => '掃',
'揤' => '揤',
'𢯱' => '𢯱',
'搢' => '搢',
'揅' => '揅',
'掩' => '掩',
'㨮' => '㨮',
'摩' => '摩',
'摾' => '摾',
'撝' => '撝',
'摷' => '摷',
'㩬' => '㩬',
'敏' => '敏',
'敬' => '敬',
'𣀊' => '𣀊',
'旣' => '旣',
'書' => '書',
'晉' => '晉',
'㬙' => '㬙',
'暑' => '暑',
'㬈' => '㬈',
'㫤' => '㫤',
'冒' => '冒',
'冕' => '冕',
'最' => '最',
'暜' => '暜',
'肭' => '肭',
'䏙' => '䏙',
'朗' => '朗',
'望' => '望',
'朡' => '朡',
'杞' => '杞',
'杓' => '杓',
'𣏃' => '𣏃',
'㭉' => '㭉',
'柺' => '柺',
'枅' => '枅',
'桒' => '桒',
'梅' => '梅',
'𣑭' => '𣑭',
'梎' => '梎',
'栟' => '栟',
'椔' => '椔',
'㮝' => '㮝',
'楂' => '楂',
'榣' => '榣',
'槪' => '槪',
'檨' => '檨',
'𣚣' => '𣚣',
'櫛' => '櫛',
'㰘' => '㰘',
'次' => '次',
'𣢧' => '𣢧',
'歔' => '歔',
'㱎' => '㱎',
'歲' => '歲',
'殟' => '殟',
'殺' => '殺',
'殻' => '殻',
'𣪍' => '𣪍',
'𡴋' => '𡴋',
'𣫺' => '𣫺',
'汎' => '汎',
'𣲼' => '𣲼',
'沿' => '沿',
'泍' => '泍',
'汧' => '汧',
'洖' => '洖',
'派' => '派',
'海' => '海',
'流' => '流',
'浩' => '浩',
'浸' => '浸',
'涅' => '涅',
'𣴞' => '𣴞',
'洴' => '洴',
'港' => '港',
'湮' => '湮',
'㴳' => '㴳',
'滋' => '滋',
'滇' => '滇',
'𣻑' => '𣻑',
'淹' => '淹',
'潮' => '潮',
'𣽞' => '𣽞',
'𣾎' => '𣾎',
'濆' => '濆',
'瀹' => '瀹',
'瀞' => '瀞',
'瀛' => '瀛',
'㶖' => '㶖',
'灊' => '灊',
'災' => '災',
'灷' => '灷',
'炭' => '炭',
'𠔥' => '𠔥',
'煅' => '煅',
'𤉣' => '𤉣',
'熜' => '熜',
'𤎫' => '𤎫',
'爨' => '爨',
'爵' => '爵',
'牐' => '牐',
'𤘈' => '𤘈',
'犀' => '犀',
'犕' => '犕',
'𤜵' => '𤜵',
'𤠔' => '𤠔',
'獺' => '獺',
'王' => '王',
'㺬' => '㺬',
'玥' => '玥',
'㺸' => '㺸',
'㺸' => '㺸',
'瑇' => '瑇',
'瑜' => '瑜',
'瑱' => '瑱',
'璅' => '璅',
'瓊' => '瓊',
'㼛' => '㼛',
'甤' => '甤',
'𤰶' => '𤰶',
'甾' => '甾',
'𤲒' => '𤲒',
'異' => '異',
'𢆟' => '𢆟',
'瘐' => '瘐',
'𤾡' => '𤾡',
'𤾸' => '𤾸',
'𥁄' => '𥁄',
'㿼' => '㿼',
'䀈' => '䀈',
'直' => '直',
'𥃳' => '𥃳',
'𥃲' => '𥃲',
'𥄙' => '𥄙',
'𥄳' => '𥄳',
'眞' => '眞',
'真' => '真',
'真' => '真',
'睊' => '睊',
'䀹' => '䀹',
'瞋' => '瞋',
'䁆' => '䁆',
'䂖' => '䂖',
'𥐝' => '𥐝',
'硎' => '硎',
'碌' => '碌',
'磌' => '磌',
'䃣' => '䃣',
'𥘦' => '𥘦',
'祖' => '祖',
'𥚚' => '𥚚',
'𥛅' => '𥛅',
'福' => '福',
'秫' => '秫',
'䄯' => '䄯',
'穀' => '穀',
'穊' => '穊',
'穏' => '穏',
'𥥼' => '𥥼',
'𥪧' => '𥪧',
'𥪧' => '𥪧',
'竮' => '竮',
'䈂' => '䈂',
'𥮫' => '𥮫',
'篆' => '篆',
'築' => '築',
'䈧' => '䈧',
'𥲀' => '𥲀',
'糒' => '糒',
'䊠' => '䊠',
'糨' => '糨',
'糣' => '糣',
'紀' => '紀',
'𥾆' => '𥾆',
'絣' => '絣',
'䌁' => '䌁',
'緇' => '緇',
'縂' => '縂',
'繅' => '繅',
'䌴' => '䌴',
'𦈨' => '𦈨',
'𦉇' => '𦉇',
'䍙' => '䍙',
'𦋙' => '𦋙',
'罺' => '罺',
'𦌾' => '𦌾',
'羕' => '羕',
'翺' => '翺',
'者' => '者',
'𦓚' => '𦓚',
'𦔣' => '𦔣',
'聠' => '聠',
'𦖨' => '𦖨',
'聰' => '聰',
'𣍟' => '𣍟',
'䏕' => '䏕',
'育' => '育',
'脃' => '脃',
'䐋' => '䐋',
'脾' => '脾',
'媵' => '媵',
'𦞧' => '𦞧',
'𦞵' => '𦞵',
'𣎓' => '𣎓',
'𣎜' => '𣎜',
'舁' => '舁',
'舄' => '舄',
'辞' => '辞',
'䑫' => '䑫',
'芑' => '芑',
'芋' => '芋',
'芝' => '芝',
'劳' => '劳',
'花' => '花',
'芳' => '芳',
'芽' => '芽',
'苦' => '苦',
'𦬼' => '𦬼',
'若' => '若',
'茝' => '茝',
'荣' => '荣',
'莭' => '莭',
'茣' => '茣',
'莽' => '莽',
'菧' => '菧',
'著' => '著',
'荓' => '荓',
'菊' => '菊',
'菌' => '菌',
'菜' => '菜',
'𦰶' => '𦰶',
'𦵫' => '𦵫',
'𦳕' => '𦳕',
'䔫' => '䔫',
'蓱' => '蓱',
'蓳' => '蓳',
'蔖' => '蔖',
'𧏊' => '𧏊',
'蕤' => '蕤',
'𦼬' => '𦼬',
'䕝' => '䕝',
'䕡' => '䕡',
'𦾱' => '𦾱',
'𧃒' => '𧃒',
'䕫' => '䕫',
'虐' => '虐',
'虜' => '虜',
'虧' => '虧',
'虩' => '虩',
'蚩' => '蚩',
'蚈' => '蚈',
'蜎' => '蜎',
'蛢' => '蛢',
'蝹' => '蝹',
'蜨' => '蜨',
'蝫' => '蝫',
'螆' => '螆',
'䗗' => '䗗',
'蟡' => '蟡',
'蠁' => '蠁',
'䗹' => '䗹',
'衠' => '衠',
'衣' => '衣',
'𧙧' => '𧙧',
'裗' => '裗',
'裞' => '裞',
'䘵' => '䘵',
'裺' => '裺',
'㒻' => '㒻',
'𧢮' => '𧢮',
'𧥦' => '𧥦',
'䚾' => '䚾',
'䛇' => '䛇',
'誠' => '誠',
'諭' => '諭',
'變' => '變',
'豕' => '豕',
'𧲨' => '𧲨',
'貫' => '貫',
'賁' => '賁',
'贛' => '贛',
'起' => '起',
'𧼯' => '𧼯',
'𠠄' => '𠠄',
'跋' => '跋',
'趼' => '趼',
'跰' => '跰',
'𠣞' => '𠣞',
'軔' => '軔',
'輸' => '輸',
'𨗒' => '𨗒',
'𨗭' => '𨗭',
'邔' => '邔',
'郱' => '郱',
'鄑' => '鄑',
'𨜮' => '𨜮',
'鄛' => '鄛',
'鈸' => '鈸',
'鋗' => '鋗',
'鋘' => '鋘',
'鉼' => '鉼',
'鏹' => '鏹',
'鐕' => '鐕',
'𨯺' => '𨯺',
'開' => '開',
'䦕' => '䦕',
'閷' => '閷',
'𨵷' => '𨵷',
'䧦' => '䧦',
'雃' => '雃',
'嶲' => '嶲',
'霣' => '霣',
'𩅅' => '𩅅',
'𩈚' => '𩈚',
'䩮' => '䩮',
'䩶' => '䩶',
'韠' => '韠',
'𩐊' => '𩐊',
'䪲' => '䪲',
'𩒖' => '𩒖',
'頋' => '頋',
'頋' => '頋',
'頩' => '頩',
'𩖶' => '𩖶',
'飢' => '飢',
'䬳' => '䬳',
'餩' => '餩',
'馧' => '馧',
'駂' => '駂',
'駾' => '駾',
'䯎' => '䯎',
'𩬰' => '𩬰',
'鬒' => '鬒',
'鱀' => '鱀',
'鳽' => '鳽',
'䳎' => '䳎',
'䳭' => '䳭',
'鵧' => '鵧',
'𪃎' => '𪃎',
'䳸' => '䳸',
'𪄅' => '𪄅',
'𪈎' => '𪈎',
'𪊑' => '𪊑',
'麻' => '麻',
'䵖' => '䵖',
'黹' => '黹',
'黾' => '黾',
'鼅' => '鼅',
'鼏' => '鼏',
'鼖' => '鼖',
'鼻' => '鼻',
'𪘀' => '𪘀',
);
<?php

class Normalizer extends Symfony\Polyfill\Intl\Normalizer\Normalizer
{



public const NONE = 2;
public const FORM_D = 4;
public const FORM_KD = 8;
public const FORM_C = 16;
public const FORM_KC = 32;
public const NFD = 4;
public const NFKD = 8;
public const NFC = 16;
public const NFKC = 32;
}
<?php










use Symfony\Polyfill\Intl\Idn as p;

if (extension_loaded('intl')) {
return;
}

if (\PHP_VERSION_ID >= 80000) {
return require __DIR__.'/bootstrap80.php';
}

if (!defined('U_IDNA_PROHIBITED_ERROR')) {
define('U_IDNA_PROHIBITED_ERROR', 66560);
}
if (!defined('U_IDNA_ERROR_START')) {
define('U_IDNA_ERROR_START', 66560);
}
if (!defined('U_IDNA_UNASSIGNED_ERROR')) {
define('U_IDNA_UNASSIGNED_ERROR', 66561);
}
if (!defined('U_IDNA_CHECK_BIDI_ERROR')) {
define('U_IDNA_CHECK_BIDI_ERROR', 66562);
}
if (!defined('U_IDNA_STD3_ASCII_RULES_ERROR')) {
define('U_IDNA_STD3_ASCII_RULES_ERROR', 66563);
}
if (!defined('U_IDNA_ACE_PREFIX_ERROR')) {
define('U_IDNA_ACE_PREFIX_ERROR', 66564);
}
if (!defined('U_IDNA_VERIFICATION_ERROR')) {
define('U_IDNA_VERIFICATION_ERROR', 66565);
}
if (!defined('U_IDNA_LABEL_TOO_LONG_ERROR')) {
define('U_IDNA_LABEL_TOO_LONG_ERROR', 66566);
}
if (!defined('U_IDNA_ZERO_LENGTH_LABEL_ERROR')) {
define('U_IDNA_ZERO_LENGTH_LABEL_ERROR', 66567);
}
if (!defined('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR')) {
define('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR', 66568);
}
if (!defined('U_IDNA_ERROR_LIMIT')) {
define('U_IDNA_ERROR_LIMIT', 66569);
}
if (!defined('U_STRINGPREP_PROHIBITED_ERROR')) {
define('U_STRINGPREP_PROHIBITED_ERROR', 66560);
}
if (!defined('U_STRINGPREP_UNASSIGNED_ERROR')) {
define('U_STRINGPREP_UNASSIGNED_ERROR', 66561);
}
if (!defined('U_STRINGPREP_CHECK_BIDI_ERROR')) {
define('U_STRINGPREP_CHECK_BIDI_ERROR', 66562);
}
if (!defined('IDNA_DEFAULT')) {
define('IDNA_DEFAULT', 0);
}
if (!defined('IDNA_ALLOW_UNASSIGNED')) {
define('IDNA_ALLOW_UNASSIGNED', 1);
}
if (!defined('IDNA_USE_STD3_RULES')) {
define('IDNA_USE_STD3_RULES', 2);
}
if (!defined('IDNA_CHECK_BIDI')) {
define('IDNA_CHECK_BIDI', 4);
}
if (!defined('IDNA_CHECK_CONTEXTJ')) {
define('IDNA_CHECK_CONTEXTJ', 8);
}
if (!defined('IDNA_NONTRANSITIONAL_TO_ASCII')) {
define('IDNA_NONTRANSITIONAL_TO_ASCII', 16);
}
if (!defined('IDNA_NONTRANSITIONAL_TO_UNICODE')) {
define('IDNA_NONTRANSITIONAL_TO_UNICODE', 32);
}
if (!defined('INTL_IDNA_VARIANT_2003')) {
define('INTL_IDNA_VARIANT_2003', 0);
}
if (!defined('INTL_IDNA_VARIANT_UTS46')) {
define('INTL_IDNA_VARIANT_UTS46', 1);
}
if (!defined('IDNA_ERROR_EMPTY_LABEL')) {
define('IDNA_ERROR_EMPTY_LABEL', 1);
}
if (!defined('IDNA_ERROR_LABEL_TOO_LONG')) {
define('IDNA_ERROR_LABEL_TOO_LONG', 2);
}
if (!defined('IDNA_ERROR_DOMAIN_NAME_TOO_LONG')) {
define('IDNA_ERROR_DOMAIN_NAME_TOO_LONG', 4);
}
if (!defined('IDNA_ERROR_LEADING_HYPHEN')) {
define('IDNA_ERROR_LEADING_HYPHEN', 8);
}
if (!defined('IDNA_ERROR_TRAILING_HYPHEN')) {
define('IDNA_ERROR_TRAILING_HYPHEN', 16);
}
if (!defined('IDNA_ERROR_HYPHEN_3_4')) {
define('IDNA_ERROR_HYPHEN_3_4', 32);
}
if (!defined('IDNA_ERROR_LEADING_COMBINING_MARK')) {
define('IDNA_ERROR_LEADING_COMBINING_MARK', 64);
}
if (!defined('IDNA_ERROR_DISALLOWED')) {
define('IDNA_ERROR_DISALLOWED', 128);
}
if (!defined('IDNA_ERROR_PUNYCODE')) {
define('IDNA_ERROR_PUNYCODE', 256);
}
if (!defined('IDNA_ERROR_LABEL_HAS_DOT')) {
define('IDNA_ERROR_LABEL_HAS_DOT', 512);
}
if (!defined('IDNA_ERROR_INVALID_ACE_LABEL')) {
define('IDNA_ERROR_INVALID_ACE_LABEL', 1024);
}
if (!defined('IDNA_ERROR_BIDI')) {
define('IDNA_ERROR_BIDI', 2048);
}
if (!defined('IDNA_ERROR_CONTEXTJ')) {
define('IDNA_ERROR_CONTEXTJ', 4096);
}

if (\PHP_VERSION_ID < 70400) {
if (!function_exists('idn_to_ascii')) {
function idn_to_ascii($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_2003, &$idna_info = null) { return p\Idn::idn_to_ascii($domain, $flags, $variant, $idna_info); }
}
if (!function_exists('idn_to_utf8')) {
function idn_to_utf8($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_2003, &$idna_info = null) { return p\Idn::idn_to_utf8($domain, $flags, $variant, $idna_info); }
}
} else {
if (!function_exists('idn_to_ascii')) {
function idn_to_ascii($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_UTS46, &$idna_info = null) { return p\Idn::idn_to_ascii($domain, $flags, $variant, $idna_info); }
}
if (!function_exists('idn_to_utf8')) {
function idn_to_utf8($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_UTS46, &$idna_info = null) { return p\Idn::idn_to_utf8($domain, $flags, $variant, $idna_info); }
}
}
<?php










namespace Symfony\Polyfill\Intl\Idn;




class Info
{
public $bidiDomain = false;
public $errors = 0;
public $validBidiDomain = true;
public $transitionalDifferent = false;
}
<?php










namespace Symfony\Polyfill\Intl\Idn;

use Exception;
use Normalizer;
use Symfony\Polyfill\Intl\Idn\Resources\unidata\DisallowedRanges;
use Symfony\Polyfill\Intl\Idn\Resources\unidata\Regex;






final class Idn
{
public const ERROR_EMPTY_LABEL = 1;
public const ERROR_LABEL_TOO_LONG = 2;
public const ERROR_DOMAIN_NAME_TOO_LONG = 4;
public const ERROR_LEADING_HYPHEN = 8;
public const ERROR_TRAILING_HYPHEN = 0x10;
public const ERROR_HYPHEN_3_4 = 0x20;
public const ERROR_LEADING_COMBINING_MARK = 0x40;
public const ERROR_DISALLOWED = 0x80;
public const ERROR_PUNYCODE = 0x100;
public const ERROR_LABEL_HAS_DOT = 0x200;
public const ERROR_INVALID_ACE_LABEL = 0x400;
public const ERROR_BIDI = 0x800;
public const ERROR_CONTEXTJ = 0x1000;
public const ERROR_CONTEXTO_PUNCTUATION = 0x2000;
public const ERROR_CONTEXTO_DIGITS = 0x4000;

public const INTL_IDNA_VARIANT_2003 = 0;
public const INTL_IDNA_VARIANT_UTS46 = 1;

public const IDNA_DEFAULT = 0;
public const IDNA_ALLOW_UNASSIGNED = 1;
public const IDNA_USE_STD3_RULES = 2;
public const IDNA_CHECK_BIDI = 4;
public const IDNA_CHECK_CONTEXTJ = 8;
public const IDNA_NONTRANSITIONAL_TO_ASCII = 16;
public const IDNA_NONTRANSITIONAL_TO_UNICODE = 32;

public const MAX_DOMAIN_SIZE = 253;
public const MAX_LABEL_SIZE = 63;

public const BASE = 36;
public const TMIN = 1;
public const TMAX = 26;
public const SKEW = 38;
public const DAMP = 700;
public const INITIAL_BIAS = 72;
public const INITIAL_N = 128;
public const DELIMITER = '-';
public const MAX_INT = 2147483647;







private static $basicToDigit = [
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,

-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,

-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,

-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,

-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,

-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,

-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,

-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
];




private static $virama;




private static $mapped;




private static $ignored;




private static $deviation;




private static $disallowed;




private static $disallowed_STD3_mapped;




private static $disallowed_STD3_valid;




private static $mappingTableLoaded = false;











public static function idn_to_ascii($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = [])
{
if (\PHP_VERSION_ID >= 70200 && self::INTL_IDNA_VARIANT_2003 === $variant) {
@trigger_error('idn_to_ascii(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED);
}

$options = [
'CheckHyphens' => true,
'CheckBidi' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 !== ($options & self::IDNA_CHECK_BIDI),
'CheckJoiners' => self::INTL_IDNA_VARIANT_UTS46 === $variant && 0 !== ($options & self::IDNA_CHECK_CONTEXTJ),
'UseSTD3ASCIIRules' => 0 !== ($options & self::IDNA_USE_STD3_RULES),
'Transitional_Processing' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 === ($options & self::IDNA_NONTRANSITIONAL_TO_ASCII),
'VerifyDnsLength' => true,
];
$info = new Info();
$labels = self::process((string) $domainName, $options, $info);

foreach ($labels as $i => $label) {

 if (1 === preg_match('/[^\x00-\x7F]/', $label)) {
try {
$label = 'xn--'.self::punycodeEncode($label);
} catch (Exception $e) {
$info->errors |= self::ERROR_PUNYCODE;
}

$labels[$i] = $label;
}
}

if ($options['VerifyDnsLength']) {
self::validateDomainAndLabelLength($labels, $info);
}

$idna_info = [
'result' => implode('.', $labels),
'isTransitionalDifferent' => $info->transitionalDifferent,
'errors' => $info->errors,
];

return 0 === $info->errors ? $idna_info['result'] : false;
}











public static function idn_to_utf8($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = [])
{
if (\PHP_VERSION_ID >= 70200 && self::INTL_IDNA_VARIANT_2003 === $variant) {
@trigger_error('idn_to_utf8(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED);
}

$info = new Info();
$labels = self::process((string) $domainName, [
'CheckHyphens' => true,
'CheckBidi' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 !== ($options & self::IDNA_CHECK_BIDI),
'CheckJoiners' => self::INTL_IDNA_VARIANT_UTS46 === $variant && 0 !== ($options & self::IDNA_CHECK_CONTEXTJ),
'UseSTD3ASCIIRules' => 0 !== ($options & self::IDNA_USE_STD3_RULES),
'Transitional_Processing' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 === ($options & self::IDNA_NONTRANSITIONAL_TO_UNICODE),
], $info);
$idna_info = [
'result' => implode('.', $labels),
'isTransitionalDifferent' => $info->transitionalDifferent,
'errors' => $info->errors,
];

return 0 === $info->errors ? $idna_info['result'] : false;
}






private static function isValidContextJ(array $codePoints, $label)
{
if (!isset(self::$virama)) {
self::$virama = require __DIR__.\DIRECTORY_SEPARATOR.'Resources'.\DIRECTORY_SEPARATOR.'unidata'.\DIRECTORY_SEPARATOR.'virama.php';
}

$offset = 0;

foreach ($codePoints as $i => $codePoint) {
if (0x200C !== $codePoint && 0x200D !== $codePoint) {
continue;
}

if (!isset($codePoints[$i - 1])) {
return false;
}


 if (isset(self::$virama[$codePoints[$i - 1]])) {
continue;
}


 
 
 if (0x200C === $codePoint && 1 === preg_match(Regex::ZWNJ, $label, $matches, \PREG_OFFSET_CAPTURE, $offset)) {
$offset += \strlen($matches[1][0]);

continue;
}

return false;
}

return true;
}









private static function mapCodePoints($input, array $options, Info $info)
{
$str = '';
$useSTD3ASCIIRules = $options['UseSTD3ASCIIRules'];
$transitional = $options['Transitional_Processing'];

foreach (self::utf8Decode($input) as $codePoint) {
$data = self::lookupCodePointStatus($codePoint, $useSTD3ASCIIRules);

switch ($data['status']) {
case 'disallowed':
$info->errors |= self::ERROR_DISALLOWED;



case 'valid':
$str .= mb_chr($codePoint, 'utf-8');

break;

case 'ignored':

 break;

case 'mapped':
$str .= $data['mapping'];

break;

case 'deviation':
$info->transitionalDifferent = true;
$str .= ($transitional ? $data['mapping'] : mb_chr($codePoint, 'utf-8'));

break;
}
}

return $str;
}









private static function process($domain, array $options, Info $info)
{

 
 $checkForEmptyLabels = !isset($options['VerifyDnsLength']) || $options['VerifyDnsLength'];

if ($checkForEmptyLabels && '' === $domain) {
$info->errors |= self::ERROR_EMPTY_LABEL;

return [$domain];
}


 $domain = self::mapCodePoints($domain, $options, $info);


 if (!Normalizer::isNormalized($domain, Normalizer::FORM_C)) {
$domain = Normalizer::normalize($domain, Normalizer::FORM_C);
}


 $labels = explode('.', $domain);
$lastLabelIndex = \count($labels) - 1;


 foreach ($labels as $i => $label) {
$validationOptions = $options;

if ('xn--' === substr($label, 0, 4)) {
try {
$label = self::punycodeDecode(substr($label, 4));
} catch (Exception $e) {
$info->errors |= self::ERROR_PUNYCODE;

continue;
}

$validationOptions['Transitional_Processing'] = false;
$labels[$i] = $label;
}

self::validateLabel($label, $info, $validationOptions, $i > 0 && $i === $lastLabelIndex);
}

if ($info->bidiDomain && !$info->validBidiDomain) {
$info->errors |= self::ERROR_BIDI;
}


 
 
 
 return $labels;
}






private static function validateBidiLabel($label, Info $info)
{
if (1 === preg_match(Regex::RTL_LABEL, $label)) {
$info->bidiDomain = true;


 
 if (1 !== preg_match(Regex::BIDI_STEP_1_RTL, $label)) {
$info->validBidiDomain = false;

return;
}


 
 if (1 === preg_match(Regex::BIDI_STEP_2, $label)) {
$info->validBidiDomain = false;

return;
}


 
 if (1 !== preg_match(Regex::BIDI_STEP_3, $label)) {
$info->validBidiDomain = false;

return;
}


 if (1 === preg_match(Regex::BIDI_STEP_4_AN, $label) && 1 === preg_match(Regex::BIDI_STEP_4_EN, $label)) {
$info->validBidiDomain = false;

return;
}

return;
}


 
 
 if (1 !== preg_match(Regex::BIDI_STEP_1_LTR, $label)) {
$info->validBidiDomain = false;

return;
}


 
 if (1 === preg_match(Regex::BIDI_STEP_5, $label)) {
$info->validBidiDomain = false;

return;
}


 
 if (1 !== preg_match(Regex::BIDI_STEP_6, $label)) {
$info->validBidiDomain = false;

return;
}
}




private static function validateDomainAndLabelLength(array $labels, Info $info)
{
$maxDomainSize = self::MAX_DOMAIN_SIZE;
$length = \count($labels);


 $domainLength = $length - 1;


 
 
 
 if ($length > 1 && '' === $labels[$length - 1]) {
++$maxDomainSize;
--$length;
}

for ($i = 0; $i < $length; ++$i) {
$bytes = \strlen($labels[$i]);
$domainLength += $bytes;

if ($bytes > self::MAX_LABEL_SIZE) {
$info->errors |= self::ERROR_LABEL_TOO_LONG;
}
}

if ($domainLength > $maxDomainSize) {
$info->errors |= self::ERROR_DOMAIN_NAME_TOO_LONG;
}
}








private static function validateLabel($label, Info $info, array $options, $canBeEmpty)
{
if ('' === $label) {
if (!$canBeEmpty && (!isset($options['VerifyDnsLength']) || $options['VerifyDnsLength'])) {
$info->errors |= self::ERROR_EMPTY_LABEL;
}

return;
}


 if (!Normalizer::isNormalized($label, Normalizer::FORM_C)) {
$info->errors |= self::ERROR_INVALID_ACE_LABEL;
}

$codePoints = self::utf8Decode($label);

if ($options['CheckHyphens']) {

 
 if (isset($codePoints[2], $codePoints[3]) && 0x002D === $codePoints[2] && 0x002D === $codePoints[3]) {
$info->errors |= self::ERROR_HYPHEN_3_4;
}


 
 if ('-' === substr($label, 0, 1)) {
$info->errors |= self::ERROR_LEADING_HYPHEN;
}

if ('-' === substr($label, -1, 1)) {
$info->errors |= self::ERROR_TRAILING_HYPHEN;
}
}


 if (false !== strpos($label, '.')) {
$info->errors |= self::ERROR_LABEL_HAS_DOT;
}


 if (1 === preg_match(Regex::COMBINING_MARK, $label)) {
$info->errors |= self::ERROR_LEADING_COMBINING_MARK;
}


 
 $transitional = $options['Transitional_Processing'];
$useSTD3ASCIIRules = $options['UseSTD3ASCIIRules'];

foreach ($codePoints as $codePoint) {
$data = self::lookupCodePointStatus($codePoint, $useSTD3ASCIIRules);
$status = $data['status'];

if ('valid' === $status || (!$transitional && 'deviation' === $status)) {
continue;
}

$info->errors |= self::ERROR_DISALLOWED;

break;
}


 
 
 if ($options['CheckJoiners'] && !self::isValidContextJ($codePoints, $label)) {
$info->errors |= self::ERROR_CONTEXTJ;
}


 
 if ($options['CheckBidi'] && (!$info->bidiDomain || $info->validBidiDomain)) {
self::validateBidiLabel($label, $info);
}
}








private static function punycodeDecode($input)
{
$n = self::INITIAL_N;
$out = 0;
$i = 0;
$bias = self::INITIAL_BIAS;
$lastDelimIndex = strrpos($input, self::DELIMITER);
$b = false === $lastDelimIndex ? 0 : $lastDelimIndex;
$inputLength = \strlen($input);
$output = [];
$bytes = array_map('ord', str_split($input));

for ($j = 0; $j < $b; ++$j) {
if ($bytes[$j] > 0x7F) {
throw new Exception('Invalid input');
}

$output[$out++] = $input[$j];
}

if ($b > 0) {
++$b;
}

for ($in = $b; $in < $inputLength; ++$out) {
$oldi = $i;
$w = 1;

for ($k = self::BASE; ; $k += self::BASE) {
if ($in >= $inputLength) {
throw new Exception('Invalid input');
}

$digit = self::$basicToDigit[$bytes[$in++] & 0xFF];

if ($digit < 0) {
throw new Exception('Invalid input');
}

if ($digit > intdiv(self::MAX_INT - $i, $w)) {
throw new Exception('Integer overflow');
}

$i += $digit * $w;

if ($k <= $bias) {
$t = self::TMIN;
} elseif ($k >= $bias + self::TMAX) {
$t = self::TMAX;
} else {
$t = $k - $bias;
}

if ($digit < $t) {
break;
}

$baseMinusT = self::BASE - $t;

if ($w > intdiv(self::MAX_INT, $baseMinusT)) {
throw new Exception('Integer overflow');
}

$w *= $baseMinusT;
}

$outPlusOne = $out + 1;
$bias = self::adaptBias($i - $oldi, $outPlusOne, 0 === $oldi);

if (intdiv($i, $outPlusOne) > self::MAX_INT - $n) {
throw new Exception('Integer overflow');
}

$n += intdiv($i, $outPlusOne);
$i %= $outPlusOne;
array_splice($output, $i++, 0, [mb_chr($n, 'utf-8')]);
}

return implode('', $output);
}








private static function punycodeEncode($input)
{
$n = self::INITIAL_N;
$delta = 0;
$out = 0;
$bias = self::INITIAL_BIAS;
$inputLength = 0;
$output = '';
$iter = self::utf8Decode($input);

foreach ($iter as $codePoint) {
++$inputLength;

if ($codePoint < 0x80) {
$output .= \chr($codePoint);
++$out;
}
}

$h = $out;
$b = $out;

if ($b > 0) {
$output .= self::DELIMITER;
++$out;
}

while ($h < $inputLength) {
$m = self::MAX_INT;

foreach ($iter as $codePoint) {
if ($codePoint >= $n && $codePoint < $m) {
$m = $codePoint;
}
}

if ($m - $n > intdiv(self::MAX_INT - $delta, $h + 1)) {
throw new Exception('Integer overflow');
}

$delta += ($m - $n) * ($h + 1);
$n = $m;

foreach ($iter as $codePoint) {
if ($codePoint < $n && 0 === ++$delta) {
throw new Exception('Integer overflow');
}

if ($codePoint === $n) {
$q = $delta;

for ($k = self::BASE; ; $k += self::BASE) {
if ($k <= $bias) {
$t = self::TMIN;
} elseif ($k >= $bias + self::TMAX) {
$t = self::TMAX;
} else {
$t = $k - $bias;
}

if ($q < $t) {
break;
}

$qMinusT = $q - $t;
$baseMinusT = self::BASE - $t;
$output .= self::encodeDigit($t + ($qMinusT) % ($baseMinusT), false);
++$out;
$q = intdiv($qMinusT, $baseMinusT);
}

$output .= self::encodeDigit($q, false);
++$out;
$bias = self::adaptBias($delta, $h + 1, $h === $b);
$delta = 0;
++$h;
}
}

++$delta;
++$n;
}

return $output;
}










private static function adaptBias($delta, $numPoints, $firstTime)
{

 $delta = $firstTime ? intdiv($delta, self::DAMP) : $delta >> 1;
$delta += intdiv($delta, $numPoints);
$k = 0;

while ($delta > ((self::BASE - self::TMIN) * self::TMAX) >> 1) {
$delta = intdiv($delta, self::BASE - self::TMIN);
$k += self::BASE;
}

return $k + intdiv((self::BASE - self::TMIN + 1) * $delta, $delta + self::SKEW);
}







private static function encodeDigit($d, $flag)
{
return \chr($d + 22 + 75 * ($d < 26 ? 1 : 0) - (($flag ? 1 : 0) << 5));
}











private static function utf8Decode($input)
{
$bytesSeen = 0;
$bytesNeeded = 0;
$lowerBoundary = 0x80;
$upperBoundary = 0xBF;
$codePoint = 0;
$codePoints = [];
$length = \strlen($input);

for ($i = 0; $i < $length; ++$i) {
$byte = \ord($input[$i]);

if (0 === $bytesNeeded) {
if ($byte >= 0x00 && $byte <= 0x7F) {
$codePoints[] = $byte;

continue;
}

if ($byte >= 0xC2 && $byte <= 0xDF) {
$bytesNeeded = 1;
$codePoint = $byte & 0x1F;
} elseif ($byte >= 0xE0 && $byte <= 0xEF) {
if (0xE0 === $byte) {
$lowerBoundary = 0xA0;
} elseif (0xED === $byte) {
$upperBoundary = 0x9F;
}

$bytesNeeded = 2;
$codePoint = $byte & 0xF;
} elseif ($byte >= 0xF0 && $byte <= 0xF4) {
if (0xF0 === $byte) {
$lowerBoundary = 0x90;
} elseif (0xF4 === $byte) {
$upperBoundary = 0x8F;
}

$bytesNeeded = 3;
$codePoint = $byte & 0x7;
} else {
$codePoints[] = 0xFFFD;
}

continue;
}

if ($byte < $lowerBoundary || $byte > $upperBoundary) {
$codePoint = 0;
$bytesNeeded = 0;
$bytesSeen = 0;
$lowerBoundary = 0x80;
$upperBoundary = 0xBF;
--$i;
$codePoints[] = 0xFFFD;

continue;
}

$lowerBoundary = 0x80;
$upperBoundary = 0xBF;
$codePoint = ($codePoint << 6) | ($byte & 0x3F);

if (++$bytesSeen !== $bytesNeeded) {
continue;
}

$codePoints[] = $codePoint;
$codePoint = 0;
$bytesNeeded = 0;
$bytesSeen = 0;
}


 if (0 !== $bytesNeeded) {
$codePoints[] = 0xFFFD;
}

return $codePoints;
}







private static function lookupCodePointStatus($codePoint, $useSTD3ASCIIRules)
{
if (!self::$mappingTableLoaded) {
self::$mappingTableLoaded = true;
self::$mapped = require __DIR__.'/Resources/unidata/mapped.php';
self::$ignored = require __DIR__.'/Resources/unidata/ignored.php';
self::$deviation = require __DIR__.'/Resources/unidata/deviation.php';
self::$disallowed = require __DIR__.'/Resources/unidata/disallowed.php';
self::$disallowed_STD3_mapped = require __DIR__.'/Resources/unidata/disallowed_STD3_mapped.php';
self::$disallowed_STD3_valid = require __DIR__.'/Resources/unidata/disallowed_STD3_valid.php';
}

if (isset(self::$mapped[$codePoint])) {
return ['status' => 'mapped', 'mapping' => self::$mapped[$codePoint]];
}

if (isset(self::$ignored[$codePoint])) {
return ['status' => 'ignored'];
}

if (isset(self::$deviation[$codePoint])) {
return ['status' => 'deviation', 'mapping' => self::$deviation[$codePoint]];
}

if (isset(self::$disallowed[$codePoint]) || DisallowedRanges::inRange($codePoint)) {
return ['status' => 'disallowed'];
}

$isDisallowedMapped = isset(self::$disallowed_STD3_mapped[$codePoint]);

if ($isDisallowedMapped || isset(self::$disallowed_STD3_valid[$codePoint])) {
$status = 'disallowed';

if (!$useSTD3ASCIIRules) {
$status = $isDisallowedMapped ? 'mapped' : 'valid';
}

if ($isDisallowedMapped) {
return ['status' => $status, 'mapping' => self::$disallowed_STD3_mapped[$codePoint]];
}

return ['status' => $status];
}

return ['status' => 'valid'];
}
}
<?php










use Symfony\Polyfill\Intl\Idn as p;

if (!defined('U_IDNA_PROHIBITED_ERROR')) {
define('U_IDNA_PROHIBITED_ERROR', 66560);
}
if (!defined('U_IDNA_ERROR_START')) {
define('U_IDNA_ERROR_START', 66560);
}
if (!defined('U_IDNA_UNASSIGNED_ERROR')) {
define('U_IDNA_UNASSIGNED_ERROR', 66561);
}
if (!defined('U_IDNA_CHECK_BIDI_ERROR')) {
define('U_IDNA_CHECK_BIDI_ERROR', 66562);
}
if (!defined('U_IDNA_STD3_ASCII_RULES_ERROR')) {
define('U_IDNA_STD3_ASCII_RULES_ERROR', 66563);
}
if (!defined('U_IDNA_ACE_PREFIX_ERROR')) {
define('U_IDNA_ACE_PREFIX_ERROR', 66564);
}
if (!defined('U_IDNA_VERIFICATION_ERROR')) {
define('U_IDNA_VERIFICATION_ERROR', 66565);
}
if (!defined('U_IDNA_LABEL_TOO_LONG_ERROR')) {
define('U_IDNA_LABEL_TOO_LONG_ERROR', 66566);
}
if (!defined('U_IDNA_ZERO_LENGTH_LABEL_ERROR')) {
define('U_IDNA_ZERO_LENGTH_LABEL_ERROR', 66567);
}
if (!defined('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR')) {
define('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR', 66568);
}
if (!defined('U_IDNA_ERROR_LIMIT')) {
define('U_IDNA_ERROR_LIMIT', 66569);
}
if (!defined('U_STRINGPREP_PROHIBITED_ERROR')) {
define('U_STRINGPREP_PROHIBITED_ERROR', 66560);
}
if (!defined('U_STRINGPREP_UNASSIGNED_ERROR')) {
define('U_STRINGPREP_UNASSIGNED_ERROR', 66561);
}
if (!defined('U_STRINGPREP_CHECK_BIDI_ERROR')) {
define('U_STRINGPREP_CHECK_BIDI_ERROR', 66562);
}
if (!defined('IDNA_DEFAULT')) {
define('IDNA_DEFAULT', 0);
}
if (!defined('IDNA_ALLOW_UNASSIGNED')) {
define('IDNA_ALLOW_UNASSIGNED', 1);
}
if (!defined('IDNA_USE_STD3_RULES')) {
define('IDNA_USE_STD3_RULES', 2);
}
if (!defined('IDNA_CHECK_BIDI')) {
define('IDNA_CHECK_BIDI', 4);
}
if (!defined('IDNA_CHECK_CONTEXTJ')) {
define('IDNA_CHECK_CONTEXTJ', 8);
}
if (!defined('IDNA_NONTRANSITIONAL_TO_ASCII')) {
define('IDNA_NONTRANSITIONAL_TO_ASCII', 16);
}
if (!defined('IDNA_NONTRANSITIONAL_TO_UNICODE')) {
define('IDNA_NONTRANSITIONAL_TO_UNICODE', 32);
}
if (!defined('INTL_IDNA_VARIANT_UTS46')) {
define('INTL_IDNA_VARIANT_UTS46', 1);
}
if (!defined('IDNA_ERROR_EMPTY_LABEL')) {
define('IDNA_ERROR_EMPTY_LABEL', 1);
}
if (!defined('IDNA_ERROR_LABEL_TOO_LONG')) {
define('IDNA_ERROR_LABEL_TOO_LONG', 2);
}
if (!defined('IDNA_ERROR_DOMAIN_NAME_TOO_LONG')) {
define('IDNA_ERROR_DOMAIN_NAME_TOO_LONG', 4);
}
if (!defined('IDNA_ERROR_LEADING_HYPHEN')) {
define('IDNA_ERROR_LEADING_HYPHEN', 8);
}
if (!defined('IDNA_ERROR_TRAILING_HYPHEN')) {
define('IDNA_ERROR_TRAILING_HYPHEN', 16);
}
if (!defined('IDNA_ERROR_HYPHEN_3_4')) {
define('IDNA_ERROR_HYPHEN_3_4', 32);
}
if (!defined('IDNA_ERROR_LEADING_COMBINING_MARK')) {
define('IDNA_ERROR_LEADING_COMBINING_MARK', 64);
}
if (!defined('IDNA_ERROR_DISALLOWED')) {
define('IDNA_ERROR_DISALLOWED', 128);
}
if (!defined('IDNA_ERROR_PUNYCODE')) {
define('IDNA_ERROR_PUNYCODE', 256);
}
if (!defined('IDNA_ERROR_LABEL_HAS_DOT')) {
define('IDNA_ERROR_LABEL_HAS_DOT', 512);
}
if (!defined('IDNA_ERROR_INVALID_ACE_LABEL')) {
define('IDNA_ERROR_INVALID_ACE_LABEL', 1024);
}
if (!defined('IDNA_ERROR_BIDI')) {
define('IDNA_ERROR_BIDI', 2048);
}
if (!defined('IDNA_ERROR_CONTEXTJ')) {
define('IDNA_ERROR_CONTEXTJ', 4096);
}

if (!function_exists('idn_to_ascii')) {
function idn_to_ascii(?string $domain, ?int $flags = 0, ?int $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = null): string|false { return p\Idn::idn_to_ascii((string) $domain, (int) $flags, (int) $variant, $idna_info); }
}
if (!function_exists('idn_to_utf8')) {
function idn_to_utf8(?string $domain, ?int $flags = 0, ?int $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = null): string|false { return p\Idn::idn_to_utf8((string) $domain, (int) $flags, (int) $variant, $idna_info); }
}
<?php

return array (
0 => true,
1 => true,
2 => true,
3 => true,
4 => true,
5 => true,
6 => true,
7 => true,
8 => true,
9 => true,
10 => true,
11 => true,
12 => true,
13 => true,
14 => true,
15 => true,
16 => true,
17 => true,
18 => true,
19 => true,
20 => true,
21 => true,
22 => true,
23 => true,
24 => true,
25 => true,
26 => true,
27 => true,
28 => true,
29 => true,
30 => true,
31 => true,
32 => true,
33 => true,
34 => true,
35 => true,
36 => true,
37 => true,
38 => true,
39 => true,
40 => true,
41 => true,
42 => true,
43 => true,
44 => true,
47 => true,
58 => true,
59 => true,
60 => true,
61 => true,
62 => true,
63 => true,
64 => true,
91 => true,
92 => true,
93 => true,
94 => true,
95 => true,
96 => true,
123 => true,
124 => true,
125 => true,
126 => true,
127 => true,
8800 => true,
8814 => true,
8815 => true,
);
<?php

namespace Symfony\Polyfill\Intl\Idn\Resources\unidata;




final class DisallowedRanges
{





public static function inRange($codePoint)
{
if ($codePoint >= 128 && $codePoint <= 159) {
return true;
}

if ($codePoint >= 2155 && $codePoint <= 2207) {
return true;
}

if ($codePoint >= 3676 && $codePoint <= 3712) {
return true;
}

if ($codePoint >= 3808 && $codePoint <= 3839) {
return true;
}

if ($codePoint >= 4059 && $codePoint <= 4095) {
return true;
}

if ($codePoint >= 4256 && $codePoint <= 4293) {
return true;
}

if ($codePoint >= 6849 && $codePoint <= 6911) {
return true;
}

if ($codePoint >= 11859 && $codePoint <= 11903) {
return true;
}

if ($codePoint >= 42955 && $codePoint <= 42996) {
return true;
}

if ($codePoint >= 55296 && $codePoint <= 57343) {
return true;
}

if ($codePoint >= 57344 && $codePoint <= 63743) {
return true;
}

if ($codePoint >= 64218 && $codePoint <= 64255) {
return true;
}

if ($codePoint >= 64976 && $codePoint <= 65007) {
return true;
}

if ($codePoint >= 65630 && $codePoint <= 65663) {
return true;
}

if ($codePoint >= 65953 && $codePoint <= 65999) {
return true;
}

if ($codePoint >= 66046 && $codePoint <= 66175) {
return true;
}

if ($codePoint >= 66518 && $codePoint <= 66559) {
return true;
}

if ($codePoint >= 66928 && $codePoint <= 67071) {
return true;
}

if ($codePoint >= 67432 && $codePoint <= 67583) {
return true;
}

if ($codePoint >= 67760 && $codePoint <= 67807) {
return true;
}

if ($codePoint >= 67904 && $codePoint <= 67967) {
return true;
}

if ($codePoint >= 68256 && $codePoint <= 68287) {
return true;
}

if ($codePoint >= 68528 && $codePoint <= 68607) {
return true;
}

if ($codePoint >= 68681 && $codePoint <= 68735) {
return true;
}

if ($codePoint >= 68922 && $codePoint <= 69215) {
return true;
}

if ($codePoint >= 69298 && $codePoint <= 69375) {
return true;
}

if ($codePoint >= 69466 && $codePoint <= 69551) {
return true;
}

if ($codePoint >= 70207 && $codePoint <= 70271) {
return true;
}

if ($codePoint >= 70517 && $codePoint <= 70655) {
return true;
}

if ($codePoint >= 70874 && $codePoint <= 71039) {
return true;
}

if ($codePoint >= 71134 && $codePoint <= 71167) {
return true;
}

if ($codePoint >= 71370 && $codePoint <= 71423) {
return true;
}

if ($codePoint >= 71488 && $codePoint <= 71679) {
return true;
}

if ($codePoint >= 71740 && $codePoint <= 71839) {
return true;
}

if ($codePoint >= 72026 && $codePoint <= 72095) {
return true;
}

if ($codePoint >= 72441 && $codePoint <= 72703) {
return true;
}

if ($codePoint >= 72887 && $codePoint <= 72959) {
return true;
}

if ($codePoint >= 73130 && $codePoint <= 73439) {
return true;
}

if ($codePoint >= 73465 && $codePoint <= 73647) {
return true;
}

if ($codePoint >= 74650 && $codePoint <= 74751) {
return true;
}

if ($codePoint >= 75076 && $codePoint <= 77823) {
return true;
}

if ($codePoint >= 78905 && $codePoint <= 82943) {
return true;
}

if ($codePoint >= 83527 && $codePoint <= 92159) {
return true;
}

if ($codePoint >= 92784 && $codePoint <= 92879) {
return true;
}

if ($codePoint >= 93072 && $codePoint <= 93759) {
return true;
}

if ($codePoint >= 93851 && $codePoint <= 93951) {
return true;
}

if ($codePoint >= 94112 && $codePoint <= 94175) {
return true;
}

if ($codePoint >= 101590 && $codePoint <= 101631) {
return true;
}

if ($codePoint >= 101641 && $codePoint <= 110591) {
return true;
}

if ($codePoint >= 110879 && $codePoint <= 110927) {
return true;
}

if ($codePoint >= 111356 && $codePoint <= 113663) {
return true;
}

if ($codePoint >= 113828 && $codePoint <= 118783) {
return true;
}

if ($codePoint >= 119366 && $codePoint <= 119519) {
return true;
}

if ($codePoint >= 119673 && $codePoint <= 119807) {
return true;
}

if ($codePoint >= 121520 && $codePoint <= 122879) {
return true;
}

if ($codePoint >= 122923 && $codePoint <= 123135) {
return true;
}

if ($codePoint >= 123216 && $codePoint <= 123583) {
return true;
}

if ($codePoint >= 123648 && $codePoint <= 124927) {
return true;
}

if ($codePoint >= 125143 && $codePoint <= 125183) {
return true;
}

if ($codePoint >= 125280 && $codePoint <= 126064) {
return true;
}

if ($codePoint >= 126133 && $codePoint <= 126208) {
return true;
}

if ($codePoint >= 126270 && $codePoint <= 126463) {
return true;
}

if ($codePoint >= 126652 && $codePoint <= 126703) {
return true;
}

if ($codePoint >= 126706 && $codePoint <= 126975) {
return true;
}

if ($codePoint >= 127406 && $codePoint <= 127461) {
return true;
}

if ($codePoint >= 127590 && $codePoint <= 127743) {
return true;
}

if ($codePoint >= 129202 && $codePoint <= 129279) {
return true;
}

if ($codePoint >= 129751 && $codePoint <= 129791) {
return true;
}

if ($codePoint >= 129995 && $codePoint <= 130031) {
return true;
}

if ($codePoint >= 130042 && $codePoint <= 131069) {
return true;
}

if ($codePoint >= 173790 && $codePoint <= 173823) {
return true;
}

if ($codePoint >= 191457 && $codePoint <= 194559) {
return true;
}

if ($codePoint >= 195102 && $codePoint <= 196605) {
return true;
}

if ($codePoint >= 201547 && $codePoint <= 262141) {
return true;
}

if ($codePoint >= 262144 && $codePoint <= 327677) {
return true;
}

if ($codePoint >= 327680 && $codePoint <= 393213) {
return true;
}

if ($codePoint >= 393216 && $codePoint <= 458749) {
return true;
}

if ($codePoint >= 458752 && $codePoint <= 524285) {
return true;
}

if ($codePoint >= 524288 && $codePoint <= 589821) {
return true;
}

if ($codePoint >= 589824 && $codePoint <= 655357) {
return true;
}

if ($codePoint >= 655360 && $codePoint <= 720893) {
return true;
}

if ($codePoint >= 720896 && $codePoint <= 786429) {
return true;
}

if ($codePoint >= 786432 && $codePoint <= 851965) {
return true;
}

if ($codePoint >= 851968 && $codePoint <= 917501) {
return true;
}

if ($codePoint >= 917536 && $codePoint <= 917631) {
return true;
}

if ($codePoint >= 917632 && $codePoint <= 917759) {
return true;
}

if ($codePoint >= 918000 && $codePoint <= 983037) {
return true;
}

if ($codePoint >= 983040 && $codePoint <= 1048573) {
return true;
}

if ($codePoint >= 1048576 && $codePoint <= 1114109) {
return true;
}

return false;
}
}
<?php

return array (
888 => true,
889 => true,
896 => true,
897 => true,
898 => true,
899 => true,
907 => true,
909 => true,
930 => true,
1216 => true,
1328 => true,
1367 => true,
1368 => true,
1419 => true,
1420 => true,
1424 => true,
1480 => true,
1481 => true,
1482 => true,
1483 => true,
1484 => true,
1485 => true,
1486 => true,
1487 => true,
1515 => true,
1516 => true,
1517 => true,
1518 => true,
1525 => true,
1526 => true,
1527 => true,
1528 => true,
1529 => true,
1530 => true,
1531 => true,
1532 => true,
1533 => true,
1534 => true,
1535 => true,
1536 => true,
1537 => true,
1538 => true,
1539 => true,
1540 => true,
1541 => true,
1564 => true,
1565 => true,
1757 => true,
1806 => true,
1807 => true,
1867 => true,
1868 => true,
1970 => true,
1971 => true,
1972 => true,
1973 => true,
1974 => true,
1975 => true,
1976 => true,
1977 => true,
1978 => true,
1979 => true,
1980 => true,
1981 => true,
1982 => true,
1983 => true,
2043 => true,
2044 => true,
2094 => true,
2095 => true,
2111 => true,
2140 => true,
2141 => true,
2143 => true,
2229 => true,
2248 => true,
2249 => true,
2250 => true,
2251 => true,
2252 => true,
2253 => true,
2254 => true,
2255 => true,
2256 => true,
2257 => true,
2258 => true,
2274 => true,
2436 => true,
2445 => true,
2446 => true,
2449 => true,
2450 => true,
2473 => true,
2481 => true,
2483 => true,
2484 => true,
2485 => true,
2490 => true,
2491 => true,
2501 => true,
2502 => true,
2505 => true,
2506 => true,
2511 => true,
2512 => true,
2513 => true,
2514 => true,
2515 => true,
2516 => true,
2517 => true,
2518 => true,
2520 => true,
2521 => true,
2522 => true,
2523 => true,
2526 => true,
2532 => true,
2533 => true,
2559 => true,
2560 => true,
2564 => true,
2571 => true,
2572 => true,
2573 => true,
2574 => true,
2577 => true,
2578 => true,
2601 => true,
2609 => true,
2612 => true,
2615 => true,
2618 => true,
2619 => true,
2621 => true,
2627 => true,
2628 => true,
2629 => true,
2630 => true,
2633 => true,
2634 => true,
2638 => true,
2639 => true,
2640 => true,
2642 => true,
2643 => true,
2644 => true,
2645 => true,
2646 => true,
2647 => true,
2648 => true,
2653 => true,
2655 => true,
2656 => true,
2657 => true,
2658 => true,
2659 => true,
2660 => true,
2661 => true,
2679 => true,
2680 => true,
2681 => true,
2682 => true,
2683 => true,
2684 => true,
2685 => true,
2686 => true,
2687 => true,
2688 => true,
2692 => true,
2702 => true,
2706 => true,
2729 => true,
2737 => true,
2740 => true,
2746 => true,
2747 => true,
2758 => true,
2762 => true,
2766 => true,
2767 => true,
2769 => true,
2770 => true,
2771 => true,
2772 => true,
2773 => true,
2774 => true,
2775 => true,
2776 => true,
2777 => true,
2778 => true,
2779 => true,
2780 => true,
2781 => true,
2782 => true,
2783 => true,
2788 => true,
2789 => true,
2802 => true,
2803 => true,
2804 => true,
2805 => true,
2806 => true,
2807 => true,
2808 => true,
2816 => true,
2820 => true,
2829 => true,
2830 => true,
2833 => true,
2834 => true,
2857 => true,
2865 => true,
2868 => true,
2874 => true,
2875 => true,
2885 => true,
2886 => true,
2889 => true,
2890 => true,
2894 => true,
2895 => true,
2896 => true,
2897 => true,
2898 => true,
2899 => true,
2900 => true,
2904 => true,
2905 => true,
2906 => true,
2907 => true,
2910 => true,
2916 => true,
2917 => true,
2936 => true,
2937 => true,
2938 => true,
2939 => true,
2940 => true,
2941 => true,
2942 => true,
2943 => true,
2944 => true,
2945 => true,
2948 => true,
2955 => true,
2956 => true,
2957 => true,
2961 => true,
2966 => true,
2967 => true,
2968 => true,
2971 => true,
2973 => true,
2976 => true,
2977 => true,
2978 => true,
2981 => true,
2982 => true,
2983 => true,
2987 => true,
2988 => true,
2989 => true,
3002 => true,
3003 => true,
3004 => true,
3005 => true,
3011 => true,
3012 => true,
3013 => true,
3017 => true,
3022 => true,
3023 => true,
3025 => true,
3026 => true,
3027 => true,
3028 => true,
3029 => true,
3030 => true,
3032 => true,
3033 => true,
3034 => true,
3035 => true,
3036 => true,
3037 => true,
3038 => true,
3039 => true,
3040 => true,
3041 => true,
3042 => true,
3043 => true,
3044 => true,
3045 => true,
3067 => true,
3068 => true,
3069 => true,
3070 => true,
3071 => true,
3085 => true,
3089 => true,
3113 => true,
3130 => true,
3131 => true,
3132 => true,
3141 => true,
3145 => true,
3150 => true,
3151 => true,
3152 => true,
3153 => true,
3154 => true,
3155 => true,
3156 => true,
3159 => true,
3163 => true,
3164 => true,
3165 => true,
3166 => true,
3167 => true,
3172 => true,
3173 => true,
3184 => true,
3185 => true,
3186 => true,
3187 => true,
3188 => true,
3189 => true,
3190 => true,
3213 => true,
3217 => true,
3241 => true,
3252 => true,
3258 => true,
3259 => true,
3269 => true,
3273 => true,
3278 => true,
3279 => true,
3280 => true,
3281 => true,
3282 => true,
3283 => true,
3284 => true,
3287 => true,
3288 => true,
3289 => true,
3290 => true,
3291 => true,
3292 => true,
3293 => true,
3295 => true,
3300 => true,
3301 => true,
3312 => true,
3315 => true,
3316 => true,
3317 => true,
3318 => true,
3319 => true,
3320 => true,
3321 => true,
3322 => true,
3323 => true,
3324 => true,
3325 => true,
3326 => true,
3327 => true,
3341 => true,
3345 => true,
3397 => true,
3401 => true,
3408 => true,
3409 => true,
3410 => true,
3411 => true,
3428 => true,
3429 => true,
3456 => true,
3460 => true,
3479 => true,
3480 => true,
3481 => true,
3506 => true,
3516 => true,
3518 => true,
3519 => true,
3527 => true,
3528 => true,
3529 => true,
3531 => true,
3532 => true,
3533 => true,
3534 => true,
3541 => true,
3543 => true,
3552 => true,
3553 => true,
3554 => true,
3555 => true,
3556 => true,
3557 => true,
3568 => true,
3569 => true,
3573 => true,
3574 => true,
3575 => true,
3576 => true,
3577 => true,
3578 => true,
3579 => true,
3580 => true,
3581 => true,
3582 => true,
3583 => true,
3584 => true,
3643 => true,
3644 => true,
3645 => true,
3646 => true,
3715 => true,
3717 => true,
3723 => true,
3748 => true,
3750 => true,
3774 => true,
3775 => true,
3781 => true,
3783 => true,
3790 => true,
3791 => true,
3802 => true,
3803 => true,
3912 => true,
3949 => true,
3950 => true,
3951 => true,
3952 => true,
3992 => true,
4029 => true,
4045 => true,
4294 => true,
4296 => true,
4297 => true,
4298 => true,
4299 => true,
4300 => true,
4302 => true,
4303 => true,
4447 => true,
4448 => true,
4681 => true,
4686 => true,
4687 => true,
4695 => true,
4697 => true,
4702 => true,
4703 => true,
4745 => true,
4750 => true,
4751 => true,
4785 => true,
4790 => true,
4791 => true,
4799 => true,
4801 => true,
4806 => true,
4807 => true,
4823 => true,
4881 => true,
4886 => true,
4887 => true,
4955 => true,
4956 => true,
4989 => true,
4990 => true,
4991 => true,
5018 => true,
5019 => true,
5020 => true,
5021 => true,
5022 => true,
5023 => true,
5110 => true,
5111 => true,
5118 => true,
5119 => true,
5760 => true,
5789 => true,
5790 => true,
5791 => true,
5881 => true,
5882 => true,
5883 => true,
5884 => true,
5885 => true,
5886 => true,
5887 => true,
5901 => true,
5909 => true,
5910 => true,
5911 => true,
5912 => true,
5913 => true,
5914 => true,
5915 => true,
5916 => true,
5917 => true,
5918 => true,
5919 => true,
5943 => true,
5944 => true,
5945 => true,
5946 => true,
5947 => true,
5948 => true,
5949 => true,
5950 => true,
5951 => true,
5972 => true,
5973 => true,
5974 => true,
5975 => true,
5976 => true,
5977 => true,
5978 => true,
5979 => true,
5980 => true,
5981 => true,
5982 => true,
5983 => true,
5997 => true,
6001 => true,
6004 => true,
6005 => true,
6006 => true,
6007 => true,
6008 => true,
6009 => true,
6010 => true,
6011 => true,
6012 => true,
6013 => true,
6014 => true,
6015 => true,
6068 => true,
6069 => true,
6110 => true,
6111 => true,
6122 => true,
6123 => true,
6124 => true,
6125 => true,
6126 => true,
6127 => true,
6138 => true,
6139 => true,
6140 => true,
6141 => true,
6142 => true,
6143 => true,
6150 => true,
6158 => true,
6159 => true,
6170 => true,
6171 => true,
6172 => true,
6173 => true,
6174 => true,
6175 => true,
6265 => true,
6266 => true,
6267 => true,
6268 => true,
6269 => true,
6270 => true,
6271 => true,
6315 => true,
6316 => true,
6317 => true,
6318 => true,
6319 => true,
6390 => true,
6391 => true,
6392 => true,
6393 => true,
6394 => true,
6395 => true,
6396 => true,
6397 => true,
6398 => true,
6399 => true,
6431 => true,
6444 => true,
6445 => true,
6446 => true,
6447 => true,
6460 => true,
6461 => true,
6462 => true,
6463 => true,
6465 => true,
6466 => true,
6467 => true,
6510 => true,
6511 => true,
6517 => true,
6518 => true,
6519 => true,
6520 => true,
6521 => true,
6522 => true,
6523 => true,
6524 => true,
6525 => true,
6526 => true,
6527 => true,
6572 => true,
6573 => true,
6574 => true,
6575 => true,
6602 => true,
6603 => true,
6604 => true,
6605 => true,
6606 => true,
6607 => true,
6619 => true,
6620 => true,
6621 => true,
6684 => true,
6685 => true,
6751 => true,
6781 => true,
6782 => true,
6794 => true,
6795 => true,
6796 => true,
6797 => true,
6798 => true,
6799 => true,
6810 => true,
6811 => true,
6812 => true,
6813 => true,
6814 => true,
6815 => true,
6830 => true,
6831 => true,
6988 => true,
6989 => true,
6990 => true,
6991 => true,
7037 => true,
7038 => true,
7039 => true,
7156 => true,
7157 => true,
7158 => true,
7159 => true,
7160 => true,
7161 => true,
7162 => true,
7163 => true,
7224 => true,
7225 => true,
7226 => true,
7242 => true,
7243 => true,
7244 => true,
7305 => true,
7306 => true,
7307 => true,
7308 => true,
7309 => true,
7310 => true,
7311 => true,
7355 => true,
7356 => true,
7368 => true,
7369 => true,
7370 => true,
7371 => true,
7372 => true,
7373 => true,
7374 => true,
7375 => true,
7419 => true,
7420 => true,
7421 => true,
7422 => true,
7423 => true,
7674 => true,
7958 => true,
7959 => true,
7966 => true,
7967 => true,
8006 => true,
8007 => true,
8014 => true,
8015 => true,
8024 => true,
8026 => true,
8028 => true,
8030 => true,
8062 => true,
8063 => true,
8117 => true,
8133 => true,
8148 => true,
8149 => true,
8156 => true,
8176 => true,
8177 => true,
8181 => true,
8191 => true,
8206 => true,
8207 => true,
8228 => true,
8229 => true,
8230 => true,
8232 => true,
8233 => true,
8234 => true,
8235 => true,
8236 => true,
8237 => true,
8238 => true,
8289 => true,
8290 => true,
8291 => true,
8293 => true,
8294 => true,
8295 => true,
8296 => true,
8297 => true,
8298 => true,
8299 => true,
8300 => true,
8301 => true,
8302 => true,
8303 => true,
8306 => true,
8307 => true,
8335 => true,
8349 => true,
8350 => true,
8351 => true,
8384 => true,
8385 => true,
8386 => true,
8387 => true,
8388 => true,
8389 => true,
8390 => true,
8391 => true,
8392 => true,
8393 => true,
8394 => true,
8395 => true,
8396 => true,
8397 => true,
8398 => true,
8399 => true,
8433 => true,
8434 => true,
8435 => true,
8436 => true,
8437 => true,
8438 => true,
8439 => true,
8440 => true,
8441 => true,
8442 => true,
8443 => true,
8444 => true,
8445 => true,
8446 => true,
8447 => true,
8498 => true,
8579 => true,
8588 => true,
8589 => true,
8590 => true,
8591 => true,
9255 => true,
9256 => true,
9257 => true,
9258 => true,
9259 => true,
9260 => true,
9261 => true,
9262 => true,
9263 => true,
9264 => true,
9265 => true,
9266 => true,
9267 => true,
9268 => true,
9269 => true,
9270 => true,
9271 => true,
9272 => true,
9273 => true,
9274 => true,
9275 => true,
9276 => true,
9277 => true,
9278 => true,
9279 => true,
9291 => true,
9292 => true,
9293 => true,
9294 => true,
9295 => true,
9296 => true,
9297 => true,
9298 => true,
9299 => true,
9300 => true,
9301 => true,
9302 => true,
9303 => true,
9304 => true,
9305 => true,
9306 => true,
9307 => true,
9308 => true,
9309 => true,
9310 => true,
9311 => true,
9352 => true,
9353 => true,
9354 => true,
9355 => true,
9356 => true,
9357 => true,
9358 => true,
9359 => true,
9360 => true,
9361 => true,
9362 => true,
9363 => true,
9364 => true,
9365 => true,
9366 => true,
9367 => true,
9368 => true,
9369 => true,
9370 => true,
9371 => true,
11124 => true,
11125 => true,
11158 => true,
11311 => true,
11359 => true,
11508 => true,
11509 => true,
11510 => true,
11511 => true,
11512 => true,
11558 => true,
11560 => true,
11561 => true,
11562 => true,
11563 => true,
11564 => true,
11566 => true,
11567 => true,
11624 => true,
11625 => true,
11626 => true,
11627 => true,
11628 => true,
11629 => true,
11630 => true,
11633 => true,
11634 => true,
11635 => true,
11636 => true,
11637 => true,
11638 => true,
11639 => true,
11640 => true,
11641 => true,
11642 => true,
11643 => true,
11644 => true,
11645 => true,
11646 => true,
11671 => true,
11672 => true,
11673 => true,
11674 => true,
11675 => true,
11676 => true,
11677 => true,
11678 => true,
11679 => true,
11687 => true,
11695 => true,
11703 => true,
11711 => true,
11719 => true,
11727 => true,
11735 => true,
11743 => true,
11930 => true,
12020 => true,
12021 => true,
12022 => true,
12023 => true,
12024 => true,
12025 => true,
12026 => true,
12027 => true,
12028 => true,
12029 => true,
12030 => true,
12031 => true,
12246 => true,
12247 => true,
12248 => true,
12249 => true,
12250 => true,
12251 => true,
12252 => true,
12253 => true,
12254 => true,
12255 => true,
12256 => true,
12257 => true,
12258 => true,
12259 => true,
12260 => true,
12261 => true,
12262 => true,
12263 => true,
12264 => true,
12265 => true,
12266 => true,
12267 => true,
12268 => true,
12269 => true,
12270 => true,
12271 => true,
12272 => true,
12273 => true,
12274 => true,
12275 => true,
12276 => true,
12277 => true,
12278 => true,
12279 => true,
12280 => true,
12281 => true,
12282 => true,
12283 => true,
12284 => true,
12285 => true,
12286 => true,
12287 => true,
12352 => true,
12439 => true,
12440 => true,
12544 => true,
12545 => true,
12546 => true,
12547 => true,
12548 => true,
12592 => true,
12644 => true,
12687 => true,
12772 => true,
12773 => true,
12774 => true,
12775 => true,
12776 => true,
12777 => true,
12778 => true,
12779 => true,
12780 => true,
12781 => true,
12782 => true,
12783 => true,
12831 => true,
13250 => true,
13255 => true,
13272 => true,
40957 => true,
40958 => true,
40959 => true,
42125 => true,
42126 => true,
42127 => true,
42183 => true,
42184 => true,
42185 => true,
42186 => true,
42187 => true,
42188 => true,
42189 => true,
42190 => true,
42191 => true,
42540 => true,
42541 => true,
42542 => true,
42543 => true,
42544 => true,
42545 => true,
42546 => true,
42547 => true,
42548 => true,
42549 => true,
42550 => true,
42551 => true,
42552 => true,
42553 => true,
42554 => true,
42555 => true,
42556 => true,
42557 => true,
42558 => true,
42559 => true,
42744 => true,
42745 => true,
42746 => true,
42747 => true,
42748 => true,
42749 => true,
42750 => true,
42751 => true,
42944 => true,
42945 => true,
43053 => true,
43054 => true,
43055 => true,
43066 => true,
43067 => true,
43068 => true,
43069 => true,
43070 => true,
43071 => true,
43128 => true,
43129 => true,
43130 => true,
43131 => true,
43132 => true,
43133 => true,
43134 => true,
43135 => true,
43206 => true,
43207 => true,
43208 => true,
43209 => true,
43210 => true,
43211 => true,
43212 => true,
43213 => true,
43226 => true,
43227 => true,
43228 => true,
43229 => true,
43230 => true,
43231 => true,
43348 => true,
43349 => true,
43350 => true,
43351 => true,
43352 => true,
43353 => true,
43354 => true,
43355 => true,
43356 => true,
43357 => true,
43358 => true,
43389 => true,
43390 => true,
43391 => true,
43470 => true,
43482 => true,
43483 => true,
43484 => true,
43485 => true,
43519 => true,
43575 => true,
43576 => true,
43577 => true,
43578 => true,
43579 => true,
43580 => true,
43581 => true,
43582 => true,
43583 => true,
43598 => true,
43599 => true,
43610 => true,
43611 => true,
43715 => true,
43716 => true,
43717 => true,
43718 => true,
43719 => true,
43720 => true,
43721 => true,
43722 => true,
43723 => true,
43724 => true,
43725 => true,
43726 => true,
43727 => true,
43728 => true,
43729 => true,
43730 => true,
43731 => true,
43732 => true,
43733 => true,
43734 => true,
43735 => true,
43736 => true,
43737 => true,
43738 => true,
43767 => true,
43768 => true,
43769 => true,
43770 => true,
43771 => true,
43772 => true,
43773 => true,
43774 => true,
43775 => true,
43776 => true,
43783 => true,
43784 => true,
43791 => true,
43792 => true,
43799 => true,
43800 => true,
43801 => true,
43802 => true,
43803 => true,
43804 => true,
43805 => true,
43806 => true,
43807 => true,
43815 => true,
43823 => true,
43884 => true,
43885 => true,
43886 => true,
43887 => true,
44014 => true,
44015 => true,
44026 => true,
44027 => true,
44028 => true,
44029 => true,
44030 => true,
44031 => true,
55204 => true,
55205 => true,
55206 => true,
55207 => true,
55208 => true,
55209 => true,
55210 => true,
55211 => true,
55212 => true,
55213 => true,
55214 => true,
55215 => true,
55239 => true,
55240 => true,
55241 => true,
55242 => true,
55292 => true,
55293 => true,
55294 => true,
55295 => true,
64110 => true,
64111 => true,
64263 => true,
64264 => true,
64265 => true,
64266 => true,
64267 => true,
64268 => true,
64269 => true,
64270 => true,
64271 => true,
64272 => true,
64273 => true,
64274 => true,
64280 => true,
64281 => true,
64282 => true,
64283 => true,
64284 => true,
64311 => true,
64317 => true,
64319 => true,
64322 => true,
64325 => true,
64450 => true,
64451 => true,
64452 => true,
64453 => true,
64454 => true,
64455 => true,
64456 => true,
64457 => true,
64458 => true,
64459 => true,
64460 => true,
64461 => true,
64462 => true,
64463 => true,
64464 => true,
64465 => true,
64466 => true,
64832 => true,
64833 => true,
64834 => true,
64835 => true,
64836 => true,
64837 => true,
64838 => true,
64839 => true,
64840 => true,
64841 => true,
64842 => true,
64843 => true,
64844 => true,
64845 => true,
64846 => true,
64847 => true,
64912 => true,
64913 => true,
64968 => true,
64969 => true,
64970 => true,
64971 => true,
64972 => true,
64973 => true,
64974 => true,
64975 => true,
65022 => true,
65023 => true,
65042 => true,
65049 => true,
65050 => true,
65051 => true,
65052 => true,
65053 => true,
65054 => true,
65055 => true,
65072 => true,
65106 => true,
65107 => true,
65127 => true,
65132 => true,
65133 => true,
65134 => true,
65135 => true,
65141 => true,
65277 => true,
65278 => true,
65280 => true,
65440 => true,
65471 => true,
65472 => true,
65473 => true,
65480 => true,
65481 => true,
65488 => true,
65489 => true,
65496 => true,
65497 => true,
65501 => true,
65502 => true,
65503 => true,
65511 => true,
65519 => true,
65520 => true,
65521 => true,
65522 => true,
65523 => true,
65524 => true,
65525 => true,
65526 => true,
65527 => true,
65528 => true,
65529 => true,
65530 => true,
65531 => true,
65532 => true,
65533 => true,
65534 => true,
65535 => true,
65548 => true,
65575 => true,
65595 => true,
65598 => true,
65614 => true,
65615 => true,
65787 => true,
65788 => true,
65789 => true,
65790 => true,
65791 => true,
65795 => true,
65796 => true,
65797 => true,
65798 => true,
65844 => true,
65845 => true,
65846 => true,
65935 => true,
65949 => true,
65950 => true,
65951 => true,
66205 => true,
66206 => true,
66207 => true,
66257 => true,
66258 => true,
66259 => true,
66260 => true,
66261 => true,
66262 => true,
66263 => true,
66264 => true,
66265 => true,
66266 => true,
66267 => true,
66268 => true,
66269 => true,
66270 => true,
66271 => true,
66300 => true,
66301 => true,
66302 => true,
66303 => true,
66340 => true,
66341 => true,
66342 => true,
66343 => true,
66344 => true,
66345 => true,
66346 => true,
66347 => true,
66348 => true,
66379 => true,
66380 => true,
66381 => true,
66382 => true,
66383 => true,
66427 => true,
66428 => true,
66429 => true,
66430 => true,
66431 => true,
66462 => true,
66500 => true,
66501 => true,
66502 => true,
66503 => true,
66718 => true,
66719 => true,
66730 => true,
66731 => true,
66732 => true,
66733 => true,
66734 => true,
66735 => true,
66772 => true,
66773 => true,
66774 => true,
66775 => true,
66812 => true,
66813 => true,
66814 => true,
66815 => true,
66856 => true,
66857 => true,
66858 => true,
66859 => true,
66860 => true,
66861 => true,
66862 => true,
66863 => true,
66916 => true,
66917 => true,
66918 => true,
66919 => true,
66920 => true,
66921 => true,
66922 => true,
66923 => true,
66924 => true,
66925 => true,
66926 => true,
67383 => true,
67384 => true,
67385 => true,
67386 => true,
67387 => true,
67388 => true,
67389 => true,
67390 => true,
67391 => true,
67414 => true,
67415 => true,
67416 => true,
67417 => true,
67418 => true,
67419 => true,
67420 => true,
67421 => true,
67422 => true,
67423 => true,
67590 => true,
67591 => true,
67593 => true,
67638 => true,
67641 => true,
67642 => true,
67643 => true,
67645 => true,
67646 => true,
67670 => true,
67743 => true,
67744 => true,
67745 => true,
67746 => true,
67747 => true,
67748 => true,
67749 => true,
67750 => true,
67827 => true,
67830 => true,
67831 => true,
67832 => true,
67833 => true,
67834 => true,
67868 => true,
67869 => true,
67870 => true,
67898 => true,
67899 => true,
67900 => true,
67901 => true,
67902 => true,
68024 => true,
68025 => true,
68026 => true,
68027 => true,
68048 => true,
68049 => true,
68100 => true,
68103 => true,
68104 => true,
68105 => true,
68106 => true,
68107 => true,
68116 => true,
68120 => true,
68150 => true,
68151 => true,
68155 => true,
68156 => true,
68157 => true,
68158 => true,
68169 => true,
68170 => true,
68171 => true,
68172 => true,
68173 => true,
68174 => true,
68175 => true,
68185 => true,
68186 => true,
68187 => true,
68188 => true,
68189 => true,
68190 => true,
68191 => true,
68327 => true,
68328 => true,
68329 => true,
68330 => true,
68343 => true,
68344 => true,
68345 => true,
68346 => true,
68347 => true,
68348 => true,
68349 => true,
68350 => true,
68351 => true,
68406 => true,
68407 => true,
68408 => true,
68438 => true,
68439 => true,
68467 => true,
68468 => true,
68469 => true,
68470 => true,
68471 => true,
68498 => true,
68499 => true,
68500 => true,
68501 => true,
68502 => true,
68503 => true,
68504 => true,
68509 => true,
68510 => true,
68511 => true,
68512 => true,
68513 => true,
68514 => true,
68515 => true,
68516 => true,
68517 => true,
68518 => true,
68519 => true,
68520 => true,
68787 => true,
68788 => true,
68789 => true,
68790 => true,
68791 => true,
68792 => true,
68793 => true,
68794 => true,
68795 => true,
68796 => true,
68797 => true,
68798 => true,
68799 => true,
68851 => true,
68852 => true,
68853 => true,
68854 => true,
68855 => true,
68856 => true,
68857 => true,
68904 => true,
68905 => true,
68906 => true,
68907 => true,
68908 => true,
68909 => true,
68910 => true,
68911 => true,
69247 => true,
69290 => true,
69294 => true,
69295 => true,
69416 => true,
69417 => true,
69418 => true,
69419 => true,
69420 => true,
69421 => true,
69422 => true,
69423 => true,
69580 => true,
69581 => true,
69582 => true,
69583 => true,
69584 => true,
69585 => true,
69586 => true,
69587 => true,
69588 => true,
69589 => true,
69590 => true,
69591 => true,
69592 => true,
69593 => true,
69594 => true,
69595 => true,
69596 => true,
69597 => true,
69598 => true,
69599 => true,
69623 => true,
69624 => true,
69625 => true,
69626 => true,
69627 => true,
69628 => true,
69629 => true,
69630 => true,
69631 => true,
69710 => true,
69711 => true,
69712 => true,
69713 => true,
69744 => true,
69745 => true,
69746 => true,
69747 => true,
69748 => true,
69749 => true,
69750 => true,
69751 => true,
69752 => true,
69753 => true,
69754 => true,
69755 => true,
69756 => true,
69757 => true,
69758 => true,
69821 => true,
69826 => true,
69827 => true,
69828 => true,
69829 => true,
69830 => true,
69831 => true,
69832 => true,
69833 => true,
69834 => true,
69835 => true,
69836 => true,
69837 => true,
69838 => true,
69839 => true,
69865 => true,
69866 => true,
69867 => true,
69868 => true,
69869 => true,
69870 => true,
69871 => true,
69882 => true,
69883 => true,
69884 => true,
69885 => true,
69886 => true,
69887 => true,
69941 => true,
69960 => true,
69961 => true,
69962 => true,
69963 => true,
69964 => true,
69965 => true,
69966 => true,
69967 => true,
70007 => true,
70008 => true,
70009 => true,
70010 => true,
70011 => true,
70012 => true,
70013 => true,
70014 => true,
70015 => true,
70112 => true,
70133 => true,
70134 => true,
70135 => true,
70136 => true,
70137 => true,
70138 => true,
70139 => true,
70140 => true,
70141 => true,
70142 => true,
70143 => true,
70162 => true,
70279 => true,
70281 => true,
70286 => true,
70302 => true,
70314 => true,
70315 => true,
70316 => true,
70317 => true,
70318 => true,
70319 => true,
70379 => true,
70380 => true,
70381 => true,
70382 => true,
70383 => true,
70394 => true,
70395 => true,
70396 => true,
70397 => true,
70398 => true,
70399 => true,
70404 => true,
70413 => true,
70414 => true,
70417 => true,
70418 => true,
70441 => true,
70449 => true,
70452 => true,
70458 => true,
70469 => true,
70470 => true,
70473 => true,
70474 => true,
70478 => true,
70479 => true,
70481 => true,
70482 => true,
70483 => true,
70484 => true,
70485 => true,
70486 => true,
70488 => true,
70489 => true,
70490 => true,
70491 => true,
70492 => true,
70500 => true,
70501 => true,
70509 => true,
70510 => true,
70511 => true,
70748 => true,
70754 => true,
70755 => true,
70756 => true,
70757 => true,
70758 => true,
70759 => true,
70760 => true,
70761 => true,
70762 => true,
70763 => true,
70764 => true,
70765 => true,
70766 => true,
70767 => true,
70768 => true,
70769 => true,
70770 => true,
70771 => true,
70772 => true,
70773 => true,
70774 => true,
70775 => true,
70776 => true,
70777 => true,
70778 => true,
70779 => true,
70780 => true,
70781 => true,
70782 => true,
70783 => true,
70856 => true,
70857 => true,
70858 => true,
70859 => true,
70860 => true,
70861 => true,
70862 => true,
70863 => true,
71094 => true,
71095 => true,
71237 => true,
71238 => true,
71239 => true,
71240 => true,
71241 => true,
71242 => true,
71243 => true,
71244 => true,
71245 => true,
71246 => true,
71247 => true,
71258 => true,
71259 => true,
71260 => true,
71261 => true,
71262 => true,
71263 => true,
71277 => true,
71278 => true,
71279 => true,
71280 => true,
71281 => true,
71282 => true,
71283 => true,
71284 => true,
71285 => true,
71286 => true,
71287 => true,
71288 => true,
71289 => true,
71290 => true,
71291 => true,
71292 => true,
71293 => true,
71294 => true,
71295 => true,
71353 => true,
71354 => true,
71355 => true,
71356 => true,
71357 => true,
71358 => true,
71359 => true,
71451 => true,
71452 => true,
71468 => true,
71469 => true,
71470 => true,
71471 => true,
71923 => true,
71924 => true,
71925 => true,
71926 => true,
71927 => true,
71928 => true,
71929 => true,
71930 => true,
71931 => true,
71932 => true,
71933 => true,
71934 => true,
71943 => true,
71944 => true,
71946 => true,
71947 => true,
71956 => true,
71959 => true,
71990 => true,
71993 => true,
71994 => true,
72007 => true,
72008 => true,
72009 => true,
72010 => true,
72011 => true,
72012 => true,
72013 => true,
72014 => true,
72015 => true,
72104 => true,
72105 => true,
72152 => true,
72153 => true,
72165 => true,
72166 => true,
72167 => true,
72168 => true,
72169 => true,
72170 => true,
72171 => true,
72172 => true,
72173 => true,
72174 => true,
72175 => true,
72176 => true,
72177 => true,
72178 => true,
72179 => true,
72180 => true,
72181 => true,
72182 => true,
72183 => true,
72184 => true,
72185 => true,
72186 => true,
72187 => true,
72188 => true,
72189 => true,
72190 => true,
72191 => true,
72264 => true,
72265 => true,
72266 => true,
72267 => true,
72268 => true,
72269 => true,
72270 => true,
72271 => true,
72355 => true,
72356 => true,
72357 => true,
72358 => true,
72359 => true,
72360 => true,
72361 => true,
72362 => true,
72363 => true,
72364 => true,
72365 => true,
72366 => true,
72367 => true,
72368 => true,
72369 => true,
72370 => true,
72371 => true,
72372 => true,
72373 => true,
72374 => true,
72375 => true,
72376 => true,
72377 => true,
72378 => true,
72379 => true,
72380 => true,
72381 => true,
72382 => true,
72383 => true,
72713 => true,
72759 => true,
72774 => true,
72775 => true,
72776 => true,
72777 => true,
72778 => true,
72779 => true,
72780 => true,
72781 => true,
72782 => true,
72783 => true,
72813 => true,
72814 => true,
72815 => true,
72848 => true,
72849 => true,
72872 => true,
72967 => true,
72970 => true,
73015 => true,
73016 => true,
73017 => true,
73019 => true,
73022 => true,
73032 => true,
73033 => true,
73034 => true,
73035 => true,
73036 => true,
73037 => true,
73038 => true,
73039 => true,
73050 => true,
73051 => true,
73052 => true,
73053 => true,
73054 => true,
73055 => true,
73062 => true,
73065 => true,
73103 => true,
73106 => true,
73113 => true,
73114 => true,
73115 => true,
73116 => true,
73117 => true,
73118 => true,
73119 => true,
73649 => true,
73650 => true,
73651 => true,
73652 => true,
73653 => true,
73654 => true,
73655 => true,
73656 => true,
73657 => true,
73658 => true,
73659 => true,
73660 => true,
73661 => true,
73662 => true,
73663 => true,
73714 => true,
73715 => true,
73716 => true,
73717 => true,
73718 => true,
73719 => true,
73720 => true,
73721 => true,
73722 => true,
73723 => true,
73724 => true,
73725 => true,
73726 => true,
74863 => true,
74869 => true,
74870 => true,
74871 => true,
74872 => true,
74873 => true,
74874 => true,
74875 => true,
74876 => true,
74877 => true,
74878 => true,
74879 => true,
78895 => true,
78896 => true,
78897 => true,
78898 => true,
78899 => true,
78900 => true,
78901 => true,
78902 => true,
78903 => true,
78904 => true,
92729 => true,
92730 => true,
92731 => true,
92732 => true,
92733 => true,
92734 => true,
92735 => true,
92767 => true,
92778 => true,
92779 => true,
92780 => true,
92781 => true,
92910 => true,
92911 => true,
92918 => true,
92919 => true,
92920 => true,
92921 => true,
92922 => true,
92923 => true,
92924 => true,
92925 => true,
92926 => true,
92927 => true,
92998 => true,
92999 => true,
93000 => true,
93001 => true,
93002 => true,
93003 => true,
93004 => true,
93005 => true,
93006 => true,
93007 => true,
93018 => true,
93026 => true,
93048 => true,
93049 => true,
93050 => true,
93051 => true,
93052 => true,
94027 => true,
94028 => true,
94029 => true,
94030 => true,
94088 => true,
94089 => true,
94090 => true,
94091 => true,
94092 => true,
94093 => true,
94094 => true,
94181 => true,
94182 => true,
94183 => true,
94184 => true,
94185 => true,
94186 => true,
94187 => true,
94188 => true,
94189 => true,
94190 => true,
94191 => true,
94194 => true,
94195 => true,
94196 => true,
94197 => true,
94198 => true,
94199 => true,
94200 => true,
94201 => true,
94202 => true,
94203 => true,
94204 => true,
94205 => true,
94206 => true,
94207 => true,
100344 => true,
100345 => true,
100346 => true,
100347 => true,
100348 => true,
100349 => true,
100350 => true,
100351 => true,
110931 => true,
110932 => true,
110933 => true,
110934 => true,
110935 => true,
110936 => true,
110937 => true,
110938 => true,
110939 => true,
110940 => true,
110941 => true,
110942 => true,
110943 => true,
110944 => true,
110945 => true,
110946 => true,
110947 => true,
110952 => true,
110953 => true,
110954 => true,
110955 => true,
110956 => true,
110957 => true,
110958 => true,
110959 => true,
113771 => true,
113772 => true,
113773 => true,
113774 => true,
113775 => true,
113789 => true,
113790 => true,
113791 => true,
113801 => true,
113802 => true,
113803 => true,
113804 => true,
113805 => true,
113806 => true,
113807 => true,
113818 => true,
113819 => true,
119030 => true,
119031 => true,
119032 => true,
119033 => true,
119034 => true,
119035 => true,
119036 => true,
119037 => true,
119038 => true,
119039 => true,
119079 => true,
119080 => true,
119155 => true,
119156 => true,
119157 => true,
119158 => true,
119159 => true,
119160 => true,
119161 => true,
119162 => true,
119273 => true,
119274 => true,
119275 => true,
119276 => true,
119277 => true,
119278 => true,
119279 => true,
119280 => true,
119281 => true,
119282 => true,
119283 => true,
119284 => true,
119285 => true,
119286 => true,
119287 => true,
119288 => true,
119289 => true,
119290 => true,
119291 => true,
119292 => true,
119293 => true,
119294 => true,
119295 => true,
119540 => true,
119541 => true,
119542 => true,
119543 => true,
119544 => true,
119545 => true,
119546 => true,
119547 => true,
119548 => true,
119549 => true,
119550 => true,
119551 => true,
119639 => true,
119640 => true,
119641 => true,
119642 => true,
119643 => true,
119644 => true,
119645 => true,
119646 => true,
119647 => true,
119893 => true,
119965 => true,
119968 => true,
119969 => true,
119971 => true,
119972 => true,
119975 => true,
119976 => true,
119981 => true,
119994 => true,
119996 => true,
120004 => true,
120070 => true,
120075 => true,
120076 => true,
120085 => true,
120093 => true,
120122 => true,
120127 => true,
120133 => true,
120135 => true,
120136 => true,
120137 => true,
120145 => true,
120486 => true,
120487 => true,
120780 => true,
120781 => true,
121484 => true,
121485 => true,
121486 => true,
121487 => true,
121488 => true,
121489 => true,
121490 => true,
121491 => true,
121492 => true,
121493 => true,
121494 => true,
121495 => true,
121496 => true,
121497 => true,
121498 => true,
121504 => true,
122887 => true,
122905 => true,
122906 => true,
122914 => true,
122917 => true,
123181 => true,
123182 => true,
123183 => true,
123198 => true,
123199 => true,
123210 => true,
123211 => true,
123212 => true,
123213 => true,
123642 => true,
123643 => true,
123644 => true,
123645 => true,
123646 => true,
125125 => true,
125126 => true,
125260 => true,
125261 => true,
125262 => true,
125263 => true,
125274 => true,
125275 => true,
125276 => true,
125277 => true,
126468 => true,
126496 => true,
126499 => true,
126501 => true,
126502 => true,
126504 => true,
126515 => true,
126520 => true,
126522 => true,
126524 => true,
126525 => true,
126526 => true,
126527 => true,
126528 => true,
126529 => true,
126531 => true,
126532 => true,
126533 => true,
126534 => true,
126536 => true,
126538 => true,
126540 => true,
126544 => true,
126547 => true,
126549 => true,
126550 => true,
126552 => true,
126554 => true,
126556 => true,
126558 => true,
126560 => true,
126563 => true,
126565 => true,
126566 => true,
126571 => true,
126579 => true,
126584 => true,
126589 => true,
126591 => true,
126602 => true,
126620 => true,
126621 => true,
126622 => true,
126623 => true,
126624 => true,
126628 => true,
126634 => true,
127020 => true,
127021 => true,
127022 => true,
127023 => true,
127124 => true,
127125 => true,
127126 => true,
127127 => true,
127128 => true,
127129 => true,
127130 => true,
127131 => true,
127132 => true,
127133 => true,
127134 => true,
127135 => true,
127151 => true,
127152 => true,
127168 => true,
127184 => true,
127222 => true,
127223 => true,
127224 => true,
127225 => true,
127226 => true,
127227 => true,
127228 => true,
127229 => true,
127230 => true,
127231 => true,
127232 => true,
127491 => true,
127492 => true,
127493 => true,
127494 => true,
127495 => true,
127496 => true,
127497 => true,
127498 => true,
127499 => true,
127500 => true,
127501 => true,
127502 => true,
127503 => true,
127548 => true,
127549 => true,
127550 => true,
127551 => true,
127561 => true,
127562 => true,
127563 => true,
127564 => true,
127565 => true,
127566 => true,
127567 => true,
127570 => true,
127571 => true,
127572 => true,
127573 => true,
127574 => true,
127575 => true,
127576 => true,
127577 => true,
127578 => true,
127579 => true,
127580 => true,
127581 => true,
127582 => true,
127583 => true,
128728 => true,
128729 => true,
128730 => true,
128731 => true,
128732 => true,
128733 => true,
128734 => true,
128735 => true,
128749 => true,
128750 => true,
128751 => true,
128765 => true,
128766 => true,
128767 => true,
128884 => true,
128885 => true,
128886 => true,
128887 => true,
128888 => true,
128889 => true,
128890 => true,
128891 => true,
128892 => true,
128893 => true,
128894 => true,
128895 => true,
128985 => true,
128986 => true,
128987 => true,
128988 => true,
128989 => true,
128990 => true,
128991 => true,
129004 => true,
129005 => true,
129006 => true,
129007 => true,
129008 => true,
129009 => true,
129010 => true,
129011 => true,
129012 => true,
129013 => true,
129014 => true,
129015 => true,
129016 => true,
129017 => true,
129018 => true,
129019 => true,
129020 => true,
129021 => true,
129022 => true,
129023 => true,
129036 => true,
129037 => true,
129038 => true,
129039 => true,
129096 => true,
129097 => true,
129098 => true,
129099 => true,
129100 => true,
129101 => true,
129102 => true,
129103 => true,
129114 => true,
129115 => true,
129116 => true,
129117 => true,
129118 => true,
129119 => true,
129160 => true,
129161 => true,
129162 => true,
129163 => true,
129164 => true,
129165 => true,
129166 => true,
129167 => true,
129198 => true,
129199 => true,
129401 => true,
129484 => true,
129620 => true,
129621 => true,
129622 => true,
129623 => true,
129624 => true,
129625 => true,
129626 => true,
129627 => true,
129628 => true,
129629 => true,
129630 => true,
129631 => true,
129646 => true,
129647 => true,
129653 => true,
129654 => true,
129655 => true,
129659 => true,
129660 => true,
129661 => true,
129662 => true,
129663 => true,
129671 => true,
129672 => true,
129673 => true,
129674 => true,
129675 => true,
129676 => true,
129677 => true,
129678 => true,
129679 => true,
129705 => true,
129706 => true,
129707 => true,
129708 => true,
129709 => true,
129710 => true,
129711 => true,
129719 => true,
129720 => true,
129721 => true,
129722 => true,
129723 => true,
129724 => true,
129725 => true,
129726 => true,
129727 => true,
129731 => true,
129732 => true,
129733 => true,
129734 => true,
129735 => true,
129736 => true,
129737 => true,
129738 => true,
129739 => true,
129740 => true,
129741 => true,
129742 => true,
129743 => true,
129939 => true,
131070 => true,
131071 => true,
177973 => true,
177974 => true,
177975 => true,
177976 => true,
177977 => true,
177978 => true,
177979 => true,
177980 => true,
177981 => true,
177982 => true,
177983 => true,
178206 => true,
178207 => true,
183970 => true,
183971 => true,
183972 => true,
183973 => true,
183974 => true,
183975 => true,
183976 => true,
183977 => true,
183978 => true,
183979 => true,
183980 => true,
183981 => true,
183982 => true,
183983 => true,
194664 => true,
194676 => true,
194847 => true,
194911 => true,
195007 => true,
196606 => true,
196607 => true,
262142 => true,
262143 => true,
327678 => true,
327679 => true,
393214 => true,
393215 => true,
458750 => true,
458751 => true,
524286 => true,
524287 => true,
589822 => true,
589823 => true,
655358 => true,
655359 => true,
720894 => true,
720895 => true,
786430 => true,
786431 => true,
851966 => true,
851967 => true,
917502 => true,
917503 => true,
917504 => true,
917505 => true,
917506 => true,
917507 => true,
917508 => true,
917509 => true,
917510 => true,
917511 => true,
917512 => true,
917513 => true,
917514 => true,
917515 => true,
917516 => true,
917517 => true,
917518 => true,
917519 => true,
917520 => true,
917521 => true,
917522 => true,
917523 => true,
917524 => true,
917525 => true,
917526 => true,
917527 => true,
917528 => true,
917529 => true,
917530 => true,
917531 => true,
917532 => true,
917533 => true,
917534 => true,
917535 => true,
983038 => true,
983039 => true,
1048574 => true,
1048575 => true,
1114110 => true,
1114111 => true,
);
<?php

return array (
160 => ' ',
168 => ' ̈',
175 => ' ̄',
180 => ' ́',
184 => ' ̧',
728 => ' ̆',
729 => ' ̇',
730 => ' ̊',
731 => ' ̨',
732 => ' ̃',
733 => ' ̋',
890 => ' ι',
894 => ';',
900 => ' ́',
901 => ' ̈́',
8125 => ' ̓',
8127 => ' ̓',
8128 => ' ͂',
8129 => ' ̈͂',
8141 => ' ̓̀',
8142 => ' ̓́',
8143 => ' ̓͂',
8157 => ' ̔̀',
8158 => ' ̔́',
8159 => ' ̔͂',
8173 => ' ̈̀',
8174 => ' ̈́',
8175 => '`',
8189 => ' ́',
8190 => ' ̔',
8192 => ' ',
8193 => ' ',
8194 => ' ',
8195 => ' ',
8196 => ' ',
8197 => ' ',
8198 => ' ',
8199 => ' ',
8200 => ' ',
8201 => ' ',
8202 => ' ',
8215 => ' ̳',
8239 => ' ',
8252 => '!!',
8254 => ' ̅',
8263 => '??',
8264 => '?!',
8265 => '!?',
8287 => ' ',
8314 => '+',
8316 => '=',
8317 => '(',
8318 => ')',
8330 => '+',
8332 => '=',
8333 => '(',
8334 => ')',
8448 => 'a/c',
8449 => 'a/s',
8453 => 'c/o',
8454 => 'c/u',
9332 => '(1)',
9333 => '(2)',
9334 => '(3)',
9335 => '(4)',
9336 => '(5)',
9337 => '(6)',
9338 => '(7)',
9339 => '(8)',
9340 => '(9)',
9341 => '(10)',
9342 => '(11)',
9343 => '(12)',
9344 => '(13)',
9345 => '(14)',
9346 => '(15)',
9347 => '(16)',
9348 => '(17)',
9349 => '(18)',
9350 => '(19)',
9351 => '(20)',
9372 => '(a)',
9373 => '(b)',
9374 => '(c)',
9375 => '(d)',
9376 => '(e)',
9377 => '(f)',
9378 => '(g)',
9379 => '(h)',
9380 => '(i)',
9381 => '(j)',
9382 => '(k)',
9383 => '(l)',
9384 => '(m)',
9385 => '(n)',
9386 => '(o)',
9387 => '(p)',
9388 => '(q)',
9389 => '(r)',
9390 => '(s)',
9391 => '(t)',
9392 => '(u)',
9393 => '(v)',
9394 => '(w)',
9395 => '(x)',
9396 => '(y)',
9397 => '(z)',
10868 => '::=',
10869 => '==',
10870 => '===',
12288 => ' ',
12443 => ' ゙',
12444 => ' ゚',
12800 => '(ᄀ)',
12801 => '(ᄂ)',
12802 => '(ᄃ)',
12803 => '(ᄅ)',
12804 => '(ᄆ)',
12805 => '(ᄇ)',
12806 => '(ᄉ)',
12807 => '(ᄋ)',
12808 => '(ᄌ)',
12809 => '(ᄎ)',
12810 => '(ᄏ)',
12811 => '(ᄐ)',
12812 => '(ᄑ)',
12813 => '(ᄒ)',
12814 => '(가)',
12815 => '(나)',
12816 => '(다)',
12817 => '(라)',
12818 => '(마)',
12819 => '(바)',
12820 => '(사)',
12821 => '(아)',
12822 => '(자)',
12823 => '(차)',
12824 => '(카)',
12825 => '(타)',
12826 => '(파)',
12827 => '(하)',
12828 => '(주)',
12829 => '(오전)',
12830 => '(오후)',
12832 => '(一)',
12833 => '(二)',
12834 => '(三)',
12835 => '(四)',
12836 => '(五)',
12837 => '(六)',
12838 => '(七)',
12839 => '(八)',
12840 => '(九)',
12841 => '(十)',
12842 => '(月)',
12843 => '(火)',
12844 => '(水)',
12845 => '(木)',
12846 => '(金)',
12847 => '(土)',
12848 => '(日)',
12849 => '(株)',
12850 => '(有)',
12851 => '(社)',
12852 => '(名)',
12853 => '(特)',
12854 => '(財)',
12855 => '(祝)',
12856 => '(労)',
12857 => '(代)',
12858 => '(呼)',
12859 => '(学)',
12860 => '(監)',
12861 => '(企)',
12862 => '(資)',
12863 => '(協)',
12864 => '(祭)',
12865 => '(休)',
12866 => '(自)',
12867 => '(至)',
64297 => '+',
64606 => ' ٌّ',
64607 => ' ٍّ',
64608 => ' َّ',
64609 => ' ُّ',
64610 => ' ِّ',
64611 => ' ّٰ',
65018 => 'صلى الله عليه وسلم',
65019 => 'جل جلاله',
65040 => ',',
65043 => ':',
65044 => ';',
65045 => '!',
65046 => '?',
65075 => '_',
65076 => '_',
65077 => '(',
65078 => ')',
65079 => '{',
65080 => '}',
65095 => '[',
65096 => ']',
65097 => ' ̅',
65098 => ' ̅',
65099 => ' ̅',
65100 => ' ̅',
65101 => '_',
65102 => '_',
65103 => '_',
65104 => ',',
65108 => ';',
65109 => ':',
65110 => '?',
65111 => '!',
65113 => '(',
65114 => ')',
65115 => '{',
65116 => '}',
65119 => '#',
65120 => '&',
65121 => '*',
65122 => '+',
65124 => '<',
65125 => '>',
65126 => '=',
65128 => '\\',
65129 => '$',
65130 => '%',
65131 => '@',
65136 => ' ً',
65138 => ' ٌ',
65140 => ' ٍ',
65142 => ' َ',
65144 => ' ُ',
65146 => ' ِ',
65148 => ' ّ',
65150 => ' ْ',
65281 => '!',
65282 => '"',
65283 => '#',
65284 => '$',
65285 => '%',
65286 => '&',
65287 => '\'',
65288 => '(',
65289 => ')',
65290 => '*',
65291 => '+',
65292 => ',',
65295 => '/',
65306 => ':',
65307 => ';',
65308 => '<',
65309 => '=',
65310 => '>',
65311 => '?',
65312 => '@',
65339 => '[',
65340 => '\\',
65341 => ']',
65342 => '^',
65343 => '_',
65344 => '`',
65371 => '{',
65372 => '|',
65373 => '}',
65374 => '~',
65507 => ' ̄',
127233 => '0,',
127234 => '1,',
127235 => '2,',
127236 => '3,',
127237 => '4,',
127238 => '5,',
127239 => '6,',
127240 => '7,',
127241 => '8,',
127242 => '9,',
127248 => '(a)',
127249 => '(b)',
127250 => '(c)',
127251 => '(d)',
127252 => '(e)',
127253 => '(f)',
127254 => '(g)',
127255 => '(h)',
127256 => '(i)',
127257 => '(j)',
127258 => '(k)',
127259 => '(l)',
127260 => '(m)',
127261 => '(n)',
127262 => '(o)',
127263 => '(p)',
127264 => '(q)',
127265 => '(r)',
127266 => '(s)',
127267 => '(t)',
127268 => '(u)',
127269 => '(v)',
127270 => '(w)',
127271 => '(x)',
127272 => '(y)',
127273 => '(z)',
);
<?php

return array (
2381 => 9,
2509 => 9,
2637 => 9,
2765 => 9,
2893 => 9,
3021 => 9,
3149 => 9,
3277 => 9,
3387 => 9,
3388 => 9,
3405 => 9,
3530 => 9,
3642 => 9,
3770 => 9,
3972 => 9,
4153 => 9,
4154 => 9,
5908 => 9,
5940 => 9,
6098 => 9,
6752 => 9,
6980 => 9,
7082 => 9,
7083 => 9,
7154 => 9,
7155 => 9,
11647 => 9,
43014 => 9,
43052 => 9,
43204 => 9,
43347 => 9,
43456 => 9,
43766 => 9,
44013 => 9,
68159 => 9,
69702 => 9,
69759 => 9,
69817 => 9,
69939 => 9,
69940 => 9,
70080 => 9,
70197 => 9,
70378 => 9,
70477 => 9,
70722 => 9,
70850 => 9,
71103 => 9,
71231 => 9,
71350 => 9,
71467 => 9,
71737 => 9,
71997 => 9,
71998 => 9,
72160 => 9,
72244 => 9,
72263 => 9,
72345 => 9,
72767 => 9,
73028 => 9,
73029 => 9,
73111 => 9,
);
<?php

return array (
65 => 'a',
66 => 'b',
67 => 'c',
68 => 'd',
69 => 'e',
70 => 'f',
71 => 'g',
72 => 'h',
73 => 'i',
74 => 'j',
75 => 'k',
76 => 'l',
77 => 'm',
78 => 'n',
79 => 'o',
80 => 'p',
81 => 'q',
82 => 'r',
83 => 's',
84 => 't',
85 => 'u',
86 => 'v',
87 => 'w',
88 => 'x',
89 => 'y',
90 => 'z',
170 => 'a',
178 => '2',
179 => '3',
181 => 'μ',
185 => '1',
186 => 'o',
188 => '1⁄4',
189 => '1⁄2',
190 => '3⁄4',
192 => 'à',
193 => 'á',
194 => 'â',
195 => 'ã',
196 => 'ä',
197 => 'å',
198 => 'æ',
199 => 'ç',
200 => 'è',
201 => 'é',
202 => 'ê',
203 => 'ë',
204 => 'ì',
205 => 'í',
206 => 'î',
207 => 'ï',
208 => 'ð',
209 => 'ñ',
210 => 'ò',
211 => 'ó',
212 => 'ô',
213 => 'õ',
214 => 'ö',
216 => 'ø',
217 => 'ù',
218 => 'ú',
219 => 'û',
220 => 'ü',
221 => 'ý',
222 => 'þ',
256 => 'ā',
258 => 'ă',
260 => 'ą',
262 => 'ć',
264 => 'ĉ',
266 => 'ċ',
268 => 'č',
270 => 'ď',
272 => 'đ',
274 => 'ē',
276 => 'ĕ',
278 => 'ė',
280 => 'ę',
282 => 'ě',
284 => 'ĝ',
286 => 'ğ',
288 => 'ġ',
290 => 'ģ',
292 => 'ĥ',
294 => 'ħ',
296 => 'ĩ',
298 => 'ī',
300 => 'ĭ',
302 => 'į',
304 => 'i̇',
306 => 'ij',
307 => 'ij',
308 => 'ĵ',
310 => 'ķ',
313 => 'ĺ',
315 => 'ļ',
317 => 'ľ',
319 => 'l·',
320 => 'l·',
321 => 'ł',
323 => 'ń',
325 => 'ņ',
327 => 'ň',
329 => 'ʼn',
330 => 'ŋ',
332 => 'ō',
334 => 'ŏ',
336 => 'ő',
338 => 'œ',
340 => 'ŕ',
342 => 'ŗ',
344 => 'ř',
346 => 'ś',
348 => 'ŝ',
350 => 'ş',
352 => 'š',
354 => 'ţ',
356 => 'ť',
358 => 'ŧ',
360 => 'ũ',
362 => 'ū',
364 => 'ŭ',
366 => 'ů',
368 => 'ű',
370 => 'ų',
372 => 'ŵ',
374 => 'ŷ',
376 => 'ÿ',
377 => 'ź',
379 => 'ż',
381 => 'ž',
383 => 's',
385 => 'ɓ',
386 => 'ƃ',
388 => 'ƅ',
390 => 'ɔ',
391 => 'ƈ',
393 => 'ɖ',
394 => 'ɗ',
395 => 'ƌ',
398 => 'ǝ',
399 => 'ə',
400 => 'ɛ',
401 => 'ƒ',
403 => 'ɠ',
404 => 'ɣ',
406 => 'ɩ',
407 => 'ɨ',
408 => 'ƙ',
412 => 'ɯ',
413 => 'ɲ',
415 => 'ɵ',
416 => 'ơ',
418 => 'ƣ',
420 => 'ƥ',
422 => 'ʀ',
423 => 'ƨ',
425 => 'ʃ',
428 => 'ƭ',
430 => 'ʈ',
431 => 'ư',
433 => 'ʊ',
434 => 'ʋ',
435 => 'ƴ',
437 => 'ƶ',
439 => 'ʒ',
440 => 'ƹ',
444 => 'ƽ',
452 => 'dž',
453 => 'dž',
454 => 'dž',
455 => 'lj',
456 => 'lj',
457 => 'lj',
458 => 'nj',
459 => 'nj',
460 => 'nj',
461 => 'ǎ',
463 => 'ǐ',
465 => 'ǒ',
467 => 'ǔ',
469 => 'ǖ',
471 => 'ǘ',
473 => 'ǚ',
475 => 'ǜ',
478 => 'ǟ',
480 => 'ǡ',
482 => 'ǣ',
484 => 'ǥ',
486 => 'ǧ',
488 => 'ǩ',
490 => 'ǫ',
492 => 'ǭ',
494 => 'ǯ',
497 => 'dz',
498 => 'dz',
499 => 'dz',
500 => 'ǵ',
502 => 'ƕ',
503 => 'ƿ',
504 => 'ǹ',
506 => 'ǻ',
508 => 'ǽ',
510 => 'ǿ',
512 => 'ȁ',
514 => 'ȃ',
516 => 'ȅ',
518 => 'ȇ',
520 => 'ȉ',
522 => 'ȋ',
524 => 'ȍ',
526 => 'ȏ',
528 => 'ȑ',
530 => 'ȓ',
532 => 'ȕ',
534 => 'ȗ',
536 => 'ș',
538 => 'ț',
540 => 'ȝ',
542 => 'ȟ',
544 => 'ƞ',
546 => 'ȣ',
548 => 'ȥ',
550 => 'ȧ',
552 => 'ȩ',
554 => 'ȫ',
556 => 'ȭ',
558 => 'ȯ',
560 => 'ȱ',
562 => 'ȳ',
570 => 'ⱥ',
571 => 'ȼ',
573 => 'ƚ',
574 => 'ⱦ',
577 => 'ɂ',
579 => 'ƀ',
580 => 'ʉ',
581 => 'ʌ',
582 => 'ɇ',
584 => 'ɉ',
586 => 'ɋ',
588 => 'ɍ',
590 => 'ɏ',
688 => 'h',
689 => 'ɦ',
690 => 'j',
691 => 'r',
692 => 'ɹ',
693 => 'ɻ',
694 => 'ʁ',
695 => 'w',
696 => 'y',
736 => 'ɣ',
737 => 'l',
738 => 's',
739 => 'x',
740 => 'ʕ',
832 => '̀',
833 => '́',
835 => '̓',
836 => '̈́',
837 => 'ι',
880 => 'ͱ',
882 => 'ͳ',
884 => 'ʹ',
886 => 'ͷ',
895 => 'ϳ',
902 => 'ά',
903 => '·',
904 => 'έ',
905 => 'ή',
906 => 'ί',
908 => 'ό',
910 => 'ύ',
911 => 'ώ',
913 => 'α',
914 => 'β',
915 => 'γ',
916 => 'δ',
917 => 'ε',
918 => 'ζ',
919 => 'η',
920 => 'θ',
921 => 'ι',
922 => 'κ',
923 => 'λ',
924 => 'μ',
925 => 'ν',
926 => 'ξ',
927 => 'ο',
928 => 'π',
929 => 'ρ',
931 => 'σ',
932 => 'τ',
933 => 'υ',
934 => 'φ',
935 => 'χ',
936 => 'ψ',
937 => 'ω',
938 => 'ϊ',
939 => 'ϋ',
975 => 'ϗ',
976 => 'β',
977 => 'θ',
978 => 'υ',
979 => 'ύ',
980 => 'ϋ',
981 => 'φ',
982 => 'π',
984 => 'ϙ',
986 => 'ϛ',
988 => 'ϝ',
990 => 'ϟ',
992 => 'ϡ',
994 => 'ϣ',
996 => 'ϥ',
998 => 'ϧ',
1000 => 'ϩ',
1002 => 'ϫ',
1004 => 'ϭ',
1006 => 'ϯ',
1008 => 'κ',
1009 => 'ρ',
1010 => 'σ',
1012 => 'θ',
1013 => 'ε',
1015 => 'ϸ',
1017 => 'σ',
1018 => 'ϻ',
1021 => 'ͻ',
1022 => 'ͼ',
1023 => 'ͽ',
1024 => 'ѐ',
1025 => 'ё',
1026 => 'ђ',
1027 => 'ѓ',
1028 => 'є',
1029 => 'ѕ',
1030 => 'і',
1031 => 'ї',
1032 => 'ј',
1033 => 'љ',
1034 => 'њ',
1035 => 'ћ',
1036 => 'ќ',
1037 => 'ѝ',
1038 => 'ў',
1039 => 'џ',
1040 => 'а',
1041 => 'б',
1042 => 'в',
1043 => 'г',
1044 => 'д',
1045 => 'е',
1046 => 'ж',
1047 => 'з',
1048 => 'и',
1049 => 'й',
1050 => 'к',
1051 => 'л',
1052 => 'м',
1053 => 'н',
1054 => 'о',
1055 => 'п',
1056 => 'р',
1057 => 'с',
1058 => 'т',
1059 => 'у',
1060 => 'ф',
1061 => 'х',
1062 => 'ц',
1063 => 'ч',
1064 => 'ш',
1065 => 'щ',
1066 => 'ъ',
1067 => 'ы',
1068 => 'ь',
1069 => 'э',
1070 => 'ю',
1071 => 'я',
1120 => 'ѡ',
1122 => 'ѣ',
1124 => 'ѥ',
1126 => 'ѧ',
1128 => 'ѩ',
1130 => 'ѫ',
1132 => 'ѭ',
1134 => 'ѯ',
1136 => 'ѱ',
1138 => 'ѳ',
1140 => 'ѵ',
1142 => 'ѷ',
1144 => 'ѹ',
1146 => 'ѻ',
1148 => 'ѽ',
1150 => 'ѿ',
1152 => 'ҁ',
1162 => 'ҋ',
1164 => 'ҍ',
1166 => 'ҏ',
1168 => 'ґ',
1170 => 'ғ',
1172 => 'ҕ',
1174 => 'җ',
1176 => 'ҙ',
1178 => 'қ',
1180 => 'ҝ',
1182 => 'ҟ',
1184 => 'ҡ',
1186 => 'ң',
1188 => 'ҥ',
1190 => 'ҧ',
1192 => 'ҩ',
1194 => 'ҫ',
1196 => 'ҭ',
1198 => 'ү',
1200 => 'ұ',
1202 => 'ҳ',
1204 => 'ҵ',
1206 => 'ҷ',
1208 => 'ҹ',
1210 => 'һ',
1212 => 'ҽ',
1214 => 'ҿ',
1217 => 'ӂ',
1219 => 'ӄ',
1221 => 'ӆ',
1223 => 'ӈ',
1225 => 'ӊ',
1227 => 'ӌ',
1229 => 'ӎ',
1232 => 'ӑ',
1234 => 'ӓ',
1236 => 'ӕ',
1238 => 'ӗ',
1240 => 'ә',
1242 => 'ӛ',
1244 => 'ӝ',
1246 => 'ӟ',
1248 => 'ӡ',
1250 => 'ӣ',
1252 => 'ӥ',
1254 => 'ӧ',
1256 => 'ө',
1258 => 'ӫ',
1260 => 'ӭ',
1262 => 'ӯ',
1264 => 'ӱ',
1266 => 'ӳ',
1268 => 'ӵ',
1270 => 'ӷ',
1272 => 'ӹ',
1274 => 'ӻ',
1276 => 'ӽ',
1278 => 'ӿ',
1280 => 'ԁ',
1282 => 'ԃ',
1284 => 'ԅ',
1286 => 'ԇ',
1288 => 'ԉ',
1290 => 'ԋ',
1292 => 'ԍ',
1294 => 'ԏ',
1296 => 'ԑ',
1298 => 'ԓ',
1300 => 'ԕ',
1302 => 'ԗ',
1304 => 'ԙ',
1306 => 'ԛ',
1308 => 'ԝ',
1310 => 'ԟ',
1312 => 'ԡ',
1314 => 'ԣ',
1316 => 'ԥ',
1318 => 'ԧ',
1320 => 'ԩ',
1322 => 'ԫ',
1324 => 'ԭ',
1326 => 'ԯ',
1329 => 'ա',
1330 => 'բ',
1331 => 'գ',
1332 => 'դ',
1333 => 'ե',
1334 => 'զ',
1335 => 'է',
1336 => 'ը',
1337 => 'թ',
1338 => 'ժ',
1339 => 'ի',
1340 => 'լ',
1341 => 'խ',
1342 => 'ծ',
1343 => 'կ',
1344 => 'հ',
1345 => 'ձ',
1346 => 'ղ',
1347 => 'ճ',
1348 => 'մ',
1349 => 'յ',
1350 => 'ն',
1351 => 'շ',
1352 => 'ո',
1353 => 'չ',
1354 => 'պ',
1355 => 'ջ',
1356 => 'ռ',
1357 => 'ս',
1358 => 'վ',
1359 => 'տ',
1360 => 'ր',
1361 => 'ց',
1362 => 'ւ',
1363 => 'փ',
1364 => 'ք',
1365 => 'օ',
1366 => 'ֆ',
1415 => 'եւ',
1653 => 'اٴ',
1654 => 'وٴ',
1655 => 'ۇٴ',
1656 => 'يٴ',
2392 => 'क़',
2393 => 'ख़',
2394 => 'ग़',
2395 => 'ज़',
2396 => 'ड़',
2397 => 'ढ़',
2398 => 'फ़',
2399 => 'य़',
2524 => 'ড়',
2525 => 'ঢ়',
2527 => 'য়',
2611 => 'ਲ਼',
2614 => 'ਸ਼',
2649 => 'ਖ਼',
2650 => 'ਗ਼',
2651 => 'ਜ਼',
2654 => 'ਫ਼',
2908 => 'ଡ଼',
2909 => 'ଢ଼',
3635 => 'ํา',
3763 => 'ໍາ',
3804 => 'ຫນ',
3805 => 'ຫມ',
3852 => '་',
3907 => 'གྷ',
3917 => 'ཌྷ',
3922 => 'དྷ',
3927 => 'བྷ',
3932 => 'ཛྷ',
3945 => 'ཀྵ',
3955 => 'ཱི',
3957 => 'ཱུ',
3958 => 'ྲྀ',
3959 => 'ྲཱྀ',
3960 => 'ླྀ',
3961 => 'ླཱྀ',
3969 => 'ཱྀ',
3987 => 'ྒྷ',
3997 => 'ྜྷ',
4002 => 'ྡྷ',
4007 => 'ྦྷ',
4012 => 'ྫྷ',
4025 => 'ྐྵ',
4295 => 'ⴧ',
4301 => 'ⴭ',
4348 => 'ნ',
5112 => 'Ᏸ',
5113 => 'Ᏹ',
5114 => 'Ᏺ',
5115 => 'Ᏻ',
5116 => 'Ᏼ',
5117 => 'Ᏽ',
7296 => 'в',
7297 => 'д',
7298 => 'о',
7299 => 'с',
7300 => 'т',
7301 => 'т',
7302 => 'ъ',
7303 => 'ѣ',
7304 => 'ꙋ',
7312 => 'ა',
7313 => 'ბ',
7314 => 'გ',
7315 => 'დ',
7316 => 'ე',
7317 => 'ვ',
7318 => 'ზ',
7319 => 'თ',
7320 => 'ი',
7321 => 'კ',
7322 => 'ლ',
7323 => 'მ',
7324 => 'ნ',
7325 => 'ო',
7326 => 'პ',
7327 => 'ჟ',
7328 => 'რ',
7329 => 'ს',
7330 => 'ტ',
7331 => 'უ',
7332 => 'ფ',
7333 => 'ქ',
7334 => 'ღ',
7335 => 'ყ',
7336 => 'შ',
7337 => 'ჩ',
7338 => 'ც',
7339 => 'ძ',
7340 => 'წ',
7341 => 'ჭ',
7342 => 'ხ',
7343 => 'ჯ',
7344 => 'ჰ',
7345 => 'ჱ',
7346 => 'ჲ',
7347 => 'ჳ',
7348 => 'ჴ',
7349 => 'ჵ',
7350 => 'ჶ',
7351 => 'ჷ',
7352 => 'ჸ',
7353 => 'ჹ',
7354 => 'ჺ',
7357 => 'ჽ',
7358 => 'ჾ',
7359 => 'ჿ',
7468 => 'a',
7469 => 'æ',
7470 => 'b',
7472 => 'd',
7473 => 'e',
7474 => 'ǝ',
7475 => 'g',
7476 => 'h',
7477 => 'i',
7478 => 'j',
7479 => 'k',
7480 => 'l',
7481 => 'm',
7482 => 'n',
7484 => 'o',
7485 => 'ȣ',
7486 => 'p',
7487 => 'r',
7488 => 't',
7489 => 'u',
7490 => 'w',
7491 => 'a',
7492 => 'ɐ',
7493 => 'ɑ',
7494 => 'ᴂ',
7495 => 'b',
7496 => 'd',
7497 => 'e',
7498 => 'ə',
7499 => 'ɛ',
7500 => 'ɜ',
7501 => 'g',
7503 => 'k',
7504 => 'm',
7505 => 'ŋ',
7506 => 'o',
7507 => 'ɔ',
7508 => 'ᴖ',
7509 => 'ᴗ',
7510 => 'p',
7511 => 't',
7512 => 'u',
7513 => 'ᴝ',
7514 => 'ɯ',
7515 => 'v',
7516 => 'ᴥ',
7517 => 'β',
7518 => 'γ',
7519 => 'δ',
7520 => 'φ',
7521 => 'χ',
7522 => 'i',
7523 => 'r',
7524 => 'u',
7525 => 'v',
7526 => 'β',
7527 => 'γ',
7528 => 'ρ',
7529 => 'φ',
7530 => 'χ',
7544 => 'н',
7579 => 'ɒ',
7580 => 'c',
7581 => 'ɕ',
7582 => 'ð',
7583 => 'ɜ',
7584 => 'f',
7585 => 'ɟ',
7586 => 'ɡ',
7587 => 'ɥ',
7588 => 'ɨ',
7589 => 'ɩ',
7590 => 'ɪ',
7591 => 'ᵻ',
7592 => 'ʝ',
7593 => 'ɭ',
7594 => 'ᶅ',
7595 => 'ʟ',
7596 => 'ɱ',
7597 => 'ɰ',
7598 => 'ɲ',
7599 => 'ɳ',
7600 => 'ɴ',
7601 => 'ɵ',
7602 => 'ɸ',
7603 => 'ʂ',
7604 => 'ʃ',
7605 => 'ƫ',
7606 => 'ʉ',
7607 => 'ʊ',
7608 => 'ᴜ',
7609 => 'ʋ',
7610 => 'ʌ',
7611 => 'z',
7612 => 'ʐ',
7613 => 'ʑ',
7614 => 'ʒ',
7615 => 'θ',
7680 => 'ḁ',
7682 => 'ḃ',
7684 => 'ḅ',
7686 => 'ḇ',
7688 => 'ḉ',
7690 => 'ḋ',
7692 => 'ḍ',
7694 => 'ḏ',
7696 => 'ḑ',
7698 => 'ḓ',
7700 => 'ḕ',
7702 => 'ḗ',
7704 => 'ḙ',
7706 => 'ḛ',
7708 => 'ḝ',
7710 => 'ḟ',
7712 => 'ḡ',
7714 => 'ḣ',
7716 => 'ḥ',
7718 => 'ḧ',
7720 => 'ḩ',
7722 => 'ḫ',
7724 => 'ḭ',
7726 => 'ḯ',
7728 => 'ḱ',
7730 => 'ḳ',
7732 => 'ḵ',
7734 => 'ḷ',
7736 => 'ḹ',
7738 => 'ḻ',
7740 => 'ḽ',
7742 => 'ḿ',
7744 => 'ṁ',
7746 => 'ṃ',
7748 => 'ṅ',
7750 => 'ṇ',
7752 => 'ṉ',
7754 => 'ṋ',
7756 => 'ṍ',
7758 => 'ṏ',
7760 => 'ṑ',
7762 => 'ṓ',
7764 => 'ṕ',
7766 => 'ṗ',
7768 => 'ṙ',
7770 => 'ṛ',
7772 => 'ṝ',
7774 => 'ṟ',
7776 => 'ṡ',
7778 => 'ṣ',
7780 => 'ṥ',
7782 => 'ṧ',
7784 => 'ṩ',
7786 => 'ṫ',
7788 => 'ṭ',
7790 => 'ṯ',
7792 => 'ṱ',
7794 => 'ṳ',
7796 => 'ṵ',
7798 => 'ṷ',
7800 => 'ṹ',
7802 => 'ṻ',
7804 => 'ṽ',
7806 => 'ṿ',
7808 => 'ẁ',
7810 => 'ẃ',
7812 => 'ẅ',
7814 => 'ẇ',
7816 => 'ẉ',
7818 => 'ẋ',
7820 => 'ẍ',
7822 => 'ẏ',
7824 => 'ẑ',
7826 => 'ẓ',
7828 => 'ẕ',
7834 => 'aʾ',
7835 => 'ṡ',
7838 => 'ss',
7840 => 'ạ',
7842 => 'ả',
7844 => 'ấ',
7846 => 'ầ',
7848 => 'ẩ',
7850 => 'ẫ',
7852 => 'ậ',
7854 => 'ắ',
7856 => 'ằ',
7858 => 'ẳ',
7860 => 'ẵ',
7862 => 'ặ',
7864 => 'ẹ',
7866 => 'ẻ',
7868 => 'ẽ',
7870 => 'ế',
7872 => 'ề',
7874 => 'ể',
7876 => 'ễ',
7878 => 'ệ',
7880 => 'ỉ',
7882 => 'ị',
7884 => 'ọ',
7886 => 'ỏ',
7888 => 'ố',
7890 => 'ồ',
7892 => 'ổ',
7894 => 'ỗ',
7896 => 'ộ',
7898 => 'ớ',
7900 => 'ờ',
7902 => 'ở',
7904 => 'ỡ',
7906 => 'ợ',
7908 => 'ụ',
7910 => 'ủ',
7912 => 'ứ',
7914 => 'ừ',
7916 => 'ử',
7918 => 'ữ',
7920 => 'ự',
7922 => 'ỳ',
7924 => 'ỵ',
7926 => 'ỷ',
7928 => 'ỹ',
7930 => 'ỻ',
7932 => 'ỽ',
7934 => 'ỿ',
7944 => 'ἀ',
7945 => 'ἁ',
7946 => 'ἂ',
7947 => 'ἃ',
7948 => 'ἄ',
7949 => 'ἅ',
7950 => 'ἆ',
7951 => 'ἇ',
7960 => 'ἐ',
7961 => 'ἑ',
7962 => 'ἒ',
7963 => 'ἓ',
7964 => 'ἔ',
7965 => 'ἕ',
7976 => 'ἠ',
7977 => 'ἡ',
7978 => 'ἢ',
7979 => 'ἣ',
7980 => 'ἤ',
7981 => 'ἥ',
7982 => 'ἦ',
7983 => 'ἧ',
7992 => 'ἰ',
7993 => 'ἱ',
7994 => 'ἲ',
7995 => 'ἳ',
7996 => 'ἴ',
7997 => 'ἵ',
7998 => 'ἶ',
7999 => 'ἷ',
8008 => 'ὀ',
8009 => 'ὁ',
8010 => 'ὂ',
8011 => 'ὃ',
8012 => 'ὄ',
8013 => 'ὅ',
8025 => 'ὑ',
8027 => 'ὓ',
8029 => 'ὕ',
8031 => 'ὗ',
8040 => 'ὠ',
8041 => 'ὡ',
8042 => 'ὢ',
8043 => 'ὣ',
8044 => 'ὤ',
8045 => 'ὥ',
8046 => 'ὦ',
8047 => 'ὧ',
8049 => 'ά',
8051 => 'έ',
8053 => 'ή',
8055 => 'ί',
8057 => 'ό',
8059 => 'ύ',
8061 => 'ώ',
8064 => 'ἀι',
8065 => 'ἁι',
8066 => 'ἂι',
8067 => 'ἃι',
8068 => 'ἄι',
8069 => 'ἅι',
8070 => 'ἆι',
8071 => 'ἇι',
8072 => 'ἀι',
8073 => 'ἁι',
8074 => 'ἂι',
8075 => 'ἃι',
8076 => 'ἄι',
8077 => 'ἅι',
8078 => 'ἆι',
8079 => 'ἇι',
8080 => 'ἠι',
8081 => 'ἡι',
8082 => 'ἢι',
8083 => 'ἣι',
8084 => 'ἤι',
8085 => 'ἥι',
8086 => 'ἦι',
8087 => 'ἧι',
8088 => 'ἠι',
8089 => 'ἡι',
8090 => 'ἢι',
8091 => 'ἣι',
8092 => 'ἤι',
8093 => 'ἥι',
8094 => 'ἦι',
8095 => 'ἧι',
8096 => 'ὠι',
8097 => 'ὡι',
8098 => 'ὢι',
8099 => 'ὣι',
8100 => 'ὤι',
8101 => 'ὥι',
8102 => 'ὦι',
8103 => 'ὧι',
8104 => 'ὠι',
8105 => 'ὡι',
8106 => 'ὢι',
8107 => 'ὣι',
8108 => 'ὤι',
8109 => 'ὥι',
8110 => 'ὦι',
8111 => 'ὧι',
8114 => 'ὰι',
8115 => 'αι',
8116 => 'άι',
8119 => 'ᾶι',
8120 => 'ᾰ',
8121 => 'ᾱ',
8122 => 'ὰ',
8123 => 'ά',
8124 => 'αι',
8126 => 'ι',
8130 => 'ὴι',
8131 => 'ηι',
8132 => 'ήι',
8135 => 'ῆι',
8136 => 'ὲ',
8137 => 'έ',
8138 => 'ὴ',
8139 => 'ή',
8140 => 'ηι',
8147 => 'ΐ',
8152 => 'ῐ',
8153 => 'ῑ',
8154 => 'ὶ',
8155 => 'ί',
8163 => 'ΰ',
8168 => 'ῠ',
8169 => 'ῡ',
8170 => 'ὺ',
8171 => 'ύ',
8172 => 'ῥ',
8178 => 'ὼι',
8179 => 'ωι',
8180 => 'ώι',
8183 => 'ῶι',
8184 => 'ὸ',
8185 => 'ό',
8186 => 'ὼ',
8187 => 'ώ',
8188 => 'ωι',
8209 => '‐',
8243 => '′′',
8244 => '′′′',
8246 => '‵‵',
8247 => '‵‵‵',
8279 => '′′′′',
8304 => '0',
8305 => 'i',
8308 => '4',
8309 => '5',
8310 => '6',
8311 => '7',
8312 => '8',
8313 => '9',
8315 => '−',
8319 => 'n',
8320 => '0',
8321 => '1',
8322 => '2',
8323 => '3',
8324 => '4',
8325 => '5',
8326 => '6',
8327 => '7',
8328 => '8',
8329 => '9',
8331 => '−',
8336 => 'a',
8337 => 'e',
8338 => 'o',
8339 => 'x',
8340 => 'ə',
8341 => 'h',
8342 => 'k',
8343 => 'l',
8344 => 'm',
8345 => 'n',
8346 => 'p',
8347 => 's',
8348 => 't',
8360 => 'rs',
8450 => 'c',
8451 => '°c',
8455 => 'ɛ',
8457 => '°f',
8458 => 'g',
8459 => 'h',
8460 => 'h',
8461 => 'h',
8462 => 'h',
8463 => 'ħ',
8464 => 'i',
8465 => 'i',
8466 => 'l',
8467 => 'l',
8469 => 'n',
8470 => 'no',
8473 => 'p',
8474 => 'q',
8475 => 'r',
8476 => 'r',
8477 => 'r',
8480 => 'sm',
8481 => 'tel',
8482 => 'tm',
8484 => 'z',
8486 => 'ω',
8488 => 'z',
8490 => 'k',
8491 => 'å',
8492 => 'b',
8493 => 'c',
8495 => 'e',
8496 => 'e',
8497 => 'f',
8499 => 'm',
8500 => 'o',
8501 => 'א',
8502 => 'ב',
8503 => 'ג',
8504 => 'ד',
8505 => 'i',
8507 => 'fax',
8508 => 'π',
8509 => 'γ',
8510 => 'γ',
8511 => 'π',
8512 => '∑',
8517 => 'd',
8518 => 'd',
8519 => 'e',
8520 => 'i',
8521 => 'j',
8528 => '1⁄7',
8529 => '1⁄9',
8530 => '1⁄10',
8531 => '1⁄3',
8532 => '2⁄3',
8533 => '1⁄5',
8534 => '2⁄5',
8535 => '3⁄5',
8536 => '4⁄5',
8537 => '1⁄6',
8538 => '5⁄6',
8539 => '1⁄8',
8540 => '3⁄8',
8541 => '5⁄8',
8542 => '7⁄8',
8543 => '1⁄',
8544 => 'i',
8545 => 'ii',
8546 => 'iii',
8547 => 'iv',
8548 => 'v',
8549 => 'vi',
8550 => 'vii',
8551 => 'viii',
8552 => 'ix',
8553 => 'x',
8554 => 'xi',
8555 => 'xii',
8556 => 'l',
8557 => 'c',
8558 => 'd',
8559 => 'm',
8560 => 'i',
8561 => 'ii',
8562 => 'iii',
8563 => 'iv',
8564 => 'v',
8565 => 'vi',
8566 => 'vii',
8567 => 'viii',
8568 => 'ix',
8569 => 'x',
8570 => 'xi',
8571 => 'xii',
8572 => 'l',
8573 => 'c',
8574 => 'd',
8575 => 'm',
8585 => '0⁄3',
8748 => '∫∫',
8749 => '∫∫∫',
8751 => '∮∮',
8752 => '∮∮∮',
9001 => '〈',
9002 => '〉',
9312 => '1',
9313 => '2',
9314 => '3',
9315 => '4',
9316 => '5',
9317 => '6',
9318 => '7',
9319 => '8',
9320 => '9',
9321 => '10',
9322 => '11',
9323 => '12',
9324 => '13',
9325 => '14',
9326 => '15',
9327 => '16',
9328 => '17',
9329 => '18',
9330 => '19',
9331 => '20',
9398 => 'a',
9399 => 'b',
9400 => 'c',
9401 => 'd',
9402 => 'e',
9403 => 'f',
9404 => 'g',
9405 => 'h',
9406 => 'i',
9407 => 'j',
9408 => 'k',
9409 => 'l',
9410 => 'm',
9411 => 'n',
9412 => 'o',
9413 => 'p',
9414 => 'q',
9415 => 'r',
9416 => 's',
9417 => 't',
9418 => 'u',
9419 => 'v',
9420 => 'w',
9421 => 'x',
9422 => 'y',
9423 => 'z',
9424 => 'a',
9425 => 'b',
9426 => 'c',
9427 => 'd',
9428 => 'e',
9429 => 'f',
9430 => 'g',
9431 => 'h',
9432 => 'i',
9433 => 'j',
9434 => 'k',
9435 => 'l',
9436 => 'm',
9437 => 'n',
9438 => 'o',
9439 => 'p',
9440 => 'q',
9441 => 'r',
9442 => 's',
9443 => 't',
9444 => 'u',
9445 => 'v',
9446 => 'w',
9447 => 'x',
9448 => 'y',
9449 => 'z',
9450 => '0',
10764 => '∫∫∫∫',
10972 => '⫝̸',
11264 => 'ⰰ',
11265 => 'ⰱ',
11266 => 'ⰲ',
11267 => 'ⰳ',
11268 => 'ⰴ',
11269 => 'ⰵ',
11270 => 'ⰶ',
11271 => 'ⰷ',
11272 => 'ⰸ',
11273 => 'ⰹ',
11274 => 'ⰺ',
11275 => 'ⰻ',
11276 => 'ⰼ',
11277 => 'ⰽ',
11278 => 'ⰾ',
11279 => 'ⰿ',
11280 => 'ⱀ',
11281 => 'ⱁ',
11282 => 'ⱂ',
11283 => 'ⱃ',
11284 => 'ⱄ',
11285 => 'ⱅ',
11286 => 'ⱆ',
11287 => 'ⱇ',
11288 => 'ⱈ',
11289 => 'ⱉ',
11290 => 'ⱊ',
11291 => 'ⱋ',
11292 => 'ⱌ',
11293 => 'ⱍ',
11294 => 'ⱎ',
11295 => 'ⱏ',
11296 => 'ⱐ',
11297 => 'ⱑ',
11298 => 'ⱒ',
11299 => 'ⱓ',
11300 => 'ⱔ',
11301 => 'ⱕ',
11302 => 'ⱖ',
11303 => 'ⱗ',
11304 => 'ⱘ',
11305 => 'ⱙ',
11306 => 'ⱚ',
11307 => 'ⱛ',
11308 => 'ⱜ',
11309 => 'ⱝ',
11310 => 'ⱞ',
11360 => 'ⱡ',
11362 => 'ɫ',
11363 => 'ᵽ',
11364 => 'ɽ',
11367 => 'ⱨ',
11369 => 'ⱪ',
11371 => 'ⱬ',
11373 => 'ɑ',
11374 => 'ɱ',
11375 => 'ɐ',
11376 => 'ɒ',
11378 => 'ⱳ',
11381 => 'ⱶ',
11388 => 'j',
11389 => 'v',
11390 => 'ȿ',
11391 => 'ɀ',
11392 => 'ⲁ',
11394 => 'ⲃ',
11396 => 'ⲅ',
11398 => 'ⲇ',
11400 => 'ⲉ',
11402 => 'ⲋ',
11404 => 'ⲍ',
11406 => 'ⲏ',
11408 => 'ⲑ',
11410 => 'ⲓ',
11412 => 'ⲕ',
11414 => 'ⲗ',
11416 => 'ⲙ',
11418 => 'ⲛ',
11420 => 'ⲝ',
11422 => 'ⲟ',
11424 => 'ⲡ',
11426 => 'ⲣ',
11428 => 'ⲥ',
11430 => 'ⲧ',
11432 => 'ⲩ',
11434 => 'ⲫ',
11436 => 'ⲭ',
11438 => 'ⲯ',
11440 => 'ⲱ',
11442 => 'ⲳ',
11444 => 'ⲵ',
11446 => 'ⲷ',
11448 => 'ⲹ',
11450 => 'ⲻ',
11452 => 'ⲽ',
11454 => 'ⲿ',
11456 => 'ⳁ',
11458 => 'ⳃ',
11460 => 'ⳅ',
11462 => 'ⳇ',
11464 => 'ⳉ',
11466 => 'ⳋ',
11468 => 'ⳍ',
11470 => 'ⳏ',
11472 => 'ⳑ',
11474 => 'ⳓ',
11476 => 'ⳕ',
11478 => 'ⳗ',
11480 => 'ⳙ',
11482 => 'ⳛ',
11484 => 'ⳝ',
11486 => 'ⳟ',
11488 => 'ⳡ',
11490 => 'ⳣ',
11499 => 'ⳬ',
11501 => 'ⳮ',
11506 => 'ⳳ',
11631 => 'ⵡ',
11935 => '母',
12019 => '龟',
12032 => '一',
12033 => '丨',
12034 => '丶',
12035 => '丿',
12036 => '乙',
12037 => '亅',
12038 => '二',
12039 => '亠',
12040 => '人',
12041 => '儿',
12042 => '入',
12043 => '八',
12044 => '冂',
12045 => '冖',
12046 => '冫',
12047 => '几',
12048 => '凵',
12049 => '刀',
12050 => '力',
12051 => '勹',
12052 => '匕',
12053 => '匚',
12054 => '匸',
12055 => '十',
12056 => '卜',
12057 => '卩',
12058 => '厂',
12059 => '厶',
12060 => '又',
12061 => '口',
12062 => '囗',
12063 => '土',
12064 => '士',
12065 => '夂',
12066 => '夊',
12067 => '夕',
12068 => '大',
12069 => '女',
12070 => '子',
12071 => '宀',
12072 => '寸',
12073 => '小',
12074 => '尢',
12075 => '尸',
12076 => '屮',
12077 => '山',
12078 => '巛',
12079 => '工',
12080 => '己',
12081 => '巾',
12082 => '干',
12083 => '幺',
12084 => '广',
12085 => '廴',
12086 => '廾',
12087 => '弋',
12088 => '弓',
12089 => '彐',
12090 => '彡',
12091 => '彳',
12092 => '心',
12093 => '戈',
12094 => '戶',
12095 => '手',
12096 => '支',
12097 => '攴',
12098 => '文',
12099 => '斗',
12100 => '斤',
12101 => '方',
12102 => '无',
12103 => '日',
12104 => '曰',
12105 => '月',
12106 => '木',
12107 => '欠',
12108 => '止',
12109 => '歹',
12110 => '殳',
12111 => '毋',
12112 => '比',
12113 => '毛',
12114 => '氏',
12115 => '气',
12116 => '水',
12117 => '火',
12118 => '爪',
12119 => '父',
12120 => '爻',
12121 => '爿',
12122 => '片',
12123 => '牙',
12124 => '牛',
12125 => '犬',
12126 => '玄',
12127 => '玉',
12128 => '瓜',
12129 => '瓦',
12130 => '甘',
12131 => '生',
12132 => '用',
12133 => '田',
12134 => '疋',
12135 => '疒',
12136 => '癶',
12137 => '白',
12138 => '皮',
12139 => '皿',
12140 => '目',
12141 => '矛',
12142 => '矢',
12143 => '石',
12144 => '示',
12145 => '禸',
12146 => '禾',
12147 => '穴',
12148 => '立',
12149 => '竹',
12150 => '米',
12151 => '糸',
12152 => '缶',
12153 => '网',
12154 => '羊',
12155 => '羽',
12156 => '老',
12157 => '而',
12158 => '耒',
12159 => '耳',
12160 => '聿',
12161 => '肉',
12162 => '臣',
12163 => '自',
12164 => '至',
12165 => '臼',
12166 => '舌',
12167 => '舛',
12168 => '舟',
12169 => '艮',
12170 => '色',
12171 => '艸',
12172 => '虍',
12173 => '虫',
12174 => '血',
12175 => '行',
12176 => '衣',
12177 => '襾',
12178 => '見',
12179 => '角',
12180 => '言',
12181 => '谷',
12182 => '豆',
12183 => '豕',
12184 => '豸',
12185 => '貝',
12186 => '赤',
12187 => '走',
12188 => '足',
12189 => '身',
12190 => '車',
12191 => '辛',
12192 => '辰',
12193 => '辵',
12194 => '邑',
12195 => '酉',
12196 => '釆',
12197 => '里',
12198 => '金',
12199 => '長',
12200 => '門',
12201 => '阜',
12202 => '隶',
12203 => '隹',
12204 => '雨',
12205 => '靑',
12206 => '非',
12207 => '面',
12208 => '革',
12209 => '韋',
12210 => '韭',
12211 => '音',
12212 => '頁',
12213 => '風',
12214 => '飛',
12215 => '食',
12216 => '首',
12217 => '香',
12218 => '馬',
12219 => '骨',
12220 => '高',
12221 => '髟',
12222 => '鬥',
12223 => '鬯',
12224 => '鬲',
12225 => '鬼',
12226 => '魚',
12227 => '鳥',
12228 => '鹵',
12229 => '鹿',
12230 => '麥',
12231 => '麻',
12232 => '黃',
12233 => '黍',
12234 => '黑',
12235 => '黹',
12236 => '黽',
12237 => '鼎',
12238 => '鼓',
12239 => '鼠',
12240 => '鼻',
12241 => '齊',
12242 => '齒',
12243 => '龍',
12244 => '龜',
12245 => '龠',
12290 => '.',
12342 => '〒',
12344 => '十',
12345 => '卄',
12346 => '卅',
12447 => 'より',
12543 => 'コト',
12593 => 'ᄀ',
12594 => 'ᄁ',
12595 => 'ᆪ',
12596 => 'ᄂ',
12597 => 'ᆬ',
12598 => 'ᆭ',
12599 => 'ᄃ',
12600 => 'ᄄ',
12601 => 'ᄅ',
12602 => 'ᆰ',
12603 => 'ᆱ',
12604 => 'ᆲ',
12605 => 'ᆳ',
12606 => 'ᆴ',
12607 => 'ᆵ',
12608 => 'ᄚ',
12609 => 'ᄆ',
12610 => 'ᄇ',
12611 => 'ᄈ',
12612 => 'ᄡ',
12613 => 'ᄉ',
12614 => 'ᄊ',
12615 => 'ᄋ',
12616 => 'ᄌ',
12617 => 'ᄍ',
12618 => 'ᄎ',
12619 => 'ᄏ',
12620 => 'ᄐ',
12621 => 'ᄑ',
12622 => 'ᄒ',
12623 => 'ᅡ',
12624 => 'ᅢ',
12625 => 'ᅣ',
12626 => 'ᅤ',
12627 => 'ᅥ',
12628 => 'ᅦ',
12629 => 'ᅧ',
12630 => 'ᅨ',
12631 => 'ᅩ',
12632 => 'ᅪ',
12633 => 'ᅫ',
12634 => 'ᅬ',
12635 => 'ᅭ',
12636 => 'ᅮ',
12637 => 'ᅯ',
12638 => 'ᅰ',
12639 => 'ᅱ',
12640 => 'ᅲ',
12641 => 'ᅳ',
12642 => 'ᅴ',
12643 => 'ᅵ',
12645 => 'ᄔ',
12646 => 'ᄕ',
12647 => 'ᇇ',
12648 => 'ᇈ',
12649 => 'ᇌ',
12650 => 'ᇎ',
12651 => 'ᇓ',
12652 => 'ᇗ',
12653 => 'ᇙ',
12654 => 'ᄜ',
12655 => 'ᇝ',
12656 => 'ᇟ',
12657 => 'ᄝ',
12658 => 'ᄞ',
12659 => 'ᄠ',
12660 => 'ᄢ',
12661 => 'ᄣ',
12662 => 'ᄧ',
12663 => 'ᄩ',
12664 => 'ᄫ',
12665 => 'ᄬ',
12666 => 'ᄭ',
12667 => 'ᄮ',
12668 => 'ᄯ',
12669 => 'ᄲ',
12670 => 'ᄶ',
12671 => 'ᅀ',
12672 => 'ᅇ',
12673 => 'ᅌ',
12674 => 'ᇱ',
12675 => 'ᇲ',
12676 => 'ᅗ',
12677 => 'ᅘ',
12678 => 'ᅙ',
12679 => 'ᆄ',
12680 => 'ᆅ',
12681 => 'ᆈ',
12682 => 'ᆑ',
12683 => 'ᆒ',
12684 => 'ᆔ',
12685 => 'ᆞ',
12686 => 'ᆡ',
12690 => '一',
12691 => '二',
12692 => '三',
12693 => '四',
12694 => '上',
12695 => '中',
12696 => '下',
12697 => '甲',
12698 => '乙',
12699 => '丙',
12700 => '丁',
12701 => '天',
12702 => '地',
12703 => '人',
12868 => '問',
12869 => '幼',
12870 => '文',
12871 => '箏',
12880 => 'pte',
12881 => '21',
12882 => '22',
12883 => '23',
12884 => '24',
12885 => '25',
12886 => '26',
12887 => '27',
12888 => '28',
12889 => '29',
12890 => '30',
12891 => '31',
12892 => '32',
12893 => '33',
12894 => '34',
12895 => '35',
12896 => 'ᄀ',
12897 => 'ᄂ',
12898 => 'ᄃ',
12899 => 'ᄅ',
12900 => 'ᄆ',
12901 => 'ᄇ',
12902 => 'ᄉ',
12903 => 'ᄋ',
12904 => 'ᄌ',
12905 => 'ᄎ',
12906 => 'ᄏ',
12907 => 'ᄐ',
12908 => 'ᄑ',
12909 => 'ᄒ',
12910 => '가',
12911 => '나',
12912 => '다',
12913 => '라',
12914 => '마',
12915 => '바',
12916 => '사',
12917 => '아',
12918 => '자',
12919 => '차',
12920 => '카',
12921 => '타',
12922 => '파',
12923 => '하',
12924 => '참고',
12925 => '주의',
12926 => '우',
12928 => '一',
12929 => '二',
12930 => '三',
12931 => '四',
12932 => '五',
12933 => '六',
12934 => '七',
12935 => '八',
12936 => '九',
12937 => '十',
12938 => '月',
12939 => '火',
12940 => '水',
12941 => '木',
12942 => '金',
12943 => '土',
12944 => '日',
12945 => '株',
12946 => '有',
12947 => '社',
12948 => '名',
12949 => '特',
12950 => '財',
12951 => '祝',
12952 => '労',
12953 => '秘',
12954 => '男',
12955 => '女',
12956 => '適',
12957 => '優',
12958 => '印',
12959 => '注',
12960 => '項',
12961 => '休',
12962 => '写',
12963 => '正',
12964 => '上',
12965 => '中',
12966 => '下',
12967 => '左',
12968 => '右',
12969 => '医',
12970 => '宗',
12971 => '学',
12972 => '監',
12973 => '企',
12974 => '資',
12975 => '協',
12976 => '夜',
12977 => '36',
12978 => '37',
12979 => '38',
12980 => '39',
12981 => '40',
12982 => '41',
12983 => '42',
12984 => '43',
12985 => '44',
12986 => '45',
12987 => '46',
12988 => '47',
12989 => '48',
12990 => '49',
12991 => '50',
12992 => '1月',
12993 => '2月',
12994 => '3月',
12995 => '4月',
12996 => '5月',
12997 => '6月',
12998 => '7月',
12999 => '8月',
13000 => '9月',
13001 => '10月',
13002 => '11月',
13003 => '12月',
13004 => 'hg',
13005 => 'erg',
13006 => 'ev',
13007 => 'ltd',
13008 => 'ア',
13009 => 'イ',
13010 => 'ウ',
13011 => 'エ',
13012 => 'オ',
13013 => 'カ',
13014 => 'キ',
13015 => 'ク',
13016 => 'ケ',
13017 => 'コ',
13018 => 'サ',
13019 => 'シ',
13020 => 'ス',
13021 => 'セ',
13022 => 'ソ',
13023 => 'タ',
13024 => 'チ',
13025 => 'ツ',
13026 => 'テ',
13027 => 'ト',
13028 => 'ナ',
13029 => 'ニ',
13030 => 'ヌ',
13031 => 'ネ',
13032 => 'ノ',
13033 => 'ハ',
13034 => 'ヒ',
13035 => 'フ',
13036 => 'ヘ',
13037 => 'ホ',
13038 => 'マ',
13039 => 'ミ',
13040 => 'ム',
13041 => 'メ',
13042 => 'モ',
13043 => 'ヤ',
13044 => 'ユ',
13045 => 'ヨ',
13046 => 'ラ',
13047 => 'リ',
13048 => 'ル',
13049 => 'レ',
13050 => 'ロ',
13051 => 'ワ',
13052 => 'ヰ',
13053 => 'ヱ',
13054 => 'ヲ',
13055 => '令和',
13056 => 'アパート',
13057 => 'アルファ',
13058 => 'アンペア',
13059 => 'アール',
13060 => 'イニング',
13061 => 'インチ',
13062 => 'ウォン',
13063 => 'エスクード',
13064 => 'エーカー',
13065 => 'オンス',
13066 => 'オーム',
13067 => 'カイリ',
13068 => 'カラット',
13069 => 'カロリー',
13070 => 'ガロン',
13071 => 'ガンマ',
13072 => 'ギガ',
13073 => 'ギニー',
13074 => 'キュリー',
13075 => 'ギルダー',
13076 => 'キロ',
13077 => 'キログラム',
13078 => 'キロメートル',
13079 => 'キロワット',
13080 => 'グラム',
13081 => 'グラムトン',
13082 => 'クルゼイロ',
13083 => 'クローネ',
13084 => 'ケース',
13085 => 'コルナ',
13086 => 'コーポ',
13087 => 'サイクル',
13088 => 'サンチーム',
13089 => 'シリング',
13090 => 'センチ',
13091 => 'セント',
13092 => 'ダース',
13093 => 'デシ',
13094 => 'ドル',
13095 => 'トン',
13096 => 'ナノ',
13097 => 'ノット',
13098 => 'ハイツ',
13099 => 'パーセント',
13100 => 'パーツ',
13101 => 'バーレル',
13102 => 'ピアストル',
13103 => 'ピクル',
13104 => 'ピコ',
13105 => 'ビル',
13106 => 'ファラッド',
13107 => 'フィート',
13108 => 'ブッシェル',
13109 => 'フラン',
13110 => 'ヘクタール',
13111 => 'ペソ',
13112 => 'ペニヒ',
13113 => 'ヘルツ',
13114 => 'ペンス',
13115 => 'ページ',
13116 => 'ベータ',
13117 => 'ポイント',
13118 => 'ボルト',
13119 => 'ホン',
13120 => 'ポンド',
13121 => 'ホール',
13122 => 'ホーン',
13123 => 'マイクロ',
13124 => 'マイル',
13125 => 'マッハ',
13126 => 'マルク',
13127 => 'マンション',
13128 => 'ミクロン',
13129 => 'ミリ',
13130 => 'ミリバール',
13131 => 'メガ',
13132 => 'メガトン',
13133 => 'メートル',
13134 => 'ヤード',
13135 => 'ヤール',
13136 => 'ユアン',
13137 => 'リットル',
13138 => 'リラ',
13139 => 'ルピー',
13140 => 'ルーブル',
13141 => 'レム',
13142 => 'レントゲン',
13143 => 'ワット',
13144 => '0点',
13145 => '1点',
13146 => '2点',
13147 => '3点',
13148 => '4点',
13149 => '5点',
13150 => '6点',
13151 => '7点',
13152 => '8点',
13153 => '9点',
13154 => '10点',
13155 => '11点',
13156 => '12点',
13157 => '13点',
13158 => '14点',
13159 => '15点',
13160 => '16点',
13161 => '17点',
13162 => '18点',
13163 => '19点',
13164 => '20点',
13165 => '21点',
13166 => '22点',
13167 => '23点',
13168 => '24点',
13169 => 'hpa',
13170 => 'da',
13171 => 'au',
13172 => 'bar',
13173 => 'ov',
13174 => 'pc',
13175 => 'dm',
13176 => 'dm2',
13177 => 'dm3',
13178 => 'iu',
13179 => '平成',
13180 => '昭和',
13181 => '大正',
13182 => '明治',
13183 => '株式会社',
13184 => 'pa',
13185 => 'na',
13186 => 'μa',
13187 => 'ma',
13188 => 'ka',
13189 => 'kb',
13190 => 'mb',
13191 => 'gb',
13192 => 'cal',
13193 => 'kcal',
13194 => 'pf',
13195 => 'nf',
13196 => 'μf',
13197 => 'μg',
13198 => 'mg',
13199 => 'kg',
13200 => 'hz',
13201 => 'khz',
13202 => 'mhz',
13203 => 'ghz',
13204 => 'thz',
13205 => 'μl',
13206 => 'ml',
13207 => 'dl',
13208 => 'kl',
13209 => 'fm',
13210 => 'nm',
13211 => 'μm',
13212 => 'mm',
13213 => 'cm',
13214 => 'km',
13215 => 'mm2',
13216 => 'cm2',
13217 => 'm2',
13218 => 'km2',
13219 => 'mm3',
13220 => 'cm3',
13221 => 'm3',
13222 => 'km3',
13223 => 'm∕s',
13224 => 'm∕s2',
13225 => 'pa',
13226 => 'kpa',
13227 => 'mpa',
13228 => 'gpa',
13229 => 'rad',
13230 => 'rad∕s',
13231 => 'rad∕s2',
13232 => 'ps',
13233 => 'ns',
13234 => 'μs',
13235 => 'ms',
13236 => 'pv',
13237 => 'nv',
13238 => 'μv',
13239 => 'mv',
13240 => 'kv',
13241 => 'mv',
13242 => 'pw',
13243 => 'nw',
13244 => 'μw',
13245 => 'mw',
13246 => 'kw',
13247 => 'mw',
13248 => 'kω',
13249 => 'mω',
13251 => 'bq',
13252 => 'cc',
13253 => 'cd',
13254 => 'c∕kg',
13256 => 'db',
13257 => 'gy',
13258 => 'ha',
13259 => 'hp',
13260 => 'in',
13261 => 'kk',
13262 => 'km',
13263 => 'kt',
13264 => 'lm',
13265 => 'ln',
13266 => 'log',
13267 => 'lx',
13268 => 'mb',
13269 => 'mil',
13270 => 'mol',
13271 => 'ph',
13273 => 'ppm',
13274 => 'pr',
13275 => 'sr',
13276 => 'sv',
13277 => 'wb',
13278 => 'v∕m',
13279 => 'a∕m',
13280 => '1日',
13281 => '2日',
13282 => '3日',
13283 => '4日',
13284 => '5日',
13285 => '6日',
13286 => '7日',
13287 => '8日',
13288 => '9日',
13289 => '10日',
13290 => '11日',
13291 => '12日',
13292 => '13日',
13293 => '14日',
13294 => '15日',
13295 => '16日',
13296 => '17日',
13297 => '18日',
13298 => '19日',
13299 => '20日',
13300 => '21日',
13301 => '22日',
13302 => '23日',
13303 => '24日',
13304 => '25日',
13305 => '26日',
13306 => '27日',
13307 => '28日',
13308 => '29日',
13309 => '30日',
13310 => '31日',
13311 => 'gal',
42560 => 'ꙁ',
42562 => 'ꙃ',
42564 => 'ꙅ',
42566 => 'ꙇ',
42568 => 'ꙉ',
42570 => 'ꙋ',
42572 => 'ꙍ',
42574 => 'ꙏ',
42576 => 'ꙑ',
42578 => 'ꙓ',
42580 => 'ꙕ',
42582 => 'ꙗ',
42584 => 'ꙙ',
42586 => 'ꙛ',
42588 => 'ꙝ',
42590 => 'ꙟ',
42592 => 'ꙡ',
42594 => 'ꙣ',
42596 => 'ꙥ',
42598 => 'ꙧ',
42600 => 'ꙩ',
42602 => 'ꙫ',
42604 => 'ꙭ',
42624 => 'ꚁ',
42626 => 'ꚃ',
42628 => 'ꚅ',
42630 => 'ꚇ',
42632 => 'ꚉ',
42634 => 'ꚋ',
42636 => 'ꚍ',
42638 => 'ꚏ',
42640 => 'ꚑ',
42642 => 'ꚓ',
42644 => 'ꚕ',
42646 => 'ꚗ',
42648 => 'ꚙ',
42650 => 'ꚛ',
42652 => 'ъ',
42653 => 'ь',
42786 => 'ꜣ',
42788 => 'ꜥ',
42790 => 'ꜧ',
42792 => 'ꜩ',
42794 => 'ꜫ',
42796 => 'ꜭ',
42798 => 'ꜯ',
42802 => 'ꜳ',
42804 => 'ꜵ',
42806 => 'ꜷ',
42808 => 'ꜹ',
42810 => 'ꜻ',
42812 => 'ꜽ',
42814 => 'ꜿ',
42816 => 'ꝁ',
42818 => 'ꝃ',
42820 => 'ꝅ',
42822 => 'ꝇ',
42824 => 'ꝉ',
42826 => 'ꝋ',
42828 => 'ꝍ',
42830 => 'ꝏ',
42832 => 'ꝑ',
42834 => 'ꝓ',
42836 => 'ꝕ',
42838 => 'ꝗ',
42840 => 'ꝙ',
42842 => 'ꝛ',
42844 => 'ꝝ',
42846 => 'ꝟ',
42848 => 'ꝡ',
42850 => 'ꝣ',
42852 => 'ꝥ',
42854 => 'ꝧ',
42856 => 'ꝩ',
42858 => 'ꝫ',
42860 => 'ꝭ',
42862 => 'ꝯ',
42864 => 'ꝯ',
42873 => 'ꝺ',
42875 => 'ꝼ',
42877 => 'ᵹ',
42878 => 'ꝿ',
42880 => 'ꞁ',
42882 => 'ꞃ',
42884 => 'ꞅ',
42886 => 'ꞇ',
42891 => 'ꞌ',
42893 => 'ɥ',
42896 => 'ꞑ',
42898 => 'ꞓ',
42902 => 'ꞗ',
42904 => 'ꞙ',
42906 => 'ꞛ',
42908 => 'ꞝ',
42910 => 'ꞟ',
42912 => 'ꞡ',
42914 => 'ꞣ',
42916 => 'ꞥ',
42918 => 'ꞧ',
42920 => 'ꞩ',
42922 => 'ɦ',
42923 => 'ɜ',
42924 => 'ɡ',
42925 => 'ɬ',
42926 => 'ɪ',
42928 => 'ʞ',
42929 => 'ʇ',
42930 => 'ʝ',
42931 => 'ꭓ',
42932 => 'ꞵ',
42934 => 'ꞷ',
42936 => 'ꞹ',
42938 => 'ꞻ',
42940 => 'ꞽ',
42942 => 'ꞿ',
42946 => 'ꟃ',
42948 => 'ꞔ',
42949 => 'ʂ',
42950 => 'ᶎ',
42951 => 'ꟈ',
42953 => 'ꟊ',
42997 => 'ꟶ',
43000 => 'ħ',
43001 => 'œ',
43868 => 'ꜧ',
43869 => 'ꬷ',
43870 => 'ɫ',
43871 => 'ꭒ',
43881 => 'ʍ',
43888 => 'Ꭰ',
43889 => 'Ꭱ',
43890 => 'Ꭲ',
43891 => 'Ꭳ',
43892 => 'Ꭴ',
43893 => 'Ꭵ',
43894 => 'Ꭶ',
43895 => 'Ꭷ',
43896 => 'Ꭸ',
43897 => 'Ꭹ',
43898 => 'Ꭺ',
43899 => 'Ꭻ',
43900 => 'Ꭼ',
43901 => 'Ꭽ',
43902 => 'Ꭾ',
43903 => 'Ꭿ',
43904 => 'Ꮀ',
43905 => 'Ꮁ',
43906 => 'Ꮂ',
43907 => 'Ꮃ',
43908 => 'Ꮄ',
43909 => 'Ꮅ',
43910 => 'Ꮆ',
43911 => 'Ꮇ',
43912 => 'Ꮈ',
43913 => 'Ꮉ',
43914 => 'Ꮊ',
43915 => 'Ꮋ',
43916 => 'Ꮌ',
43917 => 'Ꮍ',
43918 => 'Ꮎ',
43919 => 'Ꮏ',
43920 => 'Ꮐ',
43921 => 'Ꮑ',
43922 => 'Ꮒ',
43923 => 'Ꮓ',
43924 => 'Ꮔ',
43925 => 'Ꮕ',
43926 => 'Ꮖ',
43927 => 'Ꮗ',
43928 => 'Ꮘ',
43929 => 'Ꮙ',
43930 => 'Ꮚ',
43931 => 'Ꮛ',
43932 => 'Ꮜ',
43933 => 'Ꮝ',
43934 => 'Ꮞ',
43935 => 'Ꮟ',
43936 => 'Ꮠ',
43937 => 'Ꮡ',
43938 => 'Ꮢ',
43939 => 'Ꮣ',
43940 => 'Ꮤ',
43941 => 'Ꮥ',
43942 => 'Ꮦ',
43943 => 'Ꮧ',
43944 => 'Ꮨ',
43945 => 'Ꮩ',
43946 => 'Ꮪ',
43947 => 'Ꮫ',
43948 => 'Ꮬ',
43949 => 'Ꮭ',
43950 => 'Ꮮ',
43951 => 'Ꮯ',
43952 => 'Ꮰ',
43953 => 'Ꮱ',
43954 => 'Ꮲ',
43955 => 'Ꮳ',
43956 => 'Ꮴ',
43957 => 'Ꮵ',
43958 => 'Ꮶ',
43959 => 'Ꮷ',
43960 => 'Ꮸ',
43961 => 'Ꮹ',
43962 => 'Ꮺ',
43963 => 'Ꮻ',
43964 => 'Ꮼ',
43965 => 'Ꮽ',
43966 => 'Ꮾ',
43967 => 'Ꮿ',
63744 => '豈',
63745 => '更',
63746 => '車',
63747 => '賈',
63748 => '滑',
63749 => '串',
63750 => '句',
63751 => '龜',
63752 => '龜',
63753 => '契',
63754 => '金',
63755 => '喇',
63756 => '奈',
63757 => '懶',
63758 => '癩',
63759 => '羅',
63760 => '蘿',
63761 => '螺',
63762 => '裸',
63763 => '邏',
63764 => '樂',
63765 => '洛',
63766 => '烙',
63767 => '珞',
63768 => '落',
63769 => '酪',
63770 => '駱',
63771 => '亂',
63772 => '卵',
63773 => '欄',
63774 => '爛',
63775 => '蘭',
63776 => '鸞',
63777 => '嵐',
63778 => '濫',
63779 => '藍',
63780 => '襤',
63781 => '拉',
63782 => '臘',
63783 => '蠟',
63784 => '廊',
63785 => '朗',
63786 => '浪',
63787 => '狼',
63788 => '郎',
63789 => '來',
63790 => '冷',
63791 => '勞',
63792 => '擄',
63793 => '櫓',
63794 => '爐',
63795 => '盧',
63796 => '老',
63797 => '蘆',
63798 => '虜',
63799 => '路',
63800 => '露',
63801 => '魯',
63802 => '鷺',
63803 => '碌',
63804 => '祿',
63805 => '綠',
63806 => '菉',
63807 => '錄',
63808 => '鹿',
63809 => '論',
63810 => '壟',
63811 => '弄',
63812 => '籠',
63813 => '聾',
63814 => '牢',
63815 => '磊',
63816 => '賂',
63817 => '雷',
63818 => '壘',
63819 => '屢',
63820 => '樓',
63821 => '淚',
63822 => '漏',
63823 => '累',
63824 => '縷',
63825 => '陋',
63826 => '勒',
63827 => '肋',
63828 => '凜',
63829 => '凌',
63830 => '稜',
63831 => '綾',
63832 => '菱',
63833 => '陵',
63834 => '讀',
63835 => '拏',
63836 => '樂',
63837 => '諾',
63838 => '丹',
63839 => '寧',
63840 => '怒',
63841 => '率',
63842 => '異',
63843 => '北',
63844 => '磻',
63845 => '便',
63846 => '復',
63847 => '不',
63848 => '泌',
63849 => '數',
63850 => '索',
63851 => '參',
63852 => '塞',
63853 => '省',
63854 => '葉',
63855 => '說',
63856 => '殺',
63857 => '辰',
63858 => '沈',
63859 => '拾',
63860 => '若',
63861 => '掠',
63862 => '略',
63863 => '亮',
63864 => '兩',
63865 => '凉',
63866 => '梁',
63867 => '糧',
63868 => '良',
63869 => '諒',
63870 => '量',
63871 => '勵',
63872 => '呂',
63873 => '女',
63874 => '廬',
63875 => '旅',
63876 => '濾',
63877 => '礪',
63878 => '閭',
63879 => '驪',
63880 => '麗',
63881 => '黎',
63882 => '力',
63883 => '曆',
63884 => '歷',
63885 => '轢',
63886 => '年',
63887 => '憐',
63888 => '戀',
63889 => '撚',
63890 => '漣',
63891 => '煉',
63892 => '璉',
63893 => '秊',
63894 => '練',
63895 => '聯',
63896 => '輦',
63897 => '蓮',
63898 => '連',
63899 => '鍊',
63900 => '列',
63901 => '劣',
63902 => '咽',
63903 => '烈',
63904 => '裂',
63905 => '說',
63906 => '廉',
63907 => '念',
63908 => '捻',
63909 => '殮',
63910 => '簾',
63911 => '獵',
63912 => '令',
63913 => '囹',
63914 => '寧',
63915 => '嶺',
63916 => '怜',
63917 => '玲',
63918 => '瑩',
63919 => '羚',
63920 => '聆',
63921 => '鈴',
63922 => '零',
63923 => '靈',
63924 => '領',
63925 => '例',
63926 => '禮',
63927 => '醴',
63928 => '隸',
63929 => '惡',
63930 => '了',
63931 => '僚',
63932 => '寮',
63933 => '尿',
63934 => '料',
63935 => '樂',
63936 => '燎',
63937 => '療',
63938 => '蓼',
63939 => '遼',
63940 => '龍',
63941 => '暈',
63942 => '阮',
63943 => '劉',
63944 => '杻',
63945 => '柳',
63946 => '流',
63947 => '溜',
63948 => '琉',
63949 => '留',
63950 => '硫',
63951 => '紐',
63952 => '類',
63953 => '六',
63954 => '戮',
63955 => '陸',
63956 => '倫',
63957 => '崙',
63958 => '淪',
63959 => '輪',
63960 => '律',
63961 => '慄',
63962 => '栗',
63963 => '率',
63964 => '隆',
63965 => '利',
63966 => '吏',
63967 => '履',
63968 => '易',
63969 => '李',
63970 => '梨',
63971 => '泥',
63972 => '理',
63973 => '痢',
63974 => '罹',
63975 => '裏',
63976 => '裡',
63977 => '里',
63978 => '離',
63979 => '匿',
63980 => '溺',
63981 => '吝',
63982 => '燐',
63983 => '璘',
63984 => '藺',
63985 => '隣',
63986 => '鱗',
63987 => '麟',
63988 => '林',
63989 => '淋',
63990 => '臨',
63991 => '立',
63992 => '笠',
63993 => '粒',
63994 => '狀',
63995 => '炙',
63996 => '識',
63997 => '什',
63998 => '茶',
63999 => '刺',
64000 => '切',
64001 => '度',
64002 => '拓',
64003 => '糖',
64004 => '宅',
64005 => '洞',
64006 => '暴',
64007 => '輻',
64008 => '行',
64009 => '降',
64010 => '見',
64011 => '廓',
64012 => '兀',
64013 => '嗀',
64016 => '塚',
64018 => '晴',
64021 => '凞',
64022 => '猪',
64023 => '益',
64024 => '礼',
64025 => '神',
64026 => '祥',
64027 => '福',
64028 => '靖',
64029 => '精',
64030 => '羽',
64032 => '蘒',
64034 => '諸',
64037 => '逸',
64038 => '都',
64042 => '飯',
64043 => '飼',
64044 => '館',
64045 => '鶴',
64046 => '郞',
64047 => '隷',
64048 => '侮',
64049 => '僧',
64050 => '免',
64051 => '勉',
64052 => '勤',
64053 => '卑',
64054 => '喝',
64055 => '嘆',
64056 => '器',
64057 => '塀',
64058 => '墨',
64059 => '層',
64060 => '屮',
64061 => '悔',
64062 => '慨',
64063 => '憎',
64064 => '懲',
64065 => '敏',
64066 => '既',
64067 => '暑',
64068 => '梅',
64069 => '海',
64070 => '渚',
64071 => '漢',
64072 => '煮',
64073 => '爫',
64074 => '琢',
64075 => '碑',
64076 => '社',
64077 => '祉',
64078 => '祈',
64079 => '祐',
64080 => '祖',
64081 => '祝',
64082 => '禍',
64083 => '禎',
64084 => '穀',
64085 => '突',
64086 => '節',
64087 => '練',
64088 => '縉',
64089 => '繁',
64090 => '署',
64091 => '者',
64092 => '臭',
64093 => '艹',
64094 => '艹',
64095 => '著',
64096 => '褐',
64097 => '視',
64098 => '謁',
64099 => '謹',
64100 => '賓',
64101 => '贈',
64102 => '辶',
64103 => '逸',
64104 => '難',
64105 => '響',
64106 => '頻',
64107 => '恵',
64108 => '𤋮',
64109 => '舘',
64112 => '並',
64113 => '况',
64114 => '全',
64115 => '侀',
64116 => '充',
64117 => '冀',
64118 => '勇',
64119 => '勺',
64120 => '喝',
64121 => '啕',
64122 => '喙',
64123 => '嗢',
64124 => '塚',
64125 => '墳',
64126 => '奄',
64127 => '奔',
64128 => '婢',
64129 => '嬨',
64130 => '廒',
64131 => '廙',
64132 => '彩',
64133 => '徭',
64134 => '惘',
64135 => '慎',
64136 => '愈',
64137 => '憎',
64138 => '慠',
64139 => '懲',
64140 => '戴',
64141 => '揄',
64142 => '搜',
64143 => '摒',
64144 => '敖',
64145 => '晴',
64146 => '朗',
64147 => '望',
64148 => '杖',
64149 => '歹',
64150 => '殺',
64151 => '流',
64152 => '滛',
64153 => '滋',
64154 => '漢',
64155 => '瀞',
64156 => '煮',
64157 => '瞧',
64158 => '爵',
64159 => '犯',
64160 => '猪',
64161 => '瑱',
64162 => '甆',
64163 => '画',
64164 => '瘝',
64165 => '瘟',
64166 => '益',
64167 => '盛',
64168 => '直',
64169 => '睊',
64170 => '着',
64171 => '磌',
64172 => '窱',
64173 => '節',
64174 => '类',
64175 => '絛',
64176 => '練',
64177 => '缾',
64178 => '者',
64179 => '荒',
64180 => '華',
64181 => '蝹',
64182 => '襁',
64183 => '覆',
64184 => '視',
64185 => '調',
64186 => '諸',
64187 => '請',
64188 => '謁',
64189 => '諾',
64190 => '諭',
64191 => '謹',
64192 => '變',
64193 => '贈',
64194 => '輸',
64195 => '遲',
64196 => '醙',
64197 => '鉶',
64198 => '陼',
64199 => '難',
64200 => '靖',
64201 => '韛',
64202 => '響',
64203 => '頋',
64204 => '頻',
64205 => '鬒',
64206 => '龜',
64207 => '𢡊',
64208 => '𢡄',
64209 => '𣏕',
64210 => '㮝',
64211 => '䀘',
64212 => '䀹',
64213 => '𥉉',
64214 => '𥳐',
64215 => '𧻓',
64216 => '齃',
64217 => '龎',
64256 => 'ff',
64257 => 'fi',
64258 => 'fl',
64259 => 'ffi',
64260 => 'ffl',
64261 => 'st',
64262 => 'st',
64275 => 'մն',
64276 => 'մե',
64277 => 'մի',
64278 => 'վն',
64279 => 'մխ',
64285 => 'יִ',
64287 => 'ײַ',
64288 => 'ע',
64289 => 'א',
64290 => 'ד',
64291 => 'ה',
64292 => 'כ',
64293 => 'ל',
64294 => 'ם',
64295 => 'ר',
64296 => 'ת',
64298 => 'שׁ',
64299 => 'שׂ',
64300 => 'שּׁ',
64301 => 'שּׂ',
64302 => 'אַ',
64303 => 'אָ',
64304 => 'אּ',
64305 => 'בּ',
64306 => 'גּ',
64307 => 'דּ',
64308 => 'הּ',
64309 => 'וּ',
64310 => 'זּ',
64312 => 'טּ',
64313 => 'יּ',
64314 => 'ךּ',
64315 => 'כּ',
64316 => 'לּ',
64318 => 'מּ',
64320 => 'נּ',
64321 => 'סּ',
64323 => 'ףּ',
64324 => 'פּ',
64326 => 'צּ',
64327 => 'קּ',
64328 => 'רּ',
64329 => 'שּ',
64330 => 'תּ',
64331 => 'וֹ',
64332 => 'בֿ',
64333 => 'כֿ',
64334 => 'פֿ',
64335 => 'אל',
64336 => 'ٱ',
64337 => 'ٱ',
64338 => 'ٻ',
64339 => 'ٻ',
64340 => 'ٻ',
64341 => 'ٻ',
64342 => 'پ',
64343 => 'پ',
64344 => 'پ',
64345 => 'پ',
64346 => 'ڀ',
64347 => 'ڀ',
64348 => 'ڀ',
64349 => 'ڀ',
64350 => 'ٺ',
64351 => 'ٺ',
64352 => 'ٺ',
64353 => 'ٺ',
64354 => 'ٿ',
64355 => 'ٿ',
64356 => 'ٿ',
64357 => 'ٿ',
64358 => 'ٹ',
64359 => 'ٹ',
64360 => 'ٹ',
64361 => 'ٹ',
64362 => 'ڤ',
64363 => 'ڤ',
64364 => 'ڤ',
64365 => 'ڤ',
64366 => 'ڦ',
64367 => 'ڦ',
64368 => 'ڦ',
64369 => 'ڦ',
64370 => 'ڄ',
64371 => 'ڄ',
64372 => 'ڄ',
64373 => 'ڄ',
64374 => 'ڃ',
64375 => 'ڃ',
64376 => 'ڃ',
64377 => 'ڃ',
64378 => 'چ',
64379 => 'چ',
64380 => 'چ',
64381 => 'چ',
64382 => 'ڇ',
64383 => 'ڇ',
64384 => 'ڇ',
64385 => 'ڇ',
64386 => 'ڍ',
64387 => 'ڍ',
64388 => 'ڌ',
64389 => 'ڌ',
64390 => 'ڎ',
64391 => 'ڎ',
64392 => 'ڈ',
64393 => 'ڈ',
64394 => 'ژ',
64395 => 'ژ',
64396 => 'ڑ',
64397 => 'ڑ',
64398 => 'ک',
64399 => 'ک',
64400 => 'ک',
64401 => 'ک',
64402 => 'گ',
64403 => 'گ',
64404 => 'گ',
64405 => 'گ',
64406 => 'ڳ',
64407 => 'ڳ',
64408 => 'ڳ',
64409 => 'ڳ',
64410 => 'ڱ',
64411 => 'ڱ',
64412 => 'ڱ',
64413 => 'ڱ',
64414 => 'ں',
64415 => 'ں',
64416 => 'ڻ',
64417 => 'ڻ',
64418 => 'ڻ',
64419 => 'ڻ',
64420 => 'ۀ',
64421 => 'ۀ',
64422 => 'ہ',
64423 => 'ہ',
64424 => 'ہ',
64425 => 'ہ',
64426 => 'ھ',
64427 => 'ھ',
64428 => 'ھ',
64429 => 'ھ',
64430 => 'ے',
64431 => 'ے',
64432 => 'ۓ',
64433 => 'ۓ',
64467 => 'ڭ',
64468 => 'ڭ',
64469 => 'ڭ',
64470 => 'ڭ',
64471 => 'ۇ',
64472 => 'ۇ',
64473 => 'ۆ',
64474 => 'ۆ',
64475 => 'ۈ',
64476 => 'ۈ',
64477 => 'ۇٴ',
64478 => 'ۋ',
64479 => 'ۋ',
64480 => 'ۅ',
64481 => 'ۅ',
64482 => 'ۉ',
64483 => 'ۉ',
64484 => 'ې',
64485 => 'ې',
64486 => 'ې',
64487 => 'ې',
64488 => 'ى',
64489 => 'ى',
64490 => 'ئا',
64491 => 'ئا',
64492 => 'ئە',
64493 => 'ئە',
64494 => 'ئو',
64495 => 'ئو',
64496 => 'ئۇ',
64497 => 'ئۇ',
64498 => 'ئۆ',
64499 => 'ئۆ',
64500 => 'ئۈ',
64501 => 'ئۈ',
64502 => 'ئې',
64503 => 'ئې',
64504 => 'ئې',
64505 => 'ئى',
64506 => 'ئى',
64507 => 'ئى',
64508 => 'ی',
64509 => 'ی',
64510 => 'ی',
64511 => 'ی',
64512 => 'ئج',
64513 => 'ئح',
64514 => 'ئم',
64515 => 'ئى',
64516 => 'ئي',
64517 => 'بج',
64518 => 'بح',
64519 => 'بخ',
64520 => 'بم',
64521 => 'بى',
64522 => 'بي',
64523 => 'تج',
64524 => 'تح',
64525 => 'تخ',
64526 => 'تم',
64527 => 'تى',
64528 => 'تي',
64529 => 'ثج',
64530 => 'ثم',
64531 => 'ثى',
64532 => 'ثي',
64533 => 'جح',
64534 => 'جم',
64535 => 'حج',
64536 => 'حم',
64537 => 'خج',
64538 => 'خح',
64539 => 'خم',
64540 => 'سج',
64541 => 'سح',
64542 => 'سخ',
64543 => 'سم',
64544 => 'صح',
64545 => 'صم',
64546 => 'ضج',
64547 => 'ضح',
64548 => 'ضخ',
64549 => 'ضم',
64550 => 'طح',
64551 => 'طم',
64552 => 'ظم',
64553 => 'عج',
64554 => 'عم',
64555 => 'غج',
64556 => 'غم',
64557 => 'فج',
64558 => 'فح',
64559 => 'فخ',
64560 => 'فم',
64561 => 'فى',
64562 => 'في',
64563 => 'قح',
64564 => 'قم',
64565 => 'قى',
64566 => 'قي',
64567 => 'كا',
64568 => 'كج',
64569 => 'كح',
64570 => 'كخ',
64571 => 'كل',
64572 => 'كم',
64573 => 'كى',
64574 => 'كي',
64575 => 'لج',
64576 => 'لح',
64577 => 'لخ',
64578 => 'لم',
64579 => 'لى',
64580 => 'لي',
64581 => 'مج',
64582 => 'مح',
64583 => 'مخ',
64584 => 'مم',
64585 => 'مى',
64586 => 'مي',
64587 => 'نج',
64588 => 'نح',
64589 => 'نخ',
64590 => 'نم',
64591 => 'نى',
64592 => 'ني',
64593 => 'هج',
64594 => 'هم',
64595 => 'هى',
64596 => 'هي',
64597 => 'يج',
64598 => 'يح',
64599 => 'يخ',
64600 => 'يم',
64601 => 'يى',
64602 => 'يي',
64603 => 'ذٰ',
64604 => 'رٰ',
64605 => 'ىٰ',
64612 => 'ئر',
64613 => 'ئز',
64614 => 'ئم',
64615 => 'ئن',
64616 => 'ئى',
64617 => 'ئي',
64618 => 'بر',
64619 => 'بز',
64620 => 'بم',
64621 => 'بن',
64622 => 'بى',
64623 => 'بي',
64624 => 'تر',
64625 => 'تز',
64626 => 'تم',
64627 => 'تن',
64628 => 'تى',
64629 => 'تي',
64630 => 'ثر',
64631 => 'ثز',
64632 => 'ثم',
64633 => 'ثن',
64634 => 'ثى',
64635 => 'ثي',
64636 => 'فى',
64637 => 'في',
64638 => 'قى',
64639 => 'قي',
64640 => 'كا',
64641 => 'كل',
64642 => 'كم',
64643 => 'كى',
64644 => 'كي',
64645 => 'لم',
64646 => 'لى',
64647 => 'لي',
64648 => 'ما',
64649 => 'مم',
64650 => 'نر',
64651 => 'نز',
64652 => 'نم',
64653 => 'نن',
64654 => 'نى',
64655 => 'ني',
64656 => 'ىٰ',
64657 => 'ير',
64658 => 'يز',
64659 => 'يم',
64660 => 'ين',
64661 => 'يى',
64662 => 'يي',
64663 => 'ئج',
64664 => 'ئح',
64665 => 'ئخ',
64666 => 'ئم',
64667 => 'ئه',
64668 => 'بج',
64669 => 'بح',
64670 => 'بخ',
64671 => 'بم',
64672 => 'به',
64673 => 'تج',
64674 => 'تح',
64675 => 'تخ',
64676 => 'تم',
64677 => 'ته',
64678 => 'ثم',
64679 => 'جح',
64680 => 'جم',
64681 => 'حج',
64682 => 'حم',
64683 => 'خج',
64684 => 'خم',
64685 => 'سج',
64686 => 'سح',
64687 => 'سخ',
64688 => 'سم',
64689 => 'صح',
64690 => 'صخ',
64691 => 'صم',
64692 => 'ضج',
64693 => 'ضح',
64694 => 'ضخ',
64695 => 'ضم',
64696 => 'طح',
64697 => 'ظم',
64698 => 'عج',
64699 => 'عم',
64700 => 'غج',
64701 => 'غم',
64702 => 'فج',
64703 => 'فح',
64704 => 'فخ',
64705 => 'فم',
64706 => 'قح',
64707 => 'قم',
64708 => 'كج',
64709 => 'كح',
64710 => 'كخ',
64711 => 'كل',
64712 => 'كم',
64713 => 'لج',
64714 => 'لح',
64715 => 'لخ',
64716 => 'لم',
64717 => 'له',
64718 => 'مج',
64719 => 'مح',
64720 => 'مخ',
64721 => 'مم',
64722 => 'نج',
64723 => 'نح',
64724 => 'نخ',
64725 => 'نم',
64726 => 'نه',
64727 => 'هج',
64728 => 'هم',
64729 => 'هٰ',
64730 => 'يج',
64731 => 'يح',
64732 => 'يخ',
64733 => 'يم',
64734 => 'يه',
64735 => 'ئم',
64736 => 'ئه',
64737 => 'بم',
64738 => 'به',
64739 => 'تم',
64740 => 'ته',
64741 => 'ثم',
64742 => 'ثه',
64743 => 'سم',
64744 => 'سه',
64745 => 'شم',
64746 => 'شه',
64747 => 'كل',
64748 => 'كم',
64749 => 'لم',
64750 => 'نم',
64751 => 'نه',
64752 => 'يم',
64753 => 'يه',
64754 => 'ـَّ',
64755 => 'ـُّ',
64756 => 'ـِّ',
64757 => 'طى',
64758 => 'طي',
64759 => 'عى',
64760 => 'عي',
64761 => 'غى',
64762 => 'غي',
64763 => 'سى',
64764 => 'سي',
64765 => 'شى',
64766 => 'شي',
64767 => 'حى',
64768 => 'حي',
64769 => 'جى',
64770 => 'جي',
64771 => 'خى',
64772 => 'خي',
64773 => 'صى',
64774 => 'صي',
64775 => 'ضى',
64776 => 'ضي',
64777 => 'شج',
64778 => 'شح',
64779 => 'شخ',
64780 => 'شم',
64781 => 'شر',
64782 => 'سر',
64783 => 'صر',
64784 => 'ضر',
64785 => 'طى',
64786 => 'طي',
64787 => 'عى',
64788 => 'عي',
64789 => 'غى',
64790 => 'غي',
64791 => 'سى',
64792 => 'سي',
64793 => 'شى',
64794 => 'شي',
64795 => 'حى',
64796 => 'حي',
64797 => 'جى',
64798 => 'جي',
64799 => 'خى',
64800 => 'خي',
64801 => 'صى',
64802 => 'صي',
64803 => 'ضى',
64804 => 'ضي',
64805 => 'شج',
64806 => 'شح',
64807 => 'شخ',
64808 => 'شم',
64809 => 'شر',
64810 => 'سر',
64811 => 'صر',
64812 => 'ضر',
64813 => 'شج',
64814 => 'شح',
64815 => 'شخ',
64816 => 'شم',
64817 => 'سه',
64818 => 'شه',
64819 => 'طم',
64820 => 'سج',
64821 => 'سح',
64822 => 'سخ',
64823 => 'شج',
64824 => 'شح',
64825 => 'شخ',
64826 => 'طم',
64827 => 'ظم',
64828 => 'اً',
64829 => 'اً',
64848 => 'تجم',
64849 => 'تحج',
64850 => 'تحج',
64851 => 'تحم',
64852 => 'تخم',
64853 => 'تمج',
64854 => 'تمح',
64855 => 'تمخ',
64856 => 'جمح',
64857 => 'جمح',
64858 => 'حمي',
64859 => 'حمى',
64860 => 'سحج',
64861 => 'سجح',
64862 => 'سجى',
64863 => 'سمح',
64864 => 'سمح',
64865 => 'سمج',
64866 => 'سمم',
64867 => 'سمم',
64868 => 'صحح',
64869 => 'صحح',
64870 => 'صمم',
64871 => 'شحم',
64872 => 'شحم',
64873 => 'شجي',
64874 => 'شمخ',
64875 => 'شمخ',
64876 => 'شمم',
64877 => 'شمم',
64878 => 'ضحى',
64879 => 'ضخم',
64880 => 'ضخم',
64881 => 'طمح',
64882 => 'طمح',
64883 => 'طمم',
64884 => 'طمي',
64885 => 'عجم',
64886 => 'عمم',
64887 => 'عمم',
64888 => 'عمى',
64889 => 'غمم',
64890 => 'غمي',
64891 => 'غمى',
64892 => 'فخم',
64893 => 'فخم',
64894 => 'قمح',
64895 => 'قمم',
64896 => 'لحم',
64897 => 'لحي',
64898 => 'لحى',
64899 => 'لجج',
64900 => 'لجج',
64901 => 'لخم',
64902 => 'لخم',
64903 => 'لمح',
64904 => 'لمح',
64905 => 'محج',
64906 => 'محم',
64907 => 'محي',
64908 => 'مجح',
64909 => 'مجم',
64910 => 'مخج',
64911 => 'مخم',
64914 => 'مجخ',
64915 => 'همج',
64916 => 'همم',
64917 => 'نحم',
64918 => 'نحى',
64919 => 'نجم',
64920 => 'نجم',
64921 => 'نجى',
64922 => 'نمي',
64923 => 'نمى',
64924 => 'يمم',
64925 => 'يمم',
64926 => 'بخي',
64927 => 'تجي',
64928 => 'تجى',
64929 => 'تخي',
64930 => 'تخى',
64931 => 'تمي',
64932 => 'تمى',
64933 => 'جمي',
64934 => 'جحى',
64935 => 'جمى',
64936 => 'سخى',
64937 => 'صحي',
64938 => 'شحي',
64939 => 'ضحي',
64940 => 'لجي',
64941 => 'لمي',
64942 => 'يحي',
64943 => 'يجي',
64944 => 'يمي',
64945 => 'ممي',
64946 => 'قمي',
64947 => 'نحي',
64948 => 'قمح',
64949 => 'لحم',
64950 => 'عمي',
64951 => 'كمي',
64952 => 'نجح',
64953 => 'مخي',
64954 => 'لجم',
64955 => 'كمم',
64956 => 'لجم',
64957 => 'نجح',
64958 => 'جحي',
64959 => 'حجي',
64960 => 'مجي',
64961 => 'فمي',
64962 => 'بحي',
64963 => 'كمم',
64964 => 'عجم',
64965 => 'صمم',
64966 => 'سخي',
64967 => 'نجي',
65008 => 'صلے',
65009 => 'قلے',
65010 => 'الله',
65011 => 'اكبر',
65012 => 'محمد',
65013 => 'صلعم',
65014 => 'رسول',
65015 => 'عليه',
65016 => 'وسلم',
65017 => 'صلى',
65020 => 'ریال',
65041 => '、',
65047 => '〖',
65048 => '〗',
65073 => '—',
65074 => '–',
65081 => '〔',
65082 => '〕',
65083 => '【',
65084 => '】',
65085 => '《',
65086 => '》',
65087 => '〈',
65088 => '〉',
65089 => '「',
65090 => '」',
65091 => '『',
65092 => '』',
65105 => '、',
65112 => '—',
65117 => '〔',
65118 => '〕',
65123 => '-',
65137 => 'ـً',
65143 => 'ـَ',
65145 => 'ـُ',
65147 => 'ـِ',
65149 => 'ـّ',
65151 => 'ـْ',
65152 => 'ء',
65153 => 'آ',
65154 => 'آ',
65155 => 'أ',
65156 => 'أ',
65157 => 'ؤ',
65158 => 'ؤ',
65159 => 'إ',
65160 => 'إ',
65161 => 'ئ',
65162 => 'ئ',
65163 => 'ئ',
65164 => 'ئ',
65165 => 'ا',
65166 => 'ا',
65167 => 'ب',
65168 => 'ب',
65169 => 'ب',
65170 => 'ب',
65171 => 'ة',
65172 => 'ة',
65173 => 'ت',
65174 => 'ت',
65175 => 'ت',
65176 => 'ت',
65177 => 'ث',
65178 => 'ث',
65179 => 'ث',
65180 => 'ث',
65181 => 'ج',
65182 => 'ج',
65183 => 'ج',
65184 => 'ج',
65185 => 'ح',
65186 => 'ح',
65187 => 'ح',
65188 => 'ح',
65189 => 'خ',
65190 => 'خ',
65191 => 'خ',
65192 => 'خ',
65193 => 'د',
65194 => 'د',
65195 => 'ذ',
65196 => 'ذ',
65197 => 'ر',
65198 => 'ر',
65199 => 'ز',
65200 => 'ز',
65201 => 'س',
65202 => 'س',
65203 => 'س',
65204 => 'س',
65205 => 'ش',
65206 => 'ش',
65207 => 'ش',
65208 => 'ش',
65209 => 'ص',
65210 => 'ص',
65211 => 'ص',
65212 => 'ص',
65213 => 'ض',
65214 => 'ض',
65215 => 'ض',
65216 => 'ض',
65217 => 'ط',
65218 => 'ط',
65219 => 'ط',
65220 => 'ط',
65221 => 'ظ',
65222 => 'ظ',
65223 => 'ظ',
65224 => 'ظ',
65225 => 'ع',
65226 => 'ع',
65227 => 'ع',
65228 => 'ع',
65229 => 'غ',
65230 => 'غ',
65231 => 'غ',
65232 => 'غ',
65233 => 'ف',
65234 => 'ف',
65235 => 'ف',
65236 => 'ف',
65237 => 'ق',
65238 => 'ق',
65239 => 'ق',
65240 => 'ق',
65241 => 'ك',
65242 => 'ك',
65243 => 'ك',
65244 => 'ك',
65245 => 'ل',
65246 => 'ل',
65247 => 'ل',
65248 => 'ل',
65249 => 'م',
65250 => 'م',
65251 => 'م',
65252 => 'م',
65253 => 'ن',
65254 => 'ن',
65255 => 'ن',
65256 => 'ن',
65257 => 'ه',
65258 => 'ه',
65259 => 'ه',
65260 => 'ه',
65261 => 'و',
65262 => 'و',
65263 => 'ى',
65264 => 'ى',
65265 => 'ي',
65266 => 'ي',
65267 => 'ي',
65268 => 'ي',
65269 => 'لآ',
65270 => 'لآ',
65271 => 'لأ',
65272 => 'لأ',
65273 => 'لإ',
65274 => 'لإ',
65275 => 'لا',
65276 => 'لا',
65293 => '-',
65294 => '.',
65296 => '0',
65297 => '1',
65298 => '2',
65299 => '3',
65300 => '4',
65301 => '5',
65302 => '6',
65303 => '7',
65304 => '8',
65305 => '9',
65313 => 'a',
65314 => 'b',
65315 => 'c',
65316 => 'd',
65317 => 'e',
65318 => 'f',
65319 => 'g',
65320 => 'h',
65321 => 'i',
65322 => 'j',
65323 => 'k',
65324 => 'l',
65325 => 'm',
65326 => 'n',
65327 => 'o',
65328 => 'p',
65329 => 'q',
65330 => 'r',
65331 => 's',
65332 => 't',
65333 => 'u',
65334 => 'v',
65335 => 'w',
65336 => 'x',
65337 => 'y',
65338 => 'z',
65345 => 'a',
65346 => 'b',
65347 => 'c',
65348 => 'd',
65349 => 'e',
65350 => 'f',
65351 => 'g',
65352 => 'h',
65353 => 'i',
65354 => 'j',
65355 => 'k',
65356 => 'l',
65357 => 'm',
65358 => 'n',
65359 => 'o',
65360 => 'p',
65361 => 'q',
65362 => 'r',
65363 => 's',
65364 => 't',
65365 => 'u',
65366 => 'v',
65367 => 'w',
65368 => 'x',
65369 => 'y',
65370 => 'z',
65375 => '⦅',
65376 => '⦆',
65377 => '.',
65378 => '「',
65379 => '」',
65380 => '、',
65381 => '・',
65382 => 'ヲ',
65383 => 'ァ',
65384 => 'ィ',
65385 => 'ゥ',
65386 => 'ェ',
65387 => 'ォ',
65388 => 'ャ',
65389 => 'ュ',
65390 => 'ョ',
65391 => 'ッ',
65392 => 'ー',
65393 => 'ア',
65394 => 'イ',
65395 => 'ウ',
65396 => 'エ',
65397 => 'オ',
65398 => 'カ',
65399 => 'キ',
65400 => 'ク',
65401 => 'ケ',
65402 => 'コ',
65403 => 'サ',
65404 => 'シ',
65405 => 'ス',
65406 => 'セ',
65407 => 'ソ',
65408 => 'タ',
65409 => 'チ',
65410 => 'ツ',
65411 => 'テ',
65412 => 'ト',
65413 => 'ナ',
65414 => 'ニ',
65415 => 'ヌ',
65416 => 'ネ',
65417 => 'ノ',
65418 => 'ハ',
65419 => 'ヒ',
65420 => 'フ',
65421 => 'ヘ',
65422 => 'ホ',
65423 => 'マ',
65424 => 'ミ',
65425 => 'ム',
65426 => 'メ',
65427 => 'モ',
65428 => 'ヤ',
65429 => 'ユ',
65430 => 'ヨ',
65431 => 'ラ',
65432 => 'リ',
65433 => 'ル',
65434 => 'レ',
65435 => 'ロ',
65436 => 'ワ',
65437 => 'ン',
65438 => '゙',
65439 => '゚',
65441 => 'ᄀ',
65442 => 'ᄁ',
65443 => 'ᆪ',
65444 => 'ᄂ',
65445 => 'ᆬ',
65446 => 'ᆭ',
65447 => 'ᄃ',
65448 => 'ᄄ',
65449 => 'ᄅ',
65450 => 'ᆰ',
65451 => 'ᆱ',
65452 => 'ᆲ',
65453 => 'ᆳ',
65454 => 'ᆴ',
65455 => 'ᆵ',
65456 => 'ᄚ',
65457 => 'ᄆ',
65458 => 'ᄇ',
65459 => 'ᄈ',
65460 => 'ᄡ',
65461 => 'ᄉ',
65462 => 'ᄊ',
65463 => 'ᄋ',
65464 => 'ᄌ',
65465 => 'ᄍ',
65466 => 'ᄎ',
65467 => 'ᄏ',
65468 => 'ᄐ',
65469 => 'ᄑ',
65470 => 'ᄒ',
65474 => 'ᅡ',
65475 => 'ᅢ',
65476 => 'ᅣ',
65477 => 'ᅤ',
65478 => 'ᅥ',
65479 => 'ᅦ',
65482 => 'ᅧ',
65483 => 'ᅨ',
65484 => 'ᅩ',
65485 => 'ᅪ',
65486 => 'ᅫ',
65487 => 'ᅬ',
65490 => 'ᅭ',
65491 => 'ᅮ',
65492 => 'ᅯ',
65493 => 'ᅰ',
65494 => 'ᅱ',
65495 => 'ᅲ',
65498 => 'ᅳ',
65499 => 'ᅴ',
65500 => 'ᅵ',
65504 => '¢',
65505 => '£',
65506 => '¬',
65508 => '¦',
65509 => '¥',
65510 => '₩',
65512 => '│',
65513 => '←',
65514 => '↑',
65515 => '→',
65516 => '↓',
65517 => '■',
65518 => '○',
66560 => '𐐨',
66561 => '𐐩',
66562 => '𐐪',
66563 => '𐐫',
66564 => '𐐬',
66565 => '𐐭',
66566 => '𐐮',
66567 => '𐐯',
66568 => '𐐰',
66569 => '𐐱',
66570 => '𐐲',
66571 => '𐐳',
66572 => '𐐴',
66573 => '𐐵',
66574 => '𐐶',
66575 => '𐐷',
66576 => '𐐸',
66577 => '𐐹',
66578 => '𐐺',
66579 => '𐐻',
66580 => '𐐼',
66581 => '𐐽',
66582 => '𐐾',
66583 => '𐐿',
66584 => '𐑀',
66585 => '𐑁',
66586 => '𐑂',
66587 => '𐑃',
66588 => '𐑄',
66589 => '𐑅',
66590 => '𐑆',
66591 => '𐑇',
66592 => '𐑈',
66593 => '𐑉',
66594 => '𐑊',
66595 => '𐑋',
66596 => '𐑌',
66597 => '𐑍',
66598 => '𐑎',
66599 => '𐑏',
66736 => '𐓘',
66737 => '𐓙',
66738 => '𐓚',
66739 => '𐓛',
66740 => '𐓜',
66741 => '𐓝',
66742 => '𐓞',
66743 => '𐓟',
66744 => '𐓠',
66745 => '𐓡',
66746 => '𐓢',
66747 => '𐓣',
66748 => '𐓤',
66749 => '𐓥',
66750 => '𐓦',
66751 => '𐓧',
66752 => '𐓨',
66753 => '𐓩',
66754 => '𐓪',
66755 => '𐓫',
66756 => '𐓬',
66757 => '𐓭',
66758 => '𐓮',
66759 => '𐓯',
66760 => '𐓰',
66761 => '𐓱',
66762 => '𐓲',
66763 => '𐓳',
66764 => '𐓴',
66765 => '𐓵',
66766 => '𐓶',
66767 => '𐓷',
66768 => '𐓸',
66769 => '𐓹',
66770 => '𐓺',
66771 => '𐓻',
68736 => '𐳀',
68737 => '𐳁',
68738 => '𐳂',
68739 => '𐳃',
68740 => '𐳄',
68741 => '𐳅',
68742 => '𐳆',
68743 => '𐳇',
68744 => '𐳈',
68745 => '𐳉',
68746 => '𐳊',
68747 => '𐳋',
68748 => '𐳌',
68749 => '𐳍',
68750 => '𐳎',
68751 => '𐳏',
68752 => '𐳐',
68753 => '𐳑',
68754 => '𐳒',
68755 => '𐳓',
68756 => '𐳔',
68757 => '𐳕',
68758 => '𐳖',
68759 => '𐳗',
68760 => '𐳘',
68761 => '𐳙',
68762 => '𐳚',
68763 => '𐳛',
68764 => '𐳜',
68765 => '𐳝',
68766 => '𐳞',
68767 => '𐳟',
68768 => '𐳠',
68769 => '𐳡',
68770 => '𐳢',
68771 => '𐳣',
68772 => '𐳤',
68773 => '𐳥',
68774 => '𐳦',
68775 => '𐳧',
68776 => '𐳨',
68777 => '𐳩',
68778 => '𐳪',
68779 => '𐳫',
68780 => '𐳬',
68781 => '𐳭',
68782 => '𐳮',
68783 => '𐳯',
68784 => '𐳰',
68785 => '𐳱',
68786 => '𐳲',
71840 => '𑣀',
71841 => '𑣁',
71842 => '𑣂',
71843 => '𑣃',
71844 => '𑣄',
71845 => '𑣅',
71846 => '𑣆',
71847 => '𑣇',
71848 => '𑣈',
71849 => '𑣉',
71850 => '𑣊',
71851 => '𑣋',
71852 => '𑣌',
71853 => '𑣍',
71854 => '𑣎',
71855 => '𑣏',
71856 => '𑣐',
71857 => '𑣑',
71858 => '𑣒',
71859 => '𑣓',
71860 => '𑣔',
71861 => '𑣕',
71862 => '𑣖',
71863 => '𑣗',
71864 => '𑣘',
71865 => '𑣙',
71866 => '𑣚',
71867 => '𑣛',
71868 => '𑣜',
71869 => '𑣝',
71870 => '𑣞',
71871 => '𑣟',
93760 => '𖹠',
93761 => '𖹡',
93762 => '𖹢',
93763 => '𖹣',
93764 => '𖹤',
93765 => '𖹥',
93766 => '𖹦',
93767 => '𖹧',
93768 => '𖹨',
93769 => '𖹩',
93770 => '𖹪',
93771 => '𖹫',
93772 => '𖹬',
93773 => '𖹭',
93774 => '𖹮',
93775 => '𖹯',
93776 => '𖹰',
93777 => '𖹱',
93778 => '𖹲',
93779 => '𖹳',
93780 => '𖹴',
93781 => '𖹵',
93782 => '𖹶',
93783 => '𖹷',
93784 => '𖹸',
93785 => '𖹹',
93786 => '𖹺',
93787 => '𖹻',
93788 => '𖹼',
93789 => '𖹽',
93790 => '𖹾',
93791 => '𖹿',
119134 => '𝅗𝅥',
119135 => '𝅘𝅥',
119136 => '𝅘𝅥𝅮',
119137 => '𝅘𝅥𝅯',
119138 => '𝅘𝅥𝅰',
119139 => '𝅘𝅥𝅱',
119140 => '𝅘𝅥𝅲',
119227 => '𝆹𝅥',
119228 => '𝆺𝅥',
119229 => '𝆹𝅥𝅮',
119230 => '𝆺𝅥𝅮',
119231 => '𝆹𝅥𝅯',
119232 => '𝆺𝅥𝅯',
119808 => 'a',
119809 => 'b',
119810 => 'c',
119811 => 'd',
119812 => 'e',
119813 => 'f',
119814 => 'g',
119815 => 'h',
119816 => 'i',
119817 => 'j',
119818 => 'k',
119819 => 'l',
119820 => 'm',
119821 => 'n',
119822 => 'o',
119823 => 'p',
119824 => 'q',
119825 => 'r',
119826 => 's',
119827 => 't',
119828 => 'u',
119829 => 'v',
119830 => 'w',
119831 => 'x',
119832 => 'y',
119833 => 'z',
119834 => 'a',
119835 => 'b',
119836 => 'c',
119837 => 'd',
119838 => 'e',
119839 => 'f',
119840 => 'g',
119841 => 'h',
119842 => 'i',
119843 => 'j',
119844 => 'k',
119845 => 'l',
119846 => 'm',
119847 => 'n',
119848 => 'o',
119849 => 'p',
119850 => 'q',
119851 => 'r',
119852 => 's',
119853 => 't',
119854 => 'u',
119855 => 'v',
119856 => 'w',
119857 => 'x',
119858 => 'y',
119859 => 'z',
119860 => 'a',
119861 => 'b',
119862 => 'c',
119863 => 'd',
119864 => 'e',
119865 => 'f',
119866 => 'g',
119867 => 'h',
119868 => 'i',
119869 => 'j',
119870 => 'k',
119871 => 'l',
119872 => 'm',
119873 => 'n',
119874 => 'o',
119875 => 'p',
119876 => 'q',
119877 => 'r',
119878 => 's',
119879 => 't',
119880 => 'u',
119881 => 'v',
119882 => 'w',
119883 => 'x',
119884 => 'y',
119885 => 'z',
119886 => 'a',
119887 => 'b',
119888 => 'c',
119889 => 'd',
119890 => 'e',
119891 => 'f',
119892 => 'g',
119894 => 'i',
119895 => 'j',
119896 => 'k',
119897 => 'l',
119898 => 'm',
119899 => 'n',
119900 => 'o',
119901 => 'p',
119902 => 'q',
119903 => 'r',
119904 => 's',
119905 => 't',
119906 => 'u',
119907 => 'v',
119908 => 'w',
119909 => 'x',
119910 => 'y',
119911 => 'z',
119912 => 'a',
119913 => 'b',
119914 => 'c',
119915 => 'd',
119916 => 'e',
119917 => 'f',
119918 => 'g',
119919 => 'h',
119920 => 'i',
119921 => 'j',
119922 => 'k',
119923 => 'l',
119924 => 'm',
119925 => 'n',
119926 => 'o',
119927 => 'p',
119928 => 'q',
119929 => 'r',
119930 => 's',
119931 => 't',
119932 => 'u',
119933 => 'v',
119934 => 'w',
119935 => 'x',
119936 => 'y',
119937 => 'z',
119938 => 'a',
119939 => 'b',
119940 => 'c',
119941 => 'd',
119942 => 'e',
119943 => 'f',
119944 => 'g',
119945 => 'h',
119946 => 'i',
119947 => 'j',
119948 => 'k',
119949 => 'l',
119950 => 'm',
119951 => 'n',
119952 => 'o',
119953 => 'p',
119954 => 'q',
119955 => 'r',
119956 => 's',
119957 => 't',
119958 => 'u',
119959 => 'v',
119960 => 'w',
119961 => 'x',
119962 => 'y',
119963 => 'z',
119964 => 'a',
119966 => 'c',
119967 => 'd',
119970 => 'g',
119973 => 'j',
119974 => 'k',
119977 => 'n',
119978 => 'o',
119979 => 'p',
119980 => 'q',
119982 => 's',
119983 => 't',
119984 => 'u',
119985 => 'v',
119986 => 'w',
119987 => 'x',
119988 => 'y',
119989 => 'z',
119990 => 'a',
119991 => 'b',
119992 => 'c',
119993 => 'd',
119995 => 'f',
119997 => 'h',
119998 => 'i',
119999 => 'j',
120000 => 'k',
120001 => 'l',
120002 => 'm',
120003 => 'n',
120005 => 'p',
120006 => 'q',
120007 => 'r',
120008 => 's',
120009 => 't',
120010 => 'u',
120011 => 'v',
120012 => 'w',
120013 => 'x',
120014 => 'y',
120015 => 'z',
120016 => 'a',
120017 => 'b',
120018 => 'c',
120019 => 'd',
120020 => 'e',
120021 => 'f',
120022 => 'g',
120023 => 'h',
120024 => 'i',
120025 => 'j',
120026 => 'k',
120027 => 'l',
120028 => 'm',
120029 => 'n',
120030 => 'o',
120031 => 'p',
120032 => 'q',
120033 => 'r',
120034 => 's',
120035 => 't',
120036 => 'u',
120037 => 'v',
120038 => 'w',
120039 => 'x',
120040 => 'y',
120041 => 'z',
120042 => 'a',
120043 => 'b',
120044 => 'c',
120045 => 'd',
120046 => 'e',
120047 => 'f',
120048 => 'g',
120049 => 'h',
120050 => 'i',
120051 => 'j',
120052 => 'k',
120053 => 'l',
120054 => 'm',
120055 => 'n',
120056 => 'o',
120057 => 'p',
120058 => 'q',
120059 => 'r',
120060 => 's',
120061 => 't',
120062 => 'u',
120063 => 'v',
120064 => 'w',
120065 => 'x',
120066 => 'y',
120067 => 'z',
120068 => 'a',
120069 => 'b',
120071 => 'd',
120072 => 'e',
120073 => 'f',
120074 => 'g',
120077 => 'j',
120078 => 'k',
120079 => 'l',
120080 => 'm',
120081 => 'n',
120082 => 'o',
120083 => 'p',
120084 => 'q',
120086 => 's',
120087 => 't',
120088 => 'u',
120089 => 'v',
120090 => 'w',
120091 => 'x',
120092 => 'y',
120094 => 'a',
120095 => 'b',
120096 => 'c',
120097 => 'd',
120098 => 'e',
120099 => 'f',
120100 => 'g',
120101 => 'h',
120102 => 'i',
120103 => 'j',
120104 => 'k',
120105 => 'l',
120106 => 'm',
120107 => 'n',
120108 => 'o',
120109 => 'p',
120110 => 'q',
120111 => 'r',
120112 => 's',
120113 => 't',
120114 => 'u',
120115 => 'v',
120116 => 'w',
120117 => 'x',
120118 => 'y',
120119 => 'z',
120120 => 'a',
120121 => 'b',
120123 => 'd',
120124 => 'e',
120125 => 'f',
120126 => 'g',
120128 => 'i',
120129 => 'j',
120130 => 'k',
120131 => 'l',
120132 => 'm',
120134 => 'o',
120138 => 's',
120139 => 't',
120140 => 'u',
120141 => 'v',
120142 => 'w',
120143 => 'x',
120144 => 'y',
120146 => 'a',
120147 => 'b',
120148 => 'c',
120149 => 'd',
120150 => 'e',
120151 => 'f',
120152 => 'g',
120153 => 'h',
120154 => 'i',
120155 => 'j',
120156 => 'k',
120157 => 'l',
120158 => 'm',
120159 => 'n',
120160 => 'o',
120161 => 'p',
120162 => 'q',
120163 => 'r',
120164 => 's',
120165 => 't',
120166 => 'u',
120167 => 'v',
120168 => 'w',
120169 => 'x',
120170 => 'y',
120171 => 'z',
120172 => 'a',
120173 => 'b',
120174 => 'c',
120175 => 'd',
120176 => 'e',
120177 => 'f',
120178 => 'g',
120179 => 'h',
120180 => 'i',
120181 => 'j',
120182 => 'k',
120183 => 'l',
120184 => 'm',
120185 => 'n',
120186 => 'o',
120187 => 'p',
120188 => 'q',
120189 => 'r',
120190 => 's',
120191 => 't',
120192 => 'u',
120193 => 'v',
120194 => 'w',
120195 => 'x',
120196 => 'y',
120197 => 'z',
120198 => 'a',
120199 => 'b',
120200 => 'c',
120201 => 'd',
120202 => 'e',
120203 => 'f',
120204 => 'g',
120205 => 'h',
120206 => 'i',
120207 => 'j',
120208 => 'k',
120209 => 'l',
120210 => 'm',
120211 => 'n',
120212 => 'o',
120213 => 'p',
120214 => 'q',
120215 => 'r',
120216 => 's',
120217 => 't',
120218 => 'u',
120219 => 'v',
120220 => 'w',
120221 => 'x',
120222 => 'y',
120223 => 'z',
120224 => 'a',
120225 => 'b',
120226 => 'c',
120227 => 'd',
120228 => 'e',
120229 => 'f',
120230 => 'g',
120231 => 'h',
120232 => 'i',
120233 => 'j',
120234 => 'k',
120235 => 'l',
120236 => 'm',
120237 => 'n',
120238 => 'o',
120239 => 'p',
120240 => 'q',
120241 => 'r',
120242 => 's',
120243 => 't',
120244 => 'u',
120245 => 'v',
120246 => 'w',
120247 => 'x',
120248 => 'y',
120249 => 'z',
120250 => 'a',
120251 => 'b',
120252 => 'c',
120253 => 'd',
120254 => 'e',
120255 => 'f',
120256 => 'g',
120257 => 'h',
120258 => 'i',
120259 => 'j',
120260 => 'k',
120261 => 'l',
120262 => 'm',
120263 => 'n',
120264 => 'o',
120265 => 'p',
120266 => 'q',
120267 => 'r',
120268 => 's',
120269 => 't',
120270 => 'u',
120271 => 'v',
120272 => 'w',
120273 => 'x',
120274 => 'y',
120275 => 'z',
120276 => 'a',
120277 => 'b',
120278 => 'c',
120279 => 'd',
120280 => 'e',
120281 => 'f',
120282 => 'g',
120283 => 'h',
120284 => 'i',
120285 => 'j',
120286 => 'k',
120287 => 'l',
120288 => 'm',
120289 => 'n',
120290 => 'o',
120291 => 'p',
120292 => 'q',
120293 => 'r',
120294 => 's',
120295 => 't',
120296 => 'u',
120297 => 'v',
120298 => 'w',
120299 => 'x',
120300 => 'y',
120301 => 'z',
120302 => 'a',
120303 => 'b',
120304 => 'c',
120305 => 'd',
120306 => 'e',
120307 => 'f',
120308 => 'g',
120309 => 'h',
120310 => 'i',
120311 => 'j',
120312 => 'k',
120313 => 'l',
120314 => 'm',
120315 => 'n',
120316 => 'o',
120317 => 'p',
120318 => 'q',
120319 => 'r',
120320 => 's',
120321 => 't',
120322 => 'u',
120323 => 'v',
120324 => 'w',
120325 => 'x',
120326 => 'y',
120327 => 'z',
120328 => 'a',
120329 => 'b',
120330 => 'c',
120331 => 'd',
120332 => 'e',
120333 => 'f',
120334 => 'g',
120335 => 'h',
120336 => 'i',
120337 => 'j',
120338 => 'k',
120339 => 'l',
120340 => 'm',
120341 => 'n',
120342 => 'o',
120343 => 'p',
120344 => 'q',
120345 => 'r',
120346 => 's',
120347 => 't',
120348 => 'u',
120349 => 'v',
120350 => 'w',
120351 => 'x',
120352 => 'y',
120353 => 'z',
120354 => 'a',
120355 => 'b',
120356 => 'c',
120357 => 'd',
120358 => 'e',
120359 => 'f',
120360 => 'g',
120361 => 'h',
120362 => 'i',
120363 => 'j',
120364 => 'k',
120365 => 'l',
120366 => 'm',
120367 => 'n',
120368 => 'o',
120369 => 'p',
120370 => 'q',
120371 => 'r',
120372 => 's',
120373 => 't',
120374 => 'u',
120375 => 'v',
120376 => 'w',
120377 => 'x',
120378 => 'y',
120379 => 'z',
120380 => 'a',
120381 => 'b',
120382 => 'c',
120383 => 'd',
120384 => 'e',
120385 => 'f',
120386 => 'g',
120387 => 'h',
120388 => 'i',
120389 => 'j',
120390 => 'k',
120391 => 'l',
120392 => 'm',
120393 => 'n',
120394 => 'o',
120395 => 'p',
120396 => 'q',
120397 => 'r',
120398 => 's',
120399 => 't',
120400 => 'u',
120401 => 'v',
120402 => 'w',
120403 => 'x',
120404 => 'y',
120405 => 'z',
120406 => 'a',
120407 => 'b',
120408 => 'c',
120409 => 'd',
120410 => 'e',
120411 => 'f',
120412 => 'g',
120413 => 'h',
120414 => 'i',
120415 => 'j',
120416 => 'k',
120417 => 'l',
120418 => 'm',
120419 => 'n',
120420 => 'o',
120421 => 'p',
120422 => 'q',
120423 => 'r',
120424 => 's',
120425 => 't',
120426 => 'u',
120427 => 'v',
120428 => 'w',
120429 => 'x',
120430 => 'y',
120431 => 'z',
120432 => 'a',
120433 => 'b',
120434 => 'c',
120435 => 'd',
120436 => 'e',
120437 => 'f',
120438 => 'g',
120439 => 'h',
120440 => 'i',
120441 => 'j',
120442 => 'k',
120443 => 'l',
120444 => 'm',
120445 => 'n',
120446 => 'o',
120447 => 'p',
120448 => 'q',
120449 => 'r',
120450 => 's',
120451 => 't',
120452 => 'u',
120453 => 'v',
120454 => 'w',
120455 => 'x',
120456 => 'y',
120457 => 'z',
120458 => 'a',
120459 => 'b',
120460 => 'c',
120461 => 'd',
120462 => 'e',
120463 => 'f',
120464 => 'g',
120465 => 'h',
120466 => 'i',
120467 => 'j',
120468 => 'k',
120469 => 'l',
120470 => 'm',
120471 => 'n',
120472 => 'o',
120473 => 'p',
120474 => 'q',
120475 => 'r',
120476 => 's',
120477 => 't',
120478 => 'u',
120479 => 'v',
120480 => 'w',
120481 => 'x',
120482 => 'y',
120483 => 'z',
120484 => 'ı',
120485 => 'ȷ',
120488 => 'α',
120489 => 'β',
120490 => 'γ',
120491 => 'δ',
120492 => 'ε',
120493 => 'ζ',
120494 => 'η',
120495 => 'θ',
120496 => 'ι',
120497 => 'κ',
120498 => 'λ',
120499 => 'μ',
120500 => 'ν',
120501 => 'ξ',
120502 => 'ο',
120503 => 'π',
120504 => 'ρ',
120505 => 'θ',
120506 => 'σ',
120507 => 'τ',
120508 => 'υ',
120509 => 'φ',
120510 => 'χ',
120511 => 'ψ',
120512 => 'ω',
120513 => '∇',
120514 => 'α',
120515 => 'β',
120516 => 'γ',
120517 => 'δ',
120518 => 'ε',
120519 => 'ζ',
120520 => 'η',
120521 => 'θ',
120522 => 'ι',
120523 => 'κ',
120524 => 'λ',
120525 => 'μ',
120526 => 'ν',
120527 => 'ξ',
120528 => 'ο',
120529 => 'π',
120530 => 'ρ',
120531 => 'σ',
120532 => 'σ',
120533 => 'τ',
120534 => 'υ',
120535 => 'φ',
120536 => 'χ',
120537 => 'ψ',
120538 => 'ω',
120539 => '∂',
120540 => 'ε',
120541 => 'θ',
120542 => 'κ',
120543 => 'φ',
120544 => 'ρ',
120545 => 'π',
120546 => 'α',
120547 => 'β',
120548 => 'γ',
120549 => 'δ',
120550 => 'ε',
120551 => 'ζ',
120552 => 'η',
120553 => 'θ',
120554 => 'ι',
120555 => 'κ',
120556 => 'λ',
120557 => 'μ',
120558 => 'ν',
120559 => 'ξ',
120560 => 'ο',
120561 => 'π',
120562 => 'ρ',
120563 => 'θ',
120564 => 'σ',
120565 => 'τ',
120566 => 'υ',
120567 => 'φ',
120568 => 'χ',
120569 => 'ψ',
120570 => 'ω',
120571 => '∇',
120572 => 'α',
120573 => 'β',
120574 => 'γ',
120575 => 'δ',
120576 => 'ε',
120577 => 'ζ',
120578 => 'η',
120579 => 'θ',
120580 => 'ι',
120581 => 'κ',
120582 => 'λ',
120583 => 'μ',
120584 => 'ν',
120585 => 'ξ',
120586 => 'ο',
120587 => 'π',
120588 => 'ρ',
120589 => 'σ',
120590 => 'σ',
120591 => 'τ',
120592 => 'υ',
120593 => 'φ',
120594 => 'χ',
120595 => 'ψ',
120596 => 'ω',
120597 => '∂',
120598 => 'ε',
120599 => 'θ',
120600 => 'κ',
120601 => 'φ',
120602 => 'ρ',
120603 => 'π',
120604 => 'α',
120605 => 'β',
120606 => 'γ',
120607 => 'δ',
120608 => 'ε',
120609 => 'ζ',
120610 => 'η',
120611 => 'θ',
120612 => 'ι',
120613 => 'κ',
120614 => 'λ',
120615 => 'μ',
120616 => 'ν',
120617 => 'ξ',
120618 => 'ο',
120619 => 'π',
120620 => 'ρ',
120621 => 'θ',
120622 => 'σ',
120623 => 'τ',
120624 => 'υ',
120625 => 'φ',
120626 => 'χ',
120627 => 'ψ',
120628 => 'ω',
120629 => '∇',
120630 => 'α',
120631 => 'β',
120632 => 'γ',
120633 => 'δ',
120634 => 'ε',
120635 => 'ζ',
120636 => 'η',
120637 => 'θ',
120638 => 'ι',
120639 => 'κ',
120640 => 'λ',
120641 => 'μ',
120642 => 'ν',
120643 => 'ξ',
120644 => 'ο',
120645 => 'π',
120646 => 'ρ',
120647 => 'σ',
120648 => 'σ',
120649 => 'τ',
120650 => 'υ',
120651 => 'φ',
120652 => 'χ',
120653 => 'ψ',
120654 => 'ω',
120655 => '∂',
120656 => 'ε',
120657 => 'θ',
120658 => 'κ',
120659 => 'φ',
120660 => 'ρ',
120661 => 'π',
120662 => 'α',
120663 => 'β',
120664 => 'γ',
120665 => 'δ',
120666 => 'ε',
120667 => 'ζ',
120668 => 'η',
120669 => 'θ',
120670 => 'ι',
120671 => 'κ',
120672 => 'λ',
120673 => 'μ',
120674 => 'ν',
120675 => 'ξ',
120676 => 'ο',
120677 => 'π',
120678 => 'ρ',
120679 => 'θ',
120680 => 'σ',
120681 => 'τ',
120682 => 'υ',
120683 => 'φ',
120684 => 'χ',
120685 => 'ψ',
120686 => 'ω',
120687 => '∇',
120688 => 'α',
120689 => 'β',
120690 => 'γ',
120691 => 'δ',
120692 => 'ε',
120693 => 'ζ',
120694 => 'η',
120695 => 'θ',
120696 => 'ι',
120697 => 'κ',
120698 => 'λ',
120699 => 'μ',
120700 => 'ν',
120701 => 'ξ',
120702 => 'ο',
120703 => 'π',
120704 => 'ρ',
120705 => 'σ',
120706 => 'σ',
120707 => 'τ',
120708 => 'υ',
120709 => 'φ',
120710 => 'χ',
120711 => 'ψ',
120712 => 'ω',
120713 => '∂',
120714 => 'ε',
120715 => 'θ',
120716 => 'κ',
120717 => 'φ',
120718 => 'ρ',
120719 => 'π',
120720 => 'α',
120721 => 'β',
120722 => 'γ',
120723 => 'δ',
120724 => 'ε',
120725 => 'ζ',
120726 => 'η',
120727 => 'θ',
120728 => 'ι',
120729 => 'κ',
120730 => 'λ',
120731 => 'μ',
120732 => 'ν',
120733 => 'ξ',
120734 => 'ο',
120735 => 'π',
120736 => 'ρ',
120737 => 'θ',
120738 => 'σ',
120739 => 'τ',
120740 => 'υ',
120741 => 'φ',
120742 => 'χ',
120743 => 'ψ',
120744 => 'ω',
120745 => '∇',
120746 => 'α',
120747 => 'β',
120748 => 'γ',
120749 => 'δ',
120750 => 'ε',
120751 => 'ζ',
120752 => 'η',
120753 => 'θ',
120754 => 'ι',
120755 => 'κ',
120756 => 'λ',
120757 => 'μ',
120758 => 'ν',
120759 => 'ξ',
120760 => 'ο',
120761 => 'π',
120762 => 'ρ',
120763 => 'σ',
120764 => 'σ',
120765 => 'τ',
120766 => 'υ',
120767 => 'φ',
120768 => 'χ',
120769 => 'ψ',
120770 => 'ω',
120771 => '∂',
120772 => 'ε',
120773 => 'θ',
120774 => 'κ',
120775 => 'φ',
120776 => 'ρ',
120777 => 'π',
120778 => 'ϝ',
120779 => 'ϝ',
120782 => '0',
120783 => '1',
120784 => '2',
120785 => '3',
120786 => '4',
120787 => '5',
120788 => '6',
120789 => '7',
120790 => '8',
120791 => '9',
120792 => '0',
120793 => '1',
120794 => '2',
120795 => '3',
120796 => '4',
120797 => '5',
120798 => '6',
120799 => '7',
120800 => '8',
120801 => '9',
120802 => '0',
120803 => '1',
120804 => '2',
120805 => '3',
120806 => '4',
120807 => '5',
120808 => '6',
120809 => '7',
120810 => '8',
120811 => '9',
120812 => '0',
120813 => '1',
120814 => '2',
120815 => '3',
120816 => '4',
120817 => '5',
120818 => '6',
120819 => '7',
120820 => '8',
120821 => '9',
120822 => '0',
120823 => '1',
120824 => '2',
120825 => '3',
120826 => '4',
120827 => '5',
120828 => '6',
120829 => '7',
120830 => '8',
120831 => '9',
125184 => '𞤢',
125185 => '𞤣',
125186 => '𞤤',
125187 => '𞤥',
125188 => '𞤦',
125189 => '𞤧',
125190 => '𞤨',
125191 => '𞤩',
125192 => '𞤪',
125193 => '𞤫',
125194 => '𞤬',
125195 => '𞤭',
125196 => '𞤮',
125197 => '𞤯',
125198 => '𞤰',
125199 => '𞤱',
125200 => '𞤲',
125201 => '𞤳',
125202 => '𞤴',
125203 => '𞤵',
125204 => '𞤶',
125205 => '𞤷',
125206 => '𞤸',
125207 => '𞤹',
125208 => '𞤺',
125209 => '𞤻',
125210 => '𞤼',
125211 => '𞤽',
125212 => '𞤾',
125213 => '𞤿',
125214 => '𞥀',
125215 => '𞥁',
125216 => '𞥂',
125217 => '𞥃',
126464 => 'ا',
126465 => 'ب',
126466 => 'ج',
126467 => 'د',
126469 => 'و',
126470 => 'ز',
126471 => 'ح',
126472 => 'ط',
126473 => 'ي',
126474 => 'ك',
126475 => 'ل',
126476 => 'م',
126477 => 'ن',
126478 => 'س',
126479 => 'ع',
126480 => 'ف',
126481 => 'ص',
126482 => 'ق',
126483 => 'ر',
126484 => 'ش',
126485 => 'ت',
126486 => 'ث',
126487 => 'خ',
126488 => 'ذ',
126489 => 'ض',
126490 => 'ظ',
126491 => 'غ',
126492 => 'ٮ',
126493 => 'ں',
126494 => 'ڡ',
126495 => 'ٯ',
126497 => 'ب',
126498 => 'ج',
126500 => 'ه',
126503 => 'ح',
126505 => 'ي',
126506 => 'ك',
126507 => 'ل',
126508 => 'م',
126509 => 'ن',
126510 => 'س',
126511 => 'ع',
126512 => 'ف',
126513 => 'ص',
126514 => 'ق',
126516 => 'ش',
126517 => 'ت',
126518 => 'ث',
126519 => 'خ',
126521 => 'ض',
126523 => 'غ',
126530 => 'ج',
126535 => 'ح',
126537 => 'ي',
126539 => 'ل',
126541 => 'ن',
126542 => 'س',
126543 => 'ع',
126545 => 'ص',
126546 => 'ق',
126548 => 'ش',
126551 => 'خ',
126553 => 'ض',
126555 => 'غ',
126557 => 'ں',
126559 => 'ٯ',
126561 => 'ب',
126562 => 'ج',
126564 => 'ه',
126567 => 'ح',
126568 => 'ط',
126569 => 'ي',
126570 => 'ك',
126572 => 'م',
126573 => 'ن',
126574 => 'س',
126575 => 'ع',
126576 => 'ف',
126577 => 'ص',
126578 => 'ق',
126580 => 'ش',
126581 => 'ت',
126582 => 'ث',
126583 => 'خ',
126585 => 'ض',
126586 => 'ظ',
126587 => 'غ',
126588 => 'ٮ',
126590 => 'ڡ',
126592 => 'ا',
126593 => 'ب',
126594 => 'ج',
126595 => 'د',
126596 => 'ه',
126597 => 'و',
126598 => 'ز',
126599 => 'ح',
126600 => 'ط',
126601 => 'ي',
126603 => 'ل',
126604 => 'م',
126605 => 'ن',
126606 => 'س',
126607 => 'ع',
126608 => 'ف',
126609 => 'ص',
126610 => 'ق',
126611 => 'ر',
126612 => 'ش',
126613 => 'ت',
126614 => 'ث',
126615 => 'خ',
126616 => 'ذ',
126617 => 'ض',
126618 => 'ظ',
126619 => 'غ',
126625 => 'ب',
126626 => 'ج',
126627 => 'د',
126629 => 'و',
126630 => 'ز',
126631 => 'ح',
126632 => 'ط',
126633 => 'ي',
126635 => 'ل',
126636 => 'م',
126637 => 'ن',
126638 => 'س',
126639 => 'ع',
126640 => 'ف',
126641 => 'ص',
126642 => 'ق',
126643 => 'ر',
126644 => 'ش',
126645 => 'ت',
126646 => 'ث',
126647 => 'خ',
126648 => 'ذ',
126649 => 'ض',
126650 => 'ظ',
126651 => 'غ',
127274 => '〔s〕',
127275 => 'c',
127276 => 'r',
127277 => 'cd',
127278 => 'wz',
127280 => 'a',
127281 => 'b',
127282 => 'c',
127283 => 'd',
127284 => 'e',
127285 => 'f',
127286 => 'g',
127287 => 'h',
127288 => 'i',
127289 => 'j',
127290 => 'k',
127291 => 'l',
127292 => 'm',
127293 => 'n',
127294 => 'o',
127295 => 'p',
127296 => 'q',
127297 => 'r',
127298 => 's',
127299 => 't',
127300 => 'u',
127301 => 'v',
127302 => 'w',
127303 => 'x',
127304 => 'y',
127305 => 'z',
127306 => 'hv',
127307 => 'mv',
127308 => 'sd',
127309 => 'ss',
127310 => 'ppv',
127311 => 'wc',
127338 => 'mc',
127339 => 'md',
127340 => 'mr',
127376 => 'dj',
127488 => 'ほか',
127489 => 'ココ',
127490 => 'サ',
127504 => '手',
127505 => '字',
127506 => '双',
127507 => 'デ',
127508 => '二',
127509 => '多',
127510 => '解',
127511 => '天',
127512 => '交',
127513 => '映',
127514 => '無',
127515 => '料',
127516 => '前',
127517 => '後',
127518 => '再',
127519 => '新',
127520 => '初',
127521 => '終',
127522 => '生',
127523 => '販',
127524 => '声',
127525 => '吹',
127526 => '演',
127527 => '投',
127528 => '捕',
127529 => '一',
127530 => '三',
127531 => '遊',
127532 => '左',
127533 => '中',
127534 => '右',
127535 => '指',
127536 => '走',
127537 => '打',
127538 => '禁',
127539 => '空',
127540 => '合',
127541 => '満',
127542 => '有',
127543 => '月',
127544 => '申',
127545 => '割',
127546 => '営',
127547 => '配',
127552 => '〔本〕',
127553 => '〔三〕',
127554 => '〔二〕',
127555 => '〔安〕',
127556 => '〔点〕',
127557 => '〔打〕',
127558 => '〔盗〕',
127559 => '〔勝〕',
127560 => '〔敗〕',
127568 => '得',
127569 => '可',
130032 => '0',
130033 => '1',
130034 => '2',
130035 => '3',
130036 => '4',
130037 => '5',
130038 => '6',
130039 => '7',
130040 => '8',
130041 => '9',
194560 => '丽',
194561 => '丸',
194562 => '乁',
194563 => '𠄢',
194564 => '你',
194565 => '侮',
194566 => '侻',
194567 => '倂',
194568 => '偺',
194569 => '備',
194570 => '僧',
194571 => '像',
194572 => '㒞',
194573 => '𠘺',
194574 => '免',
194575 => '兔',
194576 => '兤',
194577 => '具',
194578 => '𠔜',
194579 => '㒹',
194580 => '內',
194581 => '再',
194582 => '𠕋',
194583 => '冗',
194584 => '冤',
194585 => '仌',
194586 => '冬',
194587 => '况',
194588 => '𩇟',
194589 => '凵',
194590 => '刃',
194591 => '㓟',
194592 => '刻',
194593 => '剆',
194594 => '割',
194595 => '剷',
194596 => '㔕',
194597 => '勇',
194598 => '勉',
194599 => '勤',
194600 => '勺',
194601 => '包',
194602 => '匆',
194603 => '北',
194604 => '卉',
194605 => '卑',
194606 => '博',
194607 => '即',
194608 => '卽',
194609 => '卿',
194610 => '卿',
194611 => '卿',
194612 => '𠨬',
194613 => '灰',
194614 => '及',
194615 => '叟',
194616 => '𠭣',
194617 => '叫',
194618 => '叱',
194619 => '吆',
194620 => '咞',
194621 => '吸',
194622 => '呈',
194623 => '周',
194624 => '咢',
194625 => '哶',
194626 => '唐',
194627 => '啓',
194628 => '啣',
194629 => '善',
194630 => '善',
194631 => '喙',
194632 => '喫',
194633 => '喳',
194634 => '嗂',
194635 => '圖',
194636 => '嘆',
194637 => '圗',
194638 => '噑',
194639 => '噴',
194640 => '切',
194641 => '壮',
194642 => '城',
194643 => '埴',
194644 => '堍',
194645 => '型',
194646 => '堲',
194647 => '報',
194648 => '墬',
194649 => '𡓤',
194650 => '売',
194651 => '壷',
194652 => '夆',
194653 => '多',
194654 => '夢',
194655 => '奢',
194656 => '𡚨',
194657 => '𡛪',
194658 => '姬',
194659 => '娛',
194660 => '娧',
194661 => '姘',
194662 => '婦',
194663 => '㛮',
194665 => '嬈',
194666 => '嬾',
194667 => '嬾',
194668 => '𡧈',
194669 => '寃',
194670 => '寘',
194671 => '寧',
194672 => '寳',
194673 => '𡬘',
194674 => '寿',
194675 => '将',
194677 => '尢',
194678 => '㞁',
194679 => '屠',
194680 => '屮',
194681 => '峀',
194682 => '岍',
194683 => '𡷤',
194684 => '嵃',
194685 => '𡷦',
194686 => '嵮',
194687 => '嵫',
194688 => '嵼',
194689 => '巡',
194690 => '巢',
194691 => '㠯',
194692 => '巽',
194693 => '帨',
194694 => '帽',
194695 => '幩',
194696 => '㡢',
194697 => '𢆃',
194698 => '㡼',
194699 => '庰',
194700 => '庳',
194701 => '庶',
194702 => '廊',
194703 => '𪎒',
194704 => '廾',
194705 => '𢌱',
194706 => '𢌱',
194707 => '舁',
194708 => '弢',
194709 => '弢',
194710 => '㣇',
194711 => '𣊸',
194712 => '𦇚',
194713 => '形',
194714 => '彫',
194715 => '㣣',
194716 => '徚',
194717 => '忍',
194718 => '志',
194719 => '忹',
194720 => '悁',
194721 => '㤺',
194722 => '㤜',
194723 => '悔',
194724 => '𢛔',
194725 => '惇',
194726 => '慈',
194727 => '慌',
194728 => '慎',
194729 => '慌',
194730 => '慺',
194731 => '憎',
194732 => '憲',
194733 => '憤',
194734 => '憯',
194735 => '懞',
194736 => '懲',
194737 => '懶',
194738 => '成',
194739 => '戛',
194740 => '扝',
194741 => '抱',
194742 => '拔',
194743 => '捐',
194744 => '𢬌',
194745 => '挽',
194746 => '拼',
194747 => '捨',
194748 => '掃',
194749 => '揤',
194750 => '𢯱',
194751 => '搢',
194752 => '揅',
194753 => '掩',
194754 => '㨮',
194755 => '摩',
194756 => '摾',
194757 => '撝',
194758 => '摷',
194759 => '㩬',
194760 => '敏',
194761 => '敬',
194762 => '𣀊',
194763 => '旣',
194764 => '書',
194765 => '晉',
194766 => '㬙',
194767 => '暑',
194768 => '㬈',
194769 => '㫤',
194770 => '冒',
194771 => '冕',
194772 => '最',
194773 => '暜',
194774 => '肭',
194775 => '䏙',
194776 => '朗',
194777 => '望',
194778 => '朡',
194779 => '杞',
194780 => '杓',
194781 => '𣏃',
194782 => '㭉',
194783 => '柺',
194784 => '枅',
194785 => '桒',
194786 => '梅',
194787 => '𣑭',
194788 => '梎',
194789 => '栟',
194790 => '椔',
194791 => '㮝',
194792 => '楂',
194793 => '榣',
194794 => '槪',
194795 => '檨',
194796 => '𣚣',
194797 => '櫛',
194798 => '㰘',
194799 => '次',
194800 => '𣢧',
194801 => '歔',
194802 => '㱎',
194803 => '歲',
194804 => '殟',
194805 => '殺',
194806 => '殻',
194807 => '𣪍',
194808 => '𡴋',
194809 => '𣫺',
194810 => '汎',
194811 => '𣲼',
194812 => '沿',
194813 => '泍',
194814 => '汧',
194815 => '洖',
194816 => '派',
194817 => '海',
194818 => '流',
194819 => '浩',
194820 => '浸',
194821 => '涅',
194822 => '𣴞',
194823 => '洴',
194824 => '港',
194825 => '湮',
194826 => '㴳',
194827 => '滋',
194828 => '滇',
194829 => '𣻑',
194830 => '淹',
194831 => '潮',
194832 => '𣽞',
194833 => '𣾎',
194834 => '濆',
194835 => '瀹',
194836 => '瀞',
194837 => '瀛',
194838 => '㶖',
194839 => '灊',
194840 => '災',
194841 => '灷',
194842 => '炭',
194843 => '𠔥',
194844 => '煅',
194845 => '𤉣',
194846 => '熜',
194848 => '爨',
194849 => '爵',
194850 => '牐',
194851 => '𤘈',
194852 => '犀',
194853 => '犕',
194854 => '𤜵',
194855 => '𤠔',
194856 => '獺',
194857 => '王',
194858 => '㺬',
194859 => '玥',
194860 => '㺸',
194861 => '㺸',
194862 => '瑇',
194863 => '瑜',
194864 => '瑱',
194865 => '璅',
194866 => '瓊',
194867 => '㼛',
194868 => '甤',
194869 => '𤰶',
194870 => '甾',
194871 => '𤲒',
194872 => '異',
194873 => '𢆟',
194874 => '瘐',
194875 => '𤾡',
194876 => '𤾸',
194877 => '𥁄',
194878 => '㿼',
194879 => '䀈',
194880 => '直',
194881 => '𥃳',
194882 => '𥃲',
194883 => '𥄙',
194884 => '𥄳',
194885 => '眞',
194886 => '真',
194887 => '真',
194888 => '睊',
194889 => '䀹',
194890 => '瞋',
194891 => '䁆',
194892 => '䂖',
194893 => '𥐝',
194894 => '硎',
194895 => '碌',
194896 => '磌',
194897 => '䃣',
194898 => '𥘦',
194899 => '祖',
194900 => '𥚚',
194901 => '𥛅',
194902 => '福',
194903 => '秫',
194904 => '䄯',
194905 => '穀',
194906 => '穊',
194907 => '穏',
194908 => '𥥼',
194909 => '𥪧',
194910 => '𥪧',
194912 => '䈂',
194913 => '𥮫',
194914 => '篆',
194915 => '築',
194916 => '䈧',
194917 => '𥲀',
194918 => '糒',
194919 => '䊠',
194920 => '糨',
194921 => '糣',
194922 => '紀',
194923 => '𥾆',
194924 => '絣',
194925 => '䌁',
194926 => '緇',
194927 => '縂',
194928 => '繅',
194929 => '䌴',
194930 => '𦈨',
194931 => '𦉇',
194932 => '䍙',
194933 => '𦋙',
194934 => '罺',
194935 => '𦌾',
194936 => '羕',
194937 => '翺',
194938 => '者',
194939 => '𦓚',
194940 => '𦔣',
194941 => '聠',
194942 => '𦖨',
194943 => '聰',
194944 => '𣍟',
194945 => '䏕',
194946 => '育',
194947 => '脃',
194948 => '䐋',
194949 => '脾',
194950 => '媵',
194951 => '𦞧',
194952 => '𦞵',
194953 => '𣎓',
194954 => '𣎜',
194955 => '舁',
194956 => '舄',
194957 => '辞',
194958 => '䑫',
194959 => '芑',
194960 => '芋',
194961 => '芝',
194962 => '劳',
194963 => '花',
194964 => '芳',
194965 => '芽',
194966 => '苦',
194967 => '𦬼',
194968 => '若',
194969 => '茝',
194970 => '荣',
194971 => '莭',
194972 => '茣',
194973 => '莽',
194974 => '菧',
194975 => '著',
194976 => '荓',
194977 => '菊',
194978 => '菌',
194979 => '菜',
194980 => '𦰶',
194981 => '𦵫',
194982 => '𦳕',
194983 => '䔫',
194984 => '蓱',
194985 => '蓳',
194986 => '蔖',
194987 => '𧏊',
194988 => '蕤',
194989 => '𦼬',
194990 => '䕝',
194991 => '䕡',
194992 => '𦾱',
194993 => '𧃒',
194994 => '䕫',
194995 => '虐',
194996 => '虜',
194997 => '虧',
194998 => '虩',
194999 => '蚩',
195000 => '蚈',
195001 => '蜎',
195002 => '蛢',
195003 => '蝹',
195004 => '蜨',
195005 => '蝫',
195006 => '螆',
195008 => '蟡',
195009 => '蠁',
195010 => '䗹',
195011 => '衠',
195012 => '衣',
195013 => '𧙧',
195014 => '裗',
195015 => '裞',
195016 => '䘵',
195017 => '裺',
195018 => '㒻',
195019 => '𧢮',
195020 => '𧥦',
195021 => '䚾',
195022 => '䛇',
195023 => '誠',
195024 => '諭',
195025 => '變',
195026 => '豕',
195027 => '𧲨',
195028 => '貫',
195029 => '賁',
195030 => '贛',
195031 => '起',
195032 => '𧼯',
195033 => '𠠄',
195034 => '跋',
195035 => '趼',
195036 => '跰',
195037 => '𠣞',
195038 => '軔',
195039 => '輸',
195040 => '𨗒',
195041 => '𨗭',
195042 => '邔',
195043 => '郱',
195044 => '鄑',
195045 => '𨜮',
195046 => '鄛',
195047 => '鈸',
195048 => '鋗',
195049 => '鋘',
195050 => '鉼',
195051 => '鏹',
195052 => '鐕',
195053 => '𨯺',
195054 => '開',
195055 => '䦕',
195056 => '閷',
195057 => '𨵷',
195058 => '䧦',
195059 => '雃',
195060 => '嶲',
195061 => '霣',
195062 => '𩅅',
195063 => '𩈚',
195064 => '䩮',
195065 => '䩶',
195066 => '韠',
195067 => '𩐊',
195068 => '䪲',
195069 => '𩒖',
195070 => '頋',
195071 => '頋',
195072 => '頩',
195073 => '𩖶',
195074 => '飢',
195075 => '䬳',
195076 => '餩',
195077 => '馧',
195078 => '駂',
195079 => '駾',
195080 => '䯎',
195081 => '𩬰',
195082 => '鬒',
195083 => '鱀',
195084 => '鳽',
195085 => '䳎',
195086 => '䳭',
195087 => '鵧',
195088 => '𪃎',
195089 => '䳸',
195090 => '𪄅',
195091 => '𪈎',
195092 => '𪊑',
195093 => '麻',
195094 => '䵖',
195095 => '黹',
195096 => '黾',
195097 => '鼅',
195098 => '鼏',
195099 => '鼖',
195100 => '鼻',
195101 => '𪘀',
);
<?php

namespace Symfony\Polyfill\Intl\Idn\Resources\unidata;




final class Regex
{
const COMBINING_MARK = '/^[\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{0903}\x{093A}\x{093B}\x{093C}\x{093E}-\x{0940}\x{0941}-\x{0948}\x{0949}-\x{094C}\x{094D}\x{094E}-\x{094F}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{0982}-\x{0983}\x{09BC}\x{09BE}-\x{09C0}\x{09C1}-\x{09C4}\x{09C7}-\x{09C8}\x{09CB}-\x{09CC}\x{09CD}\x{09D7}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A03}\x{0A3C}\x{0A3E}-\x{0A40}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0A83}\x{0ABC}\x{0ABE}-\x{0AC0}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0AC9}\x{0ACB}-\x{0ACC}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B02}-\x{0B03}\x{0B3C}\x{0B3E}\x{0B3F}\x{0B40}\x{0B41}-\x{0B44}\x{0B47}-\x{0B48}\x{0B4B}-\x{0B4C}\x{0B4D}\x{0B55}-\x{0B56}\x{0B57}\x{0B62}-\x{0B63}\x{0B82}\x{0BBE}-\x{0BBF}\x{0BC0}\x{0BC1}-\x{0BC2}\x{0BC6}-\x{0BC8}\x{0BCA}-\x{0BCC}\x{0BCD}\x{0BD7}\x{0C00}\x{0C01}-\x{0C03}\x{0C04}\x{0C3E}-\x{0C40}\x{0C41}-\x{0C44}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0C82}-\x{0C83}\x{0CBC}\x{0CBE}\x{0CBF}\x{0CC0}-\x{0CC4}\x{0CC6}\x{0CC7}-\x{0CC8}\x{0CCA}-\x{0CCB}\x{0CCC}-\x{0CCD}\x{0CD5}-\x{0CD6}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D02}-\x{0D03}\x{0D3B}-\x{0D3C}\x{0D3E}-\x{0D40}\x{0D41}-\x{0D44}\x{0D46}-\x{0D48}\x{0D4A}-\x{0D4C}\x{0D4D}\x{0D57}\x{0D62}-\x{0D63}\x{0D81}\x{0D82}-\x{0D83}\x{0DCA}\x{0DCF}-\x{0DD1}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0DD8}-\x{0DDF}\x{0DF2}-\x{0DF3}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3E}-\x{0F3F}\x{0F71}-\x{0F7E}\x{0F7F}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102B}-\x{102C}\x{102D}-\x{1030}\x{1031}\x{1032}-\x{1037}\x{1038}\x{1039}-\x{103A}\x{103B}-\x{103C}\x{103D}-\x{103E}\x{1056}-\x{1057}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1062}-\x{1064}\x{1067}-\x{106D}\x{1071}-\x{1074}\x{1082}\x{1083}-\x{1084}\x{1085}-\x{1086}\x{1087}-\x{108C}\x{108D}\x{108F}\x{109A}-\x{109C}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B6}\x{17B7}-\x{17BD}\x{17BE}-\x{17C5}\x{17C6}\x{17C7}-\x{17C8}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1923}-\x{1926}\x{1927}-\x{1928}\x{1929}-\x{192B}\x{1930}-\x{1931}\x{1932}\x{1933}-\x{1938}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A19}-\x{1A1A}\x{1A1B}\x{1A55}\x{1A56}\x{1A57}\x{1A58}-\x{1A5E}\x{1A60}\x{1A61}\x{1A62}\x{1A63}-\x{1A64}\x{1A65}-\x{1A6C}\x{1A6D}-\x{1A72}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B04}\x{1B34}\x{1B35}\x{1B36}-\x{1B3A}\x{1B3B}\x{1B3C}\x{1B3D}-\x{1B41}\x{1B42}\x{1B43}-\x{1B44}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1B82}\x{1BA1}\x{1BA2}-\x{1BA5}\x{1BA6}-\x{1BA7}\x{1BA8}-\x{1BA9}\x{1BAA}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE7}\x{1BE8}-\x{1BE9}\x{1BEA}-\x{1BEC}\x{1BED}\x{1BEE}\x{1BEF}-\x{1BF1}\x{1BF2}-\x{1BF3}\x{1C24}-\x{1C2B}\x{1C2C}-\x{1C33}\x{1C34}-\x{1C35}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE1}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF7}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{302E}-\x{302F}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A823}-\x{A824}\x{A825}-\x{A826}\x{A827}\x{A82C}\x{A880}-\x{A881}\x{A8B4}-\x{A8C3}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A952}-\x{A953}\x{A980}-\x{A982}\x{A983}\x{A9B3}\x{A9B4}-\x{A9B5}\x{A9B6}-\x{A9B9}\x{A9BA}-\x{A9BB}\x{A9BC}-\x{A9BD}\x{A9BE}-\x{A9C0}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA2F}-\x{AA30}\x{AA31}-\x{AA32}\x{AA33}-\x{AA34}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA4D}\x{AA7B}\x{AA7C}\x{AA7D}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEB}\x{AAEC}-\x{AAED}\x{AAEE}-\x{AAEF}\x{AAF5}\x{AAF6}\x{ABE3}-\x{ABE4}\x{ABE5}\x{ABE6}-\x{ABE7}\x{ABE8}\x{ABE9}-\x{ABEA}\x{ABEC}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11000}\x{11001}\x{11002}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{11082}\x{110B0}-\x{110B2}\x{110B3}-\x{110B6}\x{110B7}-\x{110B8}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112C}\x{1112D}-\x{11134}\x{11145}-\x{11146}\x{11173}\x{11180}-\x{11181}\x{11182}\x{111B3}-\x{111B5}\x{111B6}-\x{111BE}\x{111BF}-\x{111C0}\x{111C9}-\x{111CC}\x{111CE}\x{111CF}\x{1122C}-\x{1122E}\x{1122F}-\x{11231}\x{11232}-\x{11233}\x{11234}\x{11235}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E0}-\x{112E2}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{11302}-\x{11303}\x{1133B}-\x{1133C}\x{1133E}-\x{1133F}\x{11340}\x{11341}-\x{11344}\x{11347}-\x{11348}\x{1134B}-\x{1134D}\x{11357}\x{11362}-\x{11363}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11435}-\x{11437}\x{11438}-\x{1143F}\x{11440}-\x{11441}\x{11442}-\x{11444}\x{11445}\x{11446}\x{1145E}\x{114B0}-\x{114B2}\x{114B3}-\x{114B8}\x{114B9}\x{114BA}\x{114BB}-\x{114BE}\x{114BF}-\x{114C0}\x{114C1}\x{114C2}-\x{114C3}\x{115AF}-\x{115B1}\x{115B2}-\x{115B5}\x{115B8}-\x{115BB}\x{115BC}-\x{115BD}\x{115BE}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11630}-\x{11632}\x{11633}-\x{1163A}\x{1163B}-\x{1163C}\x{1163D}\x{1163E}\x{1163F}-\x{11640}\x{116AB}\x{116AC}\x{116AD}\x{116AE}-\x{116AF}\x{116B0}-\x{116B5}\x{116B6}\x{116B7}\x{1171D}-\x{1171F}\x{11720}-\x{11721}\x{11722}-\x{11725}\x{11726}\x{11727}-\x{1172B}\x{1182C}-\x{1182E}\x{1182F}-\x{11837}\x{11838}\x{11839}-\x{1183A}\x{11930}-\x{11935}\x{11937}-\x{11938}\x{1193B}-\x{1193C}\x{1193D}\x{1193E}\x{11940}\x{11942}\x{11943}\x{119D1}-\x{119D3}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119DC}-\x{119DF}\x{119E0}\x{119E4}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A39}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A57}-\x{11A58}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A97}\x{11A98}-\x{11A99}\x{11C2F}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3E}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CA9}\x{11CAA}-\x{11CB0}\x{11CB1}\x{11CB2}-\x{11CB3}\x{11CB4}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D8A}-\x{11D8E}\x{11D90}-\x{11D91}\x{11D93}-\x{11D94}\x{11D95}\x{11D96}\x{11D97}\x{11EF3}-\x{11EF4}\x{11EF5}-\x{11EF6}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F51}-\x{16F87}\x{16F8F}-\x{16F92}\x{16FE4}\x{16FF0}-\x{16FF1}\x{1BC9D}-\x{1BC9E}\x{1D165}-\x{1D166}\x{1D167}-\x{1D169}\x{1D16D}-\x{1D172}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]/u';

const RTL_LABEL = '/[\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{200F}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u';

const BIDI_STEP_1_LTR = '/^[^\x{0000}-\x{0008}\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{000E}-\x{001B}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{0030}-\x{0039}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0085}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B2}-\x{00B3}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00B9}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{1680}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{2000}-\x{200A}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{205F}\x{2060}-\x{2064}\x{2065}\x{2066}\x{2067}\x{2068}\x{2069}\x{206A}-\x{206F}\x{2070}\x{2074}-\x{2079}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{2080}-\x{2089}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{2488}-\x{249B}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3000}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF10}-\x{FF19}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{102E1}-\x{102FB}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1D7CE}-\x{1D7FF}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F100}-\x{1F10A}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FBF0}-\x{1FBF9}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}]/u';
const BIDI_STEP_1_RTL = '/^[\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{200F}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u';
const BIDI_STEP_2 = '/[^\x{0000}-\x{0008}\x{000E}-\x{001B}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{0030}-\x{0039}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B2}-\x{00B3}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00B9}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{2060}-\x{2064}\x{2065}\x{206A}-\x{206F}\x{2070}\x{2074}-\x{2079}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{2080}-\x{2089}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{2488}-\x{249B}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF10}-\x{FF19}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{102E1}-\x{102FB}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1D7CE}-\x{1D7FF}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F100}-\x{1F10A}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FBF0}-\x{1FBF9}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}]/u';
const BIDI_STEP_3 = '/[\x{0030}-\x{0039}\x{00B2}-\x{00B3}\x{00B9}\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{200F}\x{2070}\x{2074}-\x{2079}\x{2080}-\x{2089}\x{2488}-\x{249B}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FF10}-\x{FF19}\x{102E1}-\x{102FB}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1D7CE}-\x{1D7FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F100}-\x{1F10A}\x{1FBF0}-\x{1FBF9}][\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1D167}-\x{1D169}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]*$/u';
const BIDI_STEP_4_AN = '/[\x{0600}-\x{0605}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{06DD}\x{08E2}\x{10D30}-\x{10D39}\x{10E60}-\x{10E7E}]/u';
const BIDI_STEP_4_EN = '/[\x{0030}-\x{0039}\x{00B2}-\x{00B3}\x{00B9}\x{06F0}-\x{06F9}\x{2070}\x{2074}-\x{2079}\x{2080}-\x{2089}\x{2488}-\x{249B}\x{FF10}-\x{FF19}\x{102E1}-\x{102FB}\x{1D7CE}-\x{1D7FF}\x{1F100}-\x{1F10A}\x{1FBF0}-\x{1FBF9}]/u';
const BIDI_STEP_5 = '/[\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0085}\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{1680}\x{2000}-\x{200A}\x{200F}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{205F}\x{2066}\x{2067}\x{2068}\x{2069}\x{3000}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u';
const BIDI_STEP_6 = '/[^\x{0000}-\x{0008}\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{000E}-\x{001B}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0085}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{1680}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{2000}-\x{200A}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{205F}\x{2060}-\x{2064}\x{2065}\x{2066}\x{2067}\x{2068}\x{2069}\x{206A}-\x{206F}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3000}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}][\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1D167}-\x{1D169}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]*$/u';

const ZWNJ = '/([\x{A872}\x{10ACD}\x{10AD7}\x{10D00}\x{10FCB}\x{0620}\x{0626}\x{0628}\x{062A}-\x{062E}\x{0633}-\x{063F}\x{0641}-\x{0647}\x{0649}-\x{064A}\x{066E}-\x{066F}\x{0678}-\x{0687}\x{069A}-\x{06BF}\x{06C1}-\x{06C2}\x{06CC}\x{06CE}\x{06D0}-\x{06D1}\x{06FA}-\x{06FC}\x{06FF}\x{0712}-\x{0714}\x{071A}-\x{071D}\x{071F}-\x{0727}\x{0729}\x{072B}\x{072D}-\x{072E}\x{074E}-\x{0758}\x{075C}-\x{076A}\x{076D}-\x{0770}\x{0772}\x{0775}-\x{0777}\x{077A}-\x{077F}\x{07CA}-\x{07EA}\x{0841}-\x{0845}\x{0848}\x{084A}-\x{0853}\x{0855}\x{0860}\x{0862}-\x{0865}\x{0868}\x{08A0}-\x{08A9}\x{08AF}-\x{08B0}\x{08B3}-\x{08B4}\x{08B6}-\x{08B8}\x{08BA}-\x{08C7}\x{1807}\x{1820}-\x{1842}\x{1843}\x{1844}-\x{1878}\x{1887}-\x{18A8}\x{18AA}\x{A840}-\x{A871}\x{10AC0}-\x{10AC4}\x{10AD3}-\x{10AD6}\x{10AD8}-\x{10ADC}\x{10ADE}-\x{10AE0}\x{10AEB}-\x{10AEE}\x{10B80}\x{10B82}\x{10B86}-\x{10B88}\x{10B8A}-\x{10B8B}\x{10B8D}\x{10B90}\x{10BAD}-\x{10BAE}\x{10D01}-\x{10D21}\x{10D23}\x{10F30}-\x{10F32}\x{10F34}-\x{10F44}\x{10F51}-\x{10F53}\x{10FB0}\x{10FB2}-\x{10FB3}\x{10FB8}\x{10FBB}-\x{10FBC}\x{10FBE}-\x{10FBF}\x{10FC1}\x{10FC4}\x{10FCA}\x{1E900}-\x{1E943}][\x{00AD}\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{061C}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{070F}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CBF}\x{0CC6}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{200B}\x{200E}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{206A}-\x{206F}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{FEFF}\x{FFF9}-\x{FFFB}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{13430}-\x{13438}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{1E94B}\x{E0001}\x{E0020}-\x{E007F}\x{E0100}-\x{E01EF}]*\x{200C}[\x{00AD}\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{061C}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{070F}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CBF}\x{0CC6}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{200B}\x{200E}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{206A}-\x{206F}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{FEFF}\x{FFF9}-\x{FFFB}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{13430}-\x{13438}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{1E94B}\x{E0001}\x{E0020}-\x{E007F}\x{E0100}-\x{E01EF}]*)[\x{0622}-\x{0625}\x{0627}\x{0629}\x{062F}-\x{0632}\x{0648}\x{0671}-\x{0673}\x{0675}-\x{0677}\x{0688}-\x{0699}\x{06C0}\x{06C3}-\x{06CB}\x{06CD}\x{06CF}\x{06D2}-\x{06D3}\x{06D5}\x{06EE}-\x{06EF}\x{0710}\x{0715}-\x{0719}\x{071E}\x{0728}\x{072A}\x{072C}\x{072F}\x{074D}\x{0759}-\x{075B}\x{076B}-\x{076C}\x{0771}\x{0773}-\x{0774}\x{0778}-\x{0779}\x{0840}\x{0846}-\x{0847}\x{0849}\x{0854}\x{0856}-\x{0858}\x{0867}\x{0869}-\x{086A}\x{08AA}-\x{08AC}\x{08AE}\x{08B1}-\x{08B2}\x{08B9}\x{10AC5}\x{10AC7}\x{10AC9}-\x{10ACA}\x{10ACE}-\x{10AD2}\x{10ADD}\x{10AE1}\x{10AE4}\x{10AEF}\x{10B81}\x{10B83}-\x{10B85}\x{10B89}\x{10B8C}\x{10B8E}-\x{10B8F}\x{10B91}\x{10BA9}-\x{10BAC}\x{10D22}\x{10F33}\x{10F54}\x{10FB4}-\x{10FB6}\x{10FB9}-\x{10FBA}\x{10FBD}\x{10FC2}-\x{10FC3}\x{10FC9}\x{0620}\x{0626}\x{0628}\x{062A}-\x{062E}\x{0633}-\x{063F}\x{0641}-\x{0647}\x{0649}-\x{064A}\x{066E}-\x{066F}\x{0678}-\x{0687}\x{069A}-\x{06BF}\x{06C1}-\x{06C2}\x{06CC}\x{06CE}\x{06D0}-\x{06D1}\x{06FA}-\x{06FC}\x{06FF}\x{0712}-\x{0714}\x{071A}-\x{071D}\x{071F}-\x{0727}\x{0729}\x{072B}\x{072D}-\x{072E}\x{074E}-\x{0758}\x{075C}-\x{076A}\x{076D}-\x{0770}\x{0772}\x{0775}-\x{0777}\x{077A}-\x{077F}\x{07CA}-\x{07EA}\x{0841}-\x{0845}\x{0848}\x{084A}-\x{0853}\x{0855}\x{0860}\x{0862}-\x{0865}\x{0868}\x{08A0}-\x{08A9}\x{08AF}-\x{08B0}\x{08B3}-\x{08B4}\x{08B6}-\x{08B8}\x{08BA}-\x{08C7}\x{1807}\x{1820}-\x{1842}\x{1843}\x{1844}-\x{1878}\x{1887}-\x{18A8}\x{18AA}\x{A840}-\x{A871}\x{10AC0}-\x{10AC4}\x{10AD3}-\x{10AD6}\x{10AD8}-\x{10ADC}\x{10ADE}-\x{10AE0}\x{10AEB}-\x{10AEE}\x{10B80}\x{10B82}\x{10B86}-\x{10B88}\x{10B8A}-\x{10B8B}\x{10B8D}\x{10B90}\x{10BAD}-\x{10BAE}\x{10D01}-\x{10D21}\x{10D23}\x{10F30}-\x{10F32}\x{10F34}-\x{10F44}\x{10F51}-\x{10F53}\x{10FB0}\x{10FB2}-\x{10FB3}\x{10FB8}\x{10FBB}-\x{10FBC}\x{10FBE}-\x{10FBF}\x{10FC1}\x{10FC4}\x{10FCA}\x{1E900}-\x{1E943}]/u';
}
<?php

return array (
173 => true,
847 => true,
6155 => true,
6156 => true,
6157 => true,
8203 => true,
8288 => true,
8292 => true,
65024 => true,
65025 => true,
65026 => true,
65027 => true,
65028 => true,
65029 => true,
65030 => true,
65031 => true,
65032 => true,
65033 => true,
65034 => true,
65035 => true,
65036 => true,
65037 => true,
65038 => true,
65039 => true,
65279 => true,
113824 => true,
113825 => true,
113826 => true,
113827 => true,
917760 => true,
917761 => true,
917762 => true,
917763 => true,
917764 => true,
917765 => true,
917766 => true,
917767 => true,
917768 => true,
917769 => true,
917770 => true,
917771 => true,
917772 => true,
917773 => true,
917774 => true,
917775 => true,
917776 => true,
917777 => true,
917778 => true,
917779 => true,
917780 => true,
917781 => true,
917782 => true,
917783 => true,
917784 => true,
917785 => true,
917786 => true,
917787 => true,
917788 => true,
917789 => true,
917790 => true,
917791 => true,
917792 => true,
917793 => true,
917794 => true,
917795 => true,
917796 => true,
917797 => true,
917798 => true,
917799 => true,
917800 => true,
917801 => true,
917802 => true,
917803 => true,
917804 => true,
917805 => true,
917806 => true,
917807 => true,
917808 => true,
917809 => true,
917810 => true,
917811 => true,
917812 => true,
917813 => true,
917814 => true,
917815 => true,
917816 => true,
917817 => true,
917818 => true,
917819 => true,
917820 => true,
917821 => true,
917822 => true,
917823 => true,
917824 => true,
917825 => true,
917826 => true,
917827 => true,
917828 => true,
917829 => true,
917830 => true,
917831 => true,
917832 => true,
917833 => true,
917834 => true,
917835 => true,
917836 => true,
917837 => true,
917838 => true,
917839 => true,
917840 => true,
917841 => true,
917842 => true,
917843 => true,
917844 => true,
917845 => true,
917846 => true,
917847 => true,
917848 => true,
917849 => true,
917850 => true,
917851 => true,
917852 => true,
917853 => true,
917854 => true,
917855 => true,
917856 => true,
917857 => true,
917858 => true,
917859 => true,
917860 => true,
917861 => true,
917862 => true,
917863 => true,
917864 => true,
917865 => true,
917866 => true,
917867 => true,
917868 => true,
917869 => true,
917870 => true,
917871 => true,
917872 => true,
917873 => true,
917874 => true,
917875 => true,
917876 => true,
917877 => true,
917878 => true,
917879 => true,
917880 => true,
917881 => true,
917882 => true,
917883 => true,
917884 => true,
917885 => true,
917886 => true,
917887 => true,
917888 => true,
917889 => true,
917890 => true,
917891 => true,
917892 => true,
917893 => true,
917894 => true,
917895 => true,
917896 => true,
917897 => true,
917898 => true,
917899 => true,
917900 => true,
917901 => true,
917902 => true,
917903 => true,
917904 => true,
917905 => true,
917906 => true,
917907 => true,
917908 => true,
917909 => true,
917910 => true,
917911 => true,
917912 => true,
917913 => true,
917914 => true,
917915 => true,
917916 => true,
917917 => true,
917918 => true,
917919 => true,
917920 => true,
917921 => true,
917922 => true,
917923 => true,
917924 => true,
917925 => true,
917926 => true,
917927 => true,
917928 => true,
917929 => true,
917930 => true,
917931 => true,
917932 => true,
917933 => true,
917934 => true,
917935 => true,
917936 => true,
917937 => true,
917938 => true,
917939 => true,
917940 => true,
917941 => true,
917942 => true,
917943 => true,
917944 => true,
917945 => true,
917946 => true,
917947 => true,
917948 => true,
917949 => true,
917950 => true,
917951 => true,
917952 => true,
917953 => true,
917954 => true,
917955 => true,
917956 => true,
917957 => true,
917958 => true,
917959 => true,
917960 => true,
917961 => true,
917962 => true,
917963 => true,
917964 => true,
917965 => true,
917966 => true,
917967 => true,
917968 => true,
917969 => true,
917970 => true,
917971 => true,
917972 => true,
917973 => true,
917974 => true,
917975 => true,
917976 => true,
917977 => true,
917978 => true,
917979 => true,
917980 => true,
917981 => true,
917982 => true,
917983 => true,
917984 => true,
917985 => true,
917986 => true,
917987 => true,
917988 => true,
917989 => true,
917990 => true,
917991 => true,
917992 => true,
917993 => true,
917994 => true,
917995 => true,
917996 => true,
917997 => true,
917998 => true,
917999 => true,
);
<?php

return array (
223 => 'ss',
962 => 'σ',
8204 => '',
8205 => '',
);
<?php










namespace Symfony\Component\CssSelector\Parser;

use Symfony\Component\CssSelector\Node\SelectorNode;











interface ParserInterface
{





public function parse(string $source): array;
}
<?php










namespace Symfony\Component\CssSelector\Parser\Shortcut;

use Symfony\Component\CssSelector\Node\ElementNode;
use Symfony\Component\CssSelector\Node\HashNode;
use Symfony\Component\CssSelector\Node\SelectorNode;
use Symfony\Component\CssSelector\Parser\ParserInterface;











class HashParser implements ParserInterface
{



public function parse(string $source): array
{

 
 
 
 
 
 
 if (preg_match('/^(?:([a-z]++)\|)?+([\w-]++|\*)?+#([\w-]++)$/i', trim($source), $matches)) {
return [
new SelectorNode(new HashNode(new ElementNode($matches[1] ?: null, $matches[2] ?: null), $matches[3])),
];
}

return [];
}
}
<?php










namespace Symfony\Component\CssSelector\Parser\Shortcut;

use Symfony\Component\CssSelector\Node\ClassNode;
use Symfony\Component\CssSelector\Node\ElementNode;
use Symfony\Component\CssSelector\Node\SelectorNode;
use Symfony\Component\CssSelector\Parser\ParserInterface;











class ClassParser implements ParserInterface
{



public function parse(string $source): array
{

 
 
 
 
 
 
 if (preg_match('/^(?:([a-z]++)\|)?+([\w-]++|\*)?+\.([\w-]++)$/i', trim($source), $matches)) {
return [
new SelectorNode(new ClassNode(new ElementNode($matches[1] ?: null, $matches[2] ?: null), $matches[3])),
];
}

return [];
}
}
<?php










namespace Symfony\Component\CssSelector\Parser\Shortcut;

use Symfony\Component\CssSelector\Node\ElementNode;
use Symfony\Component\CssSelector\Node\SelectorNode;
use Symfony\Component\CssSelector\Parser\ParserInterface;















class EmptyStringParser implements ParserInterface
{



public function parse(string $source): array
{

 if ('' == $source) {
return [new SelectorNode(new ElementNode(null, '*'))];
}

return [];
}
}
<?php










namespace Symfony\Component\CssSelector\Parser\Shortcut;

use Symfony\Component\CssSelector\Node\ElementNode;
use Symfony\Component\CssSelector\Node\SelectorNode;
use Symfony\Component\CssSelector\Parser\ParserInterface;











class ElementParser implements ParserInterface
{



public function parse(string $source): array
{

 
 
 
 
 
 if (preg_match('/^(?:([a-z]++)\|)?([\w-]++|\*)$/i', trim($source), $matches)) {
return [new SelectorNode(new ElementNode($matches[1] ?: null, $matches[2]))];
}

return [];
}
}
<?php










namespace Symfony\Component\CssSelector\Parser;

use Symfony\Component\CssSelector\Exception\InternalErrorException;
use Symfony\Component\CssSelector\Exception\SyntaxErrorException;











class TokenStream
{



private $tokens = [];




private $used = [];




private $cursor = 0;




private $peeked;




private $peeking = false;






public function push(Token $token): self
{
$this->tokens[] = $token;

return $this;
}






public function freeze(): self
{
return $this;
}






public function getNext(): Token
{
if ($this->peeking) {
$this->peeking = false;
$this->used[] = $this->peeked;

return $this->peeked;
}

if (!isset($this->tokens[$this->cursor])) {
throw new InternalErrorException('Unexpected token stream end.');
}

return $this->tokens[$this->cursor++];
}




public function getPeek(): Token
{
if (!$this->peeking) {
$this->peeked = $this->getNext();
$this->peeking = true;
}

return $this->peeked;
}






public function getUsed(): array
{
return $this->used;
}








public function getNextIdentifier(): string
{
$next = $this->getNext();

if (!$next->isIdentifier()) {
throw SyntaxErrorException::unexpectedToken('identifier', $next);
}

return $next->getValue();
}








public function getNextIdentifierOrStar(): ?string
{
$next = $this->getNext();

if ($next->isIdentifier()) {
return $next->getValue();
}

if ($next->isDelimiter(['*'])) {
return null;
}

throw SyntaxErrorException::unexpectedToken('identifier or "*"', $next);
}




public function skipWhitespace()
{
$peek = $this->getPeek();

if ($peek->isWhitespace()) {
$this->getNext();
}
}
}
<?php










namespace Symfony\Component\CssSelector\Parser\Tokenizer;

use Symfony\Component\CssSelector\Parser\Handler;
use Symfony\Component\CssSelector\Parser\Reader;
use Symfony\Component\CssSelector\Parser\Token;
use Symfony\Component\CssSelector\Parser\TokenStream;











class Tokenizer
{



private $handlers;

public function __construct()
{
$patterns = new TokenizerPatterns();
$escaping = new TokenizerEscaping($patterns);

$this->handlers = [
new Handler\WhitespaceHandler(),
new Handler\IdentifierHandler($patterns, $escaping),
new Handler\HashHandler($patterns, $escaping),
new Handler\StringHandler($patterns, $escaping),
new Handler\NumberHandler($patterns),
new Handler\CommentHandler(),
];
}




public function tokenize(Reader $reader): TokenStream
{
$stream = new TokenStream();

while (!$reader->isEOF()) {
foreach ($this->handlers as $handler) {
if ($handler->handle($reader, $stream)) {
continue 2;
}
}

$stream->push(new Token(Token::TYPE_DELIMITER, $reader->getSubstring(1), $reader->getPosition()));
$reader->moveForward(1);
}

return $stream
->push(new Token(Token::TYPE_FILE_END, null, $reader->getPosition()))
->freeze();
}
}
<?php










namespace Symfony\Component\CssSelector\Parser\Tokenizer;











class TokenizerEscaping
{
private $patterns;

public function __construct(TokenizerPatterns $patterns)
{
$this->patterns = $patterns;
}

public function escapeUnicode(string $value): string
{
$value = $this->replaceUnicodeSequences($value);

return preg_replace($this->patterns->getSimpleEscapePattern(), '$1', $value);
}

public function escapeUnicodeAndNewLine(string $value): string
{
$value = preg_replace($this->patterns->getNewLineEscapePattern(), '', $value);

return $this->escapeUnicode($value);
}

private function replaceUnicodeSequences(string $value): string
{
return preg_replace_callback($this->patterns->getUnicodeEscapePattern(), function ($match) {
$c = hexdec($match[1]);

if (0x80 > $c %= 0x200000) {
return \chr($c);
}
if (0x800 > $c) {
return \chr(0xC0 | $c >> 6).\chr(0x80 | $c & 0x3F);
}
if (0x10000 > $c) {
return \chr(0xE0 | $c >> 12).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F);
}

return '';
}, $value);
}
}
<?php










namespace Symfony\Component\CssSelector\Parser\Tokenizer;











class TokenizerPatterns
{
private $unicodeEscapePattern;
private $simpleEscapePattern;
private $newLineEscapePattern;
private $escapePattern;
private $stringEscapePattern;
private $nonAsciiPattern;
private $nmCharPattern;
private $nmStartPattern;
private $identifierPattern;
private $hashPattern;
private $numberPattern;
private $quotedStringPattern;

public function __construct()
{
$this->unicodeEscapePattern = '\\\\([0-9a-f]{1,6})(?:\r\n|[ \n\r\t\f])?';
$this->simpleEscapePattern = '\\\\(.)';
$this->newLineEscapePattern = '\\\\(?:\n|\r\n|\r|\f)';
$this->escapePattern = $this->unicodeEscapePattern.'|\\\\[^\n\r\f0-9a-f]';
$this->stringEscapePattern = $this->newLineEscapePattern.'|'.$this->escapePattern;
$this->nonAsciiPattern = '[^\x00-\x7F]';
$this->nmCharPattern = '[_a-z0-9-]|'.$this->escapePattern.'|'.$this->nonAsciiPattern;
$this->nmStartPattern = '[_a-z]|'.$this->escapePattern.'|'.$this->nonAsciiPattern;
$this->identifierPattern = '-?(?:'.$this->nmStartPattern.')(?:'.$this->nmCharPattern.')*';
$this->hashPattern = '#((?:'.$this->nmCharPattern.')+)';
$this->numberPattern = '[+-]?(?:[0-9]*\.[0-9]+|[0-9]+)';
$this->quotedStringPattern = '([^\n\r\f%s]|'.$this->stringEscapePattern.')*';
}

public function getNewLineEscapePattern(): string
{
return '~^'.$this->newLineEscapePattern.'~';
}

public function getSimpleEscapePattern(): string
{
return '~^'.$this->simpleEscapePattern.'~';
}

public function getUnicodeEscapePattern(): string
{
return '~^'.$this->unicodeEscapePattern.'~i';
}

public function getIdentifierPattern(): string
{
return '~^'.$this->identifierPattern.'~i';
}

public function getHashPattern(): string
{
return '~^'.$this->hashPattern.'~i';
}

public function getNumberPattern(): string
{
return '~^'.$this->numberPattern.'~';
}

public function getQuotedStringPattern(string $quote): string
{
return '~^'.sprintf($this->quotedStringPattern, $quote).'~i';
}
}
<?php










namespace Symfony\Component\CssSelector\Parser;











class Reader
{
private $source;
private $length;
private $position = 0;

public function __construct(string $source)
{
$this->source = $source;
$this->length = \strlen($source);
}

public function isEOF(): bool
{
return $this->position >= $this->length;
}

public function getPosition(): int
{
return $this->position;
}

public function getRemainingLength(): int
{
return $this->length - $this->position;
}

public function getSubstring(int $length, int $offset = 0): string
{
return substr($this->source, $this->position + $offset, $length);
}

public function getOffset(string $string)
{
$position = strpos($this->source, $string, $this->position);

return false === $position ? false : $position - $this->position;
}




public function findPattern(string $pattern)
{
$source = substr($this->source, $this->position);

if (preg_match($pattern, $source, $matches)) {
return $matches;
}

return false;
}

public function moveForward(int $length)
{
$this->position += $length;
}

public function moveToEnd()
{
$this->position = $this->length;
}
}
<?php










namespace Symfony\Component\CssSelector\Parser\Handler;

use Symfony\Component\CssSelector\Exception\InternalErrorException;
use Symfony\Component\CssSelector\Exception\SyntaxErrorException;
use Symfony\Component\CssSelector\Parser\Reader;
use Symfony\Component\CssSelector\Parser\Token;
use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
use Symfony\Component\CssSelector\Parser\TokenStream;











class StringHandler implements HandlerInterface
{
private $patterns;
private $escaping;

public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
{
$this->patterns = $patterns;
$this->escaping = $escaping;
}




public function handle(Reader $reader, TokenStream $stream): bool
{
$quote = $reader->getSubstring(1);

if (!\in_array($quote, ["'", '"'])) {
return false;
}

$reader->moveForward(1);
$match = $reader->findPattern($this->patterns->getQuotedStringPattern($quote));

if (!$match) {
throw new InternalErrorException(sprintf('Should have found at least an empty match at %d.', $reader->getPosition()));
}


 if (\strlen($match[0]) === $reader->getRemainingLength()) {
throw SyntaxErrorException::unclosedString($reader->getPosition() - 1);
}


 if ($quote !== $reader->getSubstring(1, \strlen($match[0]))) {
throw SyntaxErrorException::unclosedString($reader->getPosition() - 1);
}

$string = $this->escaping->escapeUnicodeAndNewLine($match[0]);
$stream->push(new Token(Token::TYPE_STRING, $string, $reader->getPosition()));
$reader->moveForward(\strlen($match[0]) + 1);

return true;
}
}
<?php










namespace Symfony\Component\CssSelector\Parser\Handler;

use Symfony\Component\CssSelector\Parser\Reader;
use Symfony\Component\CssSelector\Parser\Token;
use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
use Symfony\Component\CssSelector\Parser\TokenStream;











class NumberHandler implements HandlerInterface
{
private $patterns;

public function __construct(TokenizerPatterns $patterns)
{
$this->patterns = $patterns;
}




public function handle(Reader $reader, TokenStream $stream): bool
{
$match = $reader->findPattern($this->patterns->getNumberPattern());

if (!$match) {
return false;
}

$stream->push(new Token(Token::TYPE_NUMBER, $match[0], $reader->getPosition()));
$reader->moveForward(\strlen($match[0]));

return true;
}
}
<?php










namespace Symfony\Component\CssSelector\Parser\Handler;

use Symfony\Component\CssSelector\Parser\Reader;
use Symfony\Component\CssSelector\Parser\TokenStream;











interface HandlerInterface
{
public function handle(Reader $reader, TokenStream $stream): bool;
}
<?php










namespace Symfony\Component\CssSelector\Parser\Handler;

use Symfony\Component\CssSelector\Parser\Reader;
use Symfony\Component\CssSelector\Parser\Token;
use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
use Symfony\Component\CssSelector\Parser\TokenStream;











class IdentifierHandler implements HandlerInterface
{
private $patterns;
private $escaping;

public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
{
$this->patterns = $patterns;
$this->escaping = $escaping;
}




public function handle(Reader $reader, TokenStream $stream): bool
{
$match = $reader->findPattern($this->patterns->getIdentifierPattern());

if (!$match) {
return false;
}

$value = $this->escaping->escapeUnicode($match[0]);
$stream->push(new Token(Token::TYPE_IDENTIFIER, $value, $reader->getPosition()));
$reader->moveForward(\strlen($match[0]));

return true;
}
}
<?php










namespace Symfony\Component\CssSelector\Parser\Handler;

use Symfony\Component\CssSelector\Parser\Reader;
use Symfony\Component\CssSelector\Parser\Token;
use Symfony\Component\CssSelector\Parser\TokenStream;











class WhitespaceHandler implements HandlerInterface
{



public function handle(Reader $reader, TokenStream $stream): bool
{
$match = $reader->findPattern('~^[ \t\r\n\f]+~');

if (false === $match) {
return false;
}

$stream->push(new Token(Token::TYPE_WHITESPACE, $match[0], $reader->getPosition()));
$reader->moveForward(\strlen($match[0]));

return true;
}
}
<?php










namespace Symfony\Component\CssSelector\Parser\Handler;

use Symfony\Component\CssSelector\Parser\Reader;
use Symfony\Component\CssSelector\Parser\TokenStream;











class CommentHandler implements HandlerInterface
{



public function handle(Reader $reader, TokenStream $stream): bool
{
if ('/*' !== $reader->getSubstring(2)) {
return false;
}

$offset = $reader->getOffset('*/');

if (false === $offset) {
$reader->moveToEnd();
} else {
$reader->moveForward($offset + 2);
}

return true;
}
}
<?php










namespace Symfony\Component\CssSelector\Parser\Handler;

use Symfony\Component\CssSelector\Parser\Reader;
use Symfony\Component\CssSelector\Parser\Token;
use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
use Symfony\Component\CssSelector\Parser\TokenStream;











class HashHandler implements HandlerInterface
{
private $patterns;
private $escaping;

public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
{
$this->patterns = $patterns;
$this->escaping = $escaping;
}




public function handle(Reader $reader, TokenStream $stream): bool
{
$match = $reader->findPattern($this->patterns->getHashPattern());

if (!$match) {
return false;
}

$value = $this->escaping->escapeUnicode($match[1]);
$stream->push(new Token(Token::TYPE_HASH, $value, $reader->getPosition()));
$reader->moveForward(\strlen($match[0]));

return true;
}
}
<?php










namespace Symfony\Component\CssSelector\Parser;











class Token
{
public const TYPE_FILE_END = 'eof';
public const TYPE_DELIMITER = 'delimiter';
public const TYPE_WHITESPACE = 'whitespace';
public const TYPE_IDENTIFIER = 'identifier';
public const TYPE_HASH = 'hash';
public const TYPE_NUMBER = 'number';
public const TYPE_STRING = 'string';

private $type;
private $value;
private $position;

public function __construct(?string $type, ?string $value, ?int $position)
{
$this->type = $type;
$this->value = $value;
$this->position = $position;
}

public function getType(): ?int
{
return $this->type;
}

public function getValue(): ?string
{
return $this->value;
}

public function getPosition(): ?int
{
return $this->position;
}

public function isFileEnd(): bool
{
return self::TYPE_FILE_END === $this->type;
}

public function isDelimiter(array $values = []): bool
{
if (self::TYPE_DELIMITER !== $this->type) {
return false;
}

if (empty($values)) {
return true;
}

return \in_array($this->value, $values);
}

public function isWhitespace(): bool
{
return self::TYPE_WHITESPACE === $this->type;
}

public function isIdentifier(): bool
{
return self::TYPE_IDENTIFIER === $this->type;
}

public function isHash(): bool
{
return self::TYPE_HASH === $this->type;
}

public function isNumber(): bool
{
return self::TYPE_NUMBER === $this->type;
}

public function isString(): bool
{
return self::TYPE_STRING === $this->type;
}

public function __toString(): string
{
if ($this->value) {
return sprintf('<%s "%s" at %s>', $this->type, $this->value, $this->position);
}

return sprintf('<%s at %s>', $this->type, $this->position);
}
}
<?php










namespace Symfony\Component\CssSelector\Parser;

use Symfony\Component\CssSelector\Exception\SyntaxErrorException;
use Symfony\Component\CssSelector\Node;
use Symfony\Component\CssSelector\Parser\Tokenizer\Tokenizer;











class Parser implements ParserInterface
{
private $tokenizer;

public function __construct(Tokenizer $tokenizer = null)
{
$this->tokenizer = $tokenizer ?? new Tokenizer();
}




public function parse(string $source): array
{
$reader = new Reader($source);
$stream = $this->tokenizer->tokenize($reader);

return $this->parseSelectorList($stream);
}








public static function parseSeries(array $tokens): array
{
foreach ($tokens as $token) {
if ($token->isString()) {
throw SyntaxErrorException::stringAsFunctionArgument();
}
}

$joined = trim(implode('', array_map(function (Token $token) {
return $token->getValue();
}, $tokens)));

$int = function ($string) {
if (!is_numeric($string)) {
throw SyntaxErrorException::stringAsFunctionArgument();
}

return (int) $string;
};

switch (true) {
case 'odd' === $joined:
return [2, 1];
case 'even' === $joined:
return [2, 0];
case 'n' === $joined:
return [1, 0];
case !str_contains($joined, 'n'):
return [0, $int($joined)];
}

$split = explode('n', $joined);
$first = $split[0] ?? null;

return [
$first ? ('-' === $first || '+' === $first ? $int($first.'1') : $int($first)) : 1,
isset($split[1]) && $split[1] ? $int($split[1]) : 0,
];
}

private function parseSelectorList(TokenStream $stream): array
{
$stream->skipWhitespace();
$selectors = [];

while (true) {
$selectors[] = $this->parserSelectorNode($stream);

if ($stream->getPeek()->isDelimiter([','])) {
$stream->getNext();
$stream->skipWhitespace();
} else {
break;
}
}

return $selectors;
}

private function parserSelectorNode(TokenStream $stream): Node\SelectorNode
{
[$result, $pseudoElement] = $this->parseSimpleSelector($stream);

while (true) {
$stream->skipWhitespace();
$peek = $stream->getPeek();

if ($peek->isFileEnd() || $peek->isDelimiter([','])) {
break;
}

if (null !== $pseudoElement) {
throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector');
}

if ($peek->isDelimiter(['+', '>', '~'])) {
$combinator = $stream->getNext()->getValue();
$stream->skipWhitespace();
} else {
$combinator = ' ';
}

[$nextSelector, $pseudoElement] = $this->parseSimpleSelector($stream);
$result = new Node\CombinedSelectorNode($result, $combinator, $nextSelector);
}

return new Node\SelectorNode($result, $pseudoElement);
}






private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = false): array
{
$stream->skipWhitespace();

$selectorStart = \count($stream->getUsed());
$result = $this->parseElementNode($stream);
$pseudoElement = null;

while (true) {
$peek = $stream->getPeek();
if ($peek->isWhitespace()
|| $peek->isFileEnd()
|| $peek->isDelimiter([',', '+', '>', '~'])
|| ($insideNegation && $peek->isDelimiter([')']))
) {
break;
}

if (null !== $pseudoElement) {
throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector');
}

if ($peek->isHash()) {
$result = new Node\HashNode($result, $stream->getNext()->getValue());
} elseif ($peek->isDelimiter(['.'])) {
$stream->getNext();
$result = new Node\ClassNode($result, $stream->getNextIdentifier());
} elseif ($peek->isDelimiter(['['])) {
$stream->getNext();
$result = $this->parseAttributeNode($result, $stream);
} elseif ($peek->isDelimiter([':'])) {
$stream->getNext();

if ($stream->getPeek()->isDelimiter([':'])) {
$stream->getNext();
$pseudoElement = $stream->getNextIdentifier();

continue;
}

$identifier = $stream->getNextIdentifier();
if (\in_array(strtolower($identifier), ['first-line', 'first-letter', 'before', 'after'])) {

 
 $pseudoElement = $identifier;

continue;
}

if (!$stream->getPeek()->isDelimiter(['('])) {
$result = new Node\PseudoNode($result, $identifier);

continue;
}

$stream->getNext();
$stream->skipWhitespace();

if ('not' === strtolower($identifier)) {
if ($insideNegation) {
throw SyntaxErrorException::nestedNot();
}

[$argument, $argumentPseudoElement] = $this->parseSimpleSelector($stream, true);
$next = $stream->getNext();

if (null !== $argumentPseudoElement) {
throw SyntaxErrorException::pseudoElementFound($argumentPseudoElement, 'inside ::not()');
}

if (!$next->isDelimiter([')'])) {
throw SyntaxErrorException::unexpectedToken('")"', $next);
}

$result = new Node\NegationNode($result, $argument);
} else {
$arguments = [];
$next = null;

while (true) {
$stream->skipWhitespace();
$next = $stream->getNext();

if ($next->isIdentifier()
|| $next->isString()
|| $next->isNumber()
|| $next->isDelimiter(['+', '-'])
) {
$arguments[] = $next;
} elseif ($next->isDelimiter([')'])) {
break;
} else {
throw SyntaxErrorException::unexpectedToken('an argument', $next);
}
}

if (empty($arguments)) {
throw SyntaxErrorException::unexpectedToken('at least one argument', $next);
}

$result = new Node\FunctionNode($result, $identifier, $arguments);
}
} else {
throw SyntaxErrorException::unexpectedToken('selector', $peek);
}
}

if (\count($stream->getUsed()) === $selectorStart) {
throw SyntaxErrorException::unexpectedToken('selector', $stream->getPeek());
}

return [$result, $pseudoElement];
}

private function parseElementNode(TokenStream $stream): Node\ElementNode
{
$peek = $stream->getPeek();

if ($peek->isIdentifier() || $peek->isDelimiter(['*'])) {
if ($peek->isIdentifier()) {
$namespace = $stream->getNext()->getValue();
} else {
$stream->getNext();
$namespace = null;
}

if ($stream->getPeek()->isDelimiter(['|'])) {
$stream->getNext();
$element = $stream->getNextIdentifierOrStar();
} else {
$element = $namespace;
$namespace = null;
}
} else {
$element = $namespace = null;
}

return new Node\ElementNode($namespace, $element);
}

private function parseAttributeNode(Node\NodeInterface $selector, TokenStream $stream): Node\AttributeNode
{
$stream->skipWhitespace();
$attribute = $stream->getNextIdentifierOrStar();

if (null === $attribute && !$stream->getPeek()->isDelimiter(['|'])) {
throw SyntaxErrorException::unexpectedToken('"|"', $stream->getPeek());
}

if ($stream->getPeek()->isDelimiter(['|'])) {
$stream->getNext();

if ($stream->getPeek()->isDelimiter(['='])) {
$namespace = null;
$stream->getNext();
$operator = '|=';
} else {
$namespace = $attribute;
$attribute = $stream->getNextIdentifier();
$operator = null;
}
} else {
$namespace = $operator = null;
}

if (null === $operator) {
$stream->skipWhitespace();
$next = $stream->getNext();

if ($next->isDelimiter([']'])) {
return new Node\AttributeNode($selector, $namespace, $attribute, 'exists', null);
} elseif ($next->isDelimiter(['='])) {
$operator = '=';
} elseif ($next->isDelimiter(['^', '$', '*', '~', '|', '!'])
&& $stream->getPeek()->isDelimiter(['='])
) {
$operator = $next->getValue().'=';
$stream->getNext();
} else {
throw SyntaxErrorException::unexpectedToken('operator', $next);
}
}

$stream->skipWhitespace();
$value = $stream->getNext();

if ($value->isNumber()) {

 $value = new Token(Token::TYPE_STRING, (string) $value->getValue(), $value->getPosition());
}

if (!($value->isIdentifier() || $value->isString())) {
throw SyntaxErrorException::unexpectedToken('string or identifier', $value);
}

$stream->skipWhitespace();
$next = $stream->getNext();

if (!$next->isDelimiter([']'])) {
throw SyntaxErrorException::unexpectedToken('"]"', $next);
}

return new Node\AttributeNode($selector, $namespace, $attribute, $operator, $value->getValue());
}
}
<?php










namespace Symfony\Component\CssSelector;

use Symfony\Component\CssSelector\Parser\Shortcut\ClassParser;
use Symfony\Component\CssSelector\Parser\Shortcut\ElementParser;
use Symfony\Component\CssSelector\Parser\Shortcut\EmptyStringParser;
use Symfony\Component\CssSelector\Parser\Shortcut\HashParser;
use Symfony\Component\CssSelector\XPath\Extension\HtmlExtension;
use Symfony\Component\CssSelector\XPath\Translator;







class CssSelectorConverter
{
private $translator;




public function __construct(bool $html = true)
{
$this->translator = new Translator();

if ($html) {
$this->translator->registerExtension(new HtmlExtension($this->translator));
}

$this->translator
->registerParserShortcut(new EmptyStringParser())
->registerParserShortcut(new ElementParser())
->registerParserShortcut(new ClassParser())
->registerParserShortcut(new HashParser())
;
}












public function toXPath($cssExpr, $prefix = 'descendant-or-self::')
{
return $this->translator->cssToXPath($cssExpr, $prefix);
}
}
<?php










namespace Symfony\Component\CssSelector\Node;

use Symfony\Component\CssSelector\Parser\Token;











class FunctionNode extends AbstractNode
{
private $selector;
private $name;
private $arguments;




public function __construct(NodeInterface $selector, string $name, array $arguments = [])
{
$this->selector = $selector;
$this->name = strtolower($name);
$this->arguments = $arguments;
}

public function getSelector(): NodeInterface
{
return $this->selector;
}

public function getName(): string
{
return $this->name;
}




public function getArguments(): array
{
return $this->arguments;
}




public function getSpecificity(): Specificity
{
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
}

public function __toString(): string
{
$arguments = implode(', ', array_map(function (Token $token) {
return "'".$token->getValue()."'";
}, $this->arguments));

return sprintf('%s[%s:%s(%s)]', $this->getNodeName(), $this->selector, $this->name, $arguments ? '['.$arguments.']' : '');
}
}
<?php










namespace Symfony\Component\CssSelector\Node;











class SelectorNode extends AbstractNode
{
private $tree;
private $pseudoElement;

public function __construct(NodeInterface $tree, string $pseudoElement = null)
{
$this->tree = $tree;
$this->pseudoElement = $pseudoElement ? strtolower($pseudoElement) : null;
}

public function getTree(): NodeInterface
{
return $this->tree;
}

public function getPseudoElement(): ?string
{
return $this->pseudoElement;
}




public function getSpecificity(): Specificity
{
return $this->tree->getSpecificity()->plus(new Specificity(0, 0, $this->pseudoElement ? 1 : 0));
}

public function __toString(): string
{
return sprintf('%s[%s%s]', $this->getNodeName(), $this->tree, $this->pseudoElement ? '::'.$this->pseudoElement : '');
}
}
<?php










namespace Symfony\Component\CssSelector\Node;











class ClassNode extends AbstractNode
{
private $selector;
private $name;

public function __construct(NodeInterface $selector, string $name)
{
$this->selector = $selector;
$this->name = $name;
}

public function getSelector(): NodeInterface
{
return $this->selector;
}

public function getName(): string
{
return $this->name;
}




public function getSpecificity(): Specificity
{
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
}

public function __toString(): string
{
return sprintf('%s[%s.%s]', $this->getNodeName(), $this->selector, $this->name);
}
}
<?php










namespace Symfony\Component\CssSelector\Node;











class ElementNode extends AbstractNode
{
private $namespace;
private $element;

public function __construct(string $namespace = null, string $element = null)
{
$this->namespace = $namespace;
$this->element = $element;
}

public function getNamespace(): ?string
{
return $this->namespace;
}

public function getElement(): ?string
{
return $this->element;
}




public function getSpecificity(): Specificity
{
return new Specificity(0, 0, $this->element ? 1 : 0);
}

public function __toString(): string
{
$element = $this->element ?: '*';

return sprintf('%s[%s]', $this->getNodeName(), $this->namespace ? $this->namespace.'|'.$element : $element);
}
}
<?php










namespace Symfony\Component\CssSelector\Node;











class AttributeNode extends AbstractNode
{
private $selector;
private $namespace;
private $attribute;
private $operator;
private $value;

public function __construct(NodeInterface $selector, ?string $namespace, string $attribute, string $operator, ?string $value)
{
$this->selector = $selector;
$this->namespace = $namespace;
$this->attribute = $attribute;
$this->operator = $operator;
$this->value = $value;
}

public function getSelector(): NodeInterface
{
return $this->selector;
}

public function getNamespace(): ?string
{
return $this->namespace;
}

public function getAttribute(): string
{
return $this->attribute;
}

public function getOperator(): string
{
return $this->operator;
}

public function getValue(): ?string
{
return $this->value;
}




public function getSpecificity(): Specificity
{
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
}

public function __toString(): string
{
$attribute = $this->namespace ? $this->namespace.'|'.$this->attribute : $this->attribute;

return 'exists' === $this->operator
? sprintf('%s[%s[%s]]', $this->getNodeName(), $this->selector, $attribute)
: sprintf("%s[%s[%s %s '%s']]", $this->getNodeName(), $this->selector, $attribute, $this->operator, $this->value);
}
}
<?php










namespace Symfony\Component\CssSelector\Node;











interface NodeInterface
{
public function getNodeName(): string;

public function getSpecificity(): Specificity;

public function __toString(): string;
}
<?php










namespace Symfony\Component\CssSelector\Node;













class Specificity
{
public const A_FACTOR = 100;
public const B_FACTOR = 10;
public const C_FACTOR = 1;

private $a;
private $b;
private $c;

public function __construct(int $a, int $b, int $c)
{
$this->a = $a;
$this->b = $b;
$this->c = $c;
}

public function plus(self $specificity): self
{
return new self($this->a + $specificity->a, $this->b + $specificity->b, $this->c + $specificity->c);
}

public function getValue(): int
{
return $this->a * self::A_FACTOR + $this->b * self::B_FACTOR + $this->c * self::C_FACTOR;
}





public function compareTo(self $specificity): int
{
if ($this->a !== $specificity->a) {
return $this->a > $specificity->a ? 1 : -1;
}

if ($this->b !== $specificity->b) {
return $this->b > $specificity->b ? 1 : -1;
}

if ($this->c !== $specificity->c) {
return $this->c > $specificity->c ? 1 : -1;
}

return 0;
}
}
<?php










namespace Symfony\Component\CssSelector\Node;











class NegationNode extends AbstractNode
{
private $selector;
private $subSelector;

public function __construct(NodeInterface $selector, NodeInterface $subSelector)
{
$this->selector = $selector;
$this->subSelector = $subSelector;
}

public function getSelector(): NodeInterface
{
return $this->selector;
}

public function getSubSelector(): NodeInterface
{
return $this->subSelector;
}




public function getSpecificity(): Specificity
{
return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity());
}

public function __toString(): string
{
return sprintf('%s[%s:not(%s)]', $this->getNodeName(), $this->selector, $this->subSelector);
}
}
<?php










namespace Symfony\Component\CssSelector\Node;











abstract class AbstractNode implements NodeInterface
{



private $nodeName;

public function getNodeName(): string
{
if (null === $this->nodeName) {
$this->nodeName = preg_replace('~.*\\\\([^\\\\]+)Node$~', '$1', static::class);
}

return $this->nodeName;
}
}
<?php










namespace Symfony\Component\CssSelector\Node;











class CombinedSelectorNode extends AbstractNode
{
private $selector;
private $combinator;
private $subSelector;

public function __construct(NodeInterface $selector, string $combinator, NodeInterface $subSelector)
{
$this->selector = $selector;
$this->combinator = $combinator;
$this->subSelector = $subSelector;
}

public function getSelector(): NodeInterface
{
return $this->selector;
}

public function getCombinator(): string
{
return $this->combinator;
}

public function getSubSelector(): NodeInterface
{
return $this->subSelector;
}




public function getSpecificity(): Specificity
{
return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity());
}

public function __toString(): string
{
$combinator = ' ' === $this->combinator ? '<followed>' : $this->combinator;

return sprintf('%s[%s %s %s]', $this->getNodeName(), $this->selector, $combinator, $this->subSelector);
}
}
<?php










namespace Symfony\Component\CssSelector\Node;











class PseudoNode extends AbstractNode
{
private $selector;
private $identifier;

public function __construct(NodeInterface $selector, string $identifier)
{
$this->selector = $selector;
$this->identifier = strtolower($identifier);
}

public function getSelector(): NodeInterface
{
return $this->selector;
}

public function getIdentifier(): string
{
return $this->identifier;
}




public function getSpecificity(): Specificity
{
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
}

public function __toString(): string
{
return sprintf('%s[%s:%s]', $this->getNodeName(), $this->selector, $this->identifier);
}
}
<?php










namespace Symfony\Component\CssSelector\Node;











class HashNode extends AbstractNode
{
private $selector;
private $id;

public function __construct(NodeInterface $selector, string $id)
{
$this->selector = $selector;
$this->id = $id;
}

public function getSelector(): NodeInterface
{
return $this->selector;
}

public function getId(): string
{
return $this->id;
}




public function getSpecificity(): Specificity
{
return $this->selector->getSpecificity()->plus(new Specificity(1, 0, 0));
}

public function __toString(): string
{
return sprintf('%s[%s#%s]', $this->getNodeName(), $this->selector, $this->id);
}
}
<?php










namespace Symfony\Component\CssSelector\Exception;









class ParseException extends \Exception implements ExceptionInterface
{
}
<?php










namespace Symfony\Component\CssSelector\Exception;









class InternalErrorException extends ParseException
{
}
<?php










namespace Symfony\Component\CssSelector\Exception;

use Symfony\Component\CssSelector\Parser\Token;









class SyntaxErrorException extends ParseException
{





public static function unexpectedToken($expectedValue, Token $foundToken)
{
return new self(sprintf('Expected %s, but %s found.', $expectedValue, $foundToken));
}







public static function pseudoElementFound($pseudoElement, $unexpectedLocation)
{
return new self(sprintf('Unexpected pseudo-element "::%s" found %s.', $pseudoElement, $unexpectedLocation));
}






public static function unclosedString($position)
{
return new self(sprintf('Unclosed/invalid string at %s.', $position));
}




public static function nestedNot()
{
return new self('Got nested ::not().');
}




public static function stringAsFunctionArgument()
{
return new self('String not allowed as function argument.');
}
}
<?php










namespace Symfony\Component\CssSelector\Exception;









class ExpressionErrorException extends ParseException
{
}
<?php










namespace Symfony\Component\CssSelector\Exception;









interface ExceptionInterface extends \Throwable
{
}
<?php










namespace Symfony\Component\CssSelector\XPath;

use Symfony\Component\CssSelector\Exception\ExpressionErrorException;
use Symfony\Component\CssSelector\Node\FunctionNode;
use Symfony\Component\CssSelector\Node\NodeInterface;
use Symfony\Component\CssSelector\Node\SelectorNode;
use Symfony\Component\CssSelector\Parser\Parser;
use Symfony\Component\CssSelector\Parser\ParserInterface;











class Translator implements TranslatorInterface
{
private $mainParser;




private $shortcutParsers = [];




private $extensions = [];

private $nodeTranslators = [];
private $combinationTranslators = [];
private $functionTranslators = [];
private $pseudoClassTranslators = [];
private $attributeMatchingTranslators = [];

public function __construct(ParserInterface $parser = null)
{
$this->mainParser = $parser ?? new Parser();

$this
->registerExtension(new Extension\NodeExtension())
->registerExtension(new Extension\CombinationExtension())
->registerExtension(new Extension\FunctionExtension())
->registerExtension(new Extension\PseudoClassExtension())
->registerExtension(new Extension\AttributeMatchingExtension())
;
}

public static function getXpathLiteral(string $element): string
{
if (!str_contains($element, "'")) {
return "'".$element."'";
}

if (!str_contains($element, '"')) {
return '"'.$element.'"';
}

$string = $element;
$parts = [];
while (true) {
if (false !== $pos = strpos($string, "'")) {
$parts[] = sprintf("'%s'", substr($string, 0, $pos));
$parts[] = "\"'\"";
$string = substr($string, $pos + 1);
} else {
$parts[] = "'$string'";
break;
}
}

return sprintf('concat(%s)', implode(', ', $parts));
}




public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string
{
$selectors = $this->parseSelectors($cssExpr);


foreach ($selectors as $index => $selector) {
if (null !== $selector->getPseudoElement()) {
throw new ExpressionErrorException('Pseudo-elements are not supported.');
}

$selectors[$index] = $this->selectorToXPath($selector, $prefix);
}

return implode(' | ', $selectors);
}




public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string
{
return ($prefix ?: '').$this->nodeToXPath($selector);
}




public function registerExtension(Extension\ExtensionInterface $extension): self
{
$this->extensions[$extension->getName()] = $extension;

$this->nodeTranslators = array_merge($this->nodeTranslators, $extension->getNodeTranslators());
$this->combinationTranslators = array_merge($this->combinationTranslators, $extension->getCombinationTranslators());
$this->functionTranslators = array_merge($this->functionTranslators, $extension->getFunctionTranslators());
$this->pseudoClassTranslators = array_merge($this->pseudoClassTranslators, $extension->getPseudoClassTranslators());
$this->attributeMatchingTranslators = array_merge($this->attributeMatchingTranslators, $extension->getAttributeMatchingTranslators());

return $this;
}




public function getExtension(string $name): Extension\ExtensionInterface
{
if (!isset($this->extensions[$name])) {
throw new ExpressionErrorException(sprintf('Extension "%s" not registered.', $name));
}

return $this->extensions[$name];
}




public function registerParserShortcut(ParserInterface $shortcut): self
{
$this->shortcutParsers[] = $shortcut;

return $this;
}




public function nodeToXPath(NodeInterface $node): XPathExpr
{
if (!isset($this->nodeTranslators[$node->getNodeName()])) {
throw new ExpressionErrorException(sprintf('Node "%s" not supported.', $node->getNodeName()));
}

return $this->nodeTranslators[$node->getNodeName()]($node, $this);
}




public function addCombination(string $combiner, NodeInterface $xpath, NodeInterface $combinedXpath): XPathExpr
{
if (!isset($this->combinationTranslators[$combiner])) {
throw new ExpressionErrorException(sprintf('Combiner "%s" not supported.', $combiner));
}

return $this->combinationTranslators[$combiner]($this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath));
}




public function addFunction(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
if (!isset($this->functionTranslators[$function->getName()])) {
throw new ExpressionErrorException(sprintf('Function "%s" not supported.', $function->getName()));
}

return $this->functionTranslators[$function->getName()]($xpath, $function);
}




public function addPseudoClass(XPathExpr $xpath, string $pseudoClass): XPathExpr
{
if (!isset($this->pseudoClassTranslators[$pseudoClass])) {
throw new ExpressionErrorException(sprintf('Pseudo-class "%s" not supported.', $pseudoClass));
}

return $this->pseudoClassTranslators[$pseudoClass]($xpath);
}




public function addAttributeMatching(XPathExpr $xpath, string $operator, string $attribute, $value): XPathExpr
{
if (!isset($this->attributeMatchingTranslators[$operator])) {
throw new ExpressionErrorException(sprintf('Attribute matcher operator "%s" not supported.', $operator));
}

return $this->attributeMatchingTranslators[$operator]($xpath, $attribute, $value);
}




private function parseSelectors(string $css): array
{
foreach ($this->shortcutParsers as $shortcut) {
$tokens = $shortcut->parse($css);

if (!empty($tokens)) {
return $tokens;
}
}

return $this->mainParser->parse($css);
}
}
<?php










namespace Symfony\Component\CssSelector\XPath;

use Symfony\Component\CssSelector\Node\SelectorNode;











interface TranslatorInterface
{



public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string;




public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string;
}
<?php










namespace Symfony\Component\CssSelector\XPath\Extension;

use Symfony\Component\CssSelector\XPath\Translator;
use Symfony\Component\CssSelector\XPath\XPathExpr;











class AttributeMatchingExtension extends AbstractExtension
{



public function getAttributeMatchingTranslators(): array
{
return [
'exists' => [$this, 'translateExists'],
'=' => [$this, 'translateEquals'],
'~=' => [$this, 'translateIncludes'],
'|=' => [$this, 'translateDashMatch'],
'^=' => [$this, 'translatePrefixMatch'],
'$=' => [$this, 'translateSuffixMatch'],
'*=' => [$this, 'translateSubstringMatch'],
'!=' => [$this, 'translateDifferent'],
];
}

public function translateExists(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition($attribute);
}

public function translateEquals(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition(sprintf('%s = %s', $attribute, Translator::getXpathLiteral($value)));
}

public function translateIncludes(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition($value ? sprintf(
'%1$s and contains(concat(\' \', normalize-space(%1$s), \' \'), %2$s)',
$attribute,
Translator::getXpathLiteral(' '.$value.' ')
) : '0');
}

public function translateDashMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition(sprintf(
'%1$s and (%1$s = %2$s or starts-with(%1$s, %3$s))',
$attribute,
Translator::getXpathLiteral($value),
Translator::getXpathLiteral($value.'-')
));
}

public function translatePrefixMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition($value ? sprintf(
'%1$s and starts-with(%1$s, %2$s)',
$attribute,
Translator::getXpathLiteral($value)
) : '0');
}

public function translateSuffixMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition($value ? sprintf(
'%1$s and substring(%1$s, string-length(%1$s)-%2$s) = %3$s',
$attribute,
\strlen($value) - 1,
Translator::getXpathLiteral($value)
) : '0');
}

public function translateSubstringMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition($value ? sprintf(
'%1$s and contains(%1$s, %2$s)',
$attribute,
Translator::getXpathLiteral($value)
) : '0');
}

public function translateDifferent(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition(sprintf(
$value ? 'not(%1$s) or %1$s != %2$s' : '%s != %s',
$attribute,
Translator::getXpathLiteral($value)
));
}




public function getName(): string
{
return 'attribute-matching';
}
}
<?php










namespace Symfony\Component\CssSelector\XPath\Extension;











interface ExtensionInterface
{







public function getNodeTranslators(): array;






public function getCombinationTranslators(): array;






public function getFunctionTranslators(): array;






public function getPseudoClassTranslators(): array;






public function getAttributeMatchingTranslators(): array;




public function getName(): string;
}
<?php










namespace Symfony\Component\CssSelector\XPath\Extension;

use Symfony\Component\CssSelector\Exception\ExpressionErrorException;
use Symfony\Component\CssSelector\Exception\SyntaxErrorException;
use Symfony\Component\CssSelector\Node\FunctionNode;
use Symfony\Component\CssSelector\Parser\Parser;
use Symfony\Component\CssSelector\XPath\Translator;
use Symfony\Component\CssSelector\XPath\XPathExpr;











class FunctionExtension extends AbstractExtension
{



public function getFunctionTranslators(): array
{
return [
'nth-child' => [$this, 'translateNthChild'],
'nth-last-child' => [$this, 'translateNthLastChild'],
'nth-of-type' => [$this, 'translateNthOfType'],
'nth-last-of-type' => [$this, 'translateNthLastOfType'],
'contains' => [$this, 'translateContains'],
'lang' => [$this, 'translateLang'],
];
}




public function translateNthChild(XPathExpr $xpath, FunctionNode $function, bool $last = false, bool $addNameTest = true): XPathExpr
{
try {
[$a, $b] = Parser::parseSeries($function->getArguments());
} catch (SyntaxErrorException $e) {
throw new ExpressionErrorException(sprintf('Invalid series: "%s".', implode('", "', $function->getArguments())), 0, $e);
}

$xpath->addStarPrefix();
if ($addNameTest) {
$xpath->addNameTest();
}

if (0 === $a) {
return $xpath->addCondition('position() = '.($last ? 'last() - '.($b - 1) : $b));
}

if ($a < 0) {
if ($b < 1) {
return $xpath->addCondition('false()');
}

$sign = '<=';
} else {
$sign = '>=';
}

$expr = 'position()';

if ($last) {
$expr = 'last() - '.$expr;
--$b;
}

if (0 !== $b) {
$expr .= ' - '.$b;
}

$conditions = [sprintf('%s %s 0', $expr, $sign)];

if (1 !== $a && -1 !== $a) {
$conditions[] = sprintf('(%s) mod %d = 0', $expr, $a);
}

return $xpath->addCondition(implode(' and ', $conditions));


 
 
 
 
 
 
 }

public function translateNthLastChild(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
return $this->translateNthChild($xpath, $function, true);
}

public function translateNthOfType(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
return $this->translateNthChild($xpath, $function, false, false);
}




public function translateNthLastOfType(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
if ('*' === $xpath->getElement()) {
throw new ExpressionErrorException('"*:nth-of-type()" is not implemented.');
}

return $this->translateNthChild($xpath, $function, true, false);
}




public function translateContains(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
$arguments = $function->getArguments();
foreach ($arguments as $token) {
if (!($token->isString() || $token->isIdentifier())) {
throw new ExpressionErrorException('Expected a single string or identifier for :contains(), got '.implode(', ', $arguments));
}
}

return $xpath->addCondition(sprintf(
'contains(string(.), %s)',
Translator::getXpathLiteral($arguments[0]->getValue())
));
}




public function translateLang(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
$arguments = $function->getArguments();
foreach ($arguments as $token) {
if (!($token->isString() || $token->isIdentifier())) {
throw new ExpressionErrorException('Expected a single string or identifier for :lang(), got '.implode(', ', $arguments));
}
}

return $xpath->addCondition(sprintf(
'lang(%s)',
Translator::getXpathLiteral($arguments[0]->getValue())
));
}




public function getName(): string
{
return 'function';
}
}
<?php










namespace Symfony\Component\CssSelector\XPath\Extension;











abstract class AbstractExtension implements ExtensionInterface
{



public function getNodeTranslators(): array
{
return [];
}




public function getCombinationTranslators(): array
{
return [];
}




public function getFunctionTranslators(): array
{
return [];
}




public function getPseudoClassTranslators(): array
{
return [];
}




public function getAttributeMatchingTranslators(): array
{
return [];
}
}
<?php










namespace Symfony\Component\CssSelector\XPath\Extension;

use Symfony\Component\CssSelector\Exception\ExpressionErrorException;
use Symfony\Component\CssSelector\Node\FunctionNode;
use Symfony\Component\CssSelector\XPath\Translator;
use Symfony\Component\CssSelector\XPath\XPathExpr;











class HtmlExtension extends AbstractExtension
{
public function __construct(Translator $translator)
{
$translator
->getExtension('node')
->setFlag(NodeExtension::ELEMENT_NAME_IN_LOWER_CASE, true)
->setFlag(NodeExtension::ATTRIBUTE_NAME_IN_LOWER_CASE, true);
}




public function getPseudoClassTranslators(): array
{
return [
'checked' => [$this, 'translateChecked'],
'link' => [$this, 'translateLink'],
'disabled' => [$this, 'translateDisabled'],
'enabled' => [$this, 'translateEnabled'],
'selected' => [$this, 'translateSelected'],
'invalid' => [$this, 'translateInvalid'],
'hover' => [$this, 'translateHover'],
'visited' => [$this, 'translateVisited'],
];
}




public function getFunctionTranslators(): array
{
return [
'lang' => [$this, 'translateLang'],
];
}

public function translateChecked(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition(
'(@checked '
."and (name(.) = 'input' or name(.) = 'command')"
."and (@type = 'checkbox' or @type = 'radio'))"
);
}

public function translateLink(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition("@href and (name(.) = 'a' or name(.) = 'link' or name(.) = 'area')");
}

public function translateDisabled(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition(
'('
.'@disabled and'
.'('
."(name(.) = 'input' and @type != 'hidden')"
." or name(.) = 'button'"
." or name(.) = 'select'"
." or name(.) = 'textarea'"
." or name(.) = 'command'"
." or name(.) = 'fieldset'"
." or name(.) = 'optgroup'"
." or name(.) = 'option'"
.')'
.') or ('
."(name(.) = 'input' and @type != 'hidden')"
." or name(.) = 'button'"
." or name(.) = 'select'"
." or name(.) = 'textarea'"
.')'
.' and ancestor::fieldset[@disabled]'
);

 }

public function translateEnabled(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition(
'('
.'@href and ('
."name(.) = 'a'"
." or name(.) = 'link'"
." or name(.) = 'area'"
.')'
.') or ('
.'('
."name(.) = 'command'"
." or name(.) = 'fieldset'"
." or name(.) = 'optgroup'"
.')'
.' and not(@disabled)'
.') or ('
.'('
."(name(.) = 'input' and @type != 'hidden')"
." or name(.) = 'button'"
." or name(.) = 'select'"
." or name(.) = 'textarea'"
." or name(.) = 'keygen'"
.')'
.' and not (@disabled or ancestor::fieldset[@disabled])'
.') or ('
."name(.) = 'option' and not("
.'@disabled or ancestor::optgroup[@disabled]'
.')'
.')'
);
}




public function translateLang(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
$arguments = $function->getArguments();
foreach ($arguments as $token) {
if (!($token->isString() || $token->isIdentifier())) {
throw new ExpressionErrorException('Expected a single string or identifier for :lang(), got '.implode(', ', $arguments));
}
}

return $xpath->addCondition(sprintf(
'ancestor-or-self::*[@lang][1][starts-with(concat('
."translate(@%s, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '-')"
.', %s)]',
'lang',
Translator::getXpathLiteral(strtolower($arguments[0]->getValue()).'-')
));
}

public function translateSelected(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition("(@selected and name(.) = 'option')");
}

public function translateInvalid(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition('0');
}

public function translateHover(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition('0');
}

public function translateVisited(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition('0');
}




public function getName(): string
{
return 'html';
}
}
<?php










namespace Symfony\Component\CssSelector\XPath\Extension;

use Symfony\Component\CssSelector\Node;
use Symfony\Component\CssSelector\XPath\Translator;
use Symfony\Component\CssSelector\XPath\XPathExpr;











class NodeExtension extends AbstractExtension
{
public const ELEMENT_NAME_IN_LOWER_CASE = 1;
public const ATTRIBUTE_NAME_IN_LOWER_CASE = 2;
public const ATTRIBUTE_VALUE_IN_LOWER_CASE = 4;

private $flags;

public function __construct(int $flags = 0)
{
$this->flags = $flags;
}




public function setFlag(int $flag, bool $on): self
{
if ($on && !$this->hasFlag($flag)) {
$this->flags += $flag;
}

if (!$on && $this->hasFlag($flag)) {
$this->flags -= $flag;
}

return $this;
}

public function hasFlag(int $flag): bool
{
return (bool) ($this->flags & $flag);
}




public function getNodeTranslators(): array
{
return [
'Selector' => [$this, 'translateSelector'],
'CombinedSelector' => [$this, 'translateCombinedSelector'],
'Negation' => [$this, 'translateNegation'],
'Function' => [$this, 'translateFunction'],
'Pseudo' => [$this, 'translatePseudo'],
'Attribute' => [$this, 'translateAttribute'],
'Class' => [$this, 'translateClass'],
'Hash' => [$this, 'translateHash'],
'Element' => [$this, 'translateElement'],
];
}

public function translateSelector(Node\SelectorNode $node, Translator $translator): XPathExpr
{
return $translator->nodeToXPath($node->getTree());
}

public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator): XPathExpr
{
return $translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector());
}

public function translateNegation(Node\NegationNode $node, Translator $translator): XPathExpr
{
$xpath = $translator->nodeToXPath($node->getSelector());
$subXpath = $translator->nodeToXPath($node->getSubSelector());
$subXpath->addNameTest();

if ($subXpath->getCondition()) {
return $xpath->addCondition(sprintf('not(%s)', $subXpath->getCondition()));
}

return $xpath->addCondition('0');
}

public function translateFunction(Node\FunctionNode $node, Translator $translator): XPathExpr
{
$xpath = $translator->nodeToXPath($node->getSelector());

return $translator->addFunction($xpath, $node);
}

public function translatePseudo(Node\PseudoNode $node, Translator $translator): XPathExpr
{
$xpath = $translator->nodeToXPath($node->getSelector());

return $translator->addPseudoClass($xpath, $node->getIdentifier());
}

public function translateAttribute(Node\AttributeNode $node, Translator $translator): XPathExpr
{
$name = $node->getAttribute();
$safe = $this->isSafeName($name);

if ($this->hasFlag(self::ATTRIBUTE_NAME_IN_LOWER_CASE)) {
$name = strtolower($name);
}

if ($node->getNamespace()) {
$name = sprintf('%s:%s', $node->getNamespace(), $name);
$safe = $safe && $this->isSafeName($node->getNamespace());
}

$attribute = $safe ? '@'.$name : sprintf('attribute::*[name() = %s]', Translator::getXpathLiteral($name));
$value = $node->getValue();
$xpath = $translator->nodeToXPath($node->getSelector());

if ($this->hasFlag(self::ATTRIBUTE_VALUE_IN_LOWER_CASE)) {
$value = strtolower($value);
}

return $translator->addAttributeMatching($xpath, $node->getOperator(), $attribute, $value);
}

public function translateClass(Node\ClassNode $node, Translator $translator): XPathExpr
{
$xpath = $translator->nodeToXPath($node->getSelector());

return $translator->addAttributeMatching($xpath, '~=', '@class', $node->getName());
}

public function translateHash(Node\HashNode $node, Translator $translator): XPathExpr
{
$xpath = $translator->nodeToXPath($node->getSelector());

return $translator->addAttributeMatching($xpath, '=', '@id', $node->getId());
}

public function translateElement(Node\ElementNode $node): XPathExpr
{
$element = $node->getElement();

if ($element && $this->hasFlag(self::ELEMENT_NAME_IN_LOWER_CASE)) {
$element = strtolower($element);
}

if ($element) {
$safe = $this->isSafeName($element);
} else {
$element = '*';
$safe = true;
}

if ($node->getNamespace()) {
$element = sprintf('%s:%s', $node->getNamespace(), $element);
$safe = $safe && $this->isSafeName($node->getNamespace());
}

$xpath = new XPathExpr('', $element);

if (!$safe) {
$xpath->addNameTest();
}

return $xpath;
}




public function getName(): string
{
return 'node';
}

private function isSafeName(string $name): bool
{
return 0 < preg_match('~^[a-zA-Z_][a-zA-Z0-9_.-]*$~', $name);
}
}
<?php










namespace Symfony\Component\CssSelector\XPath\Extension;

use Symfony\Component\CssSelector\XPath\XPathExpr;











class CombinationExtension extends AbstractExtension
{



public function getCombinationTranslators(): array
{
return [
' ' => [$this, 'translateDescendant'],
'>' => [$this, 'translateChild'],
'+' => [$this, 'translateDirectAdjacent'],
'~' => [$this, 'translateIndirectAdjacent'],
];
}

public function translateDescendant(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
{
return $xpath->join('/descendant-or-self::*/', $combinedXpath);
}

public function translateChild(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
{
return $xpath->join('/', $combinedXpath);
}

public function translateDirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
{
return $xpath
->join('/following-sibling::', $combinedXpath)
->addNameTest()
->addCondition('position() = 1');
}

public function translateIndirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
{
return $xpath->join('/following-sibling::', $combinedXpath);
}




public function getName(): string
{
return 'combination';
}
}
<?php










namespace Symfony\Component\CssSelector\XPath\Extension;

use Symfony\Component\CssSelector\Exception\ExpressionErrorException;
use Symfony\Component\CssSelector\XPath\XPathExpr;











class PseudoClassExtension extends AbstractExtension
{



public function getPseudoClassTranslators(): array
{
return [
'root' => [$this, 'translateRoot'],
'first-child' => [$this, 'translateFirstChild'],
'last-child' => [$this, 'translateLastChild'],
'first-of-type' => [$this, 'translateFirstOfType'],
'last-of-type' => [$this, 'translateLastOfType'],
'only-child' => [$this, 'translateOnlyChild'],
'only-of-type' => [$this, 'translateOnlyOfType'],
'empty' => [$this, 'translateEmpty'],
];
}

public function translateRoot(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition('not(parent::*)');
}

public function translateFirstChild(XPathExpr $xpath): XPathExpr
{
return $xpath
->addStarPrefix()
->addNameTest()
->addCondition('position() = 1');
}

public function translateLastChild(XPathExpr $xpath): XPathExpr
{
return $xpath
->addStarPrefix()
->addNameTest()
->addCondition('position() = last()');
}




public function translateFirstOfType(XPathExpr $xpath): XPathExpr
{
if ('*' === $xpath->getElement()) {
throw new ExpressionErrorException('"*:first-of-type" is not implemented.');
}

return $xpath
->addStarPrefix()
->addCondition('position() = 1');
}




public function translateLastOfType(XPathExpr $xpath): XPathExpr
{
if ('*' === $xpath->getElement()) {
throw new ExpressionErrorException('"*:last-of-type" is not implemented.');
}

return $xpath
->addStarPrefix()
->addCondition('position() = last()');
}

public function translateOnlyChild(XPathExpr $xpath): XPathExpr
{
return $xpath
->addStarPrefix()
->addNameTest()
->addCondition('last() = 1');
}

public function translateOnlyOfType(XPathExpr $xpath): XPathExpr
{
$element = $xpath->getElement();

return $xpath->addCondition(sprintf('count(preceding-sibling::%s)=0 and count(following-sibling::%s)=0', $element, $element));
}

public function translateEmpty(XPathExpr $xpath): XPathExpr
{
return $xpath->addCondition('not(*) and not(string-length())');
}




public function getName(): string
{
return 'pseudo-class';
}
}
<?php










namespace Symfony\Component\CssSelector\XPath;











class XPathExpr
{
private $path;
private $element;
private $condition;

public function __construct(string $path = '', string $element = '*', string $condition = '', bool $starPrefix = false)
{
$this->path = $path;
$this->element = $element;
$this->condition = $condition;

if ($starPrefix) {
$this->addStarPrefix();
}
}

public function getElement(): string
{
return $this->element;
}

public function addCondition(string $condition): self
{
$this->condition = $this->condition ? sprintf('(%s) and (%s)', $this->condition, $condition) : $condition;

return $this;
}

public function getCondition(): string
{
return $this->condition;
}

public function addNameTest(): self
{
if ('*' !== $this->element) {
$this->addCondition('name() = '.Translator::getXpathLiteral($this->element));
$this->element = '*';
}

return $this;
}

public function addStarPrefix(): self
{
$this->path .= '*/';

return $this;
}






public function join(string $combiner, self $expr): self
{
$path = $this->__toString().$combiner;

if ('*/' !== $expr->path) {
$path .= $expr->path;
}

$this->path = $path;
$this->element = $expr->element;
$this->condition = $expr->condition;

return $this;
}

public function __toString(): string
{
$path = $this->path.$this->element;
$condition = null === $this->condition || '' === $this->condition ? '' : '['.$this->condition.']';

return $path.$condition;
}
}
<?php










use Symfony\Polyfill\Ctype as p;

if (\PHP_VERSION_ID >= 80000) {
return require __DIR__.'/bootstrap80.php';
}

if (!function_exists('ctype_alnum')) {
function ctype_alnum($text) { return p\Ctype::ctype_alnum($text); }
}
if (!function_exists('ctype_alpha')) {
function ctype_alpha($text) { return p\Ctype::ctype_alpha($text); }
}
if (!function_exists('ctype_cntrl')) {
function ctype_cntrl($text) { return p\Ctype::ctype_cntrl($text); }
}
if (!function_exists('ctype_digit')) {
function ctype_digit($text) { return p\Ctype::ctype_digit($text); }
}
if (!function_exists('ctype_graph')) {
function ctype_graph($text) { return p\Ctype::ctype_graph($text); }
}
if (!function_exists('ctype_lower')) {
function ctype_lower($text) { return p\Ctype::ctype_lower($text); }
}
if (!function_exists('ctype_print')) {
function ctype_print($text) { return p\Ctype::ctype_print($text); }
}
if (!function_exists('ctype_punct')) {
function ctype_punct($text) { return p\Ctype::ctype_punct($text); }
}
if (!function_exists('ctype_space')) {
function ctype_space($text) { return p\Ctype::ctype_space($text); }
}
if (!function_exists('ctype_upper')) {
function ctype_upper($text) { return p\Ctype::ctype_upper($text); }
}
if (!function_exists('ctype_xdigit')) {
function ctype_xdigit($text) { return p\Ctype::ctype_xdigit($text); }
}
<?php










namespace Symfony\Polyfill\Ctype;








final class Ctype
{









public static function ctype_alnum($text)
{
$text = self::convert_int_to_char_for_ctype($text);

return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text);
}










public static function ctype_alpha($text)
{
$text = self::convert_int_to_char_for_ctype($text);

return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text);
}










public static function ctype_cntrl($text)
{
$text = self::convert_int_to_char_for_ctype($text);

return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text);
}










public static function ctype_digit($text)
{
$text = self::convert_int_to_char_for_ctype($text);

return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text);
}










public static function ctype_graph($text)
{
$text = self::convert_int_to_char_for_ctype($text);

return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text);
}










public static function ctype_lower($text)
{
$text = self::convert_int_to_char_for_ctype($text);

return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text);
}










public static function ctype_print($text)
{
$text = self::convert_int_to_char_for_ctype($text);

return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text);
}










public static function ctype_punct($text)
{
$text = self::convert_int_to_char_for_ctype($text);

return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text);
}










public static function ctype_space($text)
{
$text = self::convert_int_to_char_for_ctype($text);

return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text);
}










public static function ctype_upper($text)
{
$text = self::convert_int_to_char_for_ctype($text);

return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text);
}










public static function ctype_xdigit($text)
{
$text = self::convert_int_to_char_for_ctype($text);

return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text);
}













private static function convert_int_to_char_for_ctype($int)
{
if (!\is_int($int)) {
return $int;
}

if ($int < -128 || $int > 255) {
return (string) $int;
}

if ($int < 0) {
$int += 256;
}

return \chr($int);
}
}
<?php










use Symfony\Polyfill\Ctype as p;

if (!function_exists('ctype_alnum')) {
function ctype_alnum(mixed $text): bool { return p\Ctype::ctype_alnum($text); }
}
if (!function_exists('ctype_alpha')) {
function ctype_alpha(mixed $text): bool { return p\Ctype::ctype_alpha($text); }
}
if (!function_exists('ctype_cntrl')) {
function ctype_cntrl(mixed $text): bool { return p\Ctype::ctype_cntrl($text); }
}
if (!function_exists('ctype_digit')) {
function ctype_digit(mixed $text): bool { return p\Ctype::ctype_digit($text); }
}
if (!function_exists('ctype_graph')) {
function ctype_graph(mixed $text): bool { return p\Ctype::ctype_graph($text); }
}
if (!function_exists('ctype_lower')) {
function ctype_lower(mixed $text): bool { return p\Ctype::ctype_lower($text); }
}
if (!function_exists('ctype_print')) {
function ctype_print(mixed $text): bool { return p\Ctype::ctype_print($text); }
}
if (!function_exists('ctype_punct')) {
function ctype_punct(mixed $text): bool { return p\Ctype::ctype_punct($text); }
}
if (!function_exists('ctype_space')) {
function ctype_space(mixed $text): bool { return p\Ctype::ctype_space($text); }
}
if (!function_exists('ctype_upper')) {
function ctype_upper(mixed $text): bool { return p\Ctype::ctype_upper($text); }
}
if (!function_exists('ctype_xdigit')) {
function ctype_xdigit(mixed $text): bool { return p\Ctype::ctype_xdigit($text); }
}
<?php










use Symfony\Polyfill\Php73 as p;

if (\PHP_VERSION_ID >= 70300) {
return;
}

if (!function_exists('is_countable')) {
function is_countable($value) { return is_array($value) || $value instanceof Countable || $value instanceof ResourceBundle || $value instanceof SimpleXmlElement; }
}
if (!function_exists('hrtime')) {
require_once __DIR__.'/Php73.php';
p\Php73::$startAt = (int) microtime(true);
function hrtime($as_number = false) { return p\Php73::hrtime($as_number); }
}
if (!function_exists('array_key_first')) {
function array_key_first(array $array) { foreach ($array as $key => $value) { return $key; } }
}
if (!function_exists('array_key_last')) {
function array_key_last(array $array) { return key(array_slice($array, -1, 1, true)); }
}
<?php










namespace Symfony\Polyfill\Php73;







final class Php73
{
public static $startAt = 1533462603;






public static function hrtime($asNum = false)
{
$ns = microtime(false);
$s = substr($ns, 11) - self::$startAt;
$ns = 1E9 * (float) $ns;

if ($asNum) {
$ns += $s * 1E9;

return \PHP_INT_SIZE === 4 ? $ns : (int) $ns;
}

return [$s, (int) $ns];
}
}
<?php










class JsonException extends Exception
{
}
<?php










namespace Symfony\Component\BrowserKit;

use Symfony\Component\BrowserKit\Exception\BadMethodCallException;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\DomCrawler\Form;
use Symfony\Component\DomCrawler\Link;
use Symfony\Component\Process\PhpProcess;













abstract class Client
{
protected $history;
protected $cookieJar;
protected $server = [];
protected $internalRequest;
protected $request;
protected $internalResponse;
protected $response;
protected $crawler;
protected $insulated = false;
protected $redirect;
protected $followRedirects = true;
protected $followMetaRefresh = false;

private $maxRedirects = -1;
private $redirectCount = 0;
private $redirects = [];
private $isMainRequest = true;




public function __construct(array $server = [], History $history = null, CookieJar $cookieJar = null)
{
$this->setServerParameters($server);
$this->history = $history ?? new History();
$this->cookieJar = $cookieJar ?? new CookieJar();
}






public function followRedirects($followRedirect = true)
{
$this->followRedirects = (bool) $followRedirect;
}




public function followMetaRefresh(bool $followMetaRefresh = true)
{
$this->followMetaRefresh = $followMetaRefresh;
}






public function isFollowingRedirects()
{
return $this->followRedirects;
}






public function setMaxRedirects($maxRedirects)
{
$this->maxRedirects = $maxRedirects < 0 ? -1 : $maxRedirects;
$this->followRedirects = -1 != $this->maxRedirects;
}






public function getMaxRedirects()
{
return $this->maxRedirects;
}








public function insulate($insulated = true)
{
if ($insulated && !class_exists(\Symfony\Component\Process\Process::class)) {
throw new \LogicException('Unable to isolate requests as the Symfony Process Component is not installed.');
}

$this->insulated = (bool) $insulated;
}






public function setServerParameters(array $server)
{
$this->server = array_merge([
'HTTP_USER_AGENT' => 'Symfony BrowserKit',
], $server);
}







public function setServerParameter($key, $value)
{
$this->server[$key] = $value;
}









public function getServerParameter($key, $default = '')
{
return $this->server[$key] ?? $default;
}

public function xmlHttpRequest(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], string $content = null, bool $changeHistory = true): Crawler
{
$this->setServerParameter('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest');

try {
return $this->request($method, $uri, $parameters, $files, $server, $content, $changeHistory);
} finally {
unset($this->server['HTTP_X_REQUESTED_WITH']);
}
}






public function getHistory()
{
return $this->history;
}






public function getCookieJar()
{
return $this->cookieJar;
}






public function getCrawler()
{
if (null === $this->crawler) {
@trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', static::class.'::'.__FUNCTION__), \E_USER_DEPRECATED);

 }

return $this->crawler;
}






public function getInternalResponse()
{
if (null === $this->internalResponse) {
@trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', static::class.'::'.__FUNCTION__), \E_USER_DEPRECATED);

 }

return $this->internalResponse;
}











public function getResponse()
{
if (null === $this->response) {
@trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', static::class.'::'.__FUNCTION__), \E_USER_DEPRECATED);

 }

return $this->response;
}






public function getInternalRequest()
{
if (null === $this->internalRequest) {
@trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', static::class.'::'.__FUNCTION__), \E_USER_DEPRECATED);

 }

return $this->internalRequest;
}











public function getRequest()
{
if (null === $this->request) {
@trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', static::class.'::'.__FUNCTION__), \E_USER_DEPRECATED);

 }

return $this->request;
}






public function click(Link $link)
{
if ($link instanceof Form) {
return $this->submit($link);
}

return $this->request($link->getMethod(), $link->getUri());
}






public function clickLink(string $linkText): Crawler
{
if (null === $this->crawler) {
throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__));
}

return $this->click($this->crawler->selectLink($linkText)->link());
}









public function submit(Form $form, array $values = [])
{
if (\func_num_args() < 3 && __CLASS__ !== static::class && __CLASS__ !== (new \ReflectionMethod($this, __FUNCTION__))->getDeclaringClass()->getName() && !$this instanceof \PHPUnit\Framework\MockObject\MockObject && !$this instanceof \Prophecy\Prophecy\ProphecySubjectInterface && !$this instanceof \Mockery\MockInterface) {
@trigger_error(sprintf('The "%s()" method will have a new "array $serverParameters = []" argument in version 5.0, not defining it is deprecated since Symfony 4.2.', static::class.'::'.__FUNCTION__), \E_USER_DEPRECATED);
}

$form->setValues($values);
$serverParameters = 2 < \func_num_args() ? func_get_arg(2) : [];

return $this->request($form->getMethod(), $form->getUri(), $form->getPhpValues(), $form->getPhpFiles(), $serverParameters);
}










public function submitForm(string $button, array $fieldValues = [], string $method = 'POST', array $serverParameters = []): Crawler
{
if (null === $this->crawler) {
throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__));
}

$buttonNode = $this->crawler->selectButton($button);
$form = $buttonNode->form($fieldValues, $method);

return $this->submit($form, [], $serverParameters);
}














public function request(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], string $content = null, bool $changeHistory = true)
{
if ($this->isMainRequest) {
$this->redirectCount = 0;
} else {
++$this->redirectCount;
}

$originalUri = $uri;

$uri = $this->getAbsoluteUri($uri);

$server = array_merge($this->server, $server);

if (!empty($server['HTTP_HOST']) && null === parse_url($originalUri, \PHP_URL_HOST)) {
$uri = preg_replace('{^(https?\://)'.preg_quote($this->extractHost($uri)).'}', '${1}'.$server['HTTP_HOST'], $uri);
}

if (isset($server['HTTPS']) && null === parse_url($originalUri, \PHP_URL_SCHEME)) {
$uri = preg_replace('{^'.parse_url($uri, \PHP_URL_SCHEME).'}', $server['HTTPS'] ? 'https' : 'http', $uri);
}

if (!isset($server['HTTP_REFERER']) && !$this->history->isEmpty()) {
$server['HTTP_REFERER'] = $this->history->current()->getUri();
}

if (empty($server['HTTP_HOST'])) {
$server['HTTP_HOST'] = $this->extractHost($uri);
}

$server['HTTPS'] = 'https' == parse_url($uri, \PHP_URL_SCHEME);

$this->internalRequest = new Request($uri, $method, $parameters, $files, $this->cookieJar->allValues($uri), $server, $content);

$this->request = $this->filterRequest($this->internalRequest);

if (true === $changeHistory) {
$this->history->add($this->internalRequest);
}

if ($this->insulated) {
$this->response = $this->doRequestInProcess($this->request);
} else {
$this->response = $this->doRequest($this->request);
}

$this->internalResponse = $this->filterResponse($this->response);

$this->cookieJar->updateFromResponse($this->internalResponse, $uri);

$status = $this->internalResponse->getStatusCode();

if ($status >= 300 && $status < 400) {
$this->redirect = $this->internalResponse->getHeader('Location');
} else {
$this->redirect = null;
}

if ($this->followRedirects && $this->redirect) {
$this->redirects[serialize($this->history->current())] = true;

return $this->crawler = $this->followRedirect();
}

$this->crawler = $this->createCrawlerFromContent($this->internalRequest->getUri(), $this->internalResponse->getContent(), $this->internalResponse->getHeader('Content-Type'));


 if ($this->followMetaRefresh && null !== $redirect = $this->getMetaRefreshUrl()) {
$this->redirect = $redirect;
$this->redirects[serialize($this->history->current())] = true;
$this->crawler = $this->followRedirect();
}

return $this->crawler;
}










protected function doRequestInProcess($request)
{
$deprecationsFile = tempnam(sys_get_temp_dir(), 'deprec');
putenv('SYMFONY_DEPRECATIONS_SERIALIZE='.$deprecationsFile);
$_ENV['SYMFONY_DEPRECATIONS_SERIALIZE'] = $deprecationsFile;
$process = new PhpProcess($this->getScript($request), null, null);
$process->run();

if (file_exists($deprecationsFile)) {
$deprecations = file_get_contents($deprecationsFile);
unlink($deprecationsFile);
foreach ($deprecations ? unserialize($deprecations) : [] as $deprecation) {
if ($deprecation[0]) {

 trigger_error($deprecation[1], \E_USER_DEPRECATED);
} else {
@trigger_error($deprecation[1], \E_USER_DEPRECATED);
}
}
}

if (!$process->isSuccessful() || !preg_match('/^O\:\d+\:/', $process->getOutput())) {
throw new \RuntimeException(sprintf('OUTPUT: %s ERROR OUTPUT: %s.', $process->getOutput(), $process->getErrorOutput()));
}

return unserialize($process->getOutput());
}








abstract protected function doRequest($request);








protected function getScript($request)
{
throw new \LogicException('To insulate requests, you need to override the getScript() method.');
}






protected function filterRequest(Request $request)
{
return $request;
}








protected function filterResponse($response)
{
return $response;
}












protected function createCrawlerFromContent($uri, $content, $type)
{
if (!class_exists(Crawler::class)) {
return null;
}

$crawler = new Crawler(null, $uri);
$crawler->addContent($content, $type);

return $crawler;
}






public function back()
{
do {
$request = $this->history->back();
} while (\array_key_exists(serialize($request), $this->redirects));

return $this->requestFromRequest($request, false);
}






public function forward()
{
do {
$request = $this->history->forward();
} while (\array_key_exists(serialize($request), $this->redirects));

return $this->requestFromRequest($request, false);
}






public function reload()
{
return $this->requestFromRequest($this->history->current(), false);
}








public function followRedirect()
{
if (empty($this->redirect)) {
throw new \LogicException('The request was not redirected.');
}

if (-1 !== $this->maxRedirects) {
if ($this->redirectCount > $this->maxRedirects) {
$this->redirectCount = 0;
throw new \LogicException(sprintf('The maximum number (%d) of redirections was reached.', $this->maxRedirects));
}
}

$request = $this->internalRequest;

if (\in_array($this->internalResponse->getStatusCode(), [301, 302, 303])) {
$method = 'GET';
$files = [];
$content = null;
} else {
$method = $request->getMethod();
$files = $request->getFiles();
$content = $request->getContent();
}

if ('GET' === strtoupper($method)) {

 $parameters = [];
} else {
$parameters = $request->getParameters();
}

$server = $request->getServer();
$server = $this->updateServerFromUri($server, $this->redirect);

$this->isMainRequest = false;

$response = $this->request($method, $this->redirect, $parameters, $files, $server, $content);

$this->isMainRequest = true;

return $response;
}




private function getMetaRefreshUrl(): ?string
{
$metaRefresh = $this->getCrawler()->filter('head meta[http-equiv="refresh"]');
foreach ($metaRefresh->extract(['content']) as $content) {
if (preg_match('/^\s*0\s*;\s*URL\s*=\s*(?|\'([^\']++)|"([^"]++)|([^\'"].*))/i', $content, $m)) {
return str_replace("\t\r\n", '', rtrim($m[1]));
}
}

return null;
}






public function restart()
{
$this->cookieJar->clear();
$this->history->clear();
}








protected function getAbsoluteUri($uri)
{

 if (str_starts_with($uri, 'http://') || str_starts_with($uri, 'https://')) {
return $uri;
}

if (!$this->history->isEmpty()) {
$currentUri = $this->history->current()->getUri();
} else {
$currentUri = sprintf('http%s://%s/',
isset($this->server['HTTPS']) ? 's' : '',
$this->server['HTTP_HOST'] ?? 'localhost'
);
}


 if (str_starts_with($uri, '//')) {
return parse_url($currentUri, \PHP_URL_SCHEME).':'.$uri;
}


 if (!$uri || '#' == $uri[0] || '?' == $uri[0]) {
return preg_replace('/[#?].*?$/', '', $currentUri).$uri;
}

if ('/' !== $uri[0]) {
$path = parse_url($currentUri, \PHP_URL_PATH);

if (!str_ends_with($path, '/')) {
$path = substr($path, 0, strrpos($path, '/') + 1);
}

$uri = $path.$uri;
}

return preg_replace('#^(.*?//[^/]+)\/.*$#', '$1', $currentUri).$uri;
}








protected function requestFromRequest(Request $request, $changeHistory = true)
{
return $this->request($request->getMethod(), $request->getUri(), $request->getParameters(), $request->getFiles(), $request->getServer(), $request->getContent(), $changeHistory);
}

private function updateServerFromUri(array $server, string $uri): array
{
$server['HTTP_HOST'] = $this->extractHost($uri);
$scheme = parse_url($uri, \PHP_URL_SCHEME);
$server['HTTPS'] = null === $scheme ? $server['HTTPS'] : 'https' == $scheme;
unset($server['HTTP_IF_NONE_MATCH'], $server['HTTP_IF_MODIFIED_SINCE']);

return $server;
}

private function extractHost(string $uri): ?string
{
$host = parse_url($uri, \PHP_URL_HOST);

if ($port = parse_url($uri, \PHP_URL_PORT)) {
return $host.':'.$port;
}

return $host;
}
}
<?php










namespace Symfony\Component\BrowserKit\Test\Constraint;

use PHPUnit\Framework\Constraint\Constraint;
use Symfony\Component\BrowserKit\AbstractBrowser;

final class BrowserCookieValueSame extends Constraint
{
private $name;
private $value;
private $raw;
private $path;
private $domain;

public function __construct(string $name, string $value, bool $raw = false, string $path = '/', string $domain = null)
{
$this->name = $name;
$this->path = $path;
$this->domain = $domain;
$this->value = $value;
$this->raw = $raw;
}




public function toString(): string
{
$str = sprintf('has cookie "%s"', $this->name);
if ('/' !== $this->path) {
$str .= sprintf(' with path "%s"', $this->path);
}
if ($this->domain) {
$str .= sprintf(' for domain "%s"', $this->domain);
}
$str .= sprintf(' with %svalue "%s"', $this->raw ? 'raw ' : '', $this->value);

return $str;
}






protected function matches($browser): bool
{
$cookie = $browser->getCookieJar()->get($this->name, $this->path, $this->domain);
if (!$cookie) {
return false;
}

return $this->value === ($this->raw ? $cookie->getRawValue() : $cookie->getValue());
}






protected function failureDescription($browser): string
{
return 'the Browser '.$this->toString();
}
}
<?php










namespace Symfony\Component\BrowserKit\Test\Constraint;

use PHPUnit\Framework\Constraint\Constraint;
use Symfony\Component\BrowserKit\AbstractBrowser;

final class BrowserHasCookie extends Constraint
{
private $name;
private $path;
private $domain;

public function __construct(string $name, string $path = '/', string $domain = null)
{
$this->name = $name;
$this->path = $path;
$this->domain = $domain;
}




public function toString(): string
{
$str = sprintf('has cookie "%s"', $this->name);
if ('/' !== $this->path) {
$str .= sprintf(' with path "%s"', $this->path);
}
if ($this->domain) {
$str .= sprintf(' for domain "%s"', $this->domain);
}

return $str;
}






protected function matches($browser): bool
{
return null !== $browser->getCookieJar()->get($this->name, $this->path, $this->domain);
}






protected function failureDescription($browser): string
{
return 'the Browser '.$this->toString();
}
}
<?php










namespace Symfony\Component\BrowserKit;






class CookieJar
{
protected $cookieJar = [];

public function set(Cookie $cookie)
{
$this->cookieJar[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie;
}















public function get($name, $path = '/', $domain = null)
{
$this->flushExpiredCookies();

foreach ($this->cookieJar as $cookieDomain => $pathCookies) {
if ($cookieDomain && $domain) {
$cookieDomain = '.'.ltrim($cookieDomain, '.');
if (!str_ends_with('.'.$domain, $cookieDomain)) {
continue;
}
}

foreach ($pathCookies as $cookiePath => $namedCookies) {
if (!str_starts_with($path, $cookiePath)) {
continue;
}
if (isset($namedCookies[$name])) {
return $namedCookies[$name];
}
}
}

return null;
}












public function expire($name, $path = '/', $domain = null)
{
if (null === $path) {
$path = '/';
}

if (empty($domain)) {

 
 $domains = array_keys($this->cookieJar);
} else {
$domains = [$domain];
}

foreach ($domains as $domain) {
unset($this->cookieJar[$domain][$path][$name]);

if (empty($this->cookieJar[$domain][$path])) {
unset($this->cookieJar[$domain][$path]);

if (empty($this->cookieJar[$domain])) {
unset($this->cookieJar[$domain]);
}
}
}
}




public function clear()
{
$this->cookieJar = [];
}







public function updateFromSetCookie(array $setCookies, $uri = null)
{
$cookies = [];

foreach ($setCookies as $cookie) {
foreach (explode(',', $cookie) as $i => $part) {
if (0 === $i || preg_match('/^(?P<token>\s*[0-9A-Za-z!#\$%\&\'\*\+\-\.^_`\|~]+)=/', $part)) {
$cookies[] = ltrim($part);
} else {
$cookies[\count($cookies) - 1] .= ','.$part;
}
}
}

foreach ($cookies as $cookie) {
try {
$this->set(Cookie::fromString($cookie, $uri));
} catch (\InvalidArgumentException $e) {

 }
}
}






public function updateFromResponse(Response $response, $uri = null)
{
$this->updateFromSetCookie($response->getHeader('Set-Cookie', false), $uri);
}






public function all()
{
$this->flushExpiredCookies();

$flattenedCookies = [];
foreach ($this->cookieJar as $path) {
foreach ($path as $cookies) {
foreach ($cookies as $cookie) {
$flattenedCookies[] = $cookie;
}
}
}

return $flattenedCookies;
}









public function allValues($uri, $returnsRawValue = false)
{
$this->flushExpiredCookies();

$parts = array_replace(['path' => '/'], parse_url($uri));
$cookies = [];
foreach ($this->cookieJar as $domain => $pathCookies) {
if ($domain) {
$domain = '.'.ltrim($domain, '.');
if ($domain != substr('.'.$parts['host'], -\strlen($domain))) {
continue;
}
}

foreach ($pathCookies as $path => $namedCookies) {
if ($path != substr($parts['path'], 0, \strlen($path))) {
continue;
}

foreach ($namedCookies as $cookie) {
if ($cookie->isSecure() && 'https' != $parts['scheme']) {
continue;
}

$cookies[$cookie->getName()] = $returnsRawValue ? $cookie->getRawValue() : $cookie->getValue();
}
}
}

return $cookies;
}








public function allRawValues($uri)
{
return $this->allValues($uri, true);
}




public function flushExpiredCookies()
{
foreach ($this->cookieJar as $domain => $pathCookies) {
foreach ($pathCookies as $path => $namedCookies) {
foreach ($namedCookies as $name => $cookie) {
if ($cookie->isExpired()) {
unset($this->cookieJar[$domain][$path][$name]);
}
}
}
}
}
}
<?php










namespace Symfony\Component\BrowserKit;






class Cookie
{




private const DATE_FORMATS = [
'D, d M Y H:i:s T',
'D, d-M-y H:i:s T',
'D, d-M-Y H:i:s T',
'D, d-m-y H:i:s T',
'D, d-m-Y H:i:s T',
'D M j G:i:s Y',
'D M d H:i:s Y T',
];

protected $name;
protected $value;
protected $expires;
protected $path;
protected $domain;
protected $secure;
protected $httponly;
protected $rawValue;
private $samesite;














public function __construct(string $name, ?string $value, string $expires = null, string $path = null, string $domain = '', bool $secure = false, bool $httponly = true, bool $encodedValue = false, string $samesite = null)
{
if ($encodedValue) {
$this->value = urldecode($value);
$this->rawValue = $value;
} else {
$this->value = $value;
$this->rawValue = rawurlencode($value ?? '');
}
$this->name = $name;
$this->path = empty($path) ? '/' : $path;
$this->domain = $domain;
$this->secure = $secure;
$this->httponly = $httponly;
$this->samesite = $samesite;

if (null !== $expires) {
$timestampAsDateTime = \DateTime::createFromFormat('U', $expires);
if (false === $timestampAsDateTime) {
throw new \UnexpectedValueException(sprintf('The cookie expiration time "%s" is not valid.', $expires));
}

$this->expires = $timestampAsDateTime->format('U');
}
}






public function __toString()
{
$cookie = sprintf('%s=%s', $this->name, $this->rawValue);

if (null !== $this->expires) {
$dateTime = \DateTime::createFromFormat('U', $this->expires, new \DateTimeZone('GMT'));
$cookie .= '; expires='.str_replace('+0000', '', $dateTime->format(self::DATE_FORMATS[0]));
}

if ('' !== $this->domain) {
$cookie .= '; domain='.$this->domain;
}

if ($this->path) {
$cookie .= '; path='.$this->path;
}

if ($this->secure) {
$cookie .= '; secure';
}

if ($this->httponly) {
$cookie .= '; httponly';
}

if (null !== $this->samesite) {
$cookie .= '; samesite='.$this->samesite;
}

return $cookie;
}











public static function fromString($cookie, $url = null)
{
$parts = explode(';', $cookie);

if (!str_contains($parts[0], '=')) {
throw new \InvalidArgumentException(sprintf('The cookie string "%s" is not valid.', $parts[0]));
}

[$name, $value] = explode('=', array_shift($parts), 2);

$values = [
'name' => trim($name),
'value' => trim($value),
'expires' => null,
'path' => '/',
'domain' => '',
'secure' => false,
'httponly' => false,
'passedRawValue' => true,
'samesite' => null,
];

if (null !== $url) {
if ((false === $urlParts = parse_url($url)) || !isset($urlParts['host'])) {
throw new \InvalidArgumentException(sprintf('The URL "%s" is not valid.', $url));
}

$values['domain'] = $urlParts['host'];
$values['path'] = isset($urlParts['path']) ? substr($urlParts['path'], 0, strrpos($urlParts['path'], '/')) : '';
}

foreach ($parts as $part) {
$part = trim($part);

if ('secure' === strtolower($part)) {

 if (!$url || !isset($urlParts['scheme']) || 'https' != $urlParts['scheme']) {
continue;
}

$values['secure'] = true;

continue;
}

if ('httponly' === strtolower($part)) {
$values['httponly'] = true;

continue;
}

if (2 === \count($elements = explode('=', $part, 2))) {
if ('expires' === strtolower($elements[0])) {
$elements[1] = self::parseDate($elements[1]);
}

$values[strtolower($elements[0])] = $elements[1];
}
}

return new static(
$values['name'],
$values['value'],
$values['expires'],
$values['path'],
$values['domain'],
$values['secure'],
$values['httponly'],
$values['passedRawValue'],
$values['samesite']
);
}

private static function parseDate(string $dateValue): ?string
{

 if (($length = \strlen($dateValue)) > 1 && "'" === $dateValue[0] && "'" === $dateValue[$length - 1]) {
$dateValue = substr($dateValue, 1, -1);
}

foreach (self::DATE_FORMATS as $dateFormat) {
if (false !== $date = \DateTime::createFromFormat($dateFormat, $dateValue, new \DateTimeZone('GMT'))) {
return $date->format('U');
}
}


 if (false !== $date = date_create($dateValue, new \DateTimeZone('GMT'))) {
return $date->format('U');
}

return null;
}






public function getName()
{
return $this->name;
}






public function getValue()
{
return $this->value;
}






public function getRawValue()
{
return $this->rawValue;
}






public function getExpiresTime()
{
return $this->expires;
}






public function getPath()
{
return $this->path;
}






public function getDomain()
{
return $this->domain;
}






public function isSecure()
{
return $this->secure;
}






public function isHttpOnly()
{
return $this->httponly;
}






public function isExpired()
{
return null !== $this->expires && 0 != $this->expires && $this->expires <= time();
}






public function getSameSite(): ?string
{
return $this->samesite;
}
}
<?php










namespace Symfony\Component\BrowserKit;




class Request
{
protected $uri;
protected $method;
protected $parameters;
protected $files;
protected $cookies;
protected $server;
protected $content;










public function __construct(string $uri, string $method, array $parameters = [], array $files = [], array $cookies = [], array $server = [], string $content = null)
{
$this->uri = $uri;
$this->method = $method;
$this->parameters = $parameters;
$this->files = $files;
$this->cookies = $cookies;
$this->server = $server;
$this->content = $content;
}






public function getUri()
{
return $this->uri;
}






public function getMethod()
{
return $this->method;
}






public function getParameters()
{
return $this->parameters;
}






public function getFiles()
{
return $this->files;
}






public function getCookies()
{
return $this->cookies;
}






public function getServer()
{
return $this->server;
}






public function getContent()
{
return $this->content;
}
}
<?php










namespace Symfony\Component\BrowserKit;














abstract class AbstractBrowser extends Client
{
}
<?php










namespace Symfony\Component\BrowserKit;

use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\Mime\Part\AbstractPart;
use Symfony\Component\Mime\Part\DataPart;
use Symfony\Component\Mime\Part\Multipart\FormDataPart;
use Symfony\Component\Mime\Part\TextPart;
use Symfony\Contracts\HttpClient\HttpClientInterface;







class HttpBrowser extends AbstractBrowser
{
private $client;

public function __construct(HttpClientInterface $client = null, History $history = null, CookieJar $cookieJar = null)
{
if (!$client && !class_exists(HttpClient::class)) {
throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__));
}

$this->client = $client ?? HttpClient::create();

parent::__construct([], $history, $cookieJar);
}




protected function doRequest($request): Response
{
$headers = $this->getHeaders($request);
[$body, $extraHeaders] = $this->getBodyAndExtraHeaders($request, $headers);

$response = $this->client->request($request->getMethod(), $request->getUri(), [
'headers' => array_merge($headers, $extraHeaders),
'body' => $body,
'max_redirects' => 0,
]);

return new Response($response->getContent(false), $response->getStatusCode(), $response->getHeaders(false));
}




private function getBodyAndExtraHeaders(Request $request, array $headers): array
{
if (\in_array($request->getMethod(), ['GET', 'HEAD'])) {
return ['', []];
}

if (!class_exists(AbstractPart::class)) {
throw new \LogicException('You cannot pass non-empty bodies as the Mime component is not installed. Try running "composer require symfony/mime".');
}

if (null !== $content = $request->getContent()) {
if (isset($headers['content-type'])) {
return [$content, []];
}

$part = new TextPart($content, 'utf-8', 'plain', '8bit');

return [$part->bodyToString(), $part->getPreparedHeaders()->toArray()];
}

$fields = $request->getParameters();

if ($uploadedFiles = $this->getUploadedFiles($request->getFiles())) {
$part = new FormDataPart(array_merge($fields, $uploadedFiles));

return [$part->bodyToIterable(), $part->getPreparedHeaders()->toArray()];
}

if (empty($fields)) {
return ['', []];
}

return [http_build_query($fields, '', '&', \PHP_QUERY_RFC1738), ['Content-Type' => 'application/x-www-form-urlencoded']];
}

private function getHeaders(Request $request): array
{
$headers = [];
foreach ($request->getServer() as $key => $value) {
$key = strtolower(str_replace('_', '-', $key));
$contentHeaders = ['content-length' => true, 'content-md5' => true, 'content-type' => true];
if (str_starts_with($key, 'http-')) {
$headers[substr($key, 5)] = $value;
} elseif (isset($contentHeaders[$key])) {

 $headers[$key] = $value;
}
}
$cookies = [];
foreach ($this->getCookieJar()->allRawValues($request->getUri()) as $name => $value) {
$cookies[] = $name.'='.$value;
}
if ($cookies) {
$headers['cookie'] = implode('; ', $cookies);
}

return $headers;
}





private function getUploadedFiles(array $files): array
{
$uploadedFiles = [];
foreach ($files as $name => $file) {
if (!\is_array($file)) {
return $uploadedFiles;
}
if (!isset($file['tmp_name'])) {
$uploadedFiles[$name] = $this->getUploadedFiles($file);
}
if (isset($file['tmp_name'])) {
$uploadedFiles[$name] = DataPart::fromPath($file['tmp_name'], $file['name']);
}
}

return $uploadedFiles;
}
}
<?php










namespace Symfony\Component\BrowserKit;






class History
{
protected $stack = [];
protected $position = -1;




public function clear()
{
$this->stack = [];
$this->position = -1;
}




public function add(Request $request)
{
$this->stack = \array_slice($this->stack, 0, $this->position + 1);
$this->stack[] = clone $request;
$this->position = \count($this->stack) - 1;
}






public function isEmpty()
{
return 0 == \count($this->stack);
}








public function back()
{
if ($this->position < 1) {
throw new \LogicException('You are already on the first page.');
}

return clone $this->stack[--$this->position];
}








public function forward()
{
if ($this->position > \count($this->stack) - 2) {
throw new \LogicException('You are already on the last page.');
}

return clone $this->stack[++$this->position];
}








public function current()
{
if (-1 == $this->position) {
throw new \LogicException('The page history is empty.');
}

return clone $this->stack[$this->position];
}
}
<?php










namespace Symfony\Component\BrowserKit\Exception;

class BadMethodCallException extends \BadMethodCallException
{
}
<?php










namespace Symfony\Component\BrowserKit;






class Response
{

protected $content;

protected $status;

protected $headers;









public function __construct(string $content = '', int $status = 200, array $headers = [])
{
$this->content = $content;
$this->status = $status;
$this->headers = $headers;
}






public function __toString()
{
$headers = '';
foreach ($this->headers as $name => $value) {
if (\is_string($value)) {
$headers .= sprintf("%s: %s\n", $name, $value);
} else {
foreach ($value as $headerValue) {
$headers .= sprintf("%s: %s\n", $name, $headerValue);
}
}
}

return $headers."\n".$this->content;
}











protected function buildHeader($name, $value)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.3.', __METHOD__), \E_USER_DEPRECATED);

return sprintf("%s: %s\n", $name, $value);
}






public function getContent()
{
return $this->content;
}








public function getStatus()
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.3, use getStatusCode() instead.', __METHOD__), \E_USER_DEPRECATED);

return $this->status;
}

public function getStatusCode(): int
{
return $this->status;
}






public function getHeaders()
{
return $this->headers;
}









public function getHeader($header, $first = true)
{
$normalizedHeader = str_replace('-', '_', strtolower($header));
foreach ($this->headers as $key => $value) {
if (str_replace('-', '_', strtolower($key)) === $normalizedHeader) {
if ($first) {
return \is_array($value) ? (\count($value) ? $value[0] : '') : $value;
}

return \is_array($value) ? $value : [$value];
}
}

return $first ? null : [];
}
}
<?php










use Symfony\Polyfill\Php80 as p;

if (\PHP_VERSION_ID >= 80000) {
return;
}

if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) {
define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN);
}

if (!function_exists('fdiv')) {
function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); }
}
if (!function_exists('preg_last_error_msg')) {
function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); }
}
if (!function_exists('str_contains')) {
function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); }
}
if (!function_exists('str_starts_with')) {
function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); }
}
if (!function_exists('str_ends_with')) {
function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); }
}
if (!function_exists('get_debug_type')) {
function get_debug_type($value): string { return p\Php80::get_debug_type($value); }
}
if (!function_exists('get_resource_id')) {
function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); }
}
<?php










namespace Symfony\Polyfill\Php80;








final class Php80
{
public static function fdiv(float $dividend, float $divisor): float
{
return @($dividend / $divisor);
}

public static function get_debug_type($value): string
{
switch (true) {
case null === $value: return 'null';
case \is_bool($value): return 'bool';
case \is_string($value): return 'string';
case \is_array($value): return 'array';
case \is_int($value): return 'int';
case \is_float($value): return 'float';
case \is_object($value): break;
case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class';
default:
if (null === $type = @get_resource_type($value)) {
return 'unknown';
}

if ('Unknown' === $type) {
$type = 'closed';
}

return "resource ($type)";
}

$class = \get_class($value);

if (false === strpos($class, '@')) {
return $class;
}

return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous';
}

public static function get_resource_id($res): int
{
if (!\is_resource($res) && null === @get_resource_type($res)) {
throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res)));
}

return (int) $res;
}

public static function preg_last_error_msg(): string
{
switch (preg_last_error()) {
case \PREG_INTERNAL_ERROR:
return 'Internal error';
case \PREG_BAD_UTF8_ERROR:
return 'Malformed UTF-8 characters, possibly incorrectly encoded';
case \PREG_BAD_UTF8_OFFSET_ERROR:
return 'The offset did not correspond to the beginning of a valid UTF-8 code point';
case \PREG_BACKTRACK_LIMIT_ERROR:
return 'Backtrack limit exhausted';
case \PREG_RECURSION_LIMIT_ERROR:
return 'Recursion limit exhausted';
case \PREG_JIT_STACKLIMIT_ERROR:
return 'JIT stack limit exhausted';
case \PREG_NO_ERROR:
return 'No error';
default:
return 'Unknown error';
}
}

public static function str_contains(string $haystack, string $needle): bool
{
return '' === $needle || false !== strpos($haystack, $needle);
}

public static function str_starts_with(string $haystack, string $needle): bool
{
return 0 === strncmp($haystack, $needle, \strlen($needle));
}

public static function str_ends_with(string $haystack, string $needle): bool
{
return '' === $needle || ('' !== $haystack && 0 === substr_compare($haystack, $needle, -\strlen($needle)));
}
}
<?php


final class Attribute
{
public const TARGET_CLASS = 1;
public const TARGET_FUNCTION = 2;
public const TARGET_METHOD = 4;
public const TARGET_PROPERTY = 8;
public const TARGET_CLASS_CONSTANT = 16;
public const TARGET_PARAMETER = 32;
public const TARGET_ALL = 63;
public const IS_REPEATABLE = 64;


public $flags;

public function __construct(int $flags = self::TARGET_ALL)
{
$this->flags = $flags;
}
}
<?php

class ValueError extends Error
{
}
<?php

class UnhandledMatchError extends Error
{
}
<?php

if (\PHP_VERSION_ID < 80000) {
interface Stringable
{



public function __toString();
}
}
<?php










use Symfony\Polyfill\Mbstring as p;

if (\PHP_VERSION_ID >= 80000) {
return require __DIR__.'/bootstrap80.php';
}

if (!function_exists('mb_convert_encoding')) {
function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); }
}
if (!function_exists('mb_decode_mimeheader')) {
function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); }
}
if (!function_exists('mb_encode_mimeheader')) {
function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) { return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); }
}
if (!function_exists('mb_decode_numericentity')) {
function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); }
}
if (!function_exists('mb_encode_numericentity')) {
function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); }
}
if (!function_exists('mb_convert_case')) {
function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); }
}
if (!function_exists('mb_internal_encoding')) {
function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); }
}
if (!function_exists('mb_language')) {
function mb_language($language = null) { return p\Mbstring::mb_language($language); }
}
if (!function_exists('mb_list_encodings')) {
function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); }
}
if (!function_exists('mb_encoding_aliases')) {
function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); }
}
if (!function_exists('mb_check_encoding')) {
function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); }
}
if (!function_exists('mb_detect_encoding')) {
function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); }
}
if (!function_exists('mb_detect_order')) {
function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); }
}
if (!function_exists('mb_parse_str')) {
function mb_parse_str($string, &$result = []) { parse_str($string, $result); return (bool) $result; }
}
if (!function_exists('mb_strlen')) {
function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); }
}
if (!function_exists('mb_strpos')) {
function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_strtolower')) {
function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); }
}
if (!function_exists('mb_strtoupper')) {
function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); }
}
if (!function_exists('mb_substitute_character')) {
function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); }
}
if (!function_exists('mb_substr')) {
function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); }
}
if (!function_exists('mb_stripos')) {
function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_stristr')) {
function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_strrchr')) {
function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_strrichr')) {
function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_strripos')) {
function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_strrpos')) {
function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_strstr')) {
function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_get_info')) {
function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); }
}
if (!function_exists('mb_http_output')) {
function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); }
}
if (!function_exists('mb_strwidth')) {
function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); }
}
if (!function_exists('mb_substr_count')) {
function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); }
}
if (!function_exists('mb_output_handler')) {
function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); }
}
if (!function_exists('mb_http_input')) {
function mb_http_input($type = null) { return p\Mbstring::mb_http_input($type); }
}

if (!function_exists('mb_convert_variables')) {
function mb_convert_variables($to_encoding, $from_encoding, &...$vars) { return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); }
}

if (!function_exists('mb_ord')) {
function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); }
}
if (!function_exists('mb_chr')) {
function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); }
}
if (!function_exists('mb_scrub')) {
function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); }
}
if (!function_exists('mb_str_split')) {
function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); }
}

if (extension_loaded('mbstring')) {
return;
}

if (!defined('MB_CASE_UPPER')) {
define('MB_CASE_UPPER', 0);
}
if (!defined('MB_CASE_LOWER')) {
define('MB_CASE_LOWER', 1);
}
if (!defined('MB_CASE_TITLE')) {
define('MB_CASE_TITLE', 2);
}
<?php










namespace Symfony\Polyfill\Mbstring;























































final class Mbstring
{
public const MB_CASE_FOLD = \PHP_INT_MAX;

private const CASE_FOLD = [
['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"],
['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'],
];

private static $encodingList = ['ASCII', 'UTF-8'];
private static $language = 'neutral';
private static $internalEncoding = 'UTF-8';

public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
{
if (\is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) {
$fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
} else {
$fromEncoding = self::getEncoding($fromEncoding);
}

$toEncoding = self::getEncoding($toEncoding);

if ('BASE64' === $fromEncoding) {
$s = base64_decode($s);
$fromEncoding = $toEncoding;
}

if ('BASE64' === $toEncoding) {
return base64_encode($s);
}

if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
$fromEncoding = 'Windows-1252';
}
if ('UTF-8' !== $fromEncoding) {
$s = \iconv($fromEncoding, 'UTF-8//IGNORE', $s);
}

return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s);
}

if ('HTML-ENTITIES' === $fromEncoding) {
$s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8');
$fromEncoding = 'UTF-8';
}

return \iconv($fromEncoding, $toEncoding.'//IGNORE', $s);
}

public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars)
{
$ok = true;
array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
$ok = false;
}
});

return $ok ? $fromEncoding : false;
}

public static function mb_decode_mimeheader($s)
{
return \iconv_mime_decode($s, 2, self::$internalEncoding);
}

public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
{
trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING);
}

public static function mb_decode_numericentity($s, $convmap, $encoding = null)
{
if (null !== $s && !is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);

return null;
}

if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
return false;
}

if (null !== $encoding && !is_scalar($encoding)) {
trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);

return ''; 
 }

$s = (string) $s;
if ('' === $s) {
return '';
}

$encoding = self::getEncoding($encoding);

if ('UTF-8' === $encoding) {
$encoding = null;
if (!preg_match('//u', $s)) {
$s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s);
}
} else {
$s = \iconv($encoding, 'UTF-8//IGNORE', $s);
}

$cnt = floor(\count($convmap) / 4) * 4;

for ($i = 0; $i < $cnt; $i += 4) {

 $convmap[$i] += $convmap[$i + 2];
$convmap[$i + 1] += $convmap[$i + 2];
}

$s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {
$c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
for ($i = 0; $i < $cnt; $i += 4) {
if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
return self::mb_chr($c - $convmap[$i + 2]);
}
}

return $m[0];
}, $s);

if (null === $encoding) {
return $s;
}

return \iconv('UTF-8', $encoding.'//IGNORE', $s);
}

public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
{
if (null !== $s && !is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);

return null;
}

if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
return false;
}

if (null !== $encoding && !is_scalar($encoding)) {
trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);

return null; 
 }

if (null !== $is_hex && !is_scalar($is_hex)) {
trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING);

return null;
}

$s = (string) $s;
if ('' === $s) {
return '';
}

$encoding = self::getEncoding($encoding);

if ('UTF-8' === $encoding) {
$encoding = null;
if (!preg_match('//u', $s)) {
$s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s);
}
} else {
$s = \iconv($encoding, 'UTF-8//IGNORE', $s);
}

static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];

$cnt = floor(\count($convmap) / 4) * 4;
$i = 0;
$len = \strlen($s);
$result = '';

while ($i < $len) {
$ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
$uchr = substr($s, $i, $ulen);
$i += $ulen;
$c = self::mb_ord($uchr);

for ($j = 0; $j < $cnt; $j += 4) {
if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
$cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
$result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
continue 2;
}
}
$result .= $uchr;
}

if (null === $encoding) {
return $result;
}

return \iconv('UTF-8', $encoding.'//IGNORE', $result);
}

public static function mb_convert_case($s, $mode, $encoding = null)
{
$s = (string) $s;
if ('' === $s) {
return '';
}

$encoding = self::getEncoding($encoding);

if ('UTF-8' === $encoding) {
$encoding = null;
if (!preg_match('//u', $s)) {
$s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s);
}
} else {
$s = \iconv($encoding, 'UTF-8//IGNORE', $s);
}

if (\MB_CASE_TITLE == $mode) {
static $titleRegexp = null;
if (null === $titleRegexp) {
$titleRegexp = self::getData('titleCaseRegexp');
}
$s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s);
} else {
if (\MB_CASE_UPPER == $mode) {
static $upper = null;
if (null === $upper) {
$upper = self::getData('upperCase');
}
$map = $upper;
} else {
if (self::MB_CASE_FOLD === $mode) {
$s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s);
}

static $lower = null;
if (null === $lower) {
$lower = self::getData('lowerCase');
}
$map = $lower;
}

static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];

$i = 0;
$len = \strlen($s);

while ($i < $len) {
$ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
$uchr = substr($s, $i, $ulen);
$i += $ulen;

if (isset($map[$uchr])) {
$uchr = $map[$uchr];
$nlen = \strlen($uchr);

if ($nlen == $ulen) {
$nlen = $i;
do {
$s[--$nlen] = $uchr[--$ulen];
} while ($ulen);
} else {
$s = substr_replace($s, $uchr, $i - $ulen, $ulen);
$len += $nlen - $ulen;
$i += $nlen - $ulen;
}
}
}
}

if (null === $encoding) {
return $s;
}

return \iconv('UTF-8', $encoding.'//IGNORE', $s);
}

public static function mb_internal_encoding($encoding = null)
{
if (null === $encoding) {
return self::$internalEncoding;
}

$normalizedEncoding = self::getEncoding($encoding);

if ('UTF-8' === $normalizedEncoding || false !== @\iconv($normalizedEncoding, $normalizedEncoding, ' ')) {
self::$internalEncoding = $normalizedEncoding;

return true;
}

if (80000 > \PHP_VERSION_ID) {
return false;
}

throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding));
}

public static function mb_language($lang = null)
{
if (null === $lang) {
return self::$language;
}

switch ($normalizedLang = strtolower($lang)) {
case 'uni':
case 'neutral':
self::$language = $normalizedLang;

return true;
}

if (80000 > \PHP_VERSION_ID) {
return false;
}

throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang));
}

public static function mb_list_encodings()
{
return ['UTF-8'];
}

public static function mb_encoding_aliases($encoding)
{
switch (strtoupper($encoding)) {
case 'UTF8':
case 'UTF-8':
return ['utf8'];
}

return false;
}

public static function mb_check_encoding($var = null, $encoding = null)
{
if (null === $encoding) {
if (null === $var) {
return false;
}
$encoding = self::$internalEncoding;
}

return self::mb_detect_encoding($var, [$encoding]) || false !== @\iconv($encoding, $encoding, $var);
}

public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
{
if (null === $encodingList) {
$encodingList = self::$encodingList;
} else {
if (!\is_array($encodingList)) {
$encodingList = array_map('trim', explode(',', $encodingList));
}
$encodingList = array_map('strtoupper', $encodingList);
}

foreach ($encodingList as $enc) {
switch ($enc) {
case 'ASCII':
if (!preg_match('/[\x80-\xFF]/', $str)) {
return $enc;
}
break;

case 'UTF8':
case 'UTF-8':
if (preg_match('//u', $str)) {
return 'UTF-8';
}
break;

default:
if (0 === strncmp($enc, 'ISO-8859-', 9)) {
return $enc;
}
}
}

return false;
}

public static function mb_detect_order($encodingList = null)
{
if (null === $encodingList) {
return self::$encodingList;
}

if (!\is_array($encodingList)) {
$encodingList = array_map('trim', explode(',', $encodingList));
}
$encodingList = array_map('strtoupper', $encodingList);

foreach ($encodingList as $enc) {
switch ($enc) {
default:
if (strncmp($enc, 'ISO-8859-', 9)) {
return false;
}

 case 'ASCII':
case 'UTF8':
case 'UTF-8':
}
}

self::$encodingList = $encodingList;

return true;
}

public static function mb_strlen($s, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
return \strlen($s);
}

return @\iconv_strlen($s, $encoding);
}

public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
return strpos($haystack, $needle, $offset);
}

$needle = (string) $needle;
if ('' === $needle) {
if (80000 > \PHP_VERSION_ID) {
trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING);

return false;
}

return 0;
}

return \iconv_strpos($haystack, $needle, $offset, $encoding);
}

public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
return strrpos($haystack, $needle, $offset);
}

if ($offset != (int) $offset) {
$offset = 0;
} elseif ($offset = (int) $offset) {
if ($offset < 0) {
if (0 > $offset += self::mb_strlen($needle)) {
$haystack = self::mb_substr($haystack, 0, $offset, $encoding);
}
$offset = 0;
} else {
$haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
}
}

$pos = '' !== $needle || 80000 > \PHP_VERSION_ID
? \iconv_strrpos($haystack, $needle, $encoding)
: self::mb_strlen($haystack, $encoding);

return false !== $pos ? $offset + $pos : false;
}

public static function mb_str_split($string, $split_length = 1, $encoding = null)
{
if (null !== $string && !is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) {
trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING);

return null;
}

if (1 > $split_length = (int) $split_length) {
if (80000 > \PHP_VERSION_ID) {
trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING);
return false;
}

throw new \ValueError('Argument #2 ($length) must be greater than 0');
}

if (null === $encoding) {
$encoding = mb_internal_encoding();
}

if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
$rx = '/(';
while (65535 < $split_length) {
$rx .= '.{65535}';
$split_length -= 65535;
}
$rx .= '.{'.$split_length.'})/us';

return preg_split($rx, $string, null, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
}

$result = [];
$length = mb_strlen($string, $encoding);

for ($i = 0; $i < $length; $i += $split_length) {
$result[] = mb_substr($string, $i, $split_length, $encoding);
}

return $result;
}

public static function mb_strtolower($s, $encoding = null)
{
return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding);
}

public static function mb_strtoupper($s, $encoding = null)
{
return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding);
}

public static function mb_substitute_character($c = null)
{
if (null === $c) {
return 'none';
}
if (0 === strcasecmp($c, 'none')) {
return true;
}
if (80000 > \PHP_VERSION_ID) {
return false;
}

throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint');
}

public static function mb_substr($s, $start, $length = null, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
return (string) substr($s, $start, null === $length ? 2147483647 : $length);
}

if ($start < 0) {
$start = \iconv_strlen($s, $encoding) + $start;
if ($start < 0) {
$start = 0;
}
}

if (null === $length) {
$length = 2147483647;
} elseif ($length < 0) {
$length = \iconv_strlen($s, $encoding) + $length - $start;
if ($length < 0) {
return '';
}
}

return (string) \iconv_substr($s, $start, $length, $encoding);
}

public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
{
$haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
$needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);

return self::mb_strpos($haystack, $needle, $offset, $encoding);
}

public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
{
$pos = self::mb_stripos($haystack, $needle, 0, $encoding);

return self::getSubpart($pos, $part, $haystack, $encoding);
}

public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
$pos = strrpos($haystack, $needle);
} else {
$needle = self::mb_substr($needle, 0, 1, $encoding);
$pos = \iconv_strrpos($haystack, $needle, $encoding);
}

return self::getSubpart($pos, $part, $haystack, $encoding);
}

public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
{
$needle = self::mb_substr($needle, 0, 1, $encoding);
$pos = self::mb_strripos($haystack, $needle, $encoding);

return self::getSubpart($pos, $part, $haystack, $encoding);
}

public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
{
$haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
$needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);

return self::mb_strrpos($haystack, $needle, $offset, $encoding);
}

public static function mb_strstr($haystack, $needle, $part = false, $encoding = null)
{
$pos = strpos($haystack, $needle);
if (false === $pos) {
return false;
}
if ($part) {
return substr($haystack, 0, $pos);
}

return substr($haystack, $pos);
}

public static function mb_get_info($type = 'all')
{
$info = [
'internal_encoding' => self::$internalEncoding,
'http_output' => 'pass',
'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
'func_overload' => 0,
'func_overload_list' => 'no overload',
'mail_charset' => 'UTF-8',
'mail_header_encoding' => 'BASE64',
'mail_body_encoding' => 'BASE64',
'illegal_chars' => 0,
'encoding_translation' => 'Off',
'language' => self::$language,
'detect_order' => self::$encodingList,
'substitute_character' => 'none',
'strict_detection' => 'Off',
];

if ('all' === $type) {
return $info;
}
if (isset($info[$type])) {
return $info[$type];
}

return false;
}

public static function mb_http_input($type = '')
{
return false;
}

public static function mb_http_output($encoding = null)
{
return null !== $encoding ? 'pass' === $encoding : 'pass';
}

public static function mb_strwidth($s, $encoding = null)
{
$encoding = self::getEncoding($encoding);

if ('UTF-8' !== $encoding) {
$s = \iconv($encoding, 'UTF-8//IGNORE', $s);
}

$s = preg_replace('/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u', '', $s, -1, $wide);

return ($wide << 1) + \iconv_strlen($s, 'UTF-8');
}

public static function mb_substr_count($haystack, $needle, $encoding = null)
{
return substr_count($haystack, $needle);
}

public static function mb_output_handler($contents, $status)
{
return $contents;
}

public static function mb_chr($code, $encoding = null)
{
if (0x80 > $code %= 0x200000) {
$s = \chr($code);
} elseif (0x800 > $code) {
$s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
} elseif (0x10000 > $code) {
$s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
} else {
$s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
}

if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
$s = mb_convert_encoding($s, $encoding, 'UTF-8');
}

return $s;
}

public static function mb_ord($s, $encoding = null)
{
if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
$s = mb_convert_encoding($s, 'UTF-8', $encoding);
}

if (1 === \strlen($s)) {
return \ord($s);
}

$code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
if (0xF0 <= $code) {
return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
}
if (0xE0 <= $code) {
return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
}
if (0xC0 <= $code) {
return (($code - 0xC0) << 6) + $s[2] - 0x80;
}

return $code;
}

private static function getSubpart($pos, $part, $haystack, $encoding)
{
if (false === $pos) {
return false;
}
if ($part) {
return self::mb_substr($haystack, 0, $pos, $encoding);
}

return self::mb_substr($haystack, $pos, null, $encoding);
}

private static function html_encoding_callback(array $m)
{
$i = 1;
$entities = '';
$m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8'));

while (isset($m[$i])) {
if (0x80 > $m[$i]) {
$entities .= \chr($m[$i++]);
continue;
}
if (0xF0 <= $m[$i]) {
$c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
} elseif (0xE0 <= $m[$i]) {
$c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
} else {
$c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
}

$entities .= '&#'.$c.';';
}

return $entities;
}

private static function title_case(array $s)
{
return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8');
}

private static function getData($file)
{
if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
return require $file;
}

return false;
}

private static function getEncoding($encoding)
{
if (null === $encoding) {
return self::$internalEncoding;
}

if ('UTF-8' === $encoding) {
return 'UTF-8';
}

$encoding = strtoupper($encoding);

if ('8BIT' === $encoding || 'BINARY' === $encoding) {
return 'CP850';
}

if ('UTF8' === $encoding) {
return 'UTF-8';
}

return $encoding;
}
}
<?php










use Symfony\Polyfill\Mbstring as p;

if (!function_exists('mb_convert_encoding')) {
function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null): array|string|false { return p\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding); }
}
if (!function_exists('mb_decode_mimeheader')) {
function mb_decode_mimeheader(?string $string): string { return p\Mbstring::mb_decode_mimeheader((string) $string); }
}
if (!function_exists('mb_encode_mimeheader')) {
function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = "\r\n", ?int $indent = 0): string { return p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); }
}
if (!function_exists('mb_decode_numericentity')) {
function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null): string { return p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); }
}
if (!function_exists('mb_encode_numericentity')) {
function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = false): string { return p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); }
}
if (!function_exists('mb_convert_case')) {
function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null): string { return p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); }
}
if (!function_exists('mb_internal_encoding')) {
function mb_internal_encoding(?string $encoding = null): string|bool { return p\Mbstring::mb_internal_encoding($encoding); }
}
if (!function_exists('mb_language')) {
function mb_language(?string $language = null): string|bool { return p\Mbstring::mb_language($language); }
}
if (!function_exists('mb_list_encodings')) {
function mb_list_encodings(): array { return p\Mbstring::mb_list_encodings(); }
}
if (!function_exists('mb_encoding_aliases')) {
function mb_encoding_aliases(?string $encoding): array { return p\Mbstring::mb_encoding_aliases((string) $encoding); }
}
if (!function_exists('mb_check_encoding')) {
function mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool { return p\Mbstring::mb_check_encoding($value, $encoding); }
}
if (!function_exists('mb_detect_encoding')) {
function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = false): string|false { return p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); }
}
if (!function_exists('mb_detect_order')) {
function mb_detect_order(array|string|null $encoding = null): array|bool { return p\Mbstring::mb_detect_order($encoding); }
}
if (!function_exists('mb_parse_str')) {
function mb_parse_str(?string $string, &$result = []): bool { parse_str((string) $string, $result); return (bool) $result; }
}
if (!function_exists('mb_strlen')) {
function mb_strlen(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strlen((string) $string, $encoding); }
}
if (!function_exists('mb_strpos')) {
function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_strtolower')) {
function mb_strtolower(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtolower((string) $string, $encoding); }
}
if (!function_exists('mb_strtoupper')) {
function mb_strtoupper(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtoupper((string) $string, $encoding); }
}
if (!function_exists('mb_substitute_character')) {
function mb_substitute_character(string|int|null $substitute_character = null): string|int|bool { return p\Mbstring::mb_substitute_character($substitute_character); }
}
if (!function_exists('mb_substr')) {
function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null): string { return p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); }
}
if (!function_exists('mb_stripos')) {
function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_stristr')) {
function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_strrchr')) {
function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_strrichr')) {
function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_strripos')) {
function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_strrpos')) {
function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_strstr')) {
function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_get_info')) {
function mb_get_info(?string $type = 'all'): array|string|int|false { return p\Mbstring::mb_get_info((string) $type); }
}
if (!function_exists('mb_http_output')) {
function mb_http_output(?string $encoding = null): string|bool { return p\Mbstring::mb_http_output($encoding); }
}
if (!function_exists('mb_strwidth')) {
function mb_strwidth(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strwidth((string) $string, $encoding); }
}
if (!function_exists('mb_substr_count')) {
function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null): int { return p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); }
}
if (!function_exists('mb_output_handler')) {
function mb_output_handler(?string $string, ?int $status): string { return p\Mbstring::mb_output_handler((string) $string, (int) $status); }
}
if (!function_exists('mb_http_input')) {
function mb_http_input(?string $type = null): array|string|false { return p\Mbstring::mb_http_input($type); }
}

if (!function_exists('mb_convert_variables')) {
function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars): string|false { return p\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars); }
}

if (!function_exists('mb_ord')) {
function mb_ord(?string $string, ?string $encoding = null): int|false { return p\Mbstring::mb_ord((string) $string, $encoding); }
}
if (!function_exists('mb_chr')) {
function mb_chr(?int $codepoint, ?string $encoding = null): string|false { return p\Mbstring::mb_chr((int) $codepoint, $encoding); }
}
if (!function_exists('mb_scrub')) {
function mb_scrub(?string $string, ?string $encoding = null): string { $encoding ??= mb_internal_encoding(); return mb_convert_encoding((string) $string, $encoding, $encoding); }
}
if (!function_exists('mb_str_split')) {
function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); }
}

if (extension_loaded('mbstring')) {
return;
}

if (!defined('MB_CASE_UPPER')) {
define('MB_CASE_UPPER', 0);
}
if (!defined('MB_CASE_LOWER')) {
define('MB_CASE_LOWER', 1);
}
if (!defined('MB_CASE_TITLE')) {
define('MB_CASE_TITLE', 2);
}
<?php

return array (
'A' => 'a',
'B' => 'b',
'C' => 'c',
'D' => 'd',
'E' => 'e',
'F' => 'f',
'G' => 'g',
'H' => 'h',
'I' => 'i',
'J' => 'j',
'K' => 'k',
'L' => 'l',
'M' => 'm',
'N' => 'n',
'O' => 'o',
'P' => 'p',
'Q' => 'q',
'R' => 'r',
'S' => 's',
'T' => 't',
'U' => 'u',
'V' => 'v',
'W' => 'w',
'X' => 'x',
'Y' => 'y',
'Z' => 'z',
'À' => 'à',
'Á' => 'á',
'Â' => 'â',
'Ã' => 'ã',
'Ä' => 'ä',
'Å' => 'å',
'Æ' => 'æ',
'Ç' => 'ç',
'È' => 'è',
'É' => 'é',
'Ê' => 'ê',
'Ë' => 'ë',
'Ì' => 'ì',
'Í' => 'í',
'Î' => 'î',
'Ï' => 'ï',
'Ð' => 'ð',
'Ñ' => 'ñ',
'Ò' => 'ò',
'Ó' => 'ó',
'Ô' => 'ô',
'Õ' => 'õ',
'Ö' => 'ö',
'Ø' => 'ø',
'Ù' => 'ù',
'Ú' => 'ú',
'Û' => 'û',
'Ü' => 'ü',
'Ý' => 'ý',
'Þ' => 'þ',
'Ā' => 'ā',
'Ă' => 'ă',
'Ą' => 'ą',
'Ć' => 'ć',
'Ĉ' => 'ĉ',
'Ċ' => 'ċ',
'Č' => 'č',
'Ď' => 'ď',
'Đ' => 'đ',
'Ē' => 'ē',
'Ĕ' => 'ĕ',
'Ė' => 'ė',
'Ę' => 'ę',
'Ě' => 'ě',
'Ĝ' => 'ĝ',
'Ğ' => 'ğ',
'Ġ' => 'ġ',
'Ģ' => 'ģ',
'Ĥ' => 'ĥ',
'Ħ' => 'ħ',
'Ĩ' => 'ĩ',
'Ī' => 'ī',
'Ĭ' => 'ĭ',
'Į' => 'į',
'İ' => 'i̇',
'Ĳ' => 'ĳ',
'Ĵ' => 'ĵ',
'Ķ' => 'ķ',
'Ĺ' => 'ĺ',
'Ļ' => 'ļ',
'Ľ' => 'ľ',
'Ŀ' => 'ŀ',
'Ł' => 'ł',
'Ń' => 'ń',
'Ņ' => 'ņ',
'Ň' => 'ň',
'Ŋ' => 'ŋ',
'Ō' => 'ō',
'Ŏ' => 'ŏ',
'Ő' => 'ő',
'Œ' => 'œ',
'Ŕ' => 'ŕ',
'Ŗ' => 'ŗ',
'Ř' => 'ř',
'Ś' => 'ś',
'Ŝ' => 'ŝ',
'Ş' => 'ş',
'Š' => 'š',
'Ţ' => 'ţ',
'Ť' => 'ť',
'Ŧ' => 'ŧ',
'Ũ' => 'ũ',
'Ū' => 'ū',
'Ŭ' => 'ŭ',
'Ů' => 'ů',
'Ű' => 'ű',
'Ų' => 'ų',
'Ŵ' => 'ŵ',
'Ŷ' => 'ŷ',
'Ÿ' => 'ÿ',
'Ź' => 'ź',
'Ż' => 'ż',
'Ž' => 'ž',
'Ɓ' => 'ɓ',
'Ƃ' => 'ƃ',
'Ƅ' => 'ƅ',
'Ɔ' => 'ɔ',
'Ƈ' => 'ƈ',
'Ɖ' => 'ɖ',
'Ɗ' => 'ɗ',
'Ƌ' => 'ƌ',
'Ǝ' => 'ǝ',
'Ə' => 'ə',
'Ɛ' => 'ɛ',
'Ƒ' => 'ƒ',
'Ɠ' => 'ɠ',
'Ɣ' => 'ɣ',
'Ɩ' => 'ɩ',
'Ɨ' => 'ɨ',
'Ƙ' => 'ƙ',
'Ɯ' => 'ɯ',
'Ɲ' => 'ɲ',
'Ɵ' => 'ɵ',
'Ơ' => 'ơ',
'Ƣ' => 'ƣ',
'Ƥ' => 'ƥ',
'Ʀ' => 'ʀ',
'Ƨ' => 'ƨ',
'Ʃ' => 'ʃ',
'Ƭ' => 'ƭ',
'Ʈ' => 'ʈ',
'Ư' => 'ư',
'Ʊ' => 'ʊ',
'Ʋ' => 'ʋ',
'Ƴ' => 'ƴ',
'Ƶ' => 'ƶ',
'Ʒ' => 'ʒ',
'Ƹ' => 'ƹ',
'Ƽ' => 'ƽ',
'Ǆ' => 'ǆ',
'ǅ' => 'ǆ',
'Ǉ' => 'ǉ',
'ǈ' => 'ǉ',
'Ǌ' => 'ǌ',
'ǋ' => 'ǌ',
'Ǎ' => 'ǎ',
'Ǐ' => 'ǐ',
'Ǒ' => 'ǒ',
'Ǔ' => 'ǔ',
'Ǖ' => 'ǖ',
'Ǘ' => 'ǘ',
'Ǚ' => 'ǚ',
'Ǜ' => 'ǜ',
'Ǟ' => 'ǟ',
'Ǡ' => 'ǡ',
'Ǣ' => 'ǣ',
'Ǥ' => 'ǥ',
'Ǧ' => 'ǧ',
'Ǩ' => 'ǩ',
'Ǫ' => 'ǫ',
'Ǭ' => 'ǭ',
'Ǯ' => 'ǯ',
'Ǳ' => 'ǳ',
'ǲ' => 'ǳ',
'Ǵ' => 'ǵ',
'Ƕ' => 'ƕ',
'Ƿ' => 'ƿ',
'Ǹ' => 'ǹ',
'Ǻ' => 'ǻ',
'Ǽ' => 'ǽ',
'Ǿ' => 'ǿ',
'Ȁ' => 'ȁ',
'Ȃ' => 'ȃ',
'Ȅ' => 'ȅ',
'Ȇ' => 'ȇ',
'Ȉ' => 'ȉ',
'Ȋ' => 'ȋ',
'Ȍ' => 'ȍ',
'Ȏ' => 'ȏ',
'Ȑ' => 'ȑ',
'Ȓ' => 'ȓ',
'Ȕ' => 'ȕ',
'Ȗ' => 'ȗ',
'Ș' => 'ș',
'Ț' => 'ț',
'Ȝ' => 'ȝ',
'Ȟ' => 'ȟ',
'Ƞ' => 'ƞ',
'Ȣ' => 'ȣ',
'Ȥ' => 'ȥ',
'Ȧ' => 'ȧ',
'Ȩ' => 'ȩ',
'Ȫ' => 'ȫ',
'Ȭ' => 'ȭ',
'Ȯ' => 'ȯ',
'Ȱ' => 'ȱ',
'Ȳ' => 'ȳ',
'Ⱥ' => 'ⱥ',
'Ȼ' => 'ȼ',
'Ƚ' => 'ƚ',
'Ⱦ' => 'ⱦ',
'Ɂ' => 'ɂ',
'Ƀ' => 'ƀ',
'Ʉ' => 'ʉ',
'Ʌ' => 'ʌ',
'Ɇ' => 'ɇ',
'Ɉ' => 'ɉ',
'Ɋ' => 'ɋ',
'Ɍ' => 'ɍ',
'Ɏ' => 'ɏ',
'Ͱ' => 'ͱ',
'Ͳ' => 'ͳ',
'Ͷ' => 'ͷ',
'Ϳ' => 'ϳ',
'Ά' => 'ά',
'Έ' => 'έ',
'Ή' => 'ή',
'Ί' => 'ί',
'Ό' => 'ό',
'Ύ' => 'ύ',
'Ώ' => 'ώ',
'Α' => 'α',
'Β' => 'β',
'Γ' => 'γ',
'Δ' => 'δ',
'Ε' => 'ε',
'Ζ' => 'ζ',
'Η' => 'η',
'Θ' => 'θ',
'Ι' => 'ι',
'Κ' => 'κ',
'Λ' => 'λ',
'Μ' => 'μ',
'Ν' => 'ν',
'Ξ' => 'ξ',
'Ο' => 'ο',
'Π' => 'π',
'Ρ' => 'ρ',
'Σ' => 'σ',
'Τ' => 'τ',
'Υ' => 'υ',
'Φ' => 'φ',
'Χ' => 'χ',
'Ψ' => 'ψ',
'Ω' => 'ω',
'Ϊ' => 'ϊ',
'Ϋ' => 'ϋ',
'Ϗ' => 'ϗ',
'Ϙ' => 'ϙ',
'Ϛ' => 'ϛ',
'Ϝ' => 'ϝ',
'Ϟ' => 'ϟ',
'Ϡ' => 'ϡ',
'Ϣ' => 'ϣ',
'Ϥ' => 'ϥ',
'Ϧ' => 'ϧ',
'Ϩ' => 'ϩ',
'Ϫ' => 'ϫ',
'Ϭ' => 'ϭ',
'Ϯ' => 'ϯ',
'ϴ' => 'θ',
'Ϸ' => 'ϸ',
'Ϲ' => 'ϲ',
'Ϻ' => 'ϻ',
'Ͻ' => 'ͻ',
'Ͼ' => 'ͼ',
'Ͽ' => 'ͽ',
'Ѐ' => 'ѐ',
'Ё' => 'ё',
'Ђ' => 'ђ',
'Ѓ' => 'ѓ',
'Є' => 'є',
'Ѕ' => 'ѕ',
'І' => 'і',
'Ї' => 'ї',
'Ј' => 'ј',
'Љ' => 'љ',
'Њ' => 'њ',
'Ћ' => 'ћ',
'Ќ' => 'ќ',
'Ѝ' => 'ѝ',
'Ў' => 'ў',
'Џ' => 'џ',
'А' => 'а',
'Б' => 'б',
'В' => 'в',
'Г' => 'г',
'Д' => 'д',
'Е' => 'е',
'Ж' => 'ж',
'З' => 'з',
'И' => 'и',
'Й' => 'й',
'К' => 'к',
'Л' => 'л',
'М' => 'м',
'Н' => 'н',
'О' => 'о',
'П' => 'п',
'Р' => 'р',
'С' => 'с',
'Т' => 'т',
'У' => 'у',
'Ф' => 'ф',
'Х' => 'х',
'Ц' => 'ц',
'Ч' => 'ч',
'Ш' => 'ш',
'Щ' => 'щ',
'Ъ' => 'ъ',
'Ы' => 'ы',
'Ь' => 'ь',
'Э' => 'э',
'Ю' => 'ю',
'Я' => 'я',
'Ѡ' => 'ѡ',
'Ѣ' => 'ѣ',
'Ѥ' => 'ѥ',
'Ѧ' => 'ѧ',
'Ѩ' => 'ѩ',
'Ѫ' => 'ѫ',
'Ѭ' => 'ѭ',
'Ѯ' => 'ѯ',
'Ѱ' => 'ѱ',
'Ѳ' => 'ѳ',
'Ѵ' => 'ѵ',
'Ѷ' => 'ѷ',
'Ѹ' => 'ѹ',
'Ѻ' => 'ѻ',
'Ѽ' => 'ѽ',
'Ѿ' => 'ѿ',
'Ҁ' => 'ҁ',
'Ҋ' => 'ҋ',
'Ҍ' => 'ҍ',
'Ҏ' => 'ҏ',
'Ґ' => 'ґ',
'Ғ' => 'ғ',
'Ҕ' => 'ҕ',
'Җ' => 'җ',
'Ҙ' => 'ҙ',
'Қ' => 'қ',
'Ҝ' => 'ҝ',
'Ҟ' => 'ҟ',
'Ҡ' => 'ҡ',
'Ң' => 'ң',
'Ҥ' => 'ҥ',
'Ҧ' => 'ҧ',
'Ҩ' => 'ҩ',
'Ҫ' => 'ҫ',
'Ҭ' => 'ҭ',
'Ү' => 'ү',
'Ұ' => 'ұ',
'Ҳ' => 'ҳ',
'Ҵ' => 'ҵ',
'Ҷ' => 'ҷ',
'Ҹ' => 'ҹ',
'Һ' => 'һ',
'Ҽ' => 'ҽ',
'Ҿ' => 'ҿ',
'Ӏ' => 'ӏ',
'Ӂ' => 'ӂ',
'Ӄ' => 'ӄ',
'Ӆ' => 'ӆ',
'Ӈ' => 'ӈ',
'Ӊ' => 'ӊ',
'Ӌ' => 'ӌ',
'Ӎ' => 'ӎ',
'Ӑ' => 'ӑ',
'Ӓ' => 'ӓ',
'Ӕ' => 'ӕ',
'Ӗ' => 'ӗ',
'Ә' => 'ә',
'Ӛ' => 'ӛ',
'Ӝ' => 'ӝ',
'Ӟ' => 'ӟ',
'Ӡ' => 'ӡ',
'Ӣ' => 'ӣ',
'Ӥ' => 'ӥ',
'Ӧ' => 'ӧ',
'Ө' => 'ө',
'Ӫ' => 'ӫ',
'Ӭ' => 'ӭ',
'Ӯ' => 'ӯ',
'Ӱ' => 'ӱ',
'Ӳ' => 'ӳ',
'Ӵ' => 'ӵ',
'Ӷ' => 'ӷ',
'Ӹ' => 'ӹ',
'Ӻ' => 'ӻ',
'Ӽ' => 'ӽ',
'Ӿ' => 'ӿ',
'Ԁ' => 'ԁ',
'Ԃ' => 'ԃ',
'Ԅ' => 'ԅ',
'Ԇ' => 'ԇ',
'Ԉ' => 'ԉ',
'Ԋ' => 'ԋ',
'Ԍ' => 'ԍ',
'Ԏ' => 'ԏ',
'Ԑ' => 'ԑ',
'Ԓ' => 'ԓ',
'Ԕ' => 'ԕ',
'Ԗ' => 'ԗ',
'Ԙ' => 'ԙ',
'Ԛ' => 'ԛ',
'Ԝ' => 'ԝ',
'Ԟ' => 'ԟ',
'Ԡ' => 'ԡ',
'Ԣ' => 'ԣ',
'Ԥ' => 'ԥ',
'Ԧ' => 'ԧ',
'Ԩ' => 'ԩ',
'Ԫ' => 'ԫ',
'Ԭ' => 'ԭ',
'Ԯ' => 'ԯ',
'Ա' => 'ա',
'Բ' => 'բ',
'Գ' => 'գ',
'Դ' => 'դ',
'Ե' => 'ե',
'Զ' => 'զ',
'Է' => 'է',
'Ը' => 'ը',
'Թ' => 'թ',
'Ժ' => 'ժ',
'Ի' => 'ի',
'Լ' => 'լ',
'Խ' => 'խ',
'Ծ' => 'ծ',
'Կ' => 'կ',
'Հ' => 'հ',
'Ձ' => 'ձ',
'Ղ' => 'ղ',
'Ճ' => 'ճ',
'Մ' => 'մ',
'Յ' => 'յ',
'Ն' => 'ն',
'Շ' => 'շ',
'Ո' => 'ո',
'Չ' => 'չ',
'Պ' => 'պ',
'Ջ' => 'ջ',
'Ռ' => 'ռ',
'Ս' => 'ս',
'Վ' => 'վ',
'Տ' => 'տ',
'Ր' => 'ր',
'Ց' => 'ց',
'Ւ' => 'ւ',
'Փ' => 'փ',
'Ք' => 'ք',
'Օ' => 'օ',
'Ֆ' => 'ֆ',
'Ⴀ' => 'ⴀ',
'Ⴁ' => 'ⴁ',
'Ⴂ' => 'ⴂ',
'Ⴃ' => 'ⴃ',
'Ⴄ' => 'ⴄ',
'Ⴅ' => 'ⴅ',
'Ⴆ' => 'ⴆ',
'Ⴇ' => 'ⴇ',
'Ⴈ' => 'ⴈ',
'Ⴉ' => 'ⴉ',
'Ⴊ' => 'ⴊ',
'Ⴋ' => 'ⴋ',
'Ⴌ' => 'ⴌ',
'Ⴍ' => 'ⴍ',
'Ⴎ' => 'ⴎ',
'Ⴏ' => 'ⴏ',
'Ⴐ' => 'ⴐ',
'Ⴑ' => 'ⴑ',
'Ⴒ' => 'ⴒ',
'Ⴓ' => 'ⴓ',
'Ⴔ' => 'ⴔ',
'Ⴕ' => 'ⴕ',
'Ⴖ' => 'ⴖ',
'Ⴗ' => 'ⴗ',
'Ⴘ' => 'ⴘ',
'Ⴙ' => 'ⴙ',
'Ⴚ' => 'ⴚ',
'Ⴛ' => 'ⴛ',
'Ⴜ' => 'ⴜ',
'Ⴝ' => 'ⴝ',
'Ⴞ' => 'ⴞ',
'Ⴟ' => 'ⴟ',
'Ⴠ' => 'ⴠ',
'Ⴡ' => 'ⴡ',
'Ⴢ' => 'ⴢ',
'Ⴣ' => 'ⴣ',
'Ⴤ' => 'ⴤ',
'Ⴥ' => 'ⴥ',
'Ⴧ' => 'ⴧ',
'Ⴭ' => 'ⴭ',
'Ꭰ' => 'ꭰ',
'Ꭱ' => 'ꭱ',
'Ꭲ' => 'ꭲ',
'Ꭳ' => 'ꭳ',
'Ꭴ' => 'ꭴ',
'Ꭵ' => 'ꭵ',
'Ꭶ' => 'ꭶ',
'Ꭷ' => 'ꭷ',
'Ꭸ' => 'ꭸ',
'Ꭹ' => 'ꭹ',
'Ꭺ' => 'ꭺ',
'Ꭻ' => 'ꭻ',
'Ꭼ' => 'ꭼ',
'Ꭽ' => 'ꭽ',
'Ꭾ' => 'ꭾ',
'Ꭿ' => 'ꭿ',
'Ꮀ' => 'ꮀ',
'Ꮁ' => 'ꮁ',
'Ꮂ' => 'ꮂ',
'Ꮃ' => 'ꮃ',
'Ꮄ' => 'ꮄ',
'Ꮅ' => 'ꮅ',
'Ꮆ' => 'ꮆ',
'Ꮇ' => 'ꮇ',
'Ꮈ' => 'ꮈ',
'Ꮉ' => 'ꮉ',
'Ꮊ' => 'ꮊ',
'Ꮋ' => 'ꮋ',
'Ꮌ' => 'ꮌ',
'Ꮍ' => 'ꮍ',
'Ꮎ' => 'ꮎ',
'Ꮏ' => 'ꮏ',
'Ꮐ' => 'ꮐ',
'Ꮑ' => 'ꮑ',
'Ꮒ' => 'ꮒ',
'Ꮓ' => 'ꮓ',
'Ꮔ' => 'ꮔ',
'Ꮕ' => 'ꮕ',
'Ꮖ' => 'ꮖ',
'Ꮗ' => 'ꮗ',
'Ꮘ' => 'ꮘ',
'Ꮙ' => 'ꮙ',
'Ꮚ' => 'ꮚ',
'Ꮛ' => 'ꮛ',
'Ꮜ' => 'ꮜ',
'Ꮝ' => 'ꮝ',
'Ꮞ' => 'ꮞ',
'Ꮟ' => 'ꮟ',
'Ꮠ' => 'ꮠ',
'Ꮡ' => 'ꮡ',
'Ꮢ' => 'ꮢ',
'Ꮣ' => 'ꮣ',
'Ꮤ' => 'ꮤ',
'Ꮥ' => 'ꮥ',
'Ꮦ' => 'ꮦ',
'Ꮧ' => 'ꮧ',
'Ꮨ' => 'ꮨ',
'Ꮩ' => 'ꮩ',
'Ꮪ' => 'ꮪ',
'Ꮫ' => 'ꮫ',
'Ꮬ' => 'ꮬ',
'Ꮭ' => 'ꮭ',
'Ꮮ' => 'ꮮ',
'Ꮯ' => 'ꮯ',
'Ꮰ' => 'ꮰ',
'Ꮱ' => 'ꮱ',
'Ꮲ' => 'ꮲ',
'Ꮳ' => 'ꮳ',
'Ꮴ' => 'ꮴ',
'Ꮵ' => 'ꮵ',
'Ꮶ' => 'ꮶ',
'Ꮷ' => 'ꮷ',
'Ꮸ' => 'ꮸ',
'Ꮹ' => 'ꮹ',
'Ꮺ' => 'ꮺ',
'Ꮻ' => 'ꮻ',
'Ꮼ' => 'ꮼ',
'Ꮽ' => 'ꮽ',
'Ꮾ' => 'ꮾ',
'Ꮿ' => 'ꮿ',
'Ᏸ' => 'ᏸ',
'Ᏹ' => 'ᏹ',
'Ᏺ' => 'ᏺ',
'Ᏻ' => 'ᏻ',
'Ᏼ' => 'ᏼ',
'Ᏽ' => 'ᏽ',
'Ა' => 'ა',
'Ბ' => 'ბ',
'Გ' => 'გ',
'Დ' => 'დ',
'Ე' => 'ე',
'Ვ' => 'ვ',
'Ზ' => 'ზ',
'Თ' => 'თ',
'Ი' => 'ი',
'Კ' => 'კ',
'Ლ' => 'ლ',
'Მ' => 'მ',
'Ნ' => 'ნ',
'Ო' => 'ო',
'Პ' => 'პ',
'Ჟ' => 'ჟ',
'Რ' => 'რ',
'Ს' => 'ს',
'Ტ' => 'ტ',
'Უ' => 'უ',
'Ფ' => 'ფ',
'Ქ' => 'ქ',
'Ღ' => 'ღ',
'Ყ' => 'ყ',
'Შ' => 'შ',
'Ჩ' => 'ჩ',
'Ც' => 'ც',
'Ძ' => 'ძ',
'Წ' => 'წ',
'Ჭ' => 'ჭ',
'Ხ' => 'ხ',
'Ჯ' => 'ჯ',
'Ჰ' => 'ჰ',
'Ჱ' => 'ჱ',
'Ჲ' => 'ჲ',
'Ჳ' => 'ჳ',
'Ჴ' => 'ჴ',
'Ჵ' => 'ჵ',
'Ჶ' => 'ჶ',
'Ჷ' => 'ჷ',
'Ჸ' => 'ჸ',
'Ჹ' => 'ჹ',
'Ჺ' => 'ჺ',
'Ჽ' => 'ჽ',
'Ჾ' => 'ჾ',
'Ჿ' => 'ჿ',
'Ḁ' => 'ḁ',
'Ḃ' => 'ḃ',
'Ḅ' => 'ḅ',
'Ḇ' => 'ḇ',
'Ḉ' => 'ḉ',
'Ḋ' => 'ḋ',
'Ḍ' => 'ḍ',
'Ḏ' => 'ḏ',
'Ḑ' => 'ḑ',
'Ḓ' => 'ḓ',
'Ḕ' => 'ḕ',
'Ḗ' => 'ḗ',
'Ḙ' => 'ḙ',
'Ḛ' => 'ḛ',
'Ḝ' => 'ḝ',
'Ḟ' => 'ḟ',
'Ḡ' => 'ḡ',
'Ḣ' => 'ḣ',
'Ḥ' => 'ḥ',
'Ḧ' => 'ḧ',
'Ḩ' => 'ḩ',
'Ḫ' => 'ḫ',
'Ḭ' => 'ḭ',
'Ḯ' => 'ḯ',
'Ḱ' => 'ḱ',
'Ḳ' => 'ḳ',
'Ḵ' => 'ḵ',
'Ḷ' => 'ḷ',
'Ḹ' => 'ḹ',
'Ḻ' => 'ḻ',
'Ḽ' => 'ḽ',
'Ḿ' => 'ḿ',
'Ṁ' => 'ṁ',
'Ṃ' => 'ṃ',
'Ṅ' => 'ṅ',
'Ṇ' => 'ṇ',
'Ṉ' => 'ṉ',
'Ṋ' => 'ṋ',
'Ṍ' => 'ṍ',
'Ṏ' => 'ṏ',
'Ṑ' => 'ṑ',
'Ṓ' => 'ṓ',
'Ṕ' => 'ṕ',
'Ṗ' => 'ṗ',
'Ṙ' => 'ṙ',
'Ṛ' => 'ṛ',
'Ṝ' => 'ṝ',
'Ṟ' => 'ṟ',
'Ṡ' => 'ṡ',
'Ṣ' => 'ṣ',
'Ṥ' => 'ṥ',
'Ṧ' => 'ṧ',
'Ṩ' => 'ṩ',
'Ṫ' => 'ṫ',
'Ṭ' => 'ṭ',
'Ṯ' => 'ṯ',
'Ṱ' => 'ṱ',
'Ṳ' => 'ṳ',
'Ṵ' => 'ṵ',
'Ṷ' => 'ṷ',
'Ṹ' => 'ṹ',
'Ṻ' => 'ṻ',
'Ṽ' => 'ṽ',
'Ṿ' => 'ṿ',
'Ẁ' => 'ẁ',
'Ẃ' => 'ẃ',
'Ẅ' => 'ẅ',
'Ẇ' => 'ẇ',
'Ẉ' => 'ẉ',
'Ẋ' => 'ẋ',
'Ẍ' => 'ẍ',
'Ẏ' => 'ẏ',
'Ẑ' => 'ẑ',
'Ẓ' => 'ẓ',
'Ẕ' => 'ẕ',
'ẞ' => 'ß',
'Ạ' => 'ạ',
'Ả' => 'ả',
'Ấ' => 'ấ',
'Ầ' => 'ầ',
'Ẩ' => 'ẩ',
'Ẫ' => 'ẫ',
'Ậ' => 'ậ',
'Ắ' => 'ắ',
'Ằ' => 'ằ',
'Ẳ' => 'ẳ',
'Ẵ' => 'ẵ',
'Ặ' => 'ặ',
'Ẹ' => 'ẹ',
'Ẻ' => 'ẻ',
'Ẽ' => 'ẽ',
'Ế' => 'ế',
'Ề' => 'ề',
'Ể' => 'ể',
'Ễ' => 'ễ',
'Ệ' => 'ệ',
'Ỉ' => 'ỉ',
'Ị' => 'ị',
'Ọ' => 'ọ',
'Ỏ' => 'ỏ',
'Ố' => 'ố',
'Ồ' => 'ồ',
'Ổ' => 'ổ',
'Ỗ' => 'ỗ',
'Ộ' => 'ộ',
'Ớ' => 'ớ',
'Ờ' => 'ờ',
'Ở' => 'ở',
'Ỡ' => 'ỡ',
'Ợ' => 'ợ',
'Ụ' => 'ụ',
'Ủ' => 'ủ',
'Ứ' => 'ứ',
'Ừ' => 'ừ',
'Ử' => 'ử',
'Ữ' => 'ữ',
'Ự' => 'ự',
'Ỳ' => 'ỳ',
'Ỵ' => 'ỵ',
'Ỷ' => 'ỷ',
'Ỹ' => 'ỹ',
'Ỻ' => 'ỻ',
'Ỽ' => 'ỽ',
'Ỿ' => 'ỿ',
'Ἀ' => 'ἀ',
'Ἁ' => 'ἁ',
'Ἂ' => 'ἂ',
'Ἃ' => 'ἃ',
'Ἄ' => 'ἄ',
'Ἅ' => 'ἅ',
'Ἆ' => 'ἆ',
'Ἇ' => 'ἇ',
'Ἐ' => 'ἐ',
'Ἑ' => 'ἑ',
'Ἒ' => 'ἒ',
'Ἓ' => 'ἓ',
'Ἔ' => 'ἔ',
'Ἕ' => 'ἕ',
'Ἠ' => 'ἠ',
'Ἡ' => 'ἡ',
'Ἢ' => 'ἢ',
'Ἣ' => 'ἣ',
'Ἤ' => 'ἤ',
'Ἥ' => 'ἥ',
'Ἦ' => 'ἦ',
'Ἧ' => 'ἧ',
'Ἰ' => 'ἰ',
'Ἱ' => 'ἱ',
'Ἲ' => 'ἲ',
'Ἳ' => 'ἳ',
'Ἴ' => 'ἴ',
'Ἵ' => 'ἵ',
'Ἶ' => 'ἶ',
'Ἷ' => 'ἷ',
'Ὀ' => 'ὀ',
'Ὁ' => 'ὁ',
'Ὂ' => 'ὂ',
'Ὃ' => 'ὃ',
'Ὄ' => 'ὄ',
'Ὅ' => 'ὅ',
'Ὑ' => 'ὑ',
'Ὓ' => 'ὓ',
'Ὕ' => 'ὕ',
'Ὗ' => 'ὗ',
'Ὠ' => 'ὠ',
'Ὡ' => 'ὡ',
'Ὢ' => 'ὢ',
'Ὣ' => 'ὣ',
'Ὤ' => 'ὤ',
'Ὥ' => 'ὥ',
'Ὦ' => 'ὦ',
'Ὧ' => 'ὧ',
'ᾈ' => 'ᾀ',
'ᾉ' => 'ᾁ',
'ᾊ' => 'ᾂ',
'ᾋ' => 'ᾃ',
'ᾌ' => 'ᾄ',
'ᾍ' => 'ᾅ',
'ᾎ' => 'ᾆ',
'ᾏ' => 'ᾇ',
'ᾘ' => 'ᾐ',
'ᾙ' => 'ᾑ',
'ᾚ' => 'ᾒ',
'ᾛ' => 'ᾓ',
'ᾜ' => 'ᾔ',
'ᾝ' => 'ᾕ',
'ᾞ' => 'ᾖ',
'ᾟ' => 'ᾗ',
'ᾨ' => 'ᾠ',
'ᾩ' => 'ᾡ',
'ᾪ' => 'ᾢ',
'ᾫ' => 'ᾣ',
'ᾬ' => 'ᾤ',
'ᾭ' => 'ᾥ',
'ᾮ' => 'ᾦ',
'ᾯ' => 'ᾧ',
'Ᾰ' => 'ᾰ',
'Ᾱ' => 'ᾱ',
'Ὰ' => 'ὰ',
'Ά' => 'ά',
'ᾼ' => 'ᾳ',
'Ὲ' => 'ὲ',
'Έ' => 'έ',
'Ὴ' => 'ὴ',
'Ή' => 'ή',
'ῌ' => 'ῃ',
'Ῐ' => 'ῐ',
'Ῑ' => 'ῑ',
'Ὶ' => 'ὶ',
'Ί' => 'ί',
'Ῠ' => 'ῠ',
'Ῡ' => 'ῡ',
'Ὺ' => 'ὺ',
'Ύ' => 'ύ',
'Ῥ' => 'ῥ',
'Ὸ' => 'ὸ',
'Ό' => 'ό',
'Ὼ' => 'ὼ',
'Ώ' => 'ώ',
'ῼ' => 'ῳ',
'Ω' => 'ω',
'K' => 'k',
'Å' => 'å',
'Ⅎ' => 'ⅎ',
'Ⅰ' => 'ⅰ',
'Ⅱ' => 'ⅱ',
'Ⅲ' => 'ⅲ',
'Ⅳ' => 'ⅳ',
'Ⅴ' => 'ⅴ',
'Ⅵ' => 'ⅵ',
'Ⅶ' => 'ⅶ',
'Ⅷ' => 'ⅷ',
'Ⅸ' => 'ⅸ',
'Ⅹ' => 'ⅹ',
'Ⅺ' => 'ⅺ',
'Ⅻ' => 'ⅻ',
'Ⅼ' => 'ⅼ',
'Ⅽ' => 'ⅽ',
'Ⅾ' => 'ⅾ',
'Ⅿ' => 'ⅿ',
'Ↄ' => 'ↄ',
'Ⓐ' => 'ⓐ',
'Ⓑ' => 'ⓑ',
'Ⓒ' => 'ⓒ',
'Ⓓ' => 'ⓓ',
'Ⓔ' => 'ⓔ',
'Ⓕ' => 'ⓕ',
'Ⓖ' => 'ⓖ',
'Ⓗ' => 'ⓗ',
'Ⓘ' => 'ⓘ',
'Ⓙ' => 'ⓙ',
'Ⓚ' => 'ⓚ',
'Ⓛ' => 'ⓛ',
'Ⓜ' => 'ⓜ',
'Ⓝ' => 'ⓝ',
'Ⓞ' => 'ⓞ',
'Ⓟ' => 'ⓟ',
'Ⓠ' => 'ⓠ',
'Ⓡ' => 'ⓡ',
'Ⓢ' => 'ⓢ',
'Ⓣ' => 'ⓣ',
'Ⓤ' => 'ⓤ',
'Ⓥ' => 'ⓥ',
'Ⓦ' => 'ⓦ',
'Ⓧ' => 'ⓧ',
'Ⓨ' => 'ⓨ',
'Ⓩ' => 'ⓩ',
'Ⰰ' => 'ⰰ',
'Ⰱ' => 'ⰱ',
'Ⰲ' => 'ⰲ',
'Ⰳ' => 'ⰳ',
'Ⰴ' => 'ⰴ',
'Ⰵ' => 'ⰵ',
'Ⰶ' => 'ⰶ',
'Ⰷ' => 'ⰷ',
'Ⰸ' => 'ⰸ',
'Ⰹ' => 'ⰹ',
'Ⰺ' => 'ⰺ',
'Ⰻ' => 'ⰻ',
'Ⰼ' => 'ⰼ',
'Ⰽ' => 'ⰽ',
'Ⰾ' => 'ⰾ',
'Ⰿ' => 'ⰿ',
'Ⱀ' => 'ⱀ',
'Ⱁ' => 'ⱁ',
'Ⱂ' => 'ⱂ',
'Ⱃ' => 'ⱃ',
'Ⱄ' => 'ⱄ',
'Ⱅ' => 'ⱅ',
'Ⱆ' => 'ⱆ',
'Ⱇ' => 'ⱇ',
'Ⱈ' => 'ⱈ',
'Ⱉ' => 'ⱉ',
'Ⱊ' => 'ⱊ',
'Ⱋ' => 'ⱋ',
'Ⱌ' => 'ⱌ',
'Ⱍ' => 'ⱍ',
'Ⱎ' => 'ⱎ',
'Ⱏ' => 'ⱏ',
'Ⱐ' => 'ⱐ',
'Ⱑ' => 'ⱑ',
'Ⱒ' => 'ⱒ',
'Ⱓ' => 'ⱓ',
'Ⱔ' => 'ⱔ',
'Ⱕ' => 'ⱕ',
'Ⱖ' => 'ⱖ',
'Ⱗ' => 'ⱗ',
'Ⱘ' => 'ⱘ',
'Ⱙ' => 'ⱙ',
'Ⱚ' => 'ⱚ',
'Ⱛ' => 'ⱛ',
'Ⱜ' => 'ⱜ',
'Ⱝ' => 'ⱝ',
'Ⱞ' => 'ⱞ',
'Ⱡ' => 'ⱡ',
'Ɫ' => 'ɫ',
'Ᵽ' => 'ᵽ',
'Ɽ' => 'ɽ',
'Ⱨ' => 'ⱨ',
'Ⱪ' => 'ⱪ',
'Ⱬ' => 'ⱬ',
'Ɑ' => 'ɑ',
'Ɱ' => 'ɱ',
'Ɐ' => 'ɐ',
'Ɒ' => 'ɒ',
'Ⱳ' => 'ⱳ',
'Ⱶ' => 'ⱶ',
'Ȿ' => 'ȿ',
'Ɀ' => 'ɀ',
'Ⲁ' => 'ⲁ',
'Ⲃ' => 'ⲃ',
'Ⲅ' => 'ⲅ',
'Ⲇ' => 'ⲇ',
'Ⲉ' => 'ⲉ',
'Ⲋ' => 'ⲋ',
'Ⲍ' => 'ⲍ',
'Ⲏ' => 'ⲏ',
'Ⲑ' => 'ⲑ',
'Ⲓ' => 'ⲓ',
'Ⲕ' => 'ⲕ',
'Ⲗ' => 'ⲗ',
'Ⲙ' => 'ⲙ',
'Ⲛ' => 'ⲛ',
'Ⲝ' => 'ⲝ',
'Ⲟ' => 'ⲟ',
'Ⲡ' => 'ⲡ',
'Ⲣ' => 'ⲣ',
'Ⲥ' => 'ⲥ',
'Ⲧ' => 'ⲧ',
'Ⲩ' => 'ⲩ',
'Ⲫ' => 'ⲫ',
'Ⲭ' => 'ⲭ',
'Ⲯ' => 'ⲯ',
'Ⲱ' => 'ⲱ',
'Ⲳ' => 'ⲳ',
'Ⲵ' => 'ⲵ',
'Ⲷ' => 'ⲷ',
'Ⲹ' => 'ⲹ',
'Ⲻ' => 'ⲻ',
'Ⲽ' => 'ⲽ',
'Ⲿ' => 'ⲿ',
'Ⳁ' => 'ⳁ',
'Ⳃ' => 'ⳃ',
'Ⳅ' => 'ⳅ',
'Ⳇ' => 'ⳇ',
'Ⳉ' => 'ⳉ',
'Ⳋ' => 'ⳋ',
'Ⳍ' => 'ⳍ',
'Ⳏ' => 'ⳏ',
'Ⳑ' => 'ⳑ',
'Ⳓ' => 'ⳓ',
'Ⳕ' => 'ⳕ',
'Ⳗ' => 'ⳗ',
'Ⳙ' => 'ⳙ',
'Ⳛ' => 'ⳛ',
'Ⳝ' => 'ⳝ',
'Ⳟ' => 'ⳟ',
'Ⳡ' => 'ⳡ',
'Ⳣ' => 'ⳣ',
'Ⳬ' => 'ⳬ',
'Ⳮ' => 'ⳮ',
'Ⳳ' => 'ⳳ',
'Ꙁ' => 'ꙁ',
'Ꙃ' => 'ꙃ',
'Ꙅ' => 'ꙅ',
'Ꙇ' => 'ꙇ',
'Ꙉ' => 'ꙉ',
'Ꙋ' => 'ꙋ',
'Ꙍ' => 'ꙍ',
'Ꙏ' => 'ꙏ',
'Ꙑ' => 'ꙑ',
'Ꙓ' => 'ꙓ',
'Ꙕ' => 'ꙕ',
'Ꙗ' => 'ꙗ',
'Ꙙ' => 'ꙙ',
'Ꙛ' => 'ꙛ',
'Ꙝ' => 'ꙝ',
'Ꙟ' => 'ꙟ',
'Ꙡ' => 'ꙡ',
'Ꙣ' => 'ꙣ',
'Ꙥ' => 'ꙥ',
'Ꙧ' => 'ꙧ',
'Ꙩ' => 'ꙩ',
'Ꙫ' => 'ꙫ',
'Ꙭ' => 'ꙭ',
'Ꚁ' => 'ꚁ',
'Ꚃ' => 'ꚃ',
'Ꚅ' => 'ꚅ',
'Ꚇ' => 'ꚇ',
'Ꚉ' => 'ꚉ',
'Ꚋ' => 'ꚋ',
'Ꚍ' => 'ꚍ',
'Ꚏ' => 'ꚏ',
'Ꚑ' => 'ꚑ',
'Ꚓ' => 'ꚓ',
'Ꚕ' => 'ꚕ',
'Ꚗ' => 'ꚗ',
'Ꚙ' => 'ꚙ',
'Ꚛ' => 'ꚛ',
'Ꜣ' => 'ꜣ',
'Ꜥ' => 'ꜥ',
'Ꜧ' => 'ꜧ',
'Ꜩ' => 'ꜩ',
'Ꜫ' => 'ꜫ',
'Ꜭ' => 'ꜭ',
'Ꜯ' => 'ꜯ',
'Ꜳ' => 'ꜳ',
'Ꜵ' => 'ꜵ',
'Ꜷ' => 'ꜷ',
'Ꜹ' => 'ꜹ',
'Ꜻ' => 'ꜻ',
'Ꜽ' => 'ꜽ',
'Ꜿ' => 'ꜿ',
'Ꝁ' => 'ꝁ',
'Ꝃ' => 'ꝃ',
'Ꝅ' => 'ꝅ',
'Ꝇ' => 'ꝇ',
'Ꝉ' => 'ꝉ',
'Ꝋ' => 'ꝋ',
'Ꝍ' => 'ꝍ',
'Ꝏ' => 'ꝏ',
'Ꝑ' => 'ꝑ',
'Ꝓ' => 'ꝓ',
'Ꝕ' => 'ꝕ',
'Ꝗ' => 'ꝗ',
'Ꝙ' => 'ꝙ',
'Ꝛ' => 'ꝛ',
'Ꝝ' => 'ꝝ',
'Ꝟ' => 'ꝟ',
'Ꝡ' => 'ꝡ',
'Ꝣ' => 'ꝣ',
'Ꝥ' => 'ꝥ',
'Ꝧ' => 'ꝧ',
'Ꝩ' => 'ꝩ',
'Ꝫ' => 'ꝫ',
'Ꝭ' => 'ꝭ',
'Ꝯ' => 'ꝯ',
'Ꝺ' => 'ꝺ',
'Ꝼ' => 'ꝼ',
'Ᵹ' => 'ᵹ',
'Ꝿ' => 'ꝿ',
'Ꞁ' => 'ꞁ',
'Ꞃ' => 'ꞃ',
'Ꞅ' => 'ꞅ',
'Ꞇ' => 'ꞇ',
'Ꞌ' => 'ꞌ',
'Ɥ' => 'ɥ',
'Ꞑ' => 'ꞑ',
'Ꞓ' => 'ꞓ',
'Ꞗ' => 'ꞗ',
'Ꞙ' => 'ꞙ',
'Ꞛ' => 'ꞛ',
'Ꞝ' => 'ꞝ',
'Ꞟ' => 'ꞟ',
'Ꞡ' => 'ꞡ',
'Ꞣ' => 'ꞣ',
'Ꞥ' => 'ꞥ',
'Ꞧ' => 'ꞧ',
'Ꞩ' => 'ꞩ',
'Ɦ' => 'ɦ',
'Ɜ' => 'ɜ',
'Ɡ' => 'ɡ',
'Ɬ' => 'ɬ',
'Ɪ' => 'ɪ',
'Ʞ' => 'ʞ',
'Ʇ' => 'ʇ',
'Ʝ' => 'ʝ',
'Ꭓ' => 'ꭓ',
'Ꞵ' => 'ꞵ',
'Ꞷ' => 'ꞷ',
'Ꞹ' => 'ꞹ',
'Ꞻ' => 'ꞻ',
'Ꞽ' => 'ꞽ',
'Ꞿ' => 'ꞿ',
'Ꟃ' => 'ꟃ',
'Ꞔ' => 'ꞔ',
'Ʂ' => 'ʂ',
'Ᶎ' => 'ᶎ',
'Ꟈ' => 'ꟈ',
'Ꟊ' => 'ꟊ',
'Ꟶ' => 'ꟶ',
'Ａ' => 'ａ',
'Ｂ' => 'ｂ',
'Ｃ' => 'ｃ',
'Ｄ' => 'ｄ',
'Ｅ' => 'ｅ',
'Ｆ' => 'ｆ',
'Ｇ' => 'ｇ',
'Ｈ' => 'ｈ',
'Ｉ' => 'ｉ',
'Ｊ' => 'ｊ',
'Ｋ' => 'ｋ',
'Ｌ' => 'ｌ',
'Ｍ' => 'ｍ',
'Ｎ' => 'ｎ',
'Ｏ' => 'ｏ',
'Ｐ' => 'ｐ',
'Ｑ' => 'ｑ',
'Ｒ' => 'ｒ',
'Ｓ' => 'ｓ',
'Ｔ' => 'ｔ',
'Ｕ' => 'ｕ',
'Ｖ' => 'ｖ',
'Ｗ' => 'ｗ',
'Ｘ' => 'ｘ',
'Ｙ' => 'ｙ',
'Ｚ' => 'ｚ',
'𐐀' => '𐐨',
'𐐁' => '𐐩',
'𐐂' => '𐐪',
'𐐃' => '𐐫',
'𐐄' => '𐐬',
'𐐅' => '𐐭',
'𐐆' => '𐐮',
'𐐇' => '𐐯',
'𐐈' => '𐐰',
'𐐉' => '𐐱',
'𐐊' => '𐐲',
'𐐋' => '𐐳',
'𐐌' => '𐐴',
'𐐍' => '𐐵',
'𐐎' => '𐐶',
'𐐏' => '𐐷',
'𐐐' => '𐐸',
'𐐑' => '𐐹',
'𐐒' => '𐐺',
'𐐓' => '𐐻',
'𐐔' => '𐐼',
'𐐕' => '𐐽',
'𐐖' => '𐐾',
'𐐗' => '𐐿',
'𐐘' => '𐑀',
'𐐙' => '𐑁',
'𐐚' => '𐑂',
'𐐛' => '𐑃',
'𐐜' => '𐑄',
'𐐝' => '𐑅',
'𐐞' => '𐑆',
'𐐟' => '𐑇',
'𐐠' => '𐑈',
'𐐡' => '𐑉',
'𐐢' => '𐑊',
'𐐣' => '𐑋',
'𐐤' => '𐑌',
'𐐥' => '𐑍',
'𐐦' => '𐑎',
'𐐧' => '𐑏',
'𐒰' => '𐓘',
'𐒱' => '𐓙',
'𐒲' => '𐓚',
'𐒳' => '𐓛',
'𐒴' => '𐓜',
'𐒵' => '𐓝',
'𐒶' => '𐓞',
'𐒷' => '𐓟',
'𐒸' => '𐓠',
'𐒹' => '𐓡',
'𐒺' => '𐓢',
'𐒻' => '𐓣',
'𐒼' => '𐓤',
'𐒽' => '𐓥',
'𐒾' => '𐓦',
'𐒿' => '𐓧',
'𐓀' => '𐓨',
'𐓁' => '𐓩',
'𐓂' => '𐓪',
'𐓃' => '𐓫',
'𐓄' => '𐓬',
'𐓅' => '𐓭',
'𐓆' => '𐓮',
'𐓇' => '𐓯',
'𐓈' => '𐓰',
'𐓉' => '𐓱',
'𐓊' => '𐓲',
'𐓋' => '𐓳',
'𐓌' => '𐓴',
'𐓍' => '𐓵',
'𐓎' => '𐓶',
'𐓏' => '𐓷',
'𐓐' => '𐓸',
'𐓑' => '𐓹',
'𐓒' => '𐓺',
'𐓓' => '𐓻',
'𐲀' => '𐳀',
'𐲁' => '𐳁',
'𐲂' => '𐳂',
'𐲃' => '𐳃',
'𐲄' => '𐳄',
'𐲅' => '𐳅',
'𐲆' => '𐳆',
'𐲇' => '𐳇',
'𐲈' => '𐳈',
'𐲉' => '𐳉',
'𐲊' => '𐳊',
'𐲋' => '𐳋',
'𐲌' => '𐳌',
'𐲍' => '𐳍',
'𐲎' => '𐳎',
'𐲏' => '𐳏',
'𐲐' => '𐳐',
'𐲑' => '𐳑',
'𐲒' => '𐳒',
'𐲓' => '𐳓',
'𐲔' => '𐳔',
'𐲕' => '𐳕',
'𐲖' => '𐳖',
'𐲗' => '𐳗',
'𐲘' => '𐳘',
'𐲙' => '𐳙',
'𐲚' => '𐳚',
'𐲛' => '𐳛',
'𐲜' => '𐳜',
'𐲝' => '𐳝',
'𐲞' => '𐳞',
'𐲟' => '𐳟',
'𐲠' => '𐳠',
'𐲡' => '𐳡',
'𐲢' => '𐳢',
'𐲣' => '𐳣',
'𐲤' => '𐳤',
'𐲥' => '𐳥',
'𐲦' => '𐳦',
'𐲧' => '𐳧',
'𐲨' => '𐳨',
'𐲩' => '𐳩',
'𐲪' => '𐳪',
'𐲫' => '𐳫',
'𐲬' => '𐳬',
'𐲭' => '𐳭',
'𐲮' => '𐳮',
'𐲯' => '𐳯',
'𐲰' => '𐳰',
'𐲱' => '𐳱',
'𐲲' => '𐳲',
'𑢠' => '𑣀',
'𑢡' => '𑣁',
'𑢢' => '𑣂',
'𑢣' => '𑣃',
'𑢤' => '𑣄',
'𑢥' => '𑣅',
'𑢦' => '𑣆',
'𑢧' => '𑣇',
'𑢨' => '𑣈',
'𑢩' => '𑣉',
'𑢪' => '𑣊',
'𑢫' => '𑣋',
'𑢬' => '𑣌',
'𑢭' => '𑣍',
'𑢮' => '𑣎',
'𑢯' => '𑣏',
'𑢰' => '𑣐',
'𑢱' => '𑣑',
'𑢲' => '𑣒',
'𑢳' => '𑣓',
'𑢴' => '𑣔',
'𑢵' => '𑣕',
'𑢶' => '𑣖',
'𑢷' => '𑣗',
'𑢸' => '𑣘',
'𑢹' => '𑣙',
'𑢺' => '𑣚',
'𑢻' => '𑣛',
'𑢼' => '𑣜',
'𑢽' => '𑣝',
'𑢾' => '𑣞',
'𑢿' => '𑣟',
'𖹀' => '𖹠',
'𖹁' => '𖹡',
'𖹂' => '𖹢',
'𖹃' => '𖹣',
'𖹄' => '𖹤',
'𖹅' => '𖹥',
'𖹆' => '𖹦',
'𖹇' => '𖹧',
'𖹈' => '𖹨',
'𖹉' => '𖹩',
'𖹊' => '𖹪',
'𖹋' => '𖹫',
'𖹌' => '𖹬',
'𖹍' => '𖹭',
'𖹎' => '𖹮',
'𖹏' => '𖹯',
'𖹐' => '𖹰',
'𖹑' => '𖹱',
'𖹒' => '𖹲',
'𖹓' => '𖹳',
'𖹔' => '𖹴',
'𖹕' => '𖹵',
'𖹖' => '𖹶',
'𖹗' => '𖹷',
'𖹘' => '𖹸',
'𖹙' => '𖹹',
'𖹚' => '𖹺',
'𖹛' => '𖹻',
'𖹜' => '𖹼',
'𖹝' => '𖹽',
'𖹞' => '𖹾',
'𖹟' => '𖹿',
'𞤀' => '𞤢',
'𞤁' => '𞤣',
'𞤂' => '𞤤',
'𞤃' => '𞤥',
'𞤄' => '𞤦',
'𞤅' => '𞤧',
'𞤆' => '𞤨',
'𞤇' => '𞤩',
'𞤈' => '𞤪',
'𞤉' => '𞤫',
'𞤊' => '𞤬',
'𞤋' => '𞤭',
'𞤌' => '𞤮',
'𞤍' => '𞤯',
'𞤎' => '𞤰',
'𞤏' => '𞤱',
'𞤐' => '𞤲',
'𞤑' => '𞤳',
'𞤒' => '𞤴',
'𞤓' => '𞤵',
'𞤔' => '𞤶',
'𞤕' => '𞤷',
'𞤖' => '𞤸',
'𞤗' => '𞤹',
'𞤘' => '𞤺',
'𞤙' => '𞤻',
'𞤚' => '𞤼',
'𞤛' => '𞤽',
'𞤜' => '𞤾',
'𞤝' => '𞤿',
'𞤞' => '𞥀',
'𞤟' => '𞥁',
'𞤠' => '𞥂',
'𞤡' => '𞥃',
);
<?php

return array (
'a' => 'A',
'b' => 'B',
'c' => 'C',
'd' => 'D',
'e' => 'E',
'f' => 'F',
'g' => 'G',
'h' => 'H',
'i' => 'I',
'j' => 'J',
'k' => 'K',
'l' => 'L',
'm' => 'M',
'n' => 'N',
'o' => 'O',
'p' => 'P',
'q' => 'Q',
'r' => 'R',
's' => 'S',
't' => 'T',
'u' => 'U',
'v' => 'V',
'w' => 'W',
'x' => 'X',
'y' => 'Y',
'z' => 'Z',
'µ' => 'Μ',
'à' => 'À',
'á' => 'Á',
'â' => 'Â',
'ã' => 'Ã',
'ä' => 'Ä',
'å' => 'Å',
'æ' => 'Æ',
'ç' => 'Ç',
'è' => 'È',
'é' => 'É',
'ê' => 'Ê',
'ë' => 'Ë',
'ì' => 'Ì',
'í' => 'Í',
'î' => 'Î',
'ï' => 'Ï',
'ð' => 'Ð',
'ñ' => 'Ñ',
'ò' => 'Ò',
'ó' => 'Ó',
'ô' => 'Ô',
'õ' => 'Õ',
'ö' => 'Ö',
'ø' => 'Ø',
'ù' => 'Ù',
'ú' => 'Ú',
'û' => 'Û',
'ü' => 'Ü',
'ý' => 'Ý',
'þ' => 'Þ',
'ÿ' => 'Ÿ',
'ā' => 'Ā',
'ă' => 'Ă',
'ą' => 'Ą',
'ć' => 'Ć',
'ĉ' => 'Ĉ',
'ċ' => 'Ċ',
'č' => 'Č',
'ď' => 'Ď',
'đ' => 'Đ',
'ē' => 'Ē',
'ĕ' => 'Ĕ',
'ė' => 'Ė',
'ę' => 'Ę',
'ě' => 'Ě',
'ĝ' => 'Ĝ',
'ğ' => 'Ğ',
'ġ' => 'Ġ',
'ģ' => 'Ģ',
'ĥ' => 'Ĥ',
'ħ' => 'Ħ',
'ĩ' => 'Ĩ',
'ī' => 'Ī',
'ĭ' => 'Ĭ',
'į' => 'Į',
'ı' => 'I',
'ĳ' => 'Ĳ',
'ĵ' => 'Ĵ',
'ķ' => 'Ķ',
'ĺ' => 'Ĺ',
'ļ' => 'Ļ',
'ľ' => 'Ľ',
'ŀ' => 'Ŀ',
'ł' => 'Ł',
'ń' => 'Ń',
'ņ' => 'Ņ',
'ň' => 'Ň',
'ŋ' => 'Ŋ',
'ō' => 'Ō',
'ŏ' => 'Ŏ',
'ő' => 'Ő',
'œ' => 'Œ',
'ŕ' => 'Ŕ',
'ŗ' => 'Ŗ',
'ř' => 'Ř',
'ś' => 'Ś',
'ŝ' => 'Ŝ',
'ş' => 'Ş',
'š' => 'Š',
'ţ' => 'Ţ',
'ť' => 'Ť',
'ŧ' => 'Ŧ',
'ũ' => 'Ũ',
'ū' => 'Ū',
'ŭ' => 'Ŭ',
'ů' => 'Ů',
'ű' => 'Ű',
'ų' => 'Ų',
'ŵ' => 'Ŵ',
'ŷ' => 'Ŷ',
'ź' => 'Ź',
'ż' => 'Ż',
'ž' => 'Ž',
'ſ' => 'S',
'ƀ' => 'Ƀ',
'ƃ' => 'Ƃ',
'ƅ' => 'Ƅ',
'ƈ' => 'Ƈ',
'ƌ' => 'Ƌ',
'ƒ' => 'Ƒ',
'ƕ' => 'Ƕ',
'ƙ' => 'Ƙ',
'ƚ' => 'Ƚ',
'ƞ' => 'Ƞ',
'ơ' => 'Ơ',
'ƣ' => 'Ƣ',
'ƥ' => 'Ƥ',
'ƨ' => 'Ƨ',
'ƭ' => 'Ƭ',
'ư' => 'Ư',
'ƴ' => 'Ƴ',
'ƶ' => 'Ƶ',
'ƹ' => 'Ƹ',
'ƽ' => 'Ƽ',
'ƿ' => 'Ƿ',
'ǅ' => 'Ǆ',
'ǆ' => 'Ǆ',
'ǈ' => 'Ǉ',
'ǉ' => 'Ǉ',
'ǋ' => 'Ǌ',
'ǌ' => 'Ǌ',
'ǎ' => 'Ǎ',
'ǐ' => 'Ǐ',
'ǒ' => 'Ǒ',
'ǔ' => 'Ǔ',
'ǖ' => 'Ǖ',
'ǘ' => 'Ǘ',
'ǚ' => 'Ǚ',
'ǜ' => 'Ǜ',
'ǝ' => 'Ǝ',
'ǟ' => 'Ǟ',
'ǡ' => 'Ǡ',
'ǣ' => 'Ǣ',
'ǥ' => 'Ǥ',
'ǧ' => 'Ǧ',
'ǩ' => 'Ǩ',
'ǫ' => 'Ǫ',
'ǭ' => 'Ǭ',
'ǯ' => 'Ǯ',
'ǲ' => 'Ǳ',
'ǳ' => 'Ǳ',
'ǵ' => 'Ǵ',
'ǹ' => 'Ǹ',
'ǻ' => 'Ǻ',
'ǽ' => 'Ǽ',
'ǿ' => 'Ǿ',
'ȁ' => 'Ȁ',
'ȃ' => 'Ȃ',
'ȅ' => 'Ȅ',
'ȇ' => 'Ȇ',
'ȉ' => 'Ȉ',
'ȋ' => 'Ȋ',
'ȍ' => 'Ȍ',
'ȏ' => 'Ȏ',
'ȑ' => 'Ȑ',
'ȓ' => 'Ȓ',
'ȕ' => 'Ȕ',
'ȗ' => 'Ȗ',
'ș' => 'Ș',
'ț' => 'Ț',
'ȝ' => 'Ȝ',
'ȟ' => 'Ȟ',
'ȣ' => 'Ȣ',
'ȥ' => 'Ȥ',
'ȧ' => 'Ȧ',
'ȩ' => 'Ȩ',
'ȫ' => 'Ȫ',
'ȭ' => 'Ȭ',
'ȯ' => 'Ȯ',
'ȱ' => 'Ȱ',
'ȳ' => 'Ȳ',
'ȼ' => 'Ȼ',
'ȿ' => 'Ȿ',
'ɀ' => 'Ɀ',
'ɂ' => 'Ɂ',
'ɇ' => 'Ɇ',
'ɉ' => 'Ɉ',
'ɋ' => 'Ɋ',
'ɍ' => 'Ɍ',
'ɏ' => 'Ɏ',
'ɐ' => 'Ɐ',
'ɑ' => 'Ɑ',
'ɒ' => 'Ɒ',
'ɓ' => 'Ɓ',
'ɔ' => 'Ɔ',
'ɖ' => 'Ɖ',
'ɗ' => 'Ɗ',
'ə' => 'Ə',
'ɛ' => 'Ɛ',
'ɜ' => 'Ɜ',
'ɠ' => 'Ɠ',
'ɡ' => 'Ɡ',
'ɣ' => 'Ɣ',
'ɥ' => 'Ɥ',
'ɦ' => 'Ɦ',
'ɨ' => 'Ɨ',
'ɩ' => 'Ɩ',
'ɪ' => 'Ɪ',
'ɫ' => 'Ɫ',
'ɬ' => 'Ɬ',
'ɯ' => 'Ɯ',
'ɱ' => 'Ɱ',
'ɲ' => 'Ɲ',
'ɵ' => 'Ɵ',
'ɽ' => 'Ɽ',
'ʀ' => 'Ʀ',
'ʂ' => 'Ʂ',
'ʃ' => 'Ʃ',
'ʇ' => 'Ʇ',
'ʈ' => 'Ʈ',
'ʉ' => 'Ʉ',
'ʊ' => 'Ʊ',
'ʋ' => 'Ʋ',
'ʌ' => 'Ʌ',
'ʒ' => 'Ʒ',
'ʝ' => 'Ʝ',
'ʞ' => 'Ʞ',
'ͅ' => 'Ι',
'ͱ' => 'Ͱ',
'ͳ' => 'Ͳ',
'ͷ' => 'Ͷ',
'ͻ' => 'Ͻ',
'ͼ' => 'Ͼ',
'ͽ' => 'Ͽ',
'ά' => 'Ά',
'έ' => 'Έ',
'ή' => 'Ή',
'ί' => 'Ί',
'α' => 'Α',
'β' => 'Β',
'γ' => 'Γ',
'δ' => 'Δ',
'ε' => 'Ε',
'ζ' => 'Ζ',
'η' => 'Η',
'θ' => 'Θ',
'ι' => 'Ι',
'κ' => 'Κ',
'λ' => 'Λ',
'μ' => 'Μ',
'ν' => 'Ν',
'ξ' => 'Ξ',
'ο' => 'Ο',
'π' => 'Π',
'ρ' => 'Ρ',
'ς' => 'Σ',
'σ' => 'Σ',
'τ' => 'Τ',
'υ' => 'Υ',
'φ' => 'Φ',
'χ' => 'Χ',
'ψ' => 'Ψ',
'ω' => 'Ω',
'ϊ' => 'Ϊ',
'ϋ' => 'Ϋ',
'ό' => 'Ό',
'ύ' => 'Ύ',
'ώ' => 'Ώ',
'ϐ' => 'Β',
'ϑ' => 'Θ',
'ϕ' => 'Φ',
'ϖ' => 'Π',
'ϗ' => 'Ϗ',
'ϙ' => 'Ϙ',
'ϛ' => 'Ϛ',
'ϝ' => 'Ϝ',
'ϟ' => 'Ϟ',
'ϡ' => 'Ϡ',
'ϣ' => 'Ϣ',
'ϥ' => 'Ϥ',
'ϧ' => 'Ϧ',
'ϩ' => 'Ϩ',
'ϫ' => 'Ϫ',
'ϭ' => 'Ϭ',
'ϯ' => 'Ϯ',
'ϰ' => 'Κ',
'ϱ' => 'Ρ',
'ϲ' => 'Ϲ',
'ϳ' => 'Ϳ',
'ϵ' => 'Ε',
'ϸ' => 'Ϸ',
'ϻ' => 'Ϻ',
'а' => 'А',
'б' => 'Б',
'в' => 'В',
'г' => 'Г',
'д' => 'Д',
'е' => 'Е',
'ж' => 'Ж',
'з' => 'З',
'и' => 'И',
'й' => 'Й',
'к' => 'К',
'л' => 'Л',
'м' => 'М',
'н' => 'Н',
'о' => 'О',
'п' => 'П',
'р' => 'Р',
'с' => 'С',
'т' => 'Т',
'у' => 'У',
'ф' => 'Ф',
'х' => 'Х',
'ц' => 'Ц',
'ч' => 'Ч',
'ш' => 'Ш',
'щ' => 'Щ',
'ъ' => 'Ъ',
'ы' => 'Ы',
'ь' => 'Ь',
'э' => 'Э',
'ю' => 'Ю',
'я' => 'Я',
'ѐ' => 'Ѐ',
'ё' => 'Ё',
'ђ' => 'Ђ',
'ѓ' => 'Ѓ',
'є' => 'Є',
'ѕ' => 'Ѕ',
'і' => 'І',
'ї' => 'Ї',
'ј' => 'Ј',
'љ' => 'Љ',
'њ' => 'Њ',
'ћ' => 'Ћ',
'ќ' => 'Ќ',
'ѝ' => 'Ѝ',
'ў' => 'Ў',
'џ' => 'Џ',
'ѡ' => 'Ѡ',
'ѣ' => 'Ѣ',
'ѥ' => 'Ѥ',
'ѧ' => 'Ѧ',
'ѩ' => 'Ѩ',
'ѫ' => 'Ѫ',
'ѭ' => 'Ѭ',
'ѯ' => 'Ѯ',
'ѱ' => 'Ѱ',
'ѳ' => 'Ѳ',
'ѵ' => 'Ѵ',
'ѷ' => 'Ѷ',
'ѹ' => 'Ѹ',
'ѻ' => 'Ѻ',
'ѽ' => 'Ѽ',
'ѿ' => 'Ѿ',
'ҁ' => 'Ҁ',
'ҋ' => 'Ҋ',
'ҍ' => 'Ҍ',
'ҏ' => 'Ҏ',
'ґ' => 'Ґ',
'ғ' => 'Ғ',
'ҕ' => 'Ҕ',
'җ' => 'Җ',
'ҙ' => 'Ҙ',
'қ' => 'Қ',
'ҝ' => 'Ҝ',
'ҟ' => 'Ҟ',
'ҡ' => 'Ҡ',
'ң' => 'Ң',
'ҥ' => 'Ҥ',
'ҧ' => 'Ҧ',
'ҩ' => 'Ҩ',
'ҫ' => 'Ҫ',
'ҭ' => 'Ҭ',
'ү' => 'Ү',
'ұ' => 'Ұ',
'ҳ' => 'Ҳ',
'ҵ' => 'Ҵ',
'ҷ' => 'Ҷ',
'ҹ' => 'Ҹ',
'һ' => 'Һ',
'ҽ' => 'Ҽ',
'ҿ' => 'Ҿ',
'ӂ' => 'Ӂ',
'ӄ' => 'Ӄ',
'ӆ' => 'Ӆ',
'ӈ' => 'Ӈ',
'ӊ' => 'Ӊ',
'ӌ' => 'Ӌ',
'ӎ' => 'Ӎ',
'ӏ' => 'Ӏ',
'ӑ' => 'Ӑ',
'ӓ' => 'Ӓ',
'ӕ' => 'Ӕ',
'ӗ' => 'Ӗ',
'ә' => 'Ә',
'ӛ' => 'Ӛ',
'ӝ' => 'Ӝ',
'ӟ' => 'Ӟ',
'ӡ' => 'Ӡ',
'ӣ' => 'Ӣ',
'ӥ' => 'Ӥ',
'ӧ' => 'Ӧ',
'ө' => 'Ө',
'ӫ' => 'Ӫ',
'ӭ' => 'Ӭ',
'ӯ' => 'Ӯ',
'ӱ' => 'Ӱ',
'ӳ' => 'Ӳ',
'ӵ' => 'Ӵ',
'ӷ' => 'Ӷ',
'ӹ' => 'Ӹ',
'ӻ' => 'Ӻ',
'ӽ' => 'Ӽ',
'ӿ' => 'Ӿ',
'ԁ' => 'Ԁ',
'ԃ' => 'Ԃ',
'ԅ' => 'Ԅ',
'ԇ' => 'Ԇ',
'ԉ' => 'Ԉ',
'ԋ' => 'Ԋ',
'ԍ' => 'Ԍ',
'ԏ' => 'Ԏ',
'ԑ' => 'Ԑ',
'ԓ' => 'Ԓ',
'ԕ' => 'Ԕ',
'ԗ' => 'Ԗ',
'ԙ' => 'Ԙ',
'ԛ' => 'Ԛ',
'ԝ' => 'Ԝ',
'ԟ' => 'Ԟ',
'ԡ' => 'Ԡ',
'ԣ' => 'Ԣ',
'ԥ' => 'Ԥ',
'ԧ' => 'Ԧ',
'ԩ' => 'Ԩ',
'ԫ' => 'Ԫ',
'ԭ' => 'Ԭ',
'ԯ' => 'Ԯ',
'ա' => 'Ա',
'բ' => 'Բ',
'գ' => 'Գ',
'դ' => 'Դ',
'ե' => 'Ե',
'զ' => 'Զ',
'է' => 'Է',
'ը' => 'Ը',
'թ' => 'Թ',
'ժ' => 'Ժ',
'ի' => 'Ի',
'լ' => 'Լ',
'խ' => 'Խ',
'ծ' => 'Ծ',
'կ' => 'Կ',
'հ' => 'Հ',
'ձ' => 'Ձ',
'ղ' => 'Ղ',
'ճ' => 'Ճ',
'մ' => 'Մ',
'յ' => 'Յ',
'ն' => 'Ն',
'շ' => 'Շ',
'ո' => 'Ո',
'չ' => 'Չ',
'պ' => 'Պ',
'ջ' => 'Ջ',
'ռ' => 'Ռ',
'ս' => 'Ս',
'վ' => 'Վ',
'տ' => 'Տ',
'ր' => 'Ր',
'ց' => 'Ց',
'ւ' => 'Ւ',
'փ' => 'Փ',
'ք' => 'Ք',
'օ' => 'Օ',
'ֆ' => 'Ֆ',
'ა' => 'Ა',
'ბ' => 'Ბ',
'გ' => 'Გ',
'დ' => 'Დ',
'ე' => 'Ე',
'ვ' => 'Ვ',
'ზ' => 'Ზ',
'თ' => 'Თ',
'ი' => 'Ი',
'კ' => 'Კ',
'ლ' => 'Ლ',
'მ' => 'Მ',
'ნ' => 'Ნ',
'ო' => 'Ო',
'პ' => 'Პ',
'ჟ' => 'Ჟ',
'რ' => 'Რ',
'ს' => 'Ს',
'ტ' => 'Ტ',
'უ' => 'Უ',
'ფ' => 'Ფ',
'ქ' => 'Ქ',
'ღ' => 'Ღ',
'ყ' => 'Ყ',
'შ' => 'Შ',
'ჩ' => 'Ჩ',
'ც' => 'Ც',
'ძ' => 'Ძ',
'წ' => 'Წ',
'ჭ' => 'Ჭ',
'ხ' => 'Ხ',
'ჯ' => 'Ჯ',
'ჰ' => 'Ჰ',
'ჱ' => 'Ჱ',
'ჲ' => 'Ჲ',
'ჳ' => 'Ჳ',
'ჴ' => 'Ჴ',
'ჵ' => 'Ჵ',
'ჶ' => 'Ჶ',
'ჷ' => 'Ჷ',
'ჸ' => 'Ჸ',
'ჹ' => 'Ჹ',
'ჺ' => 'Ჺ',
'ჽ' => 'Ჽ',
'ჾ' => 'Ჾ',
'ჿ' => 'Ჿ',
'ᏸ' => 'Ᏸ',
'ᏹ' => 'Ᏹ',
'ᏺ' => 'Ᏺ',
'ᏻ' => 'Ᏻ',
'ᏼ' => 'Ᏼ',
'ᏽ' => 'Ᏽ',
'ᲀ' => 'В',
'ᲁ' => 'Д',
'ᲂ' => 'О',
'ᲃ' => 'С',
'ᲄ' => 'Т',
'ᲅ' => 'Т',
'ᲆ' => 'Ъ',
'ᲇ' => 'Ѣ',
'ᲈ' => 'Ꙋ',
'ᵹ' => 'Ᵹ',
'ᵽ' => 'Ᵽ',
'ᶎ' => 'Ᶎ',
'ḁ' => 'Ḁ',
'ḃ' => 'Ḃ',
'ḅ' => 'Ḅ',
'ḇ' => 'Ḇ',
'ḉ' => 'Ḉ',
'ḋ' => 'Ḋ',
'ḍ' => 'Ḍ',
'ḏ' => 'Ḏ',
'ḑ' => 'Ḑ',
'ḓ' => 'Ḓ',
'ḕ' => 'Ḕ',
'ḗ' => 'Ḗ',
'ḙ' => 'Ḙ',
'ḛ' => 'Ḛ',
'ḝ' => 'Ḝ',
'ḟ' => 'Ḟ',
'ḡ' => 'Ḡ',
'ḣ' => 'Ḣ',
'ḥ' => 'Ḥ',
'ḧ' => 'Ḧ',
'ḩ' => 'Ḩ',
'ḫ' => 'Ḫ',
'ḭ' => 'Ḭ',
'ḯ' => 'Ḯ',
'ḱ' => 'Ḱ',
'ḳ' => 'Ḳ',
'ḵ' => 'Ḵ',
'ḷ' => 'Ḷ',
'ḹ' => 'Ḹ',
'ḻ' => 'Ḻ',
'ḽ' => 'Ḽ',
'ḿ' => 'Ḿ',
'ṁ' => 'Ṁ',
'ṃ' => 'Ṃ',
'ṅ' => 'Ṅ',
'ṇ' => 'Ṇ',
'ṉ' => 'Ṉ',
'ṋ' => 'Ṋ',
'ṍ' => 'Ṍ',
'ṏ' => 'Ṏ',
'ṑ' => 'Ṑ',
'ṓ' => 'Ṓ',
'ṕ' => 'Ṕ',
'ṗ' => 'Ṗ',
'ṙ' => 'Ṙ',
'ṛ' => 'Ṛ',
'ṝ' => 'Ṝ',
'ṟ' => 'Ṟ',
'ṡ' => 'Ṡ',
'ṣ' => 'Ṣ',
'ṥ' => 'Ṥ',
'ṧ' => 'Ṧ',
'ṩ' => 'Ṩ',
'ṫ' => 'Ṫ',
'ṭ' => 'Ṭ',
'ṯ' => 'Ṯ',
'ṱ' => 'Ṱ',
'ṳ' => 'Ṳ',
'ṵ' => 'Ṵ',
'ṷ' => 'Ṷ',
'ṹ' => 'Ṹ',
'ṻ' => 'Ṻ',
'ṽ' => 'Ṽ',
'ṿ' => 'Ṿ',
'ẁ' => 'Ẁ',
'ẃ' => 'Ẃ',
'ẅ' => 'Ẅ',
'ẇ' => 'Ẇ',
'ẉ' => 'Ẉ',
'ẋ' => 'Ẋ',
'ẍ' => 'Ẍ',
'ẏ' => 'Ẏ',
'ẑ' => 'Ẑ',
'ẓ' => 'Ẓ',
'ẕ' => 'Ẕ',
'ẛ' => 'Ṡ',
'ạ' => 'Ạ',
'ả' => 'Ả',
'ấ' => 'Ấ',
'ầ' => 'Ầ',
'ẩ' => 'Ẩ',
'ẫ' => 'Ẫ',
'ậ' => 'Ậ',
'ắ' => 'Ắ',
'ằ' => 'Ằ',
'ẳ' => 'Ẳ',
'ẵ' => 'Ẵ',
'ặ' => 'Ặ',
'ẹ' => 'Ẹ',
'ẻ' => 'Ẻ',
'ẽ' => 'Ẽ',
'ế' => 'Ế',
'ề' => 'Ề',
'ể' => 'Ể',
'ễ' => 'Ễ',
'ệ' => 'Ệ',
'ỉ' => 'Ỉ',
'ị' => 'Ị',
'ọ' => 'Ọ',
'ỏ' => 'Ỏ',
'ố' => 'Ố',
'ồ' => 'Ồ',
'ổ' => 'Ổ',
'ỗ' => 'Ỗ',
'ộ' => 'Ộ',
'ớ' => 'Ớ',
'ờ' => 'Ờ',
'ở' => 'Ở',
'ỡ' => 'Ỡ',
'ợ' => 'Ợ',
'ụ' => 'Ụ',
'ủ' => 'Ủ',
'ứ' => 'Ứ',
'ừ' => 'Ừ',
'ử' => 'Ử',
'ữ' => 'Ữ',
'ự' => 'Ự',
'ỳ' => 'Ỳ',
'ỵ' => 'Ỵ',
'ỷ' => 'Ỷ',
'ỹ' => 'Ỹ',
'ỻ' => 'Ỻ',
'ỽ' => 'Ỽ',
'ỿ' => 'Ỿ',
'ἀ' => 'Ἀ',
'ἁ' => 'Ἁ',
'ἂ' => 'Ἂ',
'ἃ' => 'Ἃ',
'ἄ' => 'Ἄ',
'ἅ' => 'Ἅ',
'ἆ' => 'Ἆ',
'ἇ' => 'Ἇ',
'ἐ' => 'Ἐ',
'ἑ' => 'Ἑ',
'ἒ' => 'Ἒ',
'ἓ' => 'Ἓ',
'ἔ' => 'Ἔ',
'ἕ' => 'Ἕ',
'ἠ' => 'Ἠ',
'ἡ' => 'Ἡ',
'ἢ' => 'Ἢ',
'ἣ' => 'Ἣ',
'ἤ' => 'Ἤ',
'ἥ' => 'Ἥ',
'ἦ' => 'Ἦ',
'ἧ' => 'Ἧ',
'ἰ' => 'Ἰ',
'ἱ' => 'Ἱ',
'ἲ' => 'Ἲ',
'ἳ' => 'Ἳ',
'ἴ' => 'Ἴ',
'ἵ' => 'Ἵ',
'ἶ' => 'Ἶ',
'ἷ' => 'Ἷ',
'ὀ' => 'Ὀ',
'ὁ' => 'Ὁ',
'ὂ' => 'Ὂ',
'ὃ' => 'Ὃ',
'ὄ' => 'Ὄ',
'ὅ' => 'Ὅ',
'ὑ' => 'Ὑ',
'ὓ' => 'Ὓ',
'ὕ' => 'Ὕ',
'ὗ' => 'Ὗ',
'ὠ' => 'Ὠ',
'ὡ' => 'Ὡ',
'ὢ' => 'Ὢ',
'ὣ' => 'Ὣ',
'ὤ' => 'Ὤ',
'ὥ' => 'Ὥ',
'ὦ' => 'Ὦ',
'ὧ' => 'Ὧ',
'ὰ' => 'Ὰ',
'ά' => 'Ά',
'ὲ' => 'Ὲ',
'έ' => 'Έ',
'ὴ' => 'Ὴ',
'ή' => 'Ή',
'ὶ' => 'Ὶ',
'ί' => 'Ί',
'ὸ' => 'Ὸ',
'ό' => 'Ό',
'ὺ' => 'Ὺ',
'ύ' => 'Ύ',
'ὼ' => 'Ὼ',
'ώ' => 'Ώ',
'ᾀ' => 'ἈΙ',
'ᾁ' => 'ἉΙ',
'ᾂ' => 'ἊΙ',
'ᾃ' => 'ἋΙ',
'ᾄ' => 'ἌΙ',
'ᾅ' => 'ἍΙ',
'ᾆ' => 'ἎΙ',
'ᾇ' => 'ἏΙ',
'ᾐ' => 'ἨΙ',
'ᾑ' => 'ἩΙ',
'ᾒ' => 'ἪΙ',
'ᾓ' => 'ἫΙ',
'ᾔ' => 'ἬΙ',
'ᾕ' => 'ἭΙ',
'ᾖ' => 'ἮΙ',
'ᾗ' => 'ἯΙ',
'ᾠ' => 'ὨΙ',
'ᾡ' => 'ὩΙ',
'ᾢ' => 'ὪΙ',
'ᾣ' => 'ὫΙ',
'ᾤ' => 'ὬΙ',
'ᾥ' => 'ὭΙ',
'ᾦ' => 'ὮΙ',
'ᾧ' => 'ὯΙ',
'ᾰ' => 'Ᾰ',
'ᾱ' => 'Ᾱ',
'ᾳ' => 'ΑΙ',
'ι' => 'Ι',
'ῃ' => 'ΗΙ',
'ῐ' => 'Ῐ',
'ῑ' => 'Ῑ',
'ῠ' => 'Ῠ',
'ῡ' => 'Ῡ',
'ῥ' => 'Ῥ',
'ῳ' => 'ΩΙ',
'ⅎ' => 'Ⅎ',
'ⅰ' => 'Ⅰ',
'ⅱ' => 'Ⅱ',
'ⅲ' => 'Ⅲ',
'ⅳ' => 'Ⅳ',
'ⅴ' => 'Ⅴ',
'ⅵ' => 'Ⅵ',
'ⅶ' => 'Ⅶ',
'ⅷ' => 'Ⅷ',
'ⅸ' => 'Ⅸ',
'ⅹ' => 'Ⅹ',
'ⅺ' => 'Ⅺ',
'ⅻ' => 'Ⅻ',
'ⅼ' => 'Ⅼ',
'ⅽ' => 'Ⅽ',
'ⅾ' => 'Ⅾ',
'ⅿ' => 'Ⅿ',
'ↄ' => 'Ↄ',
'ⓐ' => 'Ⓐ',
'ⓑ' => 'Ⓑ',
'ⓒ' => 'Ⓒ',
'ⓓ' => 'Ⓓ',
'ⓔ' => 'Ⓔ',
'ⓕ' => 'Ⓕ',
'ⓖ' => 'Ⓖ',
'ⓗ' => 'Ⓗ',
'ⓘ' => 'Ⓘ',
'ⓙ' => 'Ⓙ',
'ⓚ' => 'Ⓚ',
'ⓛ' => 'Ⓛ',
'ⓜ' => 'Ⓜ',
'ⓝ' => 'Ⓝ',
'ⓞ' => 'Ⓞ',
'ⓟ' => 'Ⓟ',
'ⓠ' => 'Ⓠ',
'ⓡ' => 'Ⓡ',
'ⓢ' => 'Ⓢ',
'ⓣ' => 'Ⓣ',
'ⓤ' => 'Ⓤ',
'ⓥ' => 'Ⓥ',
'ⓦ' => 'Ⓦ',
'ⓧ' => 'Ⓧ',
'ⓨ' => 'Ⓨ',
'ⓩ' => 'Ⓩ',
'ⰰ' => 'Ⰰ',
'ⰱ' => 'Ⰱ',
'ⰲ' => 'Ⰲ',
'ⰳ' => 'Ⰳ',
'ⰴ' => 'Ⰴ',
'ⰵ' => 'Ⰵ',
'ⰶ' => 'Ⰶ',
'ⰷ' => 'Ⰷ',
'ⰸ' => 'Ⰸ',
'ⰹ' => 'Ⰹ',
'ⰺ' => 'Ⰺ',
'ⰻ' => 'Ⰻ',
'ⰼ' => 'Ⰼ',
'ⰽ' => 'Ⰽ',
'ⰾ' => 'Ⰾ',
'ⰿ' => 'Ⰿ',
'ⱀ' => 'Ⱀ',
'ⱁ' => 'Ⱁ',
'ⱂ' => 'Ⱂ',
'ⱃ' => 'Ⱃ',
'ⱄ' => 'Ⱄ',
'ⱅ' => 'Ⱅ',
'ⱆ' => 'Ⱆ',
'ⱇ' => 'Ⱇ',
'ⱈ' => 'Ⱈ',
'ⱉ' => 'Ⱉ',
'ⱊ' => 'Ⱊ',
'ⱋ' => 'Ⱋ',
'ⱌ' => 'Ⱌ',
'ⱍ' => 'Ⱍ',
'ⱎ' => 'Ⱎ',
'ⱏ' => 'Ⱏ',
'ⱐ' => 'Ⱐ',
'ⱑ' => 'Ⱑ',
'ⱒ' => 'Ⱒ',
'ⱓ' => 'Ⱓ',
'ⱔ' => 'Ⱔ',
'ⱕ' => 'Ⱕ',
'ⱖ' => 'Ⱖ',
'ⱗ' => 'Ⱗ',
'ⱘ' => 'Ⱘ',
'ⱙ' => 'Ⱙ',
'ⱚ' => 'Ⱚ',
'ⱛ' => 'Ⱛ',
'ⱜ' => 'Ⱜ',
'ⱝ' => 'Ⱝ',
'ⱞ' => 'Ⱞ',
'ⱡ' => 'Ⱡ',
'ⱥ' => 'Ⱥ',
'ⱦ' => 'Ⱦ',
'ⱨ' => 'Ⱨ',
'ⱪ' => 'Ⱪ',
'ⱬ' => 'Ⱬ',
'ⱳ' => 'Ⱳ',
'ⱶ' => 'Ⱶ',
'ⲁ' => 'Ⲁ',
'ⲃ' => 'Ⲃ',
'ⲅ' => 'Ⲅ',
'ⲇ' => 'Ⲇ',
'ⲉ' => 'Ⲉ',
'ⲋ' => 'Ⲋ',
'ⲍ' => 'Ⲍ',
'ⲏ' => 'Ⲏ',
'ⲑ' => 'Ⲑ',
'ⲓ' => 'Ⲓ',
'ⲕ' => 'Ⲕ',
'ⲗ' => 'Ⲗ',
'ⲙ' => 'Ⲙ',
'ⲛ' => 'Ⲛ',
'ⲝ' => 'Ⲝ',
'ⲟ' => 'Ⲟ',
'ⲡ' => 'Ⲡ',
'ⲣ' => 'Ⲣ',
'ⲥ' => 'Ⲥ',
'ⲧ' => 'Ⲧ',
'ⲩ' => 'Ⲩ',
'ⲫ' => 'Ⲫ',
'ⲭ' => 'Ⲭ',
'ⲯ' => 'Ⲯ',
'ⲱ' => 'Ⲱ',
'ⲳ' => 'Ⲳ',
'ⲵ' => 'Ⲵ',
'ⲷ' => 'Ⲷ',
'ⲹ' => 'Ⲹ',
'ⲻ' => 'Ⲻ',
'ⲽ' => 'Ⲽ',
'ⲿ' => 'Ⲿ',
'ⳁ' => 'Ⳁ',
'ⳃ' => 'Ⳃ',
'ⳅ' => 'Ⳅ',
'ⳇ' => 'Ⳇ',
'ⳉ' => 'Ⳉ',
'ⳋ' => 'Ⳋ',
'ⳍ' => 'Ⳍ',
'ⳏ' => 'Ⳏ',
'ⳑ' => 'Ⳑ',
'ⳓ' => 'Ⳓ',
'ⳕ' => 'Ⳕ',
'ⳗ' => 'Ⳗ',
'ⳙ' => 'Ⳙ',
'ⳛ' => 'Ⳛ',
'ⳝ' => 'Ⳝ',
'ⳟ' => 'Ⳟ',
'ⳡ' => 'Ⳡ',
'ⳣ' => 'Ⳣ',
'ⳬ' => 'Ⳬ',
'ⳮ' => 'Ⳮ',
'ⳳ' => 'Ⳳ',
'ⴀ' => 'Ⴀ',
'ⴁ' => 'Ⴁ',
'ⴂ' => 'Ⴂ',
'ⴃ' => 'Ⴃ',
'ⴄ' => 'Ⴄ',
'ⴅ' => 'Ⴅ',
'ⴆ' => 'Ⴆ',
'ⴇ' => 'Ⴇ',
'ⴈ' => 'Ⴈ',
'ⴉ' => 'Ⴉ',
'ⴊ' => 'Ⴊ',
'ⴋ' => 'Ⴋ',
'ⴌ' => 'Ⴌ',
'ⴍ' => 'Ⴍ',
'ⴎ' => 'Ⴎ',
'ⴏ' => 'Ⴏ',
'ⴐ' => 'Ⴐ',
'ⴑ' => 'Ⴑ',
'ⴒ' => 'Ⴒ',
'ⴓ' => 'Ⴓ',
'ⴔ' => 'Ⴔ',
'ⴕ' => 'Ⴕ',
'ⴖ' => 'Ⴖ',
'ⴗ' => 'Ⴗ',
'ⴘ' => 'Ⴘ',
'ⴙ' => 'Ⴙ',
'ⴚ' => 'Ⴚ',
'ⴛ' => 'Ⴛ',
'ⴜ' => 'Ⴜ',
'ⴝ' => 'Ⴝ',
'ⴞ' => 'Ⴞ',
'ⴟ' => 'Ⴟ',
'ⴠ' => 'Ⴠ',
'ⴡ' => 'Ⴡ',
'ⴢ' => 'Ⴢ',
'ⴣ' => 'Ⴣ',
'ⴤ' => 'Ⴤ',
'ⴥ' => 'Ⴥ',
'ⴧ' => 'Ⴧ',
'ⴭ' => 'Ⴭ',
'ꙁ' => 'Ꙁ',
'ꙃ' => 'Ꙃ',
'ꙅ' => 'Ꙅ',
'ꙇ' => 'Ꙇ',
'ꙉ' => 'Ꙉ',
'ꙋ' => 'Ꙋ',
'ꙍ' => 'Ꙍ',
'ꙏ' => 'Ꙏ',
'ꙑ' => 'Ꙑ',
'ꙓ' => 'Ꙓ',
'ꙕ' => 'Ꙕ',
'ꙗ' => 'Ꙗ',
'ꙙ' => 'Ꙙ',
'ꙛ' => 'Ꙛ',
'ꙝ' => 'Ꙝ',
'ꙟ' => 'Ꙟ',
'ꙡ' => 'Ꙡ',
'ꙣ' => 'Ꙣ',
'ꙥ' => 'Ꙥ',
'ꙧ' => 'Ꙧ',
'ꙩ' => 'Ꙩ',
'ꙫ' => 'Ꙫ',
'ꙭ' => 'Ꙭ',
'ꚁ' => 'Ꚁ',
'ꚃ' => 'Ꚃ',
'ꚅ' => 'Ꚅ',
'ꚇ' => 'Ꚇ',
'ꚉ' => 'Ꚉ',
'ꚋ' => 'Ꚋ',
'ꚍ' => 'Ꚍ',
'ꚏ' => 'Ꚏ',
'ꚑ' => 'Ꚑ',
'ꚓ' => 'Ꚓ',
'ꚕ' => 'Ꚕ',
'ꚗ' => 'Ꚗ',
'ꚙ' => 'Ꚙ',
'ꚛ' => 'Ꚛ',
'ꜣ' => 'Ꜣ',
'ꜥ' => 'Ꜥ',
'ꜧ' => 'Ꜧ',
'ꜩ' => 'Ꜩ',
'ꜫ' => 'Ꜫ',
'ꜭ' => 'Ꜭ',
'ꜯ' => 'Ꜯ',
'ꜳ' => 'Ꜳ',
'ꜵ' => 'Ꜵ',
'ꜷ' => 'Ꜷ',
'ꜹ' => 'Ꜹ',
'ꜻ' => 'Ꜻ',
'ꜽ' => 'Ꜽ',
'ꜿ' => 'Ꜿ',
'ꝁ' => 'Ꝁ',
'ꝃ' => 'Ꝃ',
'ꝅ' => 'Ꝅ',
'ꝇ' => 'Ꝇ',
'ꝉ' => 'Ꝉ',
'ꝋ' => 'Ꝋ',
'ꝍ' => 'Ꝍ',
'ꝏ' => 'Ꝏ',
'ꝑ' => 'Ꝑ',
'ꝓ' => 'Ꝓ',
'ꝕ' => 'Ꝕ',
'ꝗ' => 'Ꝗ',
'ꝙ' => 'Ꝙ',
'ꝛ' => 'Ꝛ',
'ꝝ' => 'Ꝝ',
'ꝟ' => 'Ꝟ',
'ꝡ' => 'Ꝡ',
'ꝣ' => 'Ꝣ',
'ꝥ' => 'Ꝥ',
'ꝧ' => 'Ꝧ',
'ꝩ' => 'Ꝩ',
'ꝫ' => 'Ꝫ',
'ꝭ' => 'Ꝭ',
'ꝯ' => 'Ꝯ',
'ꝺ' => 'Ꝺ',
'ꝼ' => 'Ꝼ',
'ꝿ' => 'Ꝿ',
'ꞁ' => 'Ꞁ',
'ꞃ' => 'Ꞃ',
'ꞅ' => 'Ꞅ',
'ꞇ' => 'Ꞇ',
'ꞌ' => 'Ꞌ',
'ꞑ' => 'Ꞑ',
'ꞓ' => 'Ꞓ',
'ꞔ' => 'Ꞔ',
'ꞗ' => 'Ꞗ',
'ꞙ' => 'Ꞙ',
'ꞛ' => 'Ꞛ',
'ꞝ' => 'Ꞝ',
'ꞟ' => 'Ꞟ',
'ꞡ' => 'Ꞡ',
'ꞣ' => 'Ꞣ',
'ꞥ' => 'Ꞥ',
'ꞧ' => 'Ꞧ',
'ꞩ' => 'Ꞩ',
'ꞵ' => 'Ꞵ',
'ꞷ' => 'Ꞷ',
'ꞹ' => 'Ꞹ',
'ꞻ' => 'Ꞻ',
'ꞽ' => 'Ꞽ',
'ꞿ' => 'Ꞿ',
'ꟃ' => 'Ꟃ',
'ꟈ' => 'Ꟈ',
'ꟊ' => 'Ꟊ',
'ꟶ' => 'Ꟶ',
'ꭓ' => 'Ꭓ',
'ꭰ' => 'Ꭰ',
'ꭱ' => 'Ꭱ',
'ꭲ' => 'Ꭲ',
'ꭳ' => 'Ꭳ',
'ꭴ' => 'Ꭴ',
'ꭵ' => 'Ꭵ',
'ꭶ' => 'Ꭶ',
'ꭷ' => 'Ꭷ',
'ꭸ' => 'Ꭸ',
'ꭹ' => 'Ꭹ',
'ꭺ' => 'Ꭺ',
'ꭻ' => 'Ꭻ',
'ꭼ' => 'Ꭼ',
'ꭽ' => 'Ꭽ',
'ꭾ' => 'Ꭾ',
'ꭿ' => 'Ꭿ',
'ꮀ' => 'Ꮀ',
'ꮁ' => 'Ꮁ',
'ꮂ' => 'Ꮂ',
'ꮃ' => 'Ꮃ',
'ꮄ' => 'Ꮄ',
'ꮅ' => 'Ꮅ',
'ꮆ' => 'Ꮆ',
'ꮇ' => 'Ꮇ',
'ꮈ' => 'Ꮈ',
'ꮉ' => 'Ꮉ',
'ꮊ' => 'Ꮊ',
'ꮋ' => 'Ꮋ',
'ꮌ' => 'Ꮌ',
'ꮍ' => 'Ꮍ',
'ꮎ' => 'Ꮎ',
'ꮏ' => 'Ꮏ',
'ꮐ' => 'Ꮐ',
'ꮑ' => 'Ꮑ',
'ꮒ' => 'Ꮒ',
'ꮓ' => 'Ꮓ',
'ꮔ' => 'Ꮔ',
'ꮕ' => 'Ꮕ',
'ꮖ' => 'Ꮖ',
'ꮗ' => 'Ꮗ',
'ꮘ' => 'Ꮘ',
'ꮙ' => 'Ꮙ',
'ꮚ' => 'Ꮚ',
'ꮛ' => 'Ꮛ',
'ꮜ' => 'Ꮜ',
'ꮝ' => 'Ꮝ',
'ꮞ' => 'Ꮞ',
'ꮟ' => 'Ꮟ',
'ꮠ' => 'Ꮠ',
'ꮡ' => 'Ꮡ',
'ꮢ' => 'Ꮢ',
'ꮣ' => 'Ꮣ',
'ꮤ' => 'Ꮤ',
'ꮥ' => 'Ꮥ',
'ꮦ' => 'Ꮦ',
'ꮧ' => 'Ꮧ',
'ꮨ' => 'Ꮨ',
'ꮩ' => 'Ꮩ',
'ꮪ' => 'Ꮪ',
'ꮫ' => 'Ꮫ',
'ꮬ' => 'Ꮬ',
'ꮭ' => 'Ꮭ',
'ꮮ' => 'Ꮮ',
'ꮯ' => 'Ꮯ',
'ꮰ' => 'Ꮰ',
'ꮱ' => 'Ꮱ',
'ꮲ' => 'Ꮲ',
'ꮳ' => 'Ꮳ',
'ꮴ' => 'Ꮴ',
'ꮵ' => 'Ꮵ',
'ꮶ' => 'Ꮶ',
'ꮷ' => 'Ꮷ',
'ꮸ' => 'Ꮸ',
'ꮹ' => 'Ꮹ',
'ꮺ' => 'Ꮺ',
'ꮻ' => 'Ꮻ',
'ꮼ' => 'Ꮼ',
'ꮽ' => 'Ꮽ',
'ꮾ' => 'Ꮾ',
'ꮿ' => 'Ꮿ',
'ａ' => 'Ａ',
'ｂ' => 'Ｂ',
'ｃ' => 'Ｃ',
'ｄ' => 'Ｄ',
'ｅ' => 'Ｅ',
'ｆ' => 'Ｆ',
'ｇ' => 'Ｇ',
'ｈ' => 'Ｈ',
'ｉ' => 'Ｉ',
'ｊ' => 'Ｊ',
'ｋ' => 'Ｋ',
'ｌ' => 'Ｌ',
'ｍ' => 'Ｍ',
'ｎ' => 'Ｎ',
'ｏ' => 'Ｏ',
'ｐ' => 'Ｐ',
'ｑ' => 'Ｑ',
'ｒ' => 'Ｒ',
'ｓ' => 'Ｓ',
'ｔ' => 'Ｔ',
'ｕ' => 'Ｕ',
'ｖ' => 'Ｖ',
'ｗ' => 'Ｗ',
'ｘ' => 'Ｘ',
'ｙ' => 'Ｙ',
'ｚ' => 'Ｚ',
'𐐨' => '𐐀',
'𐐩' => '𐐁',
'𐐪' => '𐐂',
'𐐫' => '𐐃',
'𐐬' => '𐐄',
'𐐭' => '𐐅',
'𐐮' => '𐐆',
'𐐯' => '𐐇',
'𐐰' => '𐐈',
'𐐱' => '𐐉',
'𐐲' => '𐐊',
'𐐳' => '𐐋',
'𐐴' => '𐐌',
'𐐵' => '𐐍',
'𐐶' => '𐐎',
'𐐷' => '𐐏',
'𐐸' => '𐐐',
'𐐹' => '𐐑',
'𐐺' => '𐐒',
'𐐻' => '𐐓',
'𐐼' => '𐐔',
'𐐽' => '𐐕',
'𐐾' => '𐐖',
'𐐿' => '𐐗',
'𐑀' => '𐐘',
'𐑁' => '𐐙',
'𐑂' => '𐐚',
'𐑃' => '𐐛',
'𐑄' => '𐐜',
'𐑅' => '𐐝',
'𐑆' => '𐐞',
'𐑇' => '𐐟',
'𐑈' => '𐐠',
'𐑉' => '𐐡',
'𐑊' => '𐐢',
'𐑋' => '𐐣',
'𐑌' => '𐐤',
'𐑍' => '𐐥',
'𐑎' => '𐐦',
'𐑏' => '𐐧',
'𐓘' => '𐒰',
'𐓙' => '𐒱',
'𐓚' => '𐒲',
'𐓛' => '𐒳',
'𐓜' => '𐒴',
'𐓝' => '𐒵',
'𐓞' => '𐒶',
'𐓟' => '𐒷',
'𐓠' => '𐒸',
'𐓡' => '𐒹',
'𐓢' => '𐒺',
'𐓣' => '𐒻',
'𐓤' => '𐒼',
'𐓥' => '𐒽',
'𐓦' => '𐒾',
'𐓧' => '𐒿',
'𐓨' => '𐓀',
'𐓩' => '𐓁',
'𐓪' => '𐓂',
'𐓫' => '𐓃',
'𐓬' => '𐓄',
'𐓭' => '𐓅',
'𐓮' => '𐓆',
'𐓯' => '𐓇',
'𐓰' => '𐓈',
'𐓱' => '𐓉',
'𐓲' => '𐓊',
'𐓳' => '𐓋',
'𐓴' => '𐓌',
'𐓵' => '𐓍',
'𐓶' => '𐓎',
'𐓷' => '𐓏',
'𐓸' => '𐓐',
'𐓹' => '𐓑',
'𐓺' => '𐓒',
'𐓻' => '𐓓',
'𐳀' => '𐲀',
'𐳁' => '𐲁',
'𐳂' => '𐲂',
'𐳃' => '𐲃',
'𐳄' => '𐲄',
'𐳅' => '𐲅',
'𐳆' => '𐲆',
'𐳇' => '𐲇',
'𐳈' => '𐲈',
'𐳉' => '𐲉',
'𐳊' => '𐲊',
'𐳋' => '𐲋',
'𐳌' => '𐲌',
'𐳍' => '𐲍',
'𐳎' => '𐲎',
'𐳏' => '𐲏',
'𐳐' => '𐲐',
'𐳑' => '𐲑',
'𐳒' => '𐲒',
'𐳓' => '𐲓',
'𐳔' => '𐲔',
'𐳕' => '𐲕',
'𐳖' => '𐲖',
'𐳗' => '𐲗',
'𐳘' => '𐲘',
'𐳙' => '𐲙',
'𐳚' => '𐲚',
'𐳛' => '𐲛',
'𐳜' => '𐲜',
'𐳝' => '𐲝',
'𐳞' => '𐲞',
'𐳟' => '𐲟',
'𐳠' => '𐲠',
'𐳡' => '𐲡',
'𐳢' => '𐲢',
'𐳣' => '𐲣',
'𐳤' => '𐲤',
'𐳥' => '𐲥',
'𐳦' => '𐲦',
'𐳧' => '𐲧',
'𐳨' => '𐲨',
'𐳩' => '𐲩',
'𐳪' => '𐲪',
'𐳫' => '𐲫',
'𐳬' => '𐲬',
'𐳭' => '𐲭',
'𐳮' => '𐲮',
'𐳯' => '𐲯',
'𐳰' => '𐲰',
'𐳱' => '𐲱',
'𐳲' => '𐲲',
'𑣀' => '𑢠',
'𑣁' => '𑢡',
'𑣂' => '𑢢',
'𑣃' => '𑢣',
'𑣄' => '𑢤',
'𑣅' => '𑢥',
'𑣆' => '𑢦',
'𑣇' => '𑢧',
'𑣈' => '𑢨',
'𑣉' => '𑢩',
'𑣊' => '𑢪',
'𑣋' => '𑢫',
'𑣌' => '𑢬',
'𑣍' => '𑢭',
'𑣎' => '𑢮',
'𑣏' => '𑢯',
'𑣐' => '𑢰',
'𑣑' => '𑢱',
'𑣒' => '𑢲',
'𑣓' => '𑢳',
'𑣔' => '𑢴',
'𑣕' => '𑢵',
'𑣖' => '𑢶',
'𑣗' => '𑢷',
'𑣘' => '𑢸',
'𑣙' => '𑢹',
'𑣚' => '𑢺',
'𑣛' => '𑢻',
'𑣜' => '𑢼',
'𑣝' => '𑢽',
'𑣞' => '𑢾',
'𑣟' => '𑢿',
'𖹠' => '𖹀',
'𖹡' => '𖹁',
'𖹢' => '𖹂',
'𖹣' => '𖹃',
'𖹤' => '𖹄',
'𖹥' => '𖹅',
'𖹦' => '𖹆',
'𖹧' => '𖹇',
'𖹨' => '𖹈',
'𖹩' => '𖹉',
'𖹪' => '𖹊',
'𖹫' => '𖹋',
'𖹬' => '𖹌',
'𖹭' => '𖹍',
'𖹮' => '𖹎',
'𖹯' => '𖹏',
'𖹰' => '𖹐',
'𖹱' => '𖹑',
'𖹲' => '𖹒',
'𖹳' => '𖹓',
'𖹴' => '𖹔',
'𖹵' => '𖹕',
'𖹶' => '𖹖',
'𖹷' => '𖹗',
'𖹸' => '𖹘',
'𖹹' => '𖹙',
'𖹺' => '𖹚',
'𖹻' => '𖹛',
'𖹼' => '𖹜',
'𖹽' => '𖹝',
'𖹾' => '𖹞',
'𖹿' => '𖹟',
'𞤢' => '𞤀',
'𞤣' => '𞤁',
'𞤤' => '𞤂',
'𞤥' => '𞤃',
'𞤦' => '𞤄',
'𞤧' => '𞤅',
'𞤨' => '𞤆',
'𞤩' => '𞤇',
'𞤪' => '𞤈',
'𞤫' => '𞤉',
'𞤬' => '𞤊',
'𞤭' => '𞤋',
'𞤮' => '𞤌',
'𞤯' => '𞤍',
'𞤰' => '𞤎',
'𞤱' => '𞤏',
'𞤲' => '𞤐',
'𞤳' => '𞤑',
'𞤴' => '𞤒',
'𞤵' => '𞤓',
'𞤶' => '𞤔',
'𞤷' => '𞤕',
'𞤸' => '𞤖',
'𞤹' => '𞤗',
'𞤺' => '𞤘',
'𞤻' => '𞤙',
'𞤼' => '𞤚',
'𞤽' => '𞤛',
'𞤾' => '𞤜',
'𞤿' => '𞤝',
'𞥀' => '𞤞',
'𞥁' => '𞤟',
'𞥂' => '𞤠',
'𞥃' => '𞤡',
'ß' => 'SS',
'ﬀ' => 'FF',
'ﬁ' => 'FI',
'ﬂ' => 'FL',
'ﬃ' => 'FFI',
'ﬄ' => 'FFL',
'ﬅ' => 'ST',
'ﬆ' => 'ST',
'և' => 'ԵՒ',
'ﬓ' => 'ՄՆ',
'ﬔ' => 'ՄԵ',
'ﬕ' => 'ՄԻ',
'ﬖ' => 'ՎՆ',
'ﬗ' => 'ՄԽ',
'ŉ' => 'ʼN',
'ΐ' => 'Ϊ́',
'ΰ' => 'Ϋ́',
'ǰ' => 'J̌',
'ẖ' => 'H̱',
'ẗ' => 'T̈',
'ẘ' => 'W̊',
'ẙ' => 'Y̊',
'ẚ' => 'Aʾ',
'ὐ' => 'Υ̓',
'ὒ' => 'Υ̓̀',
'ὔ' => 'Υ̓́',
'ὖ' => 'Υ̓͂',
'ᾶ' => 'Α͂',
'ῆ' => 'Η͂',
'ῒ' => 'Ϊ̀',
'ΐ' => 'Ϊ́',
'ῖ' => 'Ι͂',
'ῗ' => 'Ϊ͂',
'ῢ' => 'Ϋ̀',
'ΰ' => 'Ϋ́',
'ῤ' => 'Ρ̓',
'ῦ' => 'Υ͂',
'ῧ' => 'Ϋ͂',
'ῶ' => 'Ω͂',
'ᾈ' => 'ἈΙ',
'ᾉ' => 'ἉΙ',
'ᾊ' => 'ἊΙ',
'ᾋ' => 'ἋΙ',
'ᾌ' => 'ἌΙ',
'ᾍ' => 'ἍΙ',
'ᾎ' => 'ἎΙ',
'ᾏ' => 'ἏΙ',
'ᾘ' => 'ἨΙ',
'ᾙ' => 'ἩΙ',
'ᾚ' => 'ἪΙ',
'ᾛ' => 'ἫΙ',
'ᾜ' => 'ἬΙ',
'ᾝ' => 'ἭΙ',
'ᾞ' => 'ἮΙ',
'ᾟ' => 'ἯΙ',
'ᾨ' => 'ὨΙ',
'ᾩ' => 'ὩΙ',
'ᾪ' => 'ὪΙ',
'ᾫ' => 'ὫΙ',
'ᾬ' => 'ὬΙ',
'ᾭ' => 'ὭΙ',
'ᾮ' => 'ὮΙ',
'ᾯ' => 'ὯΙ',
'ᾼ' => 'ΑΙ',
'ῌ' => 'ΗΙ',
'ῼ' => 'ΩΙ',
'ᾲ' => 'ᾺΙ',
'ᾴ' => 'ΆΙ',
'ῂ' => 'ῊΙ',
'ῄ' => 'ΉΙ',
'ῲ' => 'ῺΙ',
'ῴ' => 'ΏΙ',
'ᾷ' => 'Α͂Ι',
'ῇ' => 'Η͂Ι',
'ῷ' => 'Ω͂Ι',
);
<?php



return '/(?<![\x{0027}\x{002E}\x{003A}\x{005E}\x{0060}\x{00A8}\x{00AD}\x{00AF}\x{00B4}\x{00B7}\x{00B8}\x{02B0}-\x{02C1}\x{02C2}-\x{02C5}\x{02C6}-\x{02D1}\x{02D2}-\x{02DF}\x{02E0}-\x{02E4}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EE}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037A}\x{0384}-\x{0385}\x{0387}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0559}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{05F4}\x{0600}-\x{0605}\x{0610}-\x{061A}\x{061C}\x{0640}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DD}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{070F}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07FA}\x{07FD}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0971}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CBF}\x{0CC6}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E46}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EB9}\x{0EBB}-\x{0EBC}\x{0EC6}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{10FC}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17D7}\x{17DD}\x{180B}-\x{180D}\x{180E}\x{1843}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AA7}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1C78}-\x{1C7D}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1D2C}-\x{1D6A}\x{1D78}\x{1D9B}-\x{1DBF}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{200B}-\x{200F}\x{2018}\x{2019}\x{2024}\x{2027}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{2066}-\x{206F}\x{2071}\x{207F}\x{2090}-\x{209C}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2C7C}-\x{2C7D}\x{2CEF}-\x{2CF1}\x{2D6F}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E2F}\x{3005}\x{302A}-\x{302D}\x{3031}-\x{3035}\x{303B}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{309D}-\x{309E}\x{30FC}-\x{30FE}\x{A015}\x{A4F8}-\x{A4FD}\x{A60C}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A67F}\x{A69C}-\x{A69D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A770}\x{A788}\x{A789}-\x{A78A}\x{A7F8}-\x{A7F9}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}\x{A9CF}\x{A9E5}\x{A9E6}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA70}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AADD}\x{AAEC}-\x{AAED}\x{AAF3}-\x{AAF4}\x{AAF6}\x{AB5B}\x{AB5C}-\x{AB5F}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FBB2}-\x{FBC1}\x{FE00}-\x{FE0F}\x{FE13}\x{FE20}-\x{FE2F}\x{FE52}\x{FE55}\x{FEFF}\x{FF07}\x{FF0E}\x{FF1A}\x{FF3E}\x{FF40}\x{FF70}\x{FF9E}-\x{FF9F}\x{FFE3}\x{FFF9}-\x{FFFB}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{110BD}\x{110CD}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16B40}-\x{16B43}\x{16F8F}-\x{16F92}\x{16F93}-\x{16F9F}\x{16FE0}-\x{16FE1}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{1F3FB}-\x{1F3FF}\x{E0001}\x{E0020}-\x{E007F}\x{E0100}-\x{E01EF}])(\pL)(\pL*+)/u';
<?php










namespace Symfony\Component\Process;







class ExecutableFinder
{
private $suffixes = ['.exe', '.bat', '.cmd', '.com'];




public function setSuffixes(array $suffixes)
{
$this->suffixes = $suffixes;
}






public function addSuffix($suffix)
{
$this->suffixes[] = $suffix;
}










public function find($name, $default = null, array $extraDirs = [])
{
if (ini_get('open_basedir')) {
$searchPath = array_merge(explode(\PATH_SEPARATOR, ini_get('open_basedir')), $extraDirs);
$dirs = [];
foreach ($searchPath as $path) {

 if (@is_dir($path)) {
$dirs[] = $path;
} else {
if (basename($path) == $name && @is_executable($path)) {
return $path;
}
}
}
} else {
$dirs = array_merge(
explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
$extraDirs
);
}

$suffixes = [''];
if ('\\' === \DIRECTORY_SEPARATOR) {
$pathExt = getenv('PATHEXT');
$suffixes = array_merge($pathExt ? explode(\PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes);
}
foreach ($suffixes as $suffix) {
foreach ($dirs as $dir) {
if (@is_file($file = $dir.\DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === \DIRECTORY_SEPARATOR || @is_executable($file))) {
return $file;
}
}
}

return $default;
}
}
<?php










namespace Symfony\Component\Process;

use Symfony\Component\Process\Exception\InvalidArgumentException;
use Symfony\Component\Process\Exception\LogicException;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Exception\ProcessSignaledException;
use Symfony\Component\Process\Exception\ProcessTimedOutException;
use Symfony\Component\Process\Exception\RuntimeException;
use Symfony\Component\Process\Pipes\PipesInterface;
use Symfony\Component\Process\Pipes\UnixPipes;
use Symfony\Component\Process\Pipes\WindowsPipes;








class Process implements \IteratorAggregate
{
public const ERR = 'err';
public const OUT = 'out';

public const STATUS_READY = 'ready';
public const STATUS_STARTED = 'started';
public const STATUS_TERMINATED = 'terminated';

public const STDIN = 0;
public const STDOUT = 1;
public const STDERR = 2;


 public const TIMEOUT_PRECISION = 0.2;

public const ITER_NON_BLOCKING = 1; 
 public const ITER_KEEP_OUTPUT = 2; 
 public const ITER_SKIP_OUT = 4; 
 public const ITER_SKIP_ERR = 8; 

private $callback;
private $hasCallback = false;
private $commandline;
private $cwd;
private $env;
private $input;
private $starttime;
private $lastOutputTime;
private $timeout;
private $idleTimeout;
private $exitcode;
private $fallbackStatus = [];
private $processInformation;
private $outputDisabled = false;
private $stdout;
private $stderr;
private $process;
private $status = self::STATUS_READY;
private $incrementalOutputOffset = 0;
private $incrementalErrorOutputOffset = 0;
private $tty = false;
private $pty;

private $useFileHandles = false;

private $processPipes;

private $latestSignal;

private static $sigchild;






public static $exitCodes = [
0 => 'OK',
1 => 'General error',
2 => 'Misuse of shell builtins',

126 => 'Invoked command cannot execute',
127 => 'Command not found',
128 => 'Invalid exit argument',


 129 => 'Hangup',
130 => 'Interrupt',
131 => 'Quit and dump core',
132 => 'Illegal instruction',
133 => 'Trace/breakpoint trap',
134 => 'Process aborted',
135 => 'Bus error: "access to undefined portion of memory object"',
136 => 'Floating point exception: "erroneous arithmetic operation"',
137 => 'Kill (terminate immediately)',
138 => 'User-defined 1',
139 => 'Segmentation violation',
140 => 'User-defined 2',
141 => 'Write to pipe with no one reading',
142 => 'Signal raised by alarm',
143 => 'Termination (request to terminate)',

 145 => 'Child process terminated, stopped (or continued*)',
146 => 'Continue if stopped',
147 => 'Stop executing temporarily',
148 => 'Terminal stop signal',
149 => 'Background process attempting to read from tty ("in")',
150 => 'Background process attempting to write to tty ("out")',
151 => 'Urgent data available on socket',
152 => 'CPU time limit exceeded',
153 => 'File size limit exceeded',
154 => 'Signal raised by timer counting virtual time: "virtual timer expired"',
155 => 'Profiling timer expired',

 157 => 'Pollable event',

 159 => 'Bad syscall',
];










public function __construct($command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
{
if (!\function_exists('proc_open')) {
throw new LogicException('The Process class relies on proc_open, which is not available on your PHP installation.');
}

if (!\is_array($command)) {
@trigger_error(sprintf('Passing a command as string when creating a "%s" instance is deprecated since Symfony 4.2, pass it as an array of its arguments instead, or use the "Process::fromShellCommandline()" constructor if you need features provided by the shell.', __CLASS__), \E_USER_DEPRECATED);
}

$this->commandline = $command;
$this->cwd = $cwd;


 
 
 
 if (null === $this->cwd && (\defined('ZEND_THREAD_SAFE') || '\\' === \DIRECTORY_SEPARATOR)) {
$this->cwd = getcwd();
}
if (null !== $env) {
$this->setEnv($env);
}

$this->setInput($input);
$this->setTimeout($timeout);
$this->useFileHandles = '\\' === \DIRECTORY_SEPARATOR;
$this->pty = false;
}
























public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
{
$process = new static([], $cwd, $env, $input, $timeout);
$process->commandline = $command;

return $process;
}




public function __sleep()
{
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
}

public function __wakeup()
{
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
}

public function __destruct()
{
$this->stop(0);
}

public function __clone()
{
$this->resetProcessData();
}
























public function run(callable $callback = null, array $env = []): int
{
$this->start($callback, $env);

return $this->wait();
}













public function mustRun(callable $callback = null, array $env = []): self
{
if (0 !== $this->run($callback, $env)) {
throw new ProcessFailedException($this);
}

return $this;
}




















public function start(callable $callback = null, array $env = [])
{
if ($this->isRunning()) {
throw new RuntimeException('Process is already running.');
}

$this->resetProcessData();
$this->starttime = $this->lastOutputTime = microtime(true);
$this->callback = $this->buildCallback($callback);
$this->hasCallback = null !== $callback;
$descriptors = $this->getDescriptors();

if ($this->env) {
$env += $this->env;
}

$env += $this->getDefaultEnv();

if (\is_array($commandline = $this->commandline)) {
$commandline = implode(' ', array_map([$this, 'escapeArgument'], $commandline));

if ('\\' !== \DIRECTORY_SEPARATOR) {

 $commandline = 'exec '.$commandline;
}
} else {
$commandline = $this->replacePlaceholders($commandline, $env);
}

$options = ['suppress_errors' => true];

if ('\\' === \DIRECTORY_SEPARATOR) {
$options['bypass_shell'] = true;
$commandline = $this->prepareWindowsCommandLine($commandline, $env);
} elseif (!$this->useFileHandles && $this->isSigchildEnabled()) {

 $descriptors[3] = ['pipe', 'w'];


 $commandline = '{ ('.$commandline.') <&3 3<&- 3>/dev/null & } 3<&0;';
$commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code';


 
 $ptsWorkaround = fopen(__FILE__, 'r');
}

$envPairs = [];
foreach ($env as $k => $v) {
if (false !== $v && 'argc' !== $k && 'argv' !== $k) {
$envPairs[] = $k.'='.$v;
}
}

if (!is_dir($this->cwd)) {
throw new RuntimeException(sprintf('The provided cwd "%s" does not exist.', $this->cwd));
}

$this->process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $options);

if (!\is_resource($this->process)) {
throw new RuntimeException('Unable to launch a new process.');
}
$this->status = self::STATUS_STARTED;

if (isset($descriptors[3])) {
$this->fallbackStatus['pid'] = (int) fgets($this->processPipes->pipes[3]);
}

if ($this->tty) {
return;
}

$this->updateStatus(false);
$this->checkTimeout();
}


















public function restart(callable $callback = null, array $env = []): self
{
if ($this->isRunning()) {
throw new RuntimeException('Process is already running.');
}

$process = clone $this;
$process->start($callback, $env);

return $process;
}
















public function wait(callable $callback = null)
{
$this->requireProcessIsStarted(__FUNCTION__);

$this->updateStatus(false);

if (null !== $callback) {
if (!$this->processPipes->haveReadSupport()) {
$this->stop(0);
throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::wait".');
}
$this->callback = $this->buildCallback($callback);
}

do {
$this->checkTimeout();
$running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
$this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
} while ($running);

while ($this->isRunning()) {
$this->checkTimeout();
usleep(1000);
}

if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) {
throw new ProcessSignaledException($this);
}

return $this->exitcode;
}












public function waitUntil(callable $callback): bool
{
$this->requireProcessIsStarted(__FUNCTION__);
$this->updateStatus(false);

if (!$this->processPipes->haveReadSupport()) {
$this->stop(0);
throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::waitUntil".');
}
$callback = $this->buildCallback($callback);

$ready = false;
while (true) {
$this->checkTimeout();
$running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
$output = $this->processPipes->readAndWrite($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);

foreach ($output as $type => $data) {
if (3 !== $type) {
$ready = $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data) || $ready;
} elseif (!isset($this->fallbackStatus['signaled'])) {
$this->fallbackStatus['exitcode'] = (int) $data;
}
}
if ($ready) {
return true;
}
if (!$running) {
return false;
}

usleep(1000);
}
}






public function getPid()
{
return $this->isRunning() ? $this->processInformation['pid'] : null;
}












public function signal($signal)
{
$this->doSignal($signal, true);

return $this;
}









public function disableOutput()
{
if ($this->isRunning()) {
throw new RuntimeException('Disabling output while the process is running is not possible.');
}
if (null !== $this->idleTimeout) {
throw new LogicException('Output can not be disabled while an idle timeout is set.');
}

$this->outputDisabled = true;

return $this;
}








public function enableOutput()
{
if ($this->isRunning()) {
throw new RuntimeException('Enabling output while the process is running is not possible.');
}

$this->outputDisabled = false;

return $this;
}






public function isOutputDisabled()
{
return $this->outputDisabled;
}









public function getOutput()
{
$this->readPipesForOutput(__FUNCTION__);

if (false === $ret = stream_get_contents($this->stdout, -1, 0)) {
return '';
}

return $ret;
}












public function getIncrementalOutput()
{
$this->readPipesForOutput(__FUNCTION__);

$latest = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
$this->incrementalOutputOffset = ftell($this->stdout);

if (false === $latest) {
return '';
}

return $latest;
}












 public function getIterator($flags = 0)
{
$this->readPipesForOutput(__FUNCTION__, false);

$clearOutput = !(self::ITER_KEEP_OUTPUT & $flags);
$blocking = !(self::ITER_NON_BLOCKING & $flags);
$yieldOut = !(self::ITER_SKIP_OUT & $flags);
$yieldErr = !(self::ITER_SKIP_ERR & $flags);

while (null !== $this->callback || ($yieldOut && !feof($this->stdout)) || ($yieldErr && !feof($this->stderr))) {
if ($yieldOut) {
$out = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);

if (isset($out[0])) {
if ($clearOutput) {
$this->clearOutput();
} else {
$this->incrementalOutputOffset = ftell($this->stdout);
}

yield self::OUT => $out;
}
}

if ($yieldErr) {
$err = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);

if (isset($err[0])) {
if ($clearOutput) {
$this->clearErrorOutput();
} else {
$this->incrementalErrorOutputOffset = ftell($this->stderr);
}

yield self::ERR => $err;
}
}

if (!$blocking && !isset($out[0]) && !isset($err[0])) {
yield self::OUT => '';
}

$this->checkTimeout();
$this->readPipesForOutput(__FUNCTION__, $blocking);
}
}






public function clearOutput()
{
ftruncate($this->stdout, 0);
fseek($this->stdout, 0);
$this->incrementalOutputOffset = 0;

return $this;
}









public function getErrorOutput()
{
$this->readPipesForOutput(__FUNCTION__);

if (false === $ret = stream_get_contents($this->stderr, -1, 0)) {
return '';
}

return $ret;
}













public function getIncrementalErrorOutput()
{
$this->readPipesForOutput(__FUNCTION__);

$latest = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
$this->incrementalErrorOutputOffset = ftell($this->stderr);

if (false === $latest) {
return '';
}

return $latest;
}






public function clearErrorOutput()
{
ftruncate($this->stderr, 0);
fseek($this->stderr, 0);
$this->incrementalErrorOutputOffset = 0;

return $this;
}






public function getExitCode()
{
$this->updateStatus(false);

return $this->exitcode;
}












public function getExitCodeText()
{
if (null === $exitcode = $this->getExitCode()) {
return null;
}

return self::$exitCodes[$exitcode] ?? 'Unknown error';
}






public function isSuccessful()
{
return 0 === $this->getExitCode();
}










public function hasBeenSignaled()
{
$this->requireProcessIsTerminated(__FUNCTION__);

return $this->processInformation['signaled'];
}











public function getTermSignal()
{
$this->requireProcessIsTerminated(__FUNCTION__);

if ($this->isSigchildEnabled() && -1 === $this->processInformation['termsig']) {
throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
}

return $this->processInformation['termsig'];
}










public function hasBeenStopped()
{
$this->requireProcessIsTerminated(__FUNCTION__);

return $this->processInformation['stopped'];
}










public function getStopSignal()
{
$this->requireProcessIsTerminated(__FUNCTION__);

return $this->processInformation['stopsig'];
}






public function isRunning()
{
if (self::STATUS_STARTED !== $this->status) {
return false;
}

$this->updateStatus(false);

return $this->processInformation['running'];
}






public function isStarted()
{
return self::STATUS_READY != $this->status;
}






public function isTerminated()
{
$this->updateStatus(false);

return self::STATUS_TERMINATED == $this->status;
}








public function getStatus()
{
$this->updateStatus(false);

return $this->status;
}









public function stop($timeout = 10, $signal = null)
{
$timeoutMicro = microtime(true) + $timeout;
if ($this->isRunning()) {

 $this->doSignal(15, false);
do {
usleep(1000);
} while ($this->isRunning() && microtime(true) < $timeoutMicro);

if ($this->isRunning()) {

 
 $this->doSignal($signal ?: 9, false);
}
}

if ($this->isRunning()) {
if (isset($this->fallbackStatus['pid'])) {
unset($this->fallbackStatus['pid']);

return $this->stop(0, $signal);
}
$this->close();
}

return $this->exitcode;
}






public function addOutput(string $line)
{
$this->lastOutputTime = microtime(true);

fseek($this->stdout, 0, \SEEK_END);
fwrite($this->stdout, $line);
fseek($this->stdout, $this->incrementalOutputOffset);
}






public function addErrorOutput(string $line)
{
$this->lastOutputTime = microtime(true);

fseek($this->stderr, 0, \SEEK_END);
fwrite($this->stderr, $line);
fseek($this->stderr, $this->incrementalErrorOutputOffset);
}






public function getLastOutputTime(): ?float
{
return $this->lastOutputTime;
}






public function getCommandLine()
{
return \is_array($this->commandline) ? implode(' ', array_map([$this, 'escapeArgument'], $this->commandline)) : $this->commandline;
}










public function setCommandLine($commandline)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED);

$this->commandline = $commandline;

return $this;
}






public function getTimeout()
{
return $this->timeout;
}






public function getIdleTimeout()
{
return $this->idleTimeout;
}












public function setTimeout($timeout)
{
$this->timeout = $this->validateTimeout($timeout);

return $this;
}













public function setIdleTimeout($timeout)
{
if (null !== $timeout && $this->outputDisabled) {
throw new LogicException('Idle timeout can not be set while the output is disabled.');
}

$this->idleTimeout = $this->validateTimeout($timeout);

return $this;
}










public function setTty($tty)
{
if ('\\' === \DIRECTORY_SEPARATOR && $tty) {
throw new RuntimeException('TTY mode is not supported on Windows platform.');
}

if ($tty && !self::isTtySupported()) {
throw new RuntimeException('TTY mode requires /dev/tty to be read/writable.');
}

$this->tty = (bool) $tty;

return $this;
}






public function isTty()
{
return $this->tty;
}








public function setPty($bool)
{
$this->pty = (bool) $bool;

return $this;
}






public function isPty()
{
return $this->pty;
}






public function getWorkingDirectory()
{
if (null === $this->cwd) {

 
 return getcwd() ?: null;
}

return $this->cwd;
}








public function setWorkingDirectory($cwd)
{
$this->cwd = $cwd;

return $this;
}






public function getEnv()
{
return $this->env;
}








public function setEnv(array $env)
{
$this->env = $env;

return $this;
}






public function getInput()
{
return $this->input;
}












public function setInput($input)
{
if ($this->isRunning()) {
throw new LogicException('Input can not be set while the process is running.');
}

$this->input = ProcessUtils::validateInput(__METHOD__, $input);

return $this;
}










public function inheritEnvironmentVariables($inheritEnv = true)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.4, env variables are always inherited.', __METHOD__), \E_USER_DEPRECATED);

if (!$inheritEnv) {
throw new InvalidArgumentException('Not inheriting environment variables is not supported.');
}

return $this;
}









public function checkTimeout()
{
if (self::STATUS_STARTED !== $this->status) {
return;
}

if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
$this->stop(0);

throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_GENERAL);
}

if (null !== $this->idleTimeout && $this->idleTimeout < microtime(true) - $this->lastOutputTime) {
$this->stop(0);

throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_IDLE);
}
}




public static function isTtySupported(): bool
{
static $isTtySupported;

if (null === $isTtySupported) {
$isTtySupported = (bool) @proc_open('echo 1 >/dev/null', [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']], $pipes);
}

return $isTtySupported;
}






public static function isPtySupported()
{
static $result;

if (null !== $result) {
return $result;
}

if ('\\' === \DIRECTORY_SEPARATOR) {
return $result = false;
}

return $result = (bool) @proc_open('echo 1 >/dev/null', [['pty'], ['pty'], ['pty']], $pipes);
}




private function getDescriptors(): array
{
if ($this->input instanceof \Iterator) {
$this->input->rewind();
}
if ('\\' === \DIRECTORY_SEPARATOR) {
$this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $this->hasCallback);
} else {
$this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $this->hasCallback);
}

return $this->processPipes->getDescriptors();
}











protected function buildCallback(callable $callback = null)
{
if ($this->outputDisabled) {
return function ($type, $data) use ($callback): bool {
return null !== $callback && $callback($type, $data);
};
}

$out = self::OUT;

return function ($type, $data) use ($callback, $out): bool {
if ($out == $type) {
$this->addOutput($data);
} else {
$this->addErrorOutput($data);
}

return null !== $callback && $callback($type, $data);
};
}






protected function updateStatus($blocking)
{
if (self::STATUS_STARTED !== $this->status) {
return;
}

$this->processInformation = proc_get_status($this->process);
$running = $this->processInformation['running'];

$this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running);

if ($this->fallbackStatus && $this->isSigchildEnabled()) {
$this->processInformation = $this->fallbackStatus + $this->processInformation;
}

if (!$running) {
$this->close();
}
}






protected function isSigchildEnabled()
{
if (null !== self::$sigchild) {
return self::$sigchild;
}

if (!\function_exists('phpinfo')) {
return self::$sigchild = false;
}

ob_start();
phpinfo(\INFO_GENERAL);

return self::$sigchild = str_contains(ob_get_clean(), '--enable-sigchild');
}









private function readPipesForOutput(string $caller, bool $blocking = false)
{
if ($this->outputDisabled) {
throw new LogicException('Output has been disabled.');
}

$this->requireProcessIsStarted($caller);

$this->updateStatus($blocking);
}






private function validateTimeout(?float $timeout): ?float
{
$timeout = (float) $timeout;

if (0.0 === $timeout) {
$timeout = null;
} elseif ($timeout < 0) {
throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
}

return $timeout;
}







private function readPipes(bool $blocking, bool $close)
{
$result = $this->processPipes->readAndWrite($blocking, $close);

$callback = $this->callback;
foreach ($result as $type => $data) {
if (3 !== $type) {
$callback(self::STDOUT === $type ? self::OUT : self::ERR, $data);
} elseif (!isset($this->fallbackStatus['signaled'])) {
$this->fallbackStatus['exitcode'] = (int) $data;
}
}
}






private function close(): int
{
$this->processPipes->close();
if (\is_resource($this->process)) {
proc_close($this->process);
}
$this->exitcode = $this->processInformation['exitcode'];
$this->status = self::STATUS_TERMINATED;

if (-1 === $this->exitcode) {
if ($this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {

 $this->exitcode = 128 + $this->processInformation['termsig'];
} elseif ($this->isSigchildEnabled()) {
$this->processInformation['signaled'] = true;
$this->processInformation['termsig'] = -1;
}
}


 
 
 $this->callback = null;

return $this->exitcode;
}




private function resetProcessData()
{
$this->starttime = null;
$this->callback = null;
$this->exitcode = null;
$this->fallbackStatus = [];
$this->processInformation = null;
$this->stdout = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+');
$this->stderr = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+');
$this->process = null;
$this->latestSignal = null;
$this->status = self::STATUS_READY;
$this->incrementalOutputOffset = 0;
$this->incrementalErrorOutputOffset = 0;
}













private function doSignal(int $signal, bool $throwException): bool
{
if (null === $pid = $this->getPid()) {
if ($throwException) {
throw new LogicException('Can not send signal on a non running process.');
}

return false;
}

if ('\\' === \DIRECTORY_SEPARATOR) {
exec(sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode);
if ($exitCode && $this->isRunning()) {
if ($throwException) {
throw new RuntimeException(sprintf('Unable to kill the process (%s).', implode(' ', $output)));
}

return false;
}
} else {
if (!$this->isSigchildEnabled()) {
$ok = @proc_terminate($this->process, $signal);
} elseif (\function_exists('posix_kill')) {
$ok = @posix_kill($pid, $signal);
} elseif ($ok = proc_open(sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) {
$ok = false === fgets($pipes[2]);
}
if (!$ok) {
if ($throwException) {
throw new RuntimeException(sprintf('Error while sending signal "%s".', $signal));
}

return false;
}
}

$this->latestSignal = $signal;
$this->fallbackStatus['signaled'] = true;
$this->fallbackStatus['exitcode'] = -1;
$this->fallbackStatus['termsig'] = $this->latestSignal;

return true;
}

private function prepareWindowsCommandLine(string $cmd, array &$env): string
{
$uid = uniqid('', true);
$varCount = 0;
$varCache = [];
$cmd = preg_replace_callback(
'/"(?:(
                [^"%!^]*+
                (?:
                    (?: !LF! | "(?:\^[%!^])?+" )
                    [^"%!^]*+
                )++
            ) | [^"]*+ )"/x',
function ($m) use (&$env, &$varCache, &$varCount, $uid) {
if (!isset($m[1])) {
return $m[0];
}
if (isset($varCache[$m[0]])) {
return $varCache[$m[0]];
}
if (str_contains($value = $m[1], "\0")) {
$value = str_replace("\0", '?', $value);
}
if (false === strpbrk($value, "\"%!\n")) {
return '"'.$value.'"';
}

$value = str_replace(['!LF!', '"^!"', '"^%"', '"^^"', '""'], ["\n", '!', '%', '^', '"'], $value);
$value = '"'.preg_replace('/(\\\\*)"/', '$1$1\\"', $value).'"';
$var = $uid.++$varCount;

$env[$var] = $value;

return $varCache[$m[0]] = '!'.$var.'!';
},
$cmd
);

$cmd = 'cmd /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')';
foreach ($this->processPipes->getFiles() as $offset => $filename) {
$cmd .= ' '.$offset.'>"'.$filename.'"';
}

return $cmd;
}






private function requireProcessIsStarted(string $functionName)
{
if (!$this->isStarted()) {
throw new LogicException(sprintf('Process must be started before calling "%s()".', $functionName));
}
}






private function requireProcessIsTerminated(string $functionName)
{
if (!$this->isTerminated()) {
throw new LogicException(sprintf('Process must be terminated before calling "%s()".', $functionName));
}
}




private function escapeArgument(?string $argument): string
{
if ('' === $argument || null === $argument) {
return '""';
}
if ('\\' !== \DIRECTORY_SEPARATOR) {
return "'".str_replace("'", "'\\''", $argument)."'";
}
if (str_contains($argument, "\0")) {
$argument = str_replace("\0", '?', $argument);
}
if (!preg_match('/[\/()%!^"<>&|\s]/', $argument)) {
return $argument;
}
$argument = preg_replace('/(\\\\+)$/', '$1$1', $argument);

return '"'.str_replace(['"', '^', '%', '!', "\n"], ['""', '"^^"', '"^%"', '"^!"', '!LF!'], $argument).'"';
}

private function replacePlaceholders(string $commandline, array $env)
{
return preg_replace_callback('/"\$\{:([_a-zA-Z]++[_a-zA-Z0-9]*+)\}"/', function ($matches) use ($commandline, $env) {
if (!isset($env[$matches[1]]) || false === $env[$matches[1]]) {
throw new InvalidArgumentException(sprintf('Command line is missing a value for parameter "%s": ', $matches[1]).$commandline);
}

return $this->escapeArgument($env[$matches[1]]);
}, $commandline);
}

private function getDefaultEnv(): array
{
$env = getenv();
$env = array_intersect_key($env, $_SERVER) ?: $env;

return $_ENV + $env;
}
}
<?php










namespace Symfony\Component\Process;

use Symfony\Component\Process\Exception\RuntimeException;






class InputStream implements \IteratorAggregate
{

private $onEmpty = null;
private $input = [];
private $open = true;




public function onEmpty(callable $onEmpty = null)
{
$this->onEmpty = $onEmpty;
}







public function write($input)
{
if (null === $input) {
return;
}
if ($this->isClosed()) {
throw new RuntimeException(sprintf('"%s" is closed.', static::class));
}
$this->input[] = ProcessUtils::validateInput(__METHOD__, $input);
}




public function close()
{
$this->open = false;
}




public function isClosed()
{
return !$this->open;
}





 public function getIterator()
{
$this->open = true;

while ($this->open || $this->input) {
if (!$this->input) {
yield '';
continue;
}
$current = array_shift($this->input);

if ($current instanceof \Iterator) {
yield from $current;
} else {
yield $current;
}
if (!$this->input && $this->open && null !== $onEmpty = $this->onEmpty) {
$this->write($onEmpty($this));
}
}
}
}
<?php










namespace Symfony\Component\Process;

use Symfony\Component\Process\Exception\InvalidArgumentException;








class ProcessUtils
{



private function __construct()
{
}











public static function validateInput($caller, $input)
{
if (null !== $input) {
if (\is_resource($input)) {
return $input;
}
if (\is_string($input)) {
return $input;
}
if (is_scalar($input)) {
return (string) $input;
}
if ($input instanceof Process) {
return $input->getIterator($input::ITER_SKIP_ERR);
}
if ($input instanceof \Iterator) {
return $input;
}
if ($input instanceof \Traversable) {
return new \IteratorIterator($input);
}

throw new InvalidArgumentException(sprintf('"%s" only accepts strings, Traversable objects or stream resources.', $caller));
}

return $input;
}
}
<?php










namespace Symfony\Component\Process\Exception;

use Symfony\Component\Process\Process;






class ProcessFailedException extends RuntimeException
{
private $process;

public function __construct(Process $process)
{
if ($process->isSuccessful()) {
throw new InvalidArgumentException('Expected a failed process, but the given process was successful.');
}

$error = sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s",
$process->getCommandLine(),
$process->getExitCode(),
$process->getExitCodeText(),
$process->getWorkingDirectory()
);

if (!$process->isOutputDisabled()) {
$error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s",
$process->getOutput(),
$process->getErrorOutput()
);
}

parent::__construct($error);

$this->process = $process;
}

public function getProcess()
{
return $this->process;
}
}
<?php










namespace Symfony\Component\Process\Exception;

use Symfony\Component\Process\Process;






class ProcessTimedOutException extends RuntimeException
{
public const TYPE_GENERAL = 1;
public const TYPE_IDLE = 2;

private $process;
private $timeoutType;

public function __construct(Process $process, int $timeoutType)
{
$this->process = $process;
$this->timeoutType = $timeoutType;

parent::__construct(sprintf(
'The process "%s" exceeded the timeout of %s seconds.',
$process->getCommandLine(),
$this->getExceededTimeout()
));
}

public function getProcess()
{
return $this->process;
}

public function isGeneralTimeout()
{
return self::TYPE_GENERAL === $this->timeoutType;
}

public function isIdleTimeout()
{
return self::TYPE_IDLE === $this->timeoutType;
}

public function getExceededTimeout()
{
switch ($this->timeoutType) {
case self::TYPE_GENERAL:
return $this->process->getTimeout();

case self::TYPE_IDLE:
return $this->process->getIdleTimeout();

default:
throw new \LogicException(sprintf('Unknown timeout type "%d".', $this->timeoutType));
}
}
}
<?php










namespace Symfony\Component\Process\Exception;






class LogicException extends \LogicException implements ExceptionInterface
{
}
<?php










namespace Symfony\Component\Process\Exception;

use Symfony\Component\Process\Process;






final class ProcessSignaledException extends RuntimeException
{
private $process;

public function __construct(Process $process)
{
$this->process = $process;

parent::__construct(sprintf('The process has been signaled with signal "%s".', $process->getTermSignal()));
}

public function getProcess(): Process
{
return $this->process;
}

public function getSignal(): int
{
return $this->getProcess()->getTermSignal();
}
}
<?php










namespace Symfony\Component\Process\Exception;






class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
<?php










namespace Symfony\Component\Process\Exception;






class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?php










namespace Symfony\Component\Process\Exception;






interface ExceptionInterface extends \Throwable
{
}
<?php










namespace Symfony\Component\Process;







class PhpExecutableFinder
{
private $executableFinder;

public function __construct()
{
$this->executableFinder = new ExecutableFinder();
}








public function find($includeArgs = true)
{
if ($php = getenv('PHP_BINARY')) {
if (!is_executable($php)) {
$command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v';
if ($php = strtok(exec($command.' '.escapeshellarg($php)), \PHP_EOL)) {
if (!is_executable($php)) {
return false;
}
} else {
return false;
}
}

return $php;
}

$args = $this->findArguments();
$args = $includeArgs && $args ? ' '.implode(' ', $args) : '';


 if (\PHP_BINARY && \in_array(\PHP_SAPI, ['cgi-fcgi', 'cli', 'cli-server', 'phpdbg'], true)) {
return \PHP_BINARY.$args;
}

if ($php = getenv('PHP_PATH')) {
if (!@is_executable($php)) {
return false;
}

return $php;
}

if ($php = getenv('PHP_PEAR_PHP_BIN')) {
if (@is_executable($php)) {
return $php;
}
}

if (@is_executable($php = \PHP_BINDIR.('\\' === \DIRECTORY_SEPARATOR ? '\\php.exe' : '/php'))) {
return $php;
}

$dirs = [\PHP_BINDIR];
if ('\\' === \DIRECTORY_SEPARATOR) {
$dirs[] = 'C:\xampp\php\\';
}

return $this->executableFinder->find('php', false, $dirs);
}






public function findArguments()
{
$arguments = [];
if ('phpdbg' === \PHP_SAPI) {
$arguments[] = '-qrr';
}

return $arguments;
}
}
<?php










namespace Symfony\Component\Process\Pipes;

use Symfony\Component\Process\Exception\RuntimeException;
use Symfony\Component\Process\Process;











class WindowsPipes extends AbstractPipes
{
private $files = [];
private $fileHandles = [];
private $lockHandles = [];
private $readBytes = [
Process::STDOUT => 0,
Process::STDERR => 0,
];
private $haveReadSupport;

public function __construct($input, bool $haveReadSupport)
{
$this->haveReadSupport = $haveReadSupport;

if ($this->haveReadSupport) {

 
 
 
 $pipes = [
Process::STDOUT => Process::OUT,
Process::STDERR => Process::ERR,
];
$tmpDir = sys_get_temp_dir();
$lastError = 'unknown reason';
set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; });
for ($i = 0;; ++$i) {
foreach ($pipes as $pipe => $name) {
$file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name);

if (!$h = fopen($file.'.lock', 'w')) {
if (file_exists($file.'.lock')) {
continue 2;
}
restore_error_handler();
throw new RuntimeException('A temporary file could not be opened to write the process output: '.$lastError);
}
if (!flock($h, \LOCK_EX | \LOCK_NB)) {
continue 2;
}
if (isset($this->lockHandles[$pipe])) {
flock($this->lockHandles[$pipe], \LOCK_UN);
fclose($this->lockHandles[$pipe]);
}
$this->lockHandles[$pipe] = $h;

if (!($h = fopen($file, 'w')) || !fclose($h) || !$h = fopen($file, 'r')) {
flock($this->lockHandles[$pipe], \LOCK_UN);
fclose($this->lockHandles[$pipe]);
unset($this->lockHandles[$pipe]);
continue 2;
}
$this->fileHandles[$pipe] = $h;
$this->files[$pipe] = $file;
}
break;
}
restore_error_handler();
}

parent::__construct($input);
}




public function __sleep()
{
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
}

public function __wakeup()
{
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
}

public function __destruct()
{
$this->close();
}




public function getDescriptors(): array
{
if (!$this->haveReadSupport) {
$nullstream = fopen('NUL', 'c');

return [
['pipe', 'r'],
$nullstream,
$nullstream,
];
}


 
 
 return [
['pipe', 'r'],
['file', 'NUL', 'w'],
['file', 'NUL', 'w'],
];
}




public function getFiles(): array
{
return $this->files;
}




public function readAndWrite(bool $blocking, bool $close = false): array
{
$this->unblock();
$w = $this->write();
$read = $r = $e = [];

if ($blocking) {
if ($w) {
@stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6);
} elseif ($this->fileHandles) {
usleep(Process::TIMEOUT_PRECISION * 1E6);
}
}
foreach ($this->fileHandles as $type => $fileHandle) {
$data = stream_get_contents($fileHandle, -1, $this->readBytes[$type]);

if (isset($data[0])) {
$this->readBytes[$type] += \strlen($data);
$read[$type] = $data;
}
if ($close) {
ftruncate($fileHandle, 0);
fclose($fileHandle);
flock($this->lockHandles[$type], \LOCK_UN);
fclose($this->lockHandles[$type]);
unset($this->fileHandles[$type], $this->lockHandles[$type]);
}
}

return $read;
}




public function haveReadSupport(): bool
{
return $this->haveReadSupport;
}




public function areOpen(): bool
{
return $this->pipes && $this->fileHandles;
}




public function close()
{
parent::close();
foreach ($this->fileHandles as $type => $handle) {
ftruncate($handle, 0);
fclose($handle);
flock($this->lockHandles[$type], \LOCK_UN);
fclose($this->lockHandles[$type]);
}
$this->fileHandles = $this->lockHandles = [];
}
}
<?php










namespace Symfony\Component\Process\Pipes;

use Symfony\Component\Process\Process;








class UnixPipes extends AbstractPipes
{
private $ttyMode;
private $ptyMode;
private $haveReadSupport;

public function __construct(?bool $ttyMode, bool $ptyMode, $input, bool $haveReadSupport)
{
$this->ttyMode = $ttyMode;
$this->ptyMode = $ptyMode;
$this->haveReadSupport = $haveReadSupport;

parent::__construct($input);
}




public function __sleep()
{
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
}

public function __wakeup()
{
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
}

public function __destruct()
{
$this->close();
}




public function getDescriptors(): array
{
if (!$this->haveReadSupport) {
$nullstream = fopen('/dev/null', 'c');

return [
['pipe', 'r'],
$nullstream,
$nullstream,
];
}

if ($this->ttyMode) {
return [
['file', '/dev/tty', 'r'],
['file', '/dev/tty', 'w'],
['file', '/dev/tty', 'w'],
];
}

if ($this->ptyMode && Process::isPtySupported()) {
return [
['pty'],
['pty'],
['pty'],
];
}

return [
['pipe', 'r'],
['pipe', 'w'], 
 ['pipe', 'w'], 
 ];
}




public function getFiles(): array
{
return [];
}




public function readAndWrite(bool $blocking, bool $close = false): array
{
$this->unblock();
$w = $this->write();

$read = $e = [];
$r = $this->pipes;
unset($r[0]);


 set_error_handler([$this, 'handleError']);
if (($r || $w) && false === stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
restore_error_handler();

 
 if (!$this->hasSystemCallBeenInterrupted()) {
$this->pipes = [];
}

return $read;
}
restore_error_handler();

foreach ($r as $pipe) {

 
 $read[$type = array_search($pipe, $this->pipes, true)] = '';

do {
$data = @fread($pipe, self::CHUNK_SIZE);
$read[$type] .= $data;
} while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1])));

if (!isset($read[$type][0])) {
unset($read[$type]);
}

if ($close && feof($pipe)) {
fclose($pipe);
unset($this->pipes[$type]);
}
}

return $read;
}




public function haveReadSupport(): bool
{
return $this->haveReadSupport;
}




public function areOpen(): bool
{
return (bool) $this->pipes;
}
}
<?php










namespace Symfony\Component\Process\Pipes;








interface PipesInterface
{
public const CHUNK_SIZE = 16384;




public function getDescriptors(): array;






public function getFiles(): array;









public function readAndWrite(bool $blocking, bool $close = false): array;




public function areOpen(): bool;




public function haveReadSupport(): bool;




public function close();
}
<?php










namespace Symfony\Component\Process\Pipes;

use Symfony\Component\Process\Exception\InvalidArgumentException;






abstract class AbstractPipes implements PipesInterface
{
public $pipes = [];

private $inputBuffer = '';
private $input;
private $blocked = true;
private $lastError;




public function __construct($input)
{
if (\is_resource($input) || $input instanceof \Iterator) {
$this->input = $input;
} elseif (\is_string($input)) {
$this->inputBuffer = $input;
} else {
$this->inputBuffer = (string) $input;
}
}




public function close()
{
foreach ($this->pipes as $pipe) {
fclose($pipe);
}
$this->pipes = [];
}




protected function hasSystemCallBeenInterrupted(): bool
{
$lastError = $this->lastError;
$this->lastError = null;


 return null !== $lastError && false !== stripos($lastError, 'interrupted system call');
}




protected function unblock()
{
if (!$this->blocked) {
return;
}

foreach ($this->pipes as $pipe) {
stream_set_blocking($pipe, 0);
}
if (\is_resource($this->input)) {
stream_set_blocking($this->input, 0);
}

$this->blocked = false;
}






protected function write(): ?array
{
if (!isset($this->pipes[0])) {
return null;
}
$input = $this->input;

if ($input instanceof \Iterator) {
if (!$input->valid()) {
$input = null;
} elseif (\is_resource($input = $input->current())) {
stream_set_blocking($input, 0);
} elseif (!isset($this->inputBuffer[0])) {
if (!\is_string($input)) {
if (!is_scalar($input)) {
throw new InvalidArgumentException(sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', \get_class($this->input), \gettype($input)));
}
$input = (string) $input;
}
$this->inputBuffer = $input;
$this->input->next();
$input = null;
} else {
$input = null;
}
}

$r = $e = [];
$w = [$this->pipes[0]];


 if (false === @stream_select($r, $w, $e, 0, 0)) {
return null;
}

foreach ($w as $stdin) {
if (isset($this->inputBuffer[0])) {
$written = fwrite($stdin, $this->inputBuffer);
$this->inputBuffer = substr($this->inputBuffer, $written);
if (isset($this->inputBuffer[0])) {
return [$this->pipes[0]];
}
}

if ($input) {
for (;;) {
$data = fread($input, self::CHUNK_SIZE);
if (!isset($data[0])) {
break;
}
$written = fwrite($stdin, $data);
$data = substr($data, $written);
if (isset($data[0])) {
$this->inputBuffer = $data;

return [$this->pipes[0]];
}
}
if (feof($input)) {
if ($this->input instanceof \Iterator) {
$this->input->next();
} else {
$this->input = null;
}
}
}
}


 if (!isset($this->inputBuffer[0]) && !($this->input instanceof \Iterator ? $this->input->valid() : $this->input)) {
$this->input = null;
fclose($this->pipes[0]);
unset($this->pipes[0]);
} elseif (!$w) {
return [$this->pipes[0]];
}

return null;
}




public function handleError(int $type, string $msg)
{
$this->lastError = $msg;
}
}
<?php










namespace Symfony\Component\Process;

use Symfony\Component\Process\Exception\LogicException;
use Symfony\Component\Process\Exception\RuntimeException;










class PhpProcess extends Process
{







public function __construct(string $script, string $cwd = null, array $env = null, int $timeout = 60, array $php = null)
{
if (null === $php) {
$executableFinder = new PhpExecutableFinder();
$php = $executableFinder->find(false);
$php = false === $php ? null : array_merge([$php], $executableFinder->findArguments());
}
if ('phpdbg' === \PHP_SAPI) {
$file = tempnam(sys_get_temp_dir(), 'dbg');
file_put_contents($file, $script);
register_shutdown_function('unlink', $file);
$php[] = $file;
$script = null;
}

parent::__construct($php, $cwd, $env, $script, $timeout);
}




public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
{
throw new LogicException(sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class));
}






public function setPhpBinary($php)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the $php argument of the constructor instead.', __METHOD__), \E_USER_DEPRECATED);

$this->setCommandLine($php);
}




public function start(callable $callback = null, array $env = [])
{
if (null === $this->getCommandLine()) {
throw new RuntimeException('Unable to find the PHP executable.');
}

parent::start($callback, $env);
}
}
<?php










namespace Symfony\Component\Finder;







class Gitignore
{





public static function toRegex(string $gitignoreFileContent): string
{
$gitignoreFileContent = preg_replace('~(?<!\\\\)#[^\n\r]*~', '', $gitignoreFileContent);
$gitignoreLines = preg_split('~\r\n?|\n~', $gitignoreFileContent);

$res = self::lineToRegex('');
foreach ($gitignoreLines as $i => $line) {
$line = preg_replace('~(?<!\\\\)[ \t]+$~', '', $line);

if ('!' === substr($line, 0, 1)) {
$line = substr($line, 1);
$isNegative = true;
} else {
$isNegative = false;
}

if ('' !== $line) {
if ($isNegative) {
$res = '(?!'.self::lineToRegex($line).'$)'.$res;
} else {
$res = '(?:'.$res.'|'.self::lineToRegex($line).')';
}
}
}

return '~^(?:'.$res.')~s';
}

private static function lineToRegex(string $gitignoreLine): string
{
if ('' === $gitignoreLine) {
return '$f'; 
 }

$slashPos = strpos($gitignoreLine, '/');
if (false !== $slashPos && \strlen($gitignoreLine) - 1 !== $slashPos) {
if (0 === $slashPos) {
$gitignoreLine = substr($gitignoreLine, 1);
}
$isAbsolute = true;
} else {
$isAbsolute = false;
}

$regex = preg_quote(str_replace('\\', '', $gitignoreLine), '~');
$regex = preg_replace_callback('~\\\\\[((?:\\\\!)?)([^\[\]]*)\\\\\]~', function (array $matches): string {
return '['.('' !== $matches[1] ? '^' : '').str_replace('\\-', '-', $matches[2]).']';
}, $regex);
$regex = preg_replace('~(?:(?:\\\\\*){2,}(/?))+~', '(?:(?:(?!//).(?<!//))+$1)?', $regex);
$regex = preg_replace('~\\\\\*~', '[^/]*', $regex);
$regex = preg_replace('~\\\\\?~', '[^/]', $regex);

return ($isAbsolute ? '' : '(?:[^/]+/)*')
.$regex
.(!str_ends_with($gitignoreLine, '/') ? '(?:$|/)' : '');
}
}
<?php










namespace Symfony\Component\Finder;






class SplFileInfo extends \SplFileInfo
{
private $relativePath;
private $relativePathname;






public function __construct(string $file, string $relativePath, string $relativePathname)
{
parent::__construct($file);
$this->relativePath = $relativePath;
$this->relativePathname = $relativePathname;
}








public function getRelativePath()
{
return $this->relativePath;
}








public function getRelativePathname()
{
return $this->relativePathname;
}

public function getFilenameWithoutExtension(): string
{
$filename = $this->getFilename();

return pathinfo($filename, \PATHINFO_FILENAME);
}








public function getContents()
{
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
$content = file_get_contents($this->getPathname());
restore_error_handler();
if (false === $content) {
throw new \RuntimeException($error);
}

return $content;
}
}
<?php










namespace Symfony\Component\Finder\Comparator;






class DateComparator extends Comparator
{





public function __construct(string $test)
{
if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) {
throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test));
}

try {
$date = new \DateTime($matches[2]);
$target = $date->format('U');
} catch (\Exception $e) {
throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2]));
}

$operator = $matches[1] ?? '==';
if ('since' === $operator || 'after' === $operator) {
$operator = '>';
}

if ('until' === $operator || 'before' === $operator) {
$operator = '<';
}

$this->setOperator($operator);
$this->setTarget($target);
}
}
<?php










namespace Symfony\Component\Finder\Comparator;






class Comparator
{
private $target;
private $operator = '==';






public function getTarget()
{
return $this->target;
}






public function setTarget($target)
{
$this->target = $target;
}






public function getOperator()
{
return $this->operator;
}








public function setOperator($operator)
{
if (!$operator) {
$operator = '==';
}

if (!\in_array($operator, ['>', '<', '>=', '<=', '==', '!='])) {
throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator));
}

$this->operator = $operator;
}








public function test($test)
{
switch ($this->operator) {
case '>':
return $test > $this->target;
case '>=':
return $test >= $this->target;
case '<':
return $test < $this->target;
case '<=':
return $test <= $this->target;
case '!=':
return $test != $this->target;
}

return $test == $this->target;
}
}
<?php










namespace Symfony\Component\Finder\Comparator;






















class NumberComparator extends Comparator
{





public function __construct(?string $test)
{
if (null === $test || !preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) {
throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test ?? 'null'));
}

$target = $matches[2];
if (!is_numeric($target)) {
throw new \InvalidArgumentException(sprintf('Invalid number "%s".', $target));
}
if (isset($matches[3])) {

 switch (strtolower($matches[3])) {
case 'k':
$target *= 1000;
break;
case 'ki':
$target *= 1024;
break;
case 'm':
$target *= 1000000;
break;
case 'mi':
$target *= 1024 * 1024;
break;
case 'g':
$target *= 1000000000;
break;
case 'gi':
$target *= 1024 * 1024 * 1024;
break;
}
}

$this->setTarget($target);
$this->setOperator($matches[1] ?? '==');
}
}
<?php










namespace Symfony\Component\Finder;

use Symfony\Component\Finder\Comparator\DateComparator;
use Symfony\Component\Finder\Comparator\NumberComparator;
use Symfony\Component\Finder\Exception\DirectoryNotFoundException;
use Symfony\Component\Finder\Iterator\CustomFilterIterator;
use Symfony\Component\Finder\Iterator\DateRangeFilterIterator;
use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator;
use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator;
use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
use Symfony\Component\Finder\Iterator\FilenameFilterIterator;
use Symfony\Component\Finder\Iterator\LazyIterator;
use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator;
use Symfony\Component\Finder\Iterator\SortableIterator;














class Finder implements \IteratorAggregate, \Countable
{
public const IGNORE_VCS_FILES = 1;
public const IGNORE_DOT_FILES = 2;
public const IGNORE_VCS_IGNORED_FILES = 4;

private $mode = 0;
private $names = [];
private $notNames = [];
private $exclude = [];
private $filters = [];
private $depths = [];
private $sizes = [];
private $followLinks = false;
private $reverseSorting = false;
private $sort = false;
private $ignore = 0;
private $dirs = [];
private $dates = [];
private $iterators = [];
private $contains = [];
private $notContains = [];
private $paths = [];
private $notPaths = [];
private $ignoreUnreadableDirs = false;

private static $vcsPatterns = ['.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg'];

public function __construct()
{
$this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
}






public static function create()
{
return new static();
}






public function directories()
{
$this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES;

return $this;
}






public function files()
{
$this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;

return $this;
}

















public function depth($levels)
{
foreach ((array) $levels as $level) {
$this->depths[] = new Comparator\NumberComparator($level);
}

return $this;
}




















public function date($dates)
{
foreach ((array) $dates as $date) {
$this->dates[] = new Comparator\DateComparator($date);
}

return $this;
}

















public function name($patterns)
{
$this->names = array_merge($this->names, (array) $patterns);

return $this;
}










public function notName($patterns)
{
$this->notNames = array_merge($this->notNames, (array) $patterns);

return $this;
}
















public function contains($patterns)
{
$this->contains = array_merge($this->contains, (array) $patterns);

return $this;
}
















public function notContains($patterns)
{
$this->notContains = array_merge($this->notContains, (array) $patterns);

return $this;
}


















public function path($patterns)
{
$this->paths = array_merge($this->paths, (array) $patterns);

return $this;
}


















public function notPath($patterns)
{
$this->notPaths = array_merge($this->notPaths, (array) $patterns);

return $this;
}
















public function size($sizes)
{
foreach ((array) $sizes as $size) {
$this->sizes[] = new Comparator\NumberComparator($size);
}

return $this;
}














public function exclude($dirs)
{
$this->exclude = array_merge($this->exclude, (array) $dirs);

return $this;
}












public function ignoreDotFiles($ignoreDotFiles)
{
if ($ignoreDotFiles) {
$this->ignore |= static::IGNORE_DOT_FILES;
} else {
$this->ignore &= ~static::IGNORE_DOT_FILES;
}

return $this;
}












public function ignoreVCS($ignoreVCS)
{
if ($ignoreVCS) {
$this->ignore |= static::IGNORE_VCS_FILES;
} else {
$this->ignore &= ~static::IGNORE_VCS_FILES;
}

return $this;
}








public function ignoreVCSIgnored(bool $ignoreVCSIgnored)
{
if ($ignoreVCSIgnored) {
$this->ignore |= static::IGNORE_VCS_IGNORED_FILES;
} else {
$this->ignore &= ~static::IGNORE_VCS_IGNORED_FILES;
}

return $this;
}








public static function addVCSPattern($pattern)
{
foreach ((array) $pattern as $p) {
self::$vcsPatterns[] = $p;
}

self::$vcsPatterns = array_unique(self::$vcsPatterns);
}












public function sort(\Closure $closure)
{
$this->sort = $closure;

return $this;
}












public function sortByName()
{
if (\func_num_args() < 1 && __CLASS__ !== static::class && __CLASS__ !== (new \ReflectionMethod($this, __FUNCTION__))->getDeclaringClass()->getName() && !$this instanceof \PHPUnit\Framework\MockObject\MockObject && !$this instanceof \Prophecy\Prophecy\ProphecySubjectInterface && !$this instanceof \Mockery\MockInterface) {
@trigger_error(sprintf('The "%s()" method will have a new "bool $useNaturalSort = false" argument in version 5.0, not defining it is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED);
}
$useNaturalSort = 0 < \func_num_args() && func_get_arg(0);

$this->sort = $useNaturalSort ? Iterator\SortableIterator::SORT_BY_NAME_NATURAL : Iterator\SortableIterator::SORT_BY_NAME;

return $this;
}










public function sortByType()
{
$this->sort = Iterator\SortableIterator::SORT_BY_TYPE;

return $this;
}












public function sortByAccessedTime()
{
$this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME;

return $this;
}






public function reverseSorting()
{
$this->reverseSorting = true;

return $this;
}














public function sortByChangedTime()
{
$this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME;

return $this;
}












public function sortByModifiedTime()
{
$this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME;

return $this;
}











public function filter(\Closure $closure)
{
$this->filters[] = $closure;

return $this;
}






public function followLinks()
{
$this->followLinks = true;

return $this;
}










public function ignoreUnreadableDirs($ignore = true)
{
$this->ignoreUnreadableDirs = (bool) $ignore;

return $this;
}










public function in($dirs)
{
$resolvedDirs = [];

foreach ((array) $dirs as $dir) {
if (is_dir($dir)) {
$resolvedDirs[] = $this->normalizeDir($dir);
} elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? \GLOB_BRACE : 0) | \GLOB_ONLYDIR | \GLOB_NOSORT)) {
sort($glob);
$resolvedDirs = array_merge($resolvedDirs, array_map([$this, 'normalizeDir'], $glob));
} else {
throw new DirectoryNotFoundException(sprintf('The "%s" directory does not exist.', $dir));
}
}

$this->dirs = array_merge($this->dirs, $resolvedDirs);

return $this;
}











 public function getIterator()
{
if (0 === \count($this->dirs) && 0 === \count($this->iterators)) {
throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.');
}

if (1 === \count($this->dirs) && 0 === \count($this->iterators)) {
$iterator = $this->searchInDirectory($this->dirs[0]);

if ($this->sort || $this->reverseSorting) {
$iterator = (new Iterator\SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator();
}

return $iterator;
}

$iterator = new \AppendIterator();
foreach ($this->dirs as $dir) {
$iterator->append(new \IteratorIterator(new LazyIterator(function () use ($dir) {
return $this->searchInDirectory($dir);
})));
}

foreach ($this->iterators as $it) {
$iterator->append($it);
}

if ($this->sort || $this->reverseSorting) {
$iterator = (new Iterator\SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator();
}

return $iterator;
}












public function append($iterator)
{
if ($iterator instanceof \IteratorAggregate) {
$this->iterators[] = $iterator->getIterator();
} elseif ($iterator instanceof \Iterator) {
$this->iterators[] = $iterator;
} elseif (is_iterable($iterator)) {
$it = new \ArrayIterator();
foreach ($iterator as $file) {
$file = $file instanceof \SplFileInfo ? $file : new \SplFileInfo($file);
$it[$file->getPathname()] = $file;
}
$this->iterators[] = $it;
} else {
throw new \InvalidArgumentException('Finder::append() method wrong argument type.');
}

return $this;
}






public function hasResults()
{
foreach ($this->getIterator() as $_) {
return true;
}

return false;
}







 public function count()
{
return iterator_count($this->getIterator());
}

private function searchInDirectory(string $dir): \Iterator
{
$exclude = $this->exclude;
$notPaths = $this->notPaths;

if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
$exclude = array_merge($exclude, self::$vcsPatterns);
}

if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
$notPaths[] = '#(^|/)\..+(/|$)#';
}

if (static::IGNORE_VCS_IGNORED_FILES === (static::IGNORE_VCS_IGNORED_FILES & $this->ignore)) {
$gitignoreFilePath = sprintf('%s/.gitignore', $dir);
if (!is_readable($gitignoreFilePath)) {
throw new \RuntimeException(sprintf('The "ignoreVCSIgnored" option cannot be used by the Finder as the "%s" file is not readable.', $gitignoreFilePath));
}
$notPaths = array_merge($notPaths, [Gitignore::toRegex(file_get_contents($gitignoreFilePath))]);
}

$minDepth = 0;
$maxDepth = \PHP_INT_MAX;

foreach ($this->depths as $comparator) {
switch ($comparator->getOperator()) {
case '>':
$minDepth = $comparator->getTarget() + 1;
break;
case '>=':
$minDepth = $comparator->getTarget();
break;
case '<':
$maxDepth = $comparator->getTarget() - 1;
break;
case '<=':
$maxDepth = $comparator->getTarget();
break;
default:
$minDepth = $maxDepth = $comparator->getTarget();
}
}

$flags = \RecursiveDirectoryIterator::SKIP_DOTS;

if ($this->followLinks) {
$flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
}

$iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);

if ($exclude) {
$iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $exclude);
}

$iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);

if ($minDepth > 0 || $maxDepth < \PHP_INT_MAX) {
$iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth);
}

if ($this->mode) {
$iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
}

if ($this->names || $this->notNames) {
$iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
}

if ($this->contains || $this->notContains) {
$iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
}

if ($this->sizes) {
$iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
}

if ($this->dates) {
$iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
}

if ($this->filters) {
$iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
}

if ($this->paths || $notPaths) {
$iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $notPaths);
}

return $iterator;
}






private function normalizeDir(string $dir): string
{
if ('/' === $dir) {
return $dir;
}

$dir = rtrim($dir, '/'.\DIRECTORY_SEPARATOR);

if (preg_match('#^(ssh2\.)?s?ftp://#', $dir)) {
$dir .= '/';
}

return $dir;
}
}
<?php










namespace Symfony\Component\Finder;























class Glob
{










public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardSlash = true, $delimiter = '#')
{
$firstByte = true;
$escaping = false;
$inCurlies = 0;
$regex = '';
$sizeGlob = \strlen($glob);
for ($i = 0; $i < $sizeGlob; ++$i) {
$car = $glob[$i];
if ($firstByte && $strictLeadingDot && '.' !== $car) {
$regex .= '(?=[^\.])';
}

$firstByte = '/' === $car;

if ($firstByte && $strictWildcardSlash && isset($glob[$i + 2]) && '**' === $glob[$i + 1].$glob[$i + 2] && (!isset($glob[$i + 3]) || '/' === $glob[$i + 3])) {
$car = '[^/]++/';
if (!isset($glob[$i + 3])) {
$car .= '?';
}

if ($strictLeadingDot) {
$car = '(?=[^\.])'.$car;
}

$car = '/(?:'.$car.')*';
$i += 2 + isset($glob[$i + 3]);

if ('/' === $delimiter) {
$car = str_replace('/', '\\/', $car);
}
}

if ($delimiter === $car || '.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
$regex .= "\\$car";
} elseif ('*' === $car) {
$regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
} elseif ('?' === $car) {
$regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
} elseif ('{' === $car) {
$regex .= $escaping ? '\\{' : '(';
if (!$escaping) {
++$inCurlies;
}
} elseif ('}' === $car && $inCurlies) {
$regex .= $escaping ? '}' : ')';
if (!$escaping) {
--$inCurlies;
}
} elseif (',' === $car && $inCurlies) {
$regex .= $escaping ? ',' : '|';
} elseif ('\\' === $car) {
if ($escaping) {
$regex .= '\\\\';
$escaping = false;
} else {
$escaping = true;
}

continue;
} else {
$regex .= $car;
}
$escaping = false;
}

return $delimiter.'^'.$regex.'$'.$delimiter;
}
}
<?php










namespace Symfony\Component\Finder\Iterator;

use Symfony\Component\Finder\Comparator\NumberComparator;






class SizeRangeFilterIterator extends \FilterIterator
{
private $comparators = [];





public function __construct(\Iterator $iterator, array $comparators)
{
$this->comparators = $comparators;

parent::__construct($iterator);
}







 public function accept()
{
$fileinfo = $this->current();
if (!$fileinfo->isFile()) {
return true;
}

$filesize = $fileinfo->getSize();
foreach ($this->comparators as $compare) {
if (!$compare->test($filesize)) {
return false;
}
}

return true;
}
}
<?php










namespace Symfony\Component\Finder\Iterator;

use Symfony\Component\Finder\Exception\AccessDeniedException;
use Symfony\Component\Finder\SplFileInfo;






class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
{



private $ignoreUnreadableDirs;




private $rewindable;


 private $rootPath;
private $subPath;
private $directorySeparator = '/';




public function __construct(string $path, int $flags, bool $ignoreUnreadableDirs = false)
{
if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
throw new \RuntimeException('This iterator only support returning current as fileinfo.');
}

parent::__construct($path, $flags);
$this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
$this->rootPath = $path;
if ('/' !== \DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) {
$this->directorySeparator = \DIRECTORY_SEPARATOR;
}
}







 public function current()
{


if (null === $subPathname = $this->subPath) {
$subPathname = $this->subPath = (string) $this->getSubPath();
}
if ('' !== $subPathname) {
$subPathname .= $this->directorySeparator;
}
$subPathname .= $this->getFilename();

if ('/' !== $basePath = $this->rootPath) {
$basePath .= $this->directorySeparator;
}

return new SplFileInfo($basePath.$subPathname, $this->subPath, $subPathname);
}







 public function getChildren()
{
try {
$children = parent::getChildren();

if ($children instanceof self) {

 $children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;


 $children->rewindable = &$this->rewindable;
$children->rootPath = $this->rootPath;
}

return $children;
} catch (\UnexpectedValueException $e) {
if ($this->ignoreUnreadableDirs) {

 return new \RecursiveArrayIterator([]);
} else {
throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
}
}
}







 public function rewind()
{
if (false === $this->isRewindable()) {
return;
}

parent::rewind();
}






public function isRewindable()
{
if (null !== $this->rewindable) {
return $this->rewindable;
}

if (false !== $stream = @opendir($this->getPath())) {
$infos = stream_get_meta_data($stream);
closedir($stream);

if ($infos['seekable']) {
return $this->rewindable = true;
}
}

return $this->rewindable = false;
}
}
<?php










namespace Symfony\Component\Finder\Iterator;






class FileTypeFilterIterator extends \FilterIterator
{
public const ONLY_FILES = 1;
public const ONLY_DIRECTORIES = 2;

private $mode;





public function __construct(\Iterator $iterator, int $mode)
{
$this->mode = $mode;

parent::__construct($iterator);
}







 public function accept()
{
$fileinfo = $this->current();
if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) {
return false;
} elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) {
return false;
}

return true;
}
}
<?php










namespace Symfony\Component\Finder\Iterator;







class FilecontentFilterIterator extends MultiplePcreFilterIterator
{






 public function accept()
{
if (!$this->matchRegexps && !$this->noMatchRegexps) {
return true;
}

$fileinfo = $this->current();

if ($fileinfo->isDir() || !$fileinfo->isReadable()) {
return false;
}

$content = $fileinfo->getContents();
if (!$content) {
return false;
}

return $this->isAccepted($content);
}








protected function toRegex($str)
{
return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
}
}
<?php










namespace Symfony\Component\Finder\Iterator;






class ExcludeDirectoryFilterIterator extends \FilterIterator implements \RecursiveIterator
{
private $iterator;
private $isRecursive;
private $excludedDirs = [];
private $excludedPattern;





public function __construct(\Iterator $iterator, array $directories)
{
$this->iterator = $iterator;
$this->isRecursive = $iterator instanceof \RecursiveIterator;
$patterns = [];
foreach ($directories as $directory) {
$directory = rtrim($directory, '/');
if (!$this->isRecursive || str_contains($directory, '/')) {
$patterns[] = preg_quote($directory, '#');
} else {
$this->excludedDirs[$directory] = true;
}
}
if ($patterns) {
$this->excludedPattern = '#(?:^|/)(?:'.implode('|', $patterns).')(?:/|$)#';
}

parent::__construct($iterator);
}







 public function accept()
{
if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) {
return false;
}

if ($this->excludedPattern) {
$path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
$path = str_replace('\\', '/', $path);

return !preg_match($this->excludedPattern, $path);
}

return true;
}





 public function hasChildren()
{
return $this->isRecursive && $this->iterator->hasChildren();
}





 public function getChildren()
{
$children = new self($this->iterator->getChildren(), []);
$children->excludedDirs = $this->excludedDirs;
$children->excludedPattern = $this->excludedPattern;

return $children;
}
}
<?php










namespace Symfony\Component\Finder\Iterator;

use Symfony\Component\Finder\Comparator\DateComparator;






class DateRangeFilterIterator extends \FilterIterator
{
private $comparators = [];





public function __construct(\Iterator $iterator, array $comparators)
{
$this->comparators = $comparators;

parent::__construct($iterator);
}







 public function accept()
{
$fileinfo = $this->current();

if (!file_exists($fileinfo->getPathname())) {
return false;
}

$filedate = $fileinfo->getMTime();
foreach ($this->comparators as $compare) {
if (!$compare->test($filedate)) {
return false;
}
}

return true;
}
}
<?php










namespace Symfony\Component\Finder\Iterator;

use Symfony\Component\Finder\Glob;






class FilenameFilterIterator extends MultiplePcreFilterIterator
{






 public function accept()
{
return $this->isAccepted($this->current()->getFilename());
}











protected function toRegex($str)
{
return $this->isRegex($str) ? $str : Glob::toRegex($str);
}
}
<?php










namespace Symfony\Component\Finder\Iterator;






class DepthRangeFilterIterator extends \FilterIterator
{
private $minDepth = 0;






public function __construct(\RecursiveIteratorIterator $iterator, int $minDepth = 0, int $maxDepth = \PHP_INT_MAX)
{
$this->minDepth = $minDepth;
$iterator->setMaxDepth(\PHP_INT_MAX === $maxDepth ? -1 : $maxDepth);

parent::__construct($iterator);
}







 public function accept()
{
return $this->getInnerIterator()->getDepth() >= $this->minDepth;
}
}
<?php










namespace Symfony\Component\Finder\Iterator;









class CustomFilterIterator extends \FilterIterator
{
private $filters = [];







public function __construct(\Iterator $iterator, array $filters)
{
foreach ($filters as $filter) {
if (!\is_callable($filter)) {
throw new \InvalidArgumentException('Invalid PHP callback.');
}
}
$this->filters = $filters;

parent::__construct($iterator);
}







 public function accept()
{
$fileinfo = $this->current();

foreach ($this->filters as $filter) {
if (false === $filter($fileinfo)) {
return false;
}
}

return true;
}
}
<?php










namespace Symfony\Component\Finder\Iterator;






abstract class MultiplePcreFilterIterator extends \FilterIterator
{
protected $matchRegexps = [];
protected $noMatchRegexps = [];






public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
{
foreach ($matchPatterns as $pattern) {
$this->matchRegexps[] = $this->toRegex($pattern);
}

foreach ($noMatchPatterns as $pattern) {
$this->noMatchRegexps[] = $this->toRegex($pattern);
}

parent::__construct($iterator);
}












protected function isAccepted($string)
{

 foreach ($this->noMatchRegexps as $regex) {
if (preg_match($regex, $string)) {
return false;
}
}


 if ($this->matchRegexps) {
foreach ($this->matchRegexps as $regex) {
if (preg_match($regex, $string)) {
return true;
}
}

return false;
}


 return true;
}








protected function isRegex($str)
{
if (preg_match('/^(.{3,}?)[imsxuADU]*$/', $str, $m)) {
$start = substr($m[1], 0, 1);
$end = substr($m[1], -1);

if ($start === $end) {
return !preg_match('/[*?[:alnum:] \\\\]/', $start);
}

foreach ([['{', '}'], ['(', ')'], ['[', ']'], ['<', '>']] as $delimiters) {
if ($start === $delimiters[0] && $end === $delimiters[1]) {
return true;
}
}
}

return false;
}








abstract protected function toRegex($str);
}
<?php










namespace Symfony\Component\Finder\Iterator;






class LazyIterator implements \IteratorAggregate
{
private $iteratorFactory;

public function __construct(callable $iteratorFactory)
{
$this->iteratorFactory = $iteratorFactory;
}

public function getIterator(): \Traversable
{
yield from ($this->iteratorFactory)();
}
}
<?php










namespace Symfony\Component\Finder\Iterator;







class PathFilterIterator extends MultiplePcreFilterIterator
{






 public function accept()
{
$filename = $this->current()->getRelativePathname();

if ('\\' === \DIRECTORY_SEPARATOR) {
$filename = str_replace('\\', '/', $filename);
}

return $this->isAccepted($filename);
}















protected function toRegex($str)
{
return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
}
}
<?php










namespace Symfony\Component\Finder\Iterator;






class SortableIterator implements \IteratorAggregate
{
public const SORT_BY_NONE = 0;
public const SORT_BY_NAME = 1;
public const SORT_BY_TYPE = 2;
public const SORT_BY_ACCESSED_TIME = 3;
public const SORT_BY_CHANGED_TIME = 4;
public const SORT_BY_MODIFIED_TIME = 5;
public const SORT_BY_NAME_NATURAL = 6;

private $iterator;
private $sort;






public function __construct(\Traversable $iterator, $sort, bool $reverseOrder = false)
{
$this->iterator = $iterator;
$order = $reverseOrder ? -1 : 1;

if (self::SORT_BY_NAME === $sort) {
$this->sort = static function ($a, $b) use ($order) {
return $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
};
} elseif (self::SORT_BY_NAME_NATURAL === $sort) {
$this->sort = static function ($a, $b) use ($order) {
return $order * strnatcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
};
} elseif (self::SORT_BY_TYPE === $sort) {
$this->sort = static function ($a, $b) use ($order) {
if ($a->isDir() && $b->isFile()) {
return -$order;
} elseif ($a->isFile() && $b->isDir()) {
return $order;
}

return $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
};
} elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
$this->sort = static function ($a, $b) use ($order) {
return $order * ($a->getATime() - $b->getATime());
};
} elseif (self::SORT_BY_CHANGED_TIME === $sort) {
$this->sort = static function ($a, $b) use ($order) {
return $order * ($a->getCTime() - $b->getCTime());
};
} elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
$this->sort = static function ($a, $b) use ($order) {
return $order * ($a->getMTime() - $b->getMTime());
};
} elseif (self::SORT_BY_NONE === $sort) {
$this->sort = $order;
} elseif (\is_callable($sort)) {
$this->sort = $reverseOrder ? static function ($a, $b) use ($sort) { return -$sort($a, $b); } : $sort;
} else {
throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
}
}





 public function getIterator()
{
if (1 === $this->sort) {
return $this->iterator;
}

$array = iterator_to_array($this->iterator, true);

if (-1 === $this->sort) {
$array = array_reverse($array);
} else {
uasort($array, $this->sort);
}

return new \ArrayIterator($array);
}
}
<?php










namespace Symfony\Component\Finder\Exception;




class DirectoryNotFoundException extends \InvalidArgumentException
{
}
<?php










namespace Symfony\Component\Finder\Exception;




class AccessDeniedException extends \UnexpectedValueException
{
}
<?php










namespace Symfony\Component\DomCrawler\Test\Constraint;

use PHPUnit\Framework\Constraint\Constraint;
use Symfony\Component\DomCrawler\Crawler;

final class CrawlerSelectorTextContains extends Constraint
{
private $selector;
private $expectedText;
private $hasNode = false;
private $nodeText;

public function __construct(string $selector, string $expectedText)
{
$this->selector = $selector;
$this->expectedText = $expectedText;
}




public function toString(): string
{
if ($this->hasNode) {
return sprintf('the text "%s" of the node matching selector "%s" contains "%s"', $this->nodeText, $this->selector, $this->expectedText);
}

return sprintf('the Crawler has a node matching selector "%s"', $this->selector);
}






protected function matches($crawler): bool
{
$crawler = $crawler->filter($this->selector);
if (!\count($crawler)) {
$this->hasNode = false;

return false;
}

$this->hasNode = true;
$this->nodeText = $crawler->text(null, true);

return false !== mb_strpos($this->nodeText, $this->expectedText);
}






protected function failureDescription($crawler): string
{
return $this->toString();
}
}
<?php










namespace Symfony\Component\DomCrawler\Test\Constraint;

use PHPUnit\Framework\Constraint\Constraint;
use Symfony\Component\DomCrawler\Crawler;

final class CrawlerSelectorAttributeValueSame extends Constraint
{
private $selector;
private $attribute;
private $expectedText;

public function __construct(string $selector, string $attribute, string $expectedText)
{
$this->selector = $selector;
$this->attribute = $attribute;
$this->expectedText = $expectedText;
}




public function toString(): string
{
return sprintf('has a node matching selector "%s" with attribute "%s" of value "%s"', $this->selector, $this->attribute, $this->expectedText);
}






protected function matches($crawler): bool
{
$crawler = $crawler->filter($this->selector);
if (!\count($crawler)) {
return false;
}

return $this->expectedText === trim($crawler->attr($this->attribute) ?? '');
}






protected function failureDescription($crawler): string
{
return 'the Crawler '.$this->toString();
}
}
<?php










namespace Symfony\Component\DomCrawler\Test\Constraint;

use PHPUnit\Framework\Constraint\Constraint;
use Symfony\Component\DomCrawler\Crawler;

final class CrawlerSelectorTextSame extends Constraint
{
private $selector;
private $expectedText;

public function __construct(string $selector, string $expectedText)
{
$this->selector = $selector;
$this->expectedText = $expectedText;
}




public function toString(): string
{
return sprintf('has a node matching selector "%s" with content "%s"', $this->selector, $this->expectedText);
}






protected function matches($crawler): bool
{
$crawler = $crawler->filter($this->selector);
if (!\count($crawler)) {
return false;
}

return $this->expectedText === trim($crawler->text(null, true));
}






protected function failureDescription($crawler): string
{
return 'the Crawler '.$this->toString();
}
}
<?php










namespace Symfony\Component\DomCrawler\Test\Constraint;

use PHPUnit\Framework\Constraint\Constraint;
use Symfony\Component\DomCrawler\Crawler;

final class CrawlerSelectorExists extends Constraint
{
private $selector;

public function __construct(string $selector)
{
$this->selector = $selector;
}




public function toString(): string
{
return sprintf('matches selector "%s"', $this->selector);
}






protected function matches($crawler): bool
{
return 0 < \count($crawler->filter($this->selector));
}






protected function failureDescription($crawler): string
{
return 'the Crawler '.$this->toString();
}
}
<?php










namespace Symfony\Component\DomCrawler;

use Symfony\Component\DomCrawler\Field\ChoiceFormField;
use Symfony\Component\DomCrawler\Field\FormField;






class Form extends Link implements \ArrayAccess
{



private $button;




private $fields;




private $baseHref;









public function __construct(\DOMElement $node, string $currentUri = null, string $method = null, string $baseHref = null)
{
parent::__construct($node, $currentUri, $method);
$this->baseHref = $baseHref;

$this->initialize();
}






public function getFormNode()
{
return $this->node;
}








public function setValues(array $values)
{
foreach ($values as $name => $value) {
$this->fields->set($name, $value);
}

return $this;
}








public function getValues()
{
$values = [];
foreach ($this->fields->all() as $name => $field) {
if ($field->isDisabled()) {
continue;
}

if (!$field instanceof Field\FileFormField && $field->hasValue()) {
$values[$name] = $field->getValue();
}
}

return $values;
}






public function getFiles()
{
if (!\in_array($this->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'])) {
return [];
}

$files = [];

foreach ($this->fields->all() as $name => $field) {
if ($field->isDisabled()) {
continue;
}

if ($field instanceof Field\FileFormField) {
$files[$name] = $field->getValue();
}
}

return $files;
}









public function getPhpValues()
{
$values = [];
foreach ($this->getValues() as $name => $value) {
$qs = http_build_query([$name => $value], '', '&');
if (!empty($qs)) {
parse_str($qs, $expandedValue);
$varName = substr($name, 0, \strlen(key($expandedValue)));
$values = array_replace_recursive($values, [$varName => current($expandedValue)]);
}
}

return $values;
}













public function getPhpFiles()
{
$values = [];
foreach ($this->getFiles() as $name => $value) {
$qs = http_build_query([$name => $value], '', '&');
if (!empty($qs)) {
parse_str($qs, $expandedValue);
$varName = substr($name, 0, \strlen(key($expandedValue)));

array_walk_recursive(
$expandedValue,
function (&$value, $key) {
if (ctype_digit($value) && ('size' === $key || 'error' === $key)) {
$value = (int) $value;
}
}
);

reset($expandedValue);

$values = array_replace_recursive($values, [$varName => current($expandedValue)]);
}
}

return $values;
}










public function getUri()
{
$uri = parent::getUri();

if (!\in_array($this->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'])) {
$query = parse_url($uri, \PHP_URL_QUERY);
$currentParameters = [];
if ($query) {
parse_str($query, $currentParameters);
}

$queryString = http_build_query(array_merge($currentParameters, $this->getValues()), '', '&');

$pos = strpos($uri, '?');
$base = false === $pos ? $uri : substr($uri, 0, $pos);
$uri = rtrim($base.'?'.$queryString, '?');
}

return $uri;
}

protected function getRawUri()
{

 if ($this->button !== $this->node && $this->button->getAttribute('formaction')) {
return $this->button->getAttribute('formaction');
}

return $this->node->getAttribute('action');
}








public function getMethod()
{
if (null !== $this->method) {
return $this->method;
}


 if ($this->button !== $this->node && $this->button->getAttribute('formmethod')) {
return strtoupper($this->button->getAttribute('formmethod'));
}

return $this->node->getAttribute('method') ? strtoupper($this->node->getAttribute('method')) : 'GET';
}






public function getName(): string
{
return $this->node->getAttribute('name');
}








public function has($name)
{
return $this->fields->has($name);
}






public function remove($name)
{
$this->fields->remove($name);
}










public function get($name)
{
return $this->fields->get($name);
}




public function set(FormField $field)
{
$this->fields->add($field);
}






public function all()
{
return $this->fields->all();
}









 public function offsetExists($name)
{
return $this->has($name);
}











 public function offsetGet($name)
{
return $this->fields->get($name);
}












 public function offsetSet($name, $value)
{
$this->fields->set($name, $value);
}









 public function offsetUnset($name)
{
$this->fields->remove($name);
}






public function disableValidation()
{
foreach ($this->fields->all() as $field) {
if ($field instanceof Field\ChoiceFormField) {
$field->disableValidation();
}
}

return $this;
}








protected function setNode(\DOMElement $node)
{
$this->button = $node;
if ('button' === $node->nodeName || ('input' === $node->nodeName && \in_array(strtolower($node->getAttribute('type')), ['submit', 'button', 'image']))) {
if ($node->hasAttribute('form')) {

 $formId = $node->getAttribute('form');
$form = $node->ownerDocument->getElementById($formId);
if (null === $form) {
throw new \LogicException(sprintf('The selected node has an invalid form attribute (%s).', $formId));
}
$this->node = $form;

return;
}

 do {
if (null === $node = $node->parentNode) {
throw new \LogicException('The selected node does not have a form ancestor.');
}
} while ('form' !== $node->nodeName);
} elseif ('form' !== $node->nodeName) {
throw new \LogicException(sprintf('Unable to submit on a "%s" tag.', $node->nodeName));
}

$this->node = $node;
}








private function initialize()
{
$this->fields = new FormFieldRegistry();

$xpath = new \DOMXPath($this->node->ownerDocument);


 if ('form' !== $this->button->nodeName && $this->button->hasAttribute('name') && $this->button->getAttribute('name')) {
if ('input' == $this->button->nodeName && 'image' == strtolower($this->button->getAttribute('type'))) {
$name = $this->button->getAttribute('name');
$this->button->setAttribute('value', '0');


 $this->button->setAttribute('name', $name.'.x');
$this->set(new Field\InputFormField($this->button));


 $this->button->setAttribute('name', $name.'.y');
$this->set(new Field\InputFormField($this->button));


 $this->button->setAttribute('name', $name);
} else {
$this->set(new Field\InputFormField($this->button));
}
}


 if ($this->node->hasAttribute('id')) {

 $formId = Crawler::xpathLiteral($this->node->getAttribute('id'));

$fieldNodes = $xpath->query(sprintf('( descendant::input[@form=%s] | descendant::button[@form=%1$s] | descendant::textarea[@form=%1$s] | descendant::select[@form=%1$s] | //form[@id=%1$s]//input[not(@form)] | //form[@id=%1$s]//button[not(@form)] | //form[@id=%1$s]//textarea[not(@form)] | //form[@id=%1$s]//select[not(@form)] )[not(ancestor::template)]', $formId));
foreach ($fieldNodes as $node) {
$this->addField($node);
}
} else {

 
 $fieldNodes = $xpath->query('( descendant::input[not(@form)] | descendant::button[not(@form)] | descendant::textarea[not(@form)] | descendant::select[not(@form)] )[not(ancestor::template)]', $this->node);
foreach ($fieldNodes as $node) {
$this->addField($node);
}
}

if ($this->baseHref && '' !== $this->node->getAttribute('action')) {
$this->currentUri = $this->baseHref;
}
}

private function addField(\DOMElement $node)
{
if (!$node->hasAttribute('name') || !$node->getAttribute('name')) {
return;
}

$nodeName = $node->nodeName;
if ('select' == $nodeName || 'input' == $nodeName && 'checkbox' == strtolower($node->getAttribute('type'))) {
$this->set(new Field\ChoiceFormField($node));
} elseif ('input' == $nodeName && 'radio' == strtolower($node->getAttribute('type'))) {

 
 if ($this->has($node->getAttribute('name')) && $this->get($node->getAttribute('name')) instanceof ChoiceFormField) {
$this->get($node->getAttribute('name'))->addChoice($node);
} else {
$this->set(new Field\ChoiceFormField($node));
}
} elseif ('input' == $nodeName && 'file' == strtolower($node->getAttribute('type'))) {
$this->set(new Field\FileFormField($node));
} elseif ('input' == $nodeName && !\in_array(strtolower($node->getAttribute('type')), ['submit', 'button', 'image'])) {
$this->set(new Field\InputFormField($node));
} elseif ('textarea' == $nodeName) {
$this->set(new Field\TextareaFormField($node));
}
}
}
<?php










namespace Symfony\Component\DomCrawler\Field;






class TextareaFormField extends FormField
{





protected function initialize()
{
if ('textarea' !== $this->node->nodeName) {
throw new \LogicException(sprintf('A TextareaFormField can only be created from a textarea tag (%s given).', $this->node->nodeName));
}

$this->value = '';
foreach ($this->node->childNodes as $node) {
$this->value .= $node->wholeText;
}
}
}
<?php










namespace Symfony\Component\DomCrawler\Field;








class ChoiceFormField extends FormField
{



private $type;



private $multiple;



private $options;



private $validationDisabled = false;






public function hasValue()
{

 if (\in_array($this->type, ['checkbox', 'radio']) && null === $this->value) {
return false;
}

return true;
}






public function isDisabled()
{
if (parent::isDisabled() && 'select' === $this->type) {
return true;
}

foreach ($this->options as $option) {
if ($option['value'] == $this->value && $option['disabled']) {
return true;
}
}

return false;
}






public function select($value)
{
$this->setValue($value);
}






public function tick()
{
if ('checkbox' !== $this->type) {
throw new \LogicException(sprintf('You cannot tick "%s" as it is not a checkbox (%s).', $this->name, $this->type));
}

$this->setValue(true);
}






public function untick()
{
if ('checkbox' !== $this->type) {
throw new \LogicException(sprintf('You cannot untick "%s" as it is not a checkbox (%s).', $this->name, $this->type));
}

$this->setValue(false);
}








public function setValue($value)
{
if ('checkbox' === $this->type && false === $value) {

 $this->value = null;
} elseif ('checkbox' === $this->type && true === $value) {

 $this->value = $this->options[0]['value'];
} else {
if (\is_array($value)) {
if (!$this->multiple) {
throw new \InvalidArgumentException(sprintf('The value for "%s" cannot be an array.', $this->name));
}

foreach ($value as $v) {
if (!$this->containsOption($v, $this->options)) {
throw new \InvalidArgumentException(sprintf('Input "%s" cannot take "%s" as a value (possible values: "%s").', $this->name, $v, implode('", "', $this->availableOptionValues())));
}
}
} elseif (!$this->containsOption($value, $this->options)) {
throw new \InvalidArgumentException(sprintf('Input "%s" cannot take "%s" as a value (possible values: "%s").', $this->name, $value, implode('", "', $this->availableOptionValues())));
}

if ($this->multiple) {
$value = (array) $value;
}

if (\is_array($value)) {
$this->value = $value;
} else {
parent::setValue($value);
}
}
}








public function addChoice(\DOMElement $node)
{
if (!$this->multiple && 'radio' !== $this->type) {
throw new \LogicException(sprintf('Unable to add a choice for "%s" as it is not multiple or is not a radio button.', $this->name));
}

$option = $this->buildOptionValue($node);
$this->options[] = $option;

if ($node->hasAttribute('checked')) {
$this->value = $option['value'];
}
}






public function getType()
{
return $this->type;
}






public function isMultiple()
{
return $this->multiple;
}






protected function initialize()
{
if ('input' !== $this->node->nodeName && 'select' !== $this->node->nodeName) {
throw new \LogicException(sprintf('A ChoiceFormField can only be created from an input or select tag (%s given).', $this->node->nodeName));
}

if ('input' === $this->node->nodeName && 'checkbox' !== strtolower($this->node->getAttribute('type')) && 'radio' !== strtolower($this->node->getAttribute('type'))) {
throw new \LogicException(sprintf('A ChoiceFormField can only be created from an input tag with a type of checkbox or radio (given type is "%s").', $this->node->getAttribute('type')));
}

$this->value = null;
$this->options = [];
$this->multiple = false;

if ('input' == $this->node->nodeName) {
$this->type = strtolower($this->node->getAttribute('type'));
$optionValue = $this->buildOptionValue($this->node);
$this->options[] = $optionValue;

if ($this->node->hasAttribute('checked')) {
$this->value = $optionValue['value'];
}
} else {
$this->type = 'select';
if ($this->node->hasAttribute('multiple')) {
$this->multiple = true;
$this->value = [];
$this->name = str_replace('[]', '', $this->name);
}

$found = false;
foreach ($this->xpath->query('descendant::option', $this->node) as $option) {
$optionValue = $this->buildOptionValue($option);
$this->options[] = $optionValue;

if ($option->hasAttribute('selected')) {
$found = true;
if ($this->multiple) {
$this->value[] = $optionValue['value'];
} else {
$this->value = $optionValue['value'];
}
}
}


 if (!$found && !$this->multiple && !empty($this->options)) {
$this->value = $this->options[0]['value'];
}
}
}




private function buildOptionValue(\DOMElement $node): array
{
$option = [];

$defaultDefaultValue = 'select' === $this->node->nodeName ? '' : 'on';
$defaultValue = (isset($node->nodeValue) && !empty($node->nodeValue)) ? $node->nodeValue : $defaultDefaultValue;
$option['value'] = $node->hasAttribute('value') ? $node->getAttribute('value') : $defaultValue;
$option['disabled'] = $node->hasAttribute('disabled');

return $option;
}









public function containsOption($optionValue, $options)
{
if ($this->validationDisabled) {
return true;
}

foreach ($options as $option) {
if ($option['value'] == $optionValue) {
return true;
}
}

return false;
}






public function availableOptionValues()
{
$values = [];

foreach ($this->options as $option) {
$values[] = $option['value'];
}

return $values;
}






public function disableValidation()
{
$this->validationDisabled = true;

return $this;
}
}
<?php










namespace Symfony\Component\DomCrawler\Field;






abstract class FormField
{



protected $node;



protected $name;



protected $value;



protected $document;



protected $xpath;



protected $disabled;




public function __construct(\DOMElement $node)
{
$this->node = $node;
$this->name = $node->getAttribute('name');
$this->xpath = new \DOMXPath($node->ownerDocument);

$this->initialize();
}






public function getLabel()
{
$xpath = new \DOMXPath($this->node->ownerDocument);

if ($this->node->hasAttribute('id')) {
$labels = $xpath->query(sprintf('descendant::label[@for="%s"]', $this->node->getAttribute('id')));
if ($labels->length > 0) {
return $labels->item(0);
}
}

$labels = $xpath->query('ancestor::label[1]', $this->node);

return $labels->length > 0 ? $labels->item(0) : null;
}






public function getName()
{
return $this->name;
}






public function getValue()
{
return $this->value;
}






public function setValue($value)
{
$this->value = (string) $value;
}






public function hasValue()
{
return true;
}






public function isDisabled()
{
return $this->node->hasAttribute('disabled');
}




abstract protected function initialize();
}
<?php










namespace Symfony\Component\DomCrawler\Field;









class InputFormField extends FormField
{





protected function initialize()
{
if ('input' !== $this->node->nodeName && 'button' !== $this->node->nodeName) {
throw new \LogicException(sprintf('An InputFormField can only be created from an input or button tag (%s given).', $this->node->nodeName));
}

$type = strtolower($this->node->getAttribute('type'));
if ('checkbox' === $type) {
throw new \LogicException('Checkboxes should be instances of ChoiceFormField.');
}

if ('file' === $type) {
throw new \LogicException('File inputs should be instances of FileFormField.');
}

$this->value = $this->node->getAttribute('value');
}
}
<?php










namespace Symfony\Component\DomCrawler\Field;






class FileFormField extends FormField
{







public function setErrorCode($error)
{
$codes = [\UPLOAD_ERR_INI_SIZE, \UPLOAD_ERR_FORM_SIZE, \UPLOAD_ERR_PARTIAL, \UPLOAD_ERR_NO_FILE, \UPLOAD_ERR_NO_TMP_DIR, \UPLOAD_ERR_CANT_WRITE, \UPLOAD_ERR_EXTENSION];
if (!\in_array($error, $codes)) {
throw new \InvalidArgumentException(sprintf('The error code "%s" is not valid.', $error));
}

$this->value = ['name' => '', 'type' => '', 'tmp_name' => '', 'error' => $error, 'size' => 0];
}






public function upload($value)
{
$this->setValue($value);
}






public function setValue($value)
{
if (null !== $value && is_readable($value)) {
$error = \UPLOAD_ERR_OK;
$size = filesize($value);
$info = pathinfo($value);
$name = $info['basename'];


 $tmp = sys_get_temp_dir().'/'.strtr(substr(base64_encode(hash('sha256', uniqid(mt_rand(), true), true)), 0, 7), '/', '_');
if (\array_key_exists('extension', $info)) {
$tmp .= '.'.$info['extension'];
}
if (is_file($tmp)) {
unlink($tmp);
}
copy($value, $tmp);
$value = $tmp;
} else {
$error = \UPLOAD_ERR_NO_FILE;
$size = 0;
$name = '';
$value = '';
}

$this->value = ['name' => $name, 'type' => '', 'tmp_name' => $value, 'error' => $error, 'size' => $size];
}






public function setFilePath($path)
{
parent::setValue($path);
}






protected function initialize()
{
if ('input' !== $this->node->nodeName) {
throw new \LogicException(sprintf('A FileFormField can only be created from an input tag (%s given).', $this->node->nodeName));
}

if ('file' !== strtolower($this->node->getAttribute('type'))) {
throw new \LogicException(sprintf('A FileFormField can only be created from an input tag with a type of file (given type is "%s").', $this->node->getAttribute('type')));
}

$this->setValue(null);
}
}
<?php










namespace Symfony\Component\DomCrawler;






class Link extends AbstractUriElement
{
protected function getRawUri()
{
return $this->node->getAttribute('href');
}

protected function setNode(\DOMElement $node)
{
if ('a' !== $node->nodeName && 'area' !== $node->nodeName && 'link' !== $node->nodeName) {
throw new \LogicException(sprintf('Unable to navigate from a "%s" tag.', $node->nodeName));
}

$this->node = $node;
}
}
<?php










namespace Symfony\Component\DomCrawler;

use Masterminds\HTML5;
use Symfony\Component\CssSelector\CssSelectorConverter;






class Crawler implements \Countable, \IteratorAggregate
{



protected $uri;






private $defaultNamespacePrefix = 'default';






private $namespaces = [];






private $baseHref;




private $document;




private $nodes = [];






private $isHtml = true;




private $html5Parser;




public function __construct($node = null, string $uri = null, string $baseHref = null)
{
$this->uri = $uri;
$this->baseHref = $baseHref ?: $uri;
$this->html5Parser = class_exists(HTML5::class) ? new HTML5(['disable_html_ns' => true]) : null;

$this->add($node);
}






public function getUri()
{
return $this->uri;
}






public function getBaseHref()
{
return $this->baseHref;
}




public function clear()
{
$this->nodes = [];
$this->document = null;
}











public function add($node)
{
if ($node instanceof \DOMNodeList) {
$this->addNodeList($node);
} elseif ($node instanceof \DOMNode) {
$this->addNode($node);
} elseif (\is_array($node)) {
$this->addNodes($node);
} elseif (\is_string($node)) {
$this->addContent($node);
} elseif (null !== $node) {
throw new \InvalidArgumentException(sprintf('Expecting a DOMNodeList or DOMNode instance, an array, a string, or null, but got "%s".', \is_object($node) ? \get_class($node) : \gettype($node)));
}
}











public function addContent($content, $type = null)
{
if (empty($type)) {
$type = str_starts_with($content, '<?xml') ? 'application/xml' : 'text/html';
}


 if (!preg_match('/(x|ht)ml/i', $type, $xmlMatches)) {
return;
}

$charset = null;
if (false !== $pos = stripos($type, 'charset=')) {
$charset = substr($type, $pos + 8);
if (false !== $pos = strpos($charset, ';')) {
$charset = substr($charset, 0, $pos);
}
}


 
 if (null === $charset &&
preg_match('/\<meta[^\>]+charset *= *["\']?([a-zA-Z\-0-9_:.]+)/i', $content, $matches)) {
$charset = $matches[1];
}

if (null === $charset) {
$charset = preg_match('//u', $content) ? 'UTF-8' : 'ISO-8859-1';
}

if ('x' === $xmlMatches[1]) {
$this->addXmlContent($content, $charset);
} else {
$this->addHtmlContent($content, $charset);
}
}














public function addHtmlContent($content, $charset = 'UTF-8')
{
$dom = $this->parseHtmlString($content, $charset);
$this->addDocument($dom);

$base = $this->filterRelativeXPath('descendant-or-self::base')->extract(['href']);

$baseHref = current($base);
if (\count($base) && !empty($baseHref)) {
if ($this->baseHref) {
$linkNode = $dom->createElement('a');
$linkNode->setAttribute('href', $baseHref);
$link = new Link($linkNode, $this->baseHref);
$this->baseHref = $link->getUri();
} else {
$this->baseHref = $baseHref;
}
}
}

















public function addXmlContent($content, $charset = 'UTF-8', $options = \LIBXML_NONET)
{

 if (!preg_match('/xmlns:/', $content)) {
$content = str_replace('xmlns', 'ns', $content);
}

$internalErrors = libxml_use_internal_errors(true);
if (\LIBXML_VERSION < 20900) {
$disableEntities = libxml_disable_entity_loader(true);
}

$dom = new \DOMDocument('1.0', $charset);
$dom->validateOnParse = true;

if ('' !== trim($content)) {
@$dom->loadXML($content, $options);
}

libxml_use_internal_errors($internalErrors);
if (\LIBXML_VERSION < 20900) {
libxml_disable_entity_loader($disableEntities);
}

$this->addDocument($dom);

$this->isHtml = false;
}






public function addDocument(\DOMDocument $dom)
{
if ($dom->documentElement) {
$this->addNode($dom->documentElement);
}
}






public function addNodeList(\DOMNodeList $nodes)
{
foreach ($nodes as $node) {
if ($node instanceof \DOMNode) {
$this->addNode($node);
}
}
}






public function addNodes(array $nodes)
{
foreach ($nodes as $node) {
$this->add($node);
}
}






public function addNode(\DOMNode $node)
{
if ($node instanceof \DOMDocument) {
$node = $node->documentElement;
}

if (null !== $this->document && $this->document !== $node->ownerDocument) {
throw new \InvalidArgumentException('Attaching DOM nodes from multiple documents in the same crawler is forbidden.');
}

if (null === $this->document) {
$this->document = $node->ownerDocument;
}


 if (\in_array($node, $this->nodes, true)) {
return;
}

$this->nodes[] = $node;
}








public function eq($position)
{
if (isset($this->nodes[$position])) {
return $this->createSubCrawler($this->nodes[$position]);
}

return $this->createSubCrawler(null);
}

















public function each(\Closure $closure)
{
$data = [];
foreach ($this->nodes as $i => $node) {
$data[] = $closure($this->createSubCrawler($node), $i);
}

return $data;
}









public function slice($offset = 0, $length = null)
{
return $this->createSubCrawler(\array_slice($this->nodes, $offset, $length));
}










public function reduce(\Closure $closure)
{
$nodes = [];
foreach ($this->nodes as $i => $node) {
if (false !== $closure($this->createSubCrawler($node), $i)) {
$nodes[] = $node;
}
}

return $this->createSubCrawler($nodes);
}






public function first()
{
return $this->eq(0);
}






public function last()
{
return $this->eq(\count($this->nodes) - 1);
}








public function siblings()
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}

return $this->createSubCrawler($this->sibling($this->getNode(0)->parentNode->firstChild));
}

public function matches(string $selector): bool
{
if (!$this->nodes) {
return false;
}

$converter = $this->createCssSelectorConverter();
$xpath = $converter->toXPath($selector, 'self::');

return 0 !== $this->filterRelativeXPath($xpath)->count();
}








public function closest(string $selector): ?self
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}

$domNode = $this->getNode(0);

while (\XML_ELEMENT_NODE === $domNode->nodeType) {
$node = $this->createSubCrawler($domNode);
if ($node->matches($selector)) {
return $node;
}

$domNode = $node->getNode(0)->parentNode;
}

return null;
}








public function nextAll()
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}

return $this->createSubCrawler($this->sibling($this->getNode(0)));
}








public function previousAll()
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}

return $this->createSubCrawler($this->sibling($this->getNode(0), 'previousSibling'));
}








public function parents()
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}

$node = $this->getNode(0);
$nodes = [];

while ($node = $node->parentNode) {
if (\XML_ELEMENT_NODE === $node->nodeType) {
$nodes[] = $node;
}
}

return $this->createSubCrawler($nodes);
}











public function children()
{
if (\func_num_args() < 1 && __CLASS__ !== static::class && __CLASS__ !== (new \ReflectionMethod($this, __FUNCTION__))->getDeclaringClass()->getName() && !$this instanceof \PHPUnit\Framework\MockObject\MockObject && !$this instanceof \Prophecy\Prophecy\ProphecySubjectInterface && !$this instanceof \Mockery\MockInterface) {
@trigger_error(sprintf('The "%s()" method will have a new "string $selector = null" argument in version 5.0, not defining it is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED);
}
$selector = 0 < \func_num_args() ? func_get_arg(0) : null;

if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}

if (null !== $selector) {
$converter = $this->createCssSelectorConverter();
$xpath = $converter->toXPath($selector, 'child::');

return $this->filterRelativeXPath($xpath);
}

$node = $this->getNode(0)->firstChild;

return $this->createSubCrawler($node ? $this->sibling($node) : []);
}










public function attr($attribute)
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}

$node = $this->getNode(0);

return $node->hasAttribute($attribute) ? $node->getAttribute($attribute) : null;
}








public function nodeName()
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}

return $this->getNode(0)->nodeName;
}













public function text()
{
if (!$this->nodes) {
if (0 < \func_num_args() && null !== func_get_arg(0)) {
return (string) func_get_arg(0);
}

throw new \InvalidArgumentException('The current node list is empty.');
}

$text = $this->getNode(0)->nodeValue;

if (\func_num_args() <= 1) {
if (trim(preg_replace('/(?:\s{2,}+|[^\S ])/', ' ', $text)) !== $text) {
@trigger_error(sprintf('"%s()" will normalize whitespaces by default in Symfony 5.0, set the second "$normalizeWhitespace" argument to false to retrieve the non-normalized version of the text.', __METHOD__), \E_USER_DEPRECATED);
}

return $text;
}

if (\func_num_args() > 1 && func_get_arg(1)) {
return trim(preg_replace('/(?:\s{2,}+|[^\S ])/', ' ', $text));
}

return $text;
}










public function html()
{
if (!$this->nodes) {
if (0 < \func_num_args() && null !== func_get_arg(0)) {
return (string) func_get_arg(0);
}

throw new \InvalidArgumentException('The current node list is empty.');
}

$node = $this->getNode(0);
$owner = $node->ownerDocument;

if (null !== $this->html5Parser && '<!DOCTYPE html>' === $owner->saveXML($owner->childNodes[0])) {
$owner = $this->html5Parser;
}

$html = '';
foreach ($node->childNodes as $child) {
$html .= $owner->saveHTML($child);
}

return $html;
}

public function outerHtml(): string
{
if (!\count($this)) {
throw new \InvalidArgumentException('The current node list is empty.');
}

$node = $this->getNode(0);
$owner = $node->ownerDocument;

if (null !== $this->html5Parser && '<!DOCTYPE html>' === $owner->saveXML($owner->childNodes[0])) {
$owner = $this->html5Parser;
}

return $owner->saveHTML($node);
}











public function evaluate($xpath)
{
if (null === $this->document) {
throw new \LogicException('Cannot evaluate the expression on an uninitialized crawler.');
}

$data = [];
$domxpath = $this->createDOMXPath($this->document, $this->findNamespacePrefixes($xpath));

foreach ($this->nodes as $node) {
$data[] = $domxpath->evaluate($xpath, $node);
}

if (isset($data[0]) && $data[0] instanceof \DOMNodeList) {
return $this->createSubCrawler($data);
}

return $data;
}














public function extract($attributes)
{
$attributes = (array) $attributes;
$count = \count($attributes);

$data = [];
foreach ($this->nodes as $node) {
$elements = [];
foreach ($attributes as $attribute) {
if ('_text' === $attribute) {
$elements[] = $node->nodeValue;
} elseif ('_name' === $attribute) {
$elements[] = $node->nodeName;
} else {
$elements[] = $node->getAttribute($attribute);
}
}

$data[] = 1 === $count ? $elements[0] : $elements;
}

return $data;
}













public function filterXPath($xpath)
{
$xpath = $this->relativize($xpath);


 if ('' === $xpath) {
return $this->createSubCrawler(null);
}

return $this->filterRelativeXPath($xpath);
}












public function filter($selector)
{
$converter = $this->createCssSelectorConverter();


 return $this->filterRelativeXPath($converter->toXPath($selector));
}








public function selectLink($value)
{
return $this->filterRelativeXPath(
sprintf('descendant-or-self::a[contains(concat(\' \', normalize-space(string(.)), \' \'), %1$s) or ./img[contains(concat(\' \', normalize-space(string(@alt)), \' \'), %1$s)]]', static::xpathLiteral(' '.$value.' '))
);
}








public function selectImage($value)
{
$xpath = sprintf('descendant-or-self::img[contains(normalize-space(string(@alt)), %s)]', static::xpathLiteral($value));

return $this->filterRelativeXPath($xpath);
}








public function selectButton($value)
{
return $this->filterRelativeXPath(
sprintf('descendant-or-self::input[((contains(%1$s, "submit") or contains(%1$s, "button")) and contains(concat(\' \', normalize-space(string(@value)), \' \'), %2$s)) or (contains(%1$s, "image") and contains(concat(\' \', normalize-space(string(@alt)), \' \'), %2$s)) or @id=%3$s or @name=%3$s] | descendant-or-self::button[contains(concat(\' \', normalize-space(string(.)), \' \'), %2$s) or @id=%3$s or @name=%3$s]', 'translate(@type, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz")', static::xpathLiteral(' '.$value.' '), static::xpathLiteral($value))
);
}










public function link($method = 'get')
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}

$node = $this->getNode(0);

if (!$node instanceof \DOMElement) {
throw new \InvalidArgumentException(sprintf('The selected node should be instance of DOMElement, got "%s".', \get_class($node)));
}

return new Link($node, $this->baseHref, $method);
}








public function links()
{
$links = [];
foreach ($this->nodes as $node) {
if (!$node instanceof \DOMElement) {
throw new \InvalidArgumentException(sprintf('The current node list should contain only DOMElement instances, "%s" found.', \get_class($node)));
}

$links[] = new Link($node, $this->baseHref, 'get');
}

return $links;
}








public function image()
{
if (!\count($this)) {
throw new \InvalidArgumentException('The current node list is empty.');
}

$node = $this->getNode(0);

if (!$node instanceof \DOMElement) {
throw new \InvalidArgumentException(sprintf('The selected node should be instance of DOMElement, got "%s".', \get_class($node)));
}

return new Image($node, $this->baseHref);
}






public function images()
{
$images = [];
foreach ($this as $node) {
if (!$node instanceof \DOMElement) {
throw new \InvalidArgumentException(sprintf('The current node list should contain only DOMElement instances, "%s" found.', \get_class($node)));
}

$images[] = new Image($node, $this->baseHref);
}

return $images;
}











public function form(array $values = null, $method = null)
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
}

$node = $this->getNode(0);

if (!$node instanceof \DOMElement) {
throw new \InvalidArgumentException(sprintf('The selected node should be instance of DOMElement, got "%s".', \get_class($node)));
}

$form = new Form($node, $this->uri, $method, $this->baseHref);

if (null !== $values) {
$form->setValues($values);
}

return $form;
}






public function setDefaultNamespacePrefix($prefix)
{
$this->defaultNamespacePrefix = $prefix;
}





public function registerNamespace($prefix, $namespace)
{
$this->namespaces[$prefix] = $namespace;
}





















public static function xpathLiteral($s)
{
if (!str_contains($s, "'")) {
return sprintf("'%s'", $s);
}

if (!str_contains($s, '"')) {
return sprintf('"%s"', $s);
}

$string = $s;
$parts = [];
while (true) {
if (false !== $pos = strpos($string, "'")) {
$parts[] = sprintf("'%s'", substr($string, 0, $pos));
$parts[] = "\"'\"";
$string = substr($string, $pos + 1);
} else {
$parts[] = "'$string'";
break;
}
}

return sprintf('concat(%s)', implode(', ', $parts));
}








private function filterRelativeXPath(string $xpath)
{
$prefixes = $this->findNamespacePrefixes($xpath);

$crawler = $this->createSubCrawler(null);

foreach ($this->nodes as $node) {
$domxpath = $this->createDOMXPath($node->ownerDocument, $prefixes);
$crawler->add($domxpath->query($xpath, $node));
}

return $crawler;
}







private function relativize(string $xpath): string
{
$expressions = [];


 
 $nonMatchingExpression = 'a[name() = "b"]';

$xpathLen = \strlen($xpath);
$openedBrackets = 0;
$startPosition = strspn($xpath, " \t\n\r\0\x0B");

for ($i = $startPosition; $i <= $xpathLen; ++$i) {
$i += strcspn($xpath, '"\'[]|', $i);

if ($i < $xpathLen) {
switch ($xpath[$i]) {
case '"':
case "'":
if (false === $i = strpos($xpath, $xpath[$i], $i + 1)) {
return $xpath; 
 }
continue 2;
case '[':
++$openedBrackets;
continue 2;
case ']':
--$openedBrackets;
continue 2;
}
}
if ($openedBrackets) {
continue;
}

if ($startPosition < $xpathLen && '(' === $xpath[$startPosition]) {

 
 $j = 1 + strspn($xpath, "( \t\n\r\0\x0B", $startPosition + 1);
$parenthesis = substr($xpath, $startPosition, $j);
$startPosition += $j;
} else {
$parenthesis = '';
}
$expression = rtrim(substr($xpath, $startPosition, $i - $startPosition));

if (str_starts_with($expression, 'self::*/')) {
$expression = './'.substr($expression, 8);
}


 if ('' === $expression) {
$expression = $nonMatchingExpression;
} elseif (str_starts_with($expression, '//')) {
$expression = 'descendant-or-self::'.substr($expression, 2);
} elseif (str_starts_with($expression, './/')) {
$expression = 'descendant-or-self::'.substr($expression, 3);
} elseif (str_starts_with($expression, './')) {
$expression = 'self::'.substr($expression, 2);
} elseif (str_starts_with($expression, 'child::')) {
$expression = 'self::'.substr($expression, 7);
} elseif ('/' === $expression[0] || '.' === $expression[0] || str_starts_with($expression, 'self::')) {
$expression = $nonMatchingExpression;
} elseif (str_starts_with($expression, 'descendant::')) {
$expression = 'descendant-or-self::'.substr($expression, 12);
} elseif (preg_match('/^(ancestor|ancestor-or-self|attribute|following|following-sibling|namespace|parent|preceding|preceding-sibling)::/', $expression)) {

 $expression = $nonMatchingExpression;
} elseif (!str_starts_with($expression, 'descendant-or-self::')) {
$expression = 'self::'.$expression;
}
$expressions[] = $parenthesis.$expression;

if ($i === $xpathLen) {
return implode(' | ', $expressions);
}

$i += strspn($xpath, " \t\n\r\0\x0B", $i + 1);
$startPosition = $i + 1;
}

return $xpath; 
 }






public function getNode($position)
{
return $this->nodes[$position] ?? null;
}





 public function count()
{
return \count($this->nodes);
}





 public function getIterator()
{
return new \ArrayIterator($this->nodes);
}







protected function sibling($node, $siblingDir = 'nextSibling')
{
$nodes = [];

$currentNode = $this->getNode(0);
do {
if ($node !== $currentNode && \XML_ELEMENT_NODE === $node->nodeType) {
$nodes[] = $node;
}
} while ($node = $node->$siblingDir);

return $nodes;
}

private function parseHtml5(string $htmlContent, string $charset = 'UTF-8'): \DOMDocument
{
return $this->html5Parser->parse($this->convertToHtmlEntities($htmlContent, $charset), [], $charset);
}

private function parseXhtml(string $htmlContent, string $charset = 'UTF-8'): \DOMDocument
{
$htmlContent = $this->convertToHtmlEntities($htmlContent, $charset);

$internalErrors = libxml_use_internal_errors(true);
if (\LIBXML_VERSION < 20900) {
$disableEntities = libxml_disable_entity_loader(true);
}

$dom = new \DOMDocument('1.0', $charset);
$dom->validateOnParse = true;

if ('' !== trim($htmlContent)) {
@$dom->loadHTML($htmlContent);
}

libxml_use_internal_errors($internalErrors);
if (\LIBXML_VERSION < 20900) {
libxml_disable_entity_loader($disableEntities);
}

return $dom;
}




private function convertToHtmlEntities(string $htmlContent, string $charset = 'UTF-8'): string
{
set_error_handler(function () { throw new \Exception(); });

try {
return mb_convert_encoding($htmlContent, 'HTML-ENTITIES', $charset);
} catch (\Exception | \ValueError $e) {
try {
$htmlContent = iconv($charset, 'UTF-8', $htmlContent);
$htmlContent = mb_convert_encoding($htmlContent, 'HTML-ENTITIES', 'UTF-8');
} catch (\Exception | \ValueError $e) {
}

return $htmlContent;
} finally {
restore_error_handler();
}
}




private function createDOMXPath(\DOMDocument $document, array $prefixes = []): \DOMXPath
{
$domxpath = new \DOMXPath($document);

foreach ($prefixes as $prefix) {
$namespace = $this->discoverNamespace($domxpath, $prefix);
if (null !== $namespace) {
$domxpath->registerNamespace($prefix, $namespace);
}
}

return $domxpath;
}




private function discoverNamespace(\DOMXPath $domxpath, string $prefix): ?string
{
if (isset($this->namespaces[$prefix])) {
return $this->namespaces[$prefix];
}


 $namespaces = $domxpath->query(sprintf('(//namespace::*[name()="%s"])[last()]', $this->defaultNamespacePrefix === $prefix ? '' : $prefix));

return ($node = $namespaces->item(0)) ? $node->nodeValue : null;
}

private function findNamespacePrefixes(string $xpath): array
{
if (preg_match_all('/(?P<prefix>[a-z_][a-z_0-9\-\.]*+):[^"\/:]/i', $xpath, $matches)) {
return array_unique($matches['prefix']);
}

return [];
}








private function createSubCrawler($nodes)
{
$crawler = new static($nodes, $this->uri, $this->baseHref);
$crawler->isHtml = $this->isHtml;
$crawler->document = $this->document;
$crawler->namespaces = $this->namespaces;
$crawler->html5Parser = $this->html5Parser;

return $crawler;
}




private function createCssSelectorConverter(): CssSelectorConverter
{
if (!class_exists(CssSelectorConverter::class)) {
throw new \LogicException('To filter with a CSS selector, install the CssSelector component ("composer require symfony/css-selector"). Or use filterXpath instead.');
}

return new CssSelectorConverter($this->isHtml);
}





private function parseHtmlString(string $content, string $charset): \DOMDocument
{
if ($this->canParseHtml5String($content)) {
return $this->parseHtml5($content, $charset);
}

return $this->parseXhtml($content, $charset);
}

private function canParseHtml5String(string $content): bool
{
if (null === $this->html5Parser) {
return false;
}
if (false === ($pos = stripos($content, '<!doctype html>'))) {
return false;
}
$header = substr($content, 0, $pos);

return '' === $header || $this->isValidHtml5Heading($header);
}

private function isValidHtml5Heading(string $heading): bool
{
return 1 === preg_match('/^\x{FEFF}?\s*(<!--[^>]*?-->\s*)*$/u', $heading);
}
}
<?php










namespace Symfony\Component\DomCrawler;




class Image extends AbstractUriElement
{
public function __construct(\DOMElement $node, string $currentUri = null)
{
parent::__construct($node, $currentUri, 'GET');
}

protected function getRawUri()
{
return $this->node->getAttribute('src');
}

protected function setNode(\DOMElement $node)
{
if ('img' !== $node->nodeName) {
throw new \LogicException(sprintf('Unable to visualize a "%s" tag.', $node->nodeName));
}

$this->node = $node;
}
}
<?php










namespace Symfony\Component\DomCrawler;

use Symfony\Component\DomCrawler\Field\FormField;






class FormFieldRegistry
{
private $fields = [];

private $base = '';




public function add(FormField $field)
{
$segments = $this->getSegments($field->getName());

$target = &$this->fields;
while ($segments) {
if (!\is_array($target)) {
$target = [];
}
$path = array_shift($segments);
if ('' === $path) {
$target = &$target[];
} else {
$target = &$target[$path];
}
}
$target = $field;
}




public function remove(string $name)
{
$segments = $this->getSegments($name);
$target = &$this->fields;
while (\count($segments) > 1) {
$path = array_shift($segments);
if (!\is_array($target) || !\array_key_exists($path, $target)) {
return;
}
$target = &$target[$path];
}
unset($target[array_shift($segments)]);
}








public function &get(string $name)
{
$segments = $this->getSegments($name);
$target = &$this->fields;
while ($segments) {
$path = array_shift($segments);
if (!\is_array($target) || !\array_key_exists($path, $target)) {
throw new \InvalidArgumentException(sprintf('Unreachable field "%s".', $path));
}
$target = &$target[$path];
}

return $target;
}






public function has(string $name): bool
{
try {
$this->get($name);

return true;
} catch (\InvalidArgumentException $e) {
return false;
}
}








public function set(string $name, $value)
{
$target = &$this->get($name);
if ((!\is_array($value) && $target instanceof Field\FormField) || $target instanceof Field\ChoiceFormField) {
$target->setValue($value);
} elseif (\is_array($value)) {
$registry = new static();
$registry->base = $name;
$registry->fields = $value;
foreach ($registry->all() as $k => $v) {
$this->set($k, $v);
}
} else {
throw new \InvalidArgumentException(sprintf('Cannot set value on a compound field "%s".', $name));
}
}






public function all(): array
{
return $this->walk($this->fields, $this->base);
}




private function walk(array $array, ?string $base = '', array &$output = []): array
{
foreach ($array as $k => $v) {
$path = empty($base) ? $k : sprintf('%s[%s]', $base, $k);
if (\is_array($v)) {
$this->walk($v, $path, $output);
} else {
$output[$path] = $v;
}
}

return $output;
}








private function getSegments(string $name): array
{
if (preg_match('/^(?P<base>[^[]+)(?P<extra>(\[.*)|$)/', $name, $m)) {
$segments = [$m['base']];
while (!empty($m['extra'])) {
$extra = $m['extra'];
if (preg_match('/^\[(?P<segment>.*?)\](?P<extra>.*)$/', $extra, $m)) {
$segments[] = $m['segment'];
} else {
$segments[] = $extra;
}
}

return $segments;
}

return [$name];
}
}
<?php










namespace Symfony\Component\DomCrawler;






abstract class AbstractUriElement
{



protected $node;




protected $method;




protected $currentUri;








public function __construct(\DOMElement $node, string $currentUri = null, ?string $method = 'GET')
{
$this->setNode($node);
$this->method = $method ? strtoupper($method) : null;
$this->currentUri = $currentUri;

$elementUriIsRelative = null === parse_url(trim($this->getRawUri()), \PHP_URL_SCHEME);
$baseUriIsAbsolute = null !== $this->currentUri && \in_array(strtolower(substr($this->currentUri, 0, 4)), ['http', 'file']);
if ($elementUriIsRelative && !$baseUriIsAbsolute) {
throw new \InvalidArgumentException(sprintf('The URL of the element is relative, so you must define its base URI passing an absolute URL to the constructor of the "%s" class ("%s" was passed).', __CLASS__, $this->currentUri));
}
}






public function getNode()
{
return $this->node;
}






public function getMethod()
{
return $this->method ?? 'GET';
}






public function getUri()
{
$uri = trim($this->getRawUri());


 if (null !== parse_url($uri, \PHP_URL_SCHEME)) {
return $uri;
}


 if (!$uri) {
return $this->currentUri;
}


 if ('#' === $uri[0]) {
return $this->cleanupAnchor($this->currentUri).$uri;
}

$baseUri = $this->cleanupUri($this->currentUri);

if ('?' === $uri[0]) {
return $baseUri.$uri;
}


 if (str_starts_with($uri, '//')) {
return preg_replace('#^([^/]*)//.*$#', '$1', $baseUri).$uri;
}

$baseUri = preg_replace('#^(.*?//[^/]*)(?:\/.*)?$#', '$1', $baseUri);


 if ('/' === $uri[0]) {
return $baseUri.$uri;
}


 $path = parse_url(substr($this->currentUri, \strlen($baseUri)), \PHP_URL_PATH);
$path = $this->canonicalizePath(substr($path, 0, strrpos($path, '/')).'/'.$uri);

return $baseUri.('' === $path || '/' !== $path[0] ? '/' : '').$path;
}






abstract protected function getRawUri();








protected function canonicalizePath($path)
{
if ('' === $path || '/' === $path) {
return $path;
}

if (str_ends_with($path, '.')) {
$path .= '/';
}

$output = [];

foreach (explode('/', $path) as $segment) {
if ('..' === $segment) {
array_pop($output);
} elseif ('.' !== $segment) {
$output[] = $segment;
}
}

return implode('/', $output);
}








abstract protected function setNode(\DOMElement $node);




private function cleanupUri(string $uri): string
{
return $this->cleanupQuery($this->cleanupAnchor($uri));
}




private function cleanupQuery(string $uri): string
{
if (false !== $pos = strpos($uri, '?')) {
return substr($uri, 0, $pos);
}

return $uri;
}




private function cleanupAnchor(string $uri): string
{
if (false !== $pos = strpos($uri, '#')) {
return substr($uri, 0, $pos);
}

return $uri;
}
}
<?php










namespace Symfony\Component\Console\Event;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;






final class ConsoleErrorEvent extends ConsoleEvent
{
private $error;
private $exitCode;

public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, Command $command = null)
{
parent::__construct($command, $input, $output);

$this->error = $error;
}

public function getError(): \Throwable
{
return $this->error;
}

public function setError(\Throwable $error): void
{
$this->error = $error;
}

public function setExitCode(int $exitCode): void
{
$this->exitCode = $exitCode;

$r = new \ReflectionProperty($this->error, 'code');
$r->setAccessible(true);
$r->setValue($this->error, $this->exitCode);
}

public function getExitCode(): int
{
return $this->exitCode ?? (\is_int($this->error->getCode()) && 0 !== $this->error->getCode() ? $this->error->getCode() : 1);
}
}
<?php










namespace Symfony\Component\Console\Event;








class ConsoleCommandEvent extends ConsoleEvent
{



public const RETURN_CODE_DISABLED = 113;




private $commandShouldRun = true;






public function disableCommand()
{
return $this->commandShouldRun = false;
}






public function enableCommand()
{
return $this->commandShouldRun = true;
}






public function commandShouldRun()
{
return $this->commandShouldRun;
}
}
<?php










namespace Symfony\Component\Console\Event;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;








class ConsoleTerminateEvent extends ConsoleEvent
{
private $exitCode;

public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $exitCode)
{
parent::__construct($command, $input, $output);

$this->setExitCode($exitCode);
}






public function setExitCode($exitCode)
{
$this->exitCode = (int) $exitCode;
}






public function getExitCode()
{
return $this->exitCode;
}
}
<?php










namespace Symfony\Component\Console\Event;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\EventDispatcher\Event;






class ConsoleEvent extends Event
{
protected $command;

private $input;
private $output;

public function __construct(?Command $command, InputInterface $input, OutputInterface $output)
{
$this->command = $command;
$this->input = $input;
$this->output = $output;
}






public function getCommand()
{
return $this->command;
}






public function getInput()
{
return $this->input;
}






public function getOutput()
{
return $this->output;
}
}
<?php










namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;









class NullOutput implements OutputInterface
{



public function setFormatter(OutputFormatterInterface $formatter)
{

 }




public function getFormatter()
{

 return new OutputFormatter();
}




public function setDecorated($decorated)
{

 }




public function isDecorated()
{
return false;
}




public function setVerbosity($level)
{

 }




public function getVerbosity()
{
return self::VERBOSITY_QUIET;
}




public function isQuiet()
{
return true;
}




public function isVerbose()
{
return false;
}




public function isVeryVerbose()
{
return false;
}




public function isDebug()
{
return false;
}




public function writeln($messages, $options = self::OUTPUT_NORMAL)
{

 }




public function write($messages, $newline = false, $options = self::OUTPUT_NORMAL)
{

 }
}
<?php










namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Formatter\OutputFormatterInterface;






interface OutputInterface
{
public const VERBOSITY_QUIET = 16;
public const VERBOSITY_NORMAL = 32;
public const VERBOSITY_VERBOSE = 64;
public const VERBOSITY_VERY_VERBOSE = 128;
public const VERBOSITY_DEBUG = 256;

public const OUTPUT_NORMAL = 1;
public const OUTPUT_RAW = 2;
public const OUTPUT_PLAIN = 4;








public function write($messages, $newline = false, $options = 0);







public function writeln($messages, $options = 0);






public function setVerbosity($level);






public function getVerbosity();






public function isQuiet();






public function isVerbose();






public function isVeryVerbose();






public function isDebug();






public function setDecorated($decorated);






public function isDecorated();

public function setFormatter(OutputFormatterInterface $formatter);






public function getFormatter();
}
<?php










namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Formatter\OutputFormatterInterface;















class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
{
private $stderr;
private $consoleSectionOutputs = [];






public function __construct(int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = null, OutputFormatterInterface $formatter = null)
{
parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter);

if (null === $formatter) {

 $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated);

return;
}

$actualDecorated = $this->isDecorated();
$this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter());

if (null === $decorated) {
$this->setDecorated($actualDecorated && $this->stderr->isDecorated());
}
}




public function section(): ConsoleSectionOutput
{
return new ConsoleSectionOutput($this->getStream(), $this->consoleSectionOutputs, $this->getVerbosity(), $this->isDecorated(), $this->getFormatter());
}




public function setDecorated($decorated)
{
parent::setDecorated($decorated);
$this->stderr->setDecorated($decorated);
}




public function setFormatter(OutputFormatterInterface $formatter)
{
parent::setFormatter($formatter);
$this->stderr->setFormatter($formatter);
}




public function setVerbosity($level)
{
parent::setVerbosity($level);
$this->stderr->setVerbosity($level);
}




public function getErrorOutput()
{
return $this->stderr;
}




public function setErrorOutput(OutputInterface $error)
{
$this->stderr = $error;
}







protected function hasStdoutSupport()
{
return false === $this->isRunningOS400();
}







protected function hasStderrSupport()
{
return false === $this->isRunningOS400();
}





private function isRunningOS400(): bool
{
$checks = [
\function_exists('php_uname') ? php_uname('s') : '',
getenv('OSTYPE'),
\PHP_OS,
];

return false !== stripos(implode(';', $checks), 'OS400');
}




private function openOutputStream()
{
if (!$this->hasStdoutSupport()) {
return fopen('php://output', 'w');
}

return @fopen('php://stdout', 'w') ?: fopen('php://output', 'w');
}




private function openErrorStream()
{
return fopen($this->hasStderrSupport() ? 'php://stderr' : 'php://output', 'w');
}
}
<?php










namespace Symfony\Component\Console\Output;




class BufferedOutput extends Output
{
private $buffer = '';






public function fetch()
{
$content = $this->buffer;
$this->buffer = '';

return $content;
}




protected function doWrite($message, $newline)
{
$this->buffer .= $message;

if ($newline) {
$this->buffer .= \PHP_EOL;
}
}
}
<?php










namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;






class TrimmedBufferOutput extends Output
{
private $maxLength;
private $buffer = '';

public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null)
{
if ($maxLength <= 0) {
throw new InvalidArgumentException(sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength));
}

parent::__construct($verbosity, $decorated, $formatter);
$this->maxLength = $maxLength;
}






public function fetch()
{
$content = $this->buffer;
$this->buffer = '';

return $content;
}




protected function doWrite($message, $newline)
{
$this->buffer .= $message;

if ($newline) {
$this->buffer .= \PHP_EOL;
}

$this->buffer = substr($this->buffer, 0 - $this->maxLength);
}
}
<?php










namespace Symfony\Component\Console\Output;









interface ConsoleOutputInterface extends OutputInterface
{





public function getErrorOutput();

public function setErrorOutput(OutputInterface $error);
}
<?php










namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;














abstract class Output implements OutputInterface
{
private $verbosity;
private $formatter;






public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null)
{
$this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity;
$this->formatter = $formatter ?? new OutputFormatter();
$this->formatter->setDecorated($decorated);
}




public function setFormatter(OutputFormatterInterface $formatter)
{
$this->formatter = $formatter;
}




public function getFormatter()
{
return $this->formatter;
}




public function setDecorated($decorated)
{
$this->formatter->setDecorated($decorated);
}




public function isDecorated()
{
return $this->formatter->isDecorated();
}




public function setVerbosity($level)
{
$this->verbosity = (int) $level;
}




public function getVerbosity()
{
return $this->verbosity;
}




public function isQuiet()
{
return self::VERBOSITY_QUIET === $this->verbosity;
}




public function isVerbose()
{
return self::VERBOSITY_VERBOSE <= $this->verbosity;
}




public function isVeryVerbose()
{
return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity;
}




public function isDebug()
{
return self::VERBOSITY_DEBUG <= $this->verbosity;
}




public function writeln($messages, $options = self::OUTPUT_NORMAL)
{
$this->write($messages, true, $options);
}




public function write($messages, $newline = false, $options = self::OUTPUT_NORMAL)
{
if (!is_iterable($messages)) {
$messages = [$messages];
}

$types = self::OUTPUT_NORMAL | self::OUTPUT_RAW | self::OUTPUT_PLAIN;
$type = $types & $options ?: self::OUTPUT_NORMAL;

$verbosities = self::VERBOSITY_QUIET | self::VERBOSITY_NORMAL | self::VERBOSITY_VERBOSE | self::VERBOSITY_VERY_VERBOSE | self::VERBOSITY_DEBUG;
$verbosity = $verbosities & $options ?: self::VERBOSITY_NORMAL;

if ($verbosity > $this->getVerbosity()) {
return;
}

foreach ($messages as $message) {
switch ($type) {
case OutputInterface::OUTPUT_NORMAL:
$message = $this->formatter->format($message);
break;
case OutputInterface::OUTPUT_RAW:
break;
case OutputInterface::OUTPUT_PLAIN:
$message = strip_tags($this->formatter->format($message));
break;
}

$this->doWrite($message ?? '', $newline);
}
}







abstract protected function doWrite($message, $newline);
}
<?php










namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;














class StreamOutput extends Output
{
private $stream;









public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = null, OutputFormatterInterface $formatter = null)
{
if (!\is_resource($stream) || 'stream' !== get_resource_type($stream)) {
throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
}

$this->stream = $stream;

if (null === $decorated) {
$decorated = $this->hasColorSupport();
}

parent::__construct($verbosity, $decorated, $formatter);
}






public function getStream()
{
return $this->stream;
}




protected function doWrite($message, $newline)
{
if ($newline) {
$message .= \PHP_EOL;
}

@fwrite($this->stream, $message);

fflush($this->stream);
}














protected function hasColorSupport()
{

 if (isset($_SERVER['NO_COLOR']) || false !== getenv('NO_COLOR')) {
return false;
}

if ('Hyper' === getenv('TERM_PROGRAM')) {
return true;
}

if (\DIRECTORY_SEPARATOR === '\\') {
return (\function_exists('sapi_windows_vt100_support')
&& @sapi_windows_vt100_support($this->stream))
|| false !== getenv('ANSICON')
|| 'ON' === getenv('ConEmuANSI')
|| 'xterm' === getenv('TERM');
}

if (\function_exists('stream_isatty')) {
return @stream_isatty($this->stream);
}

if (\function_exists('posix_isatty')) {
return @posix_isatty($this->stream);
}

$stat = @fstat($this->stream);

 return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
}
}
<?php










namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Formatter\OutputFormatterInterface;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Terminal;





class ConsoleSectionOutput extends StreamOutput
{
private $content = [];
private $lines = 0;
private $sections;
private $terminal;





public function __construct($stream, array &$sections, int $verbosity, bool $decorated, OutputFormatterInterface $formatter)
{
parent::__construct($stream, $verbosity, $decorated, $formatter);
array_unshift($sections, $this);
$this->sections = &$sections;
$this->terminal = new Terminal();
}






public function clear(int $lines = null)
{
if (empty($this->content) || !$this->isDecorated()) {
return;
}

if ($lines) {
array_splice($this->content, -($lines * 2)); 
 } else {
$lines = $this->lines;
$this->content = [];
}

$this->lines -= $lines;

parent::doWrite($this->popStreamContentUntilCurrentSection($lines), false);
}






public function overwrite($message)
{
$this->clear();
$this->writeln($message);
}

public function getContent(): string
{
return implode('', $this->content);
}




public function addContent(string $input)
{
foreach (explode(\PHP_EOL, $input) as $lineContent) {
$this->lines += ceil($this->getDisplayLength($lineContent) / $this->terminal->getWidth()) ?: 1;
$this->content[] = $lineContent;
$this->content[] = \PHP_EOL;
}
}




protected function doWrite($message, $newline)
{
if (!$this->isDecorated()) {
parent::doWrite($message, $newline);

return;
}

$erasedContent = $this->popStreamContentUntilCurrentSection();

$this->addContent($message);

parent::doWrite($message, true);
parent::doWrite($erasedContent, false);
}





private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFromCurrentSection = 0): string
{
$numberOfLinesToClear = $numberOfLinesToClearFromCurrentSection;
$erasedContent = [];

foreach ($this->sections as $section) {
if ($section === $this) {
break;
}

$numberOfLinesToClear += $section->lines;
$erasedContent[] = $section->getContent();
}

if ($numberOfLinesToClear > 0) {

 parent::doWrite(sprintf("\x1b[%dA", $numberOfLinesToClear), false);

 parent::doWrite("\x1b[0J", false);
}

return implode('', array_reverse($erasedContent));
}

private function getDisplayLength(string $text): string
{
return Helper::strlenWithoutDecoration($this->getFormatter(), str_replace("\t", '        ', $text));
}
}
<?php










namespace Symfony\Component\Console;

class Terminal
{
private static $width;
private static $height;
private static $stty;






public function getWidth()
{
$width = getenv('COLUMNS');
if (false !== $width) {
return (int) trim($width);
}

if (null === self::$width) {
self::initDimensions();
}

return self::$width ?: 80;
}






public function getHeight()
{
$height = getenv('LINES');
if (false !== $height) {
return (int) trim($height);
}

if (null === self::$height) {
self::initDimensions();
}

return self::$height ?: 50;
}






public static function hasSttyAvailable()
{
if (null !== self::$stty) {
return self::$stty;
}


 if (!\function_exists('exec')) {
return false;
}

exec('stty 2>&1', $output, $exitcode);

return self::$stty = 0 === $exitcode;
}

private static function initDimensions()
{
if ('\\' === \DIRECTORY_SEPARATOR) {
if (preg_match('/^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$/', trim(getenv('ANSICON')), $matches)) {

 
 self::$width = (int) $matches[1];
self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2];
} elseif (!self::hasVt100Support() && self::hasSttyAvailable()) {

 
 self::initDimensionsUsingStty();
} elseif (null !== $dimensions = self::getConsoleMode()) {

 self::$width = (int) $dimensions[0];
self::$height = (int) $dimensions[1];
}
} else {
self::initDimensionsUsingStty();
}
}




private static function hasVt100Support(): bool
{
return \function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support(fopen('php://stdout', 'w'));
}




private static function initDimensionsUsingStty()
{
if ($sttyString = self::getSttyColumns()) {
if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {

 self::$width = (int) $matches[2];
self::$height = (int) $matches[1];
} elseif (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) {

 self::$width = (int) $matches[2];
self::$height = (int) $matches[1];
}
}
}






private static function getConsoleMode(): ?array
{
$info = self::readFromProcess('mode CON');

if (null === $info || !preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
return null;
}

return [(int) $matches[2], (int) $matches[1]];
}




private static function getSttyColumns(): ?string
{
return self::readFromProcess('stty -a | grep columns');
}

private static function readFromProcess(string $command): ?string
{
if (!\function_exists('proc_open')) {
return null;
}

$descriptorspec = [
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
];

$process = proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true]);
if (!\is_resource($process)) {
return null;
}

$info = stream_get_contents($pipes[1]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);

return $info;
}
}
<?php










namespace Symfony\Component\Console;






final class ConsoleEvents
{







public const COMMAND = 'console.command';







public const TERMINATE = 'console.terminate';









public const ERROR = 'console.error';
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Input\InputAwareInterface;
use Symfony\Component\Console\Input\InputInterface;






abstract class InputAwareHelper extends Helper implements InputAwareInterface
{
protected $input;




public function setInput(InputInterface $input)
{
$this->input = $input;
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Formatter\WrappableOutputFormatterInterface;
use Symfony\Component\Console\Output\ConsoleSectionOutput;
use Symfony\Component\Console\Output\OutputInterface;










class Table
{
private const SEPARATOR_TOP = 0;
private const SEPARATOR_TOP_BOTTOM = 1;
private const SEPARATOR_MID = 2;
private const SEPARATOR_BOTTOM = 3;
private const BORDER_OUTSIDE = 0;
private const BORDER_INSIDE = 1;

private $headerTitle;
private $footerTitle;




private $headers = [];




private $rows = [];
private $horizontal = false;




private $effectiveColumnWidths = [];






private $numberOfColumns;




private $output;




private $style;




private $columnStyles = [];






private $columnWidths = [];
private $columnMaxWidths = [];

private static $styles;

private $rendered = false;

public function __construct(OutputInterface $output)
{
$this->output = $output;

if (!self::$styles) {
self::$styles = self::initStyles();
}

$this->setStyle('default');
}






public static function setStyleDefinition($name, TableStyle $style)
{
if (!self::$styles) {
self::$styles = self::initStyles();
}

self::$styles[$name] = $style;
}








public static function getStyleDefinition($name)
{
if (!self::$styles) {
self::$styles = self::initStyles();
}

if (isset(self::$styles[$name])) {
return self::$styles[$name];
}

throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
}








public function setStyle($name)
{
$this->style = $this->resolveStyle($name);

return $this;
}






public function getStyle()
{
return $this->style;
}









public function setColumnStyle($columnIndex, $name)
{
$columnIndex = (int) $columnIndex;

$this->columnStyles[$columnIndex] = $this->resolveStyle($name);

return $this;
}










public function getColumnStyle($columnIndex)
{
return $this->columnStyles[$columnIndex] ?? $this->getStyle();
}









public function setColumnWidth($columnIndex, $width)
{
$this->columnWidths[(int) $columnIndex] = (int) $width;

return $this;
}






public function setColumnWidths(array $widths)
{
$this->columnWidths = [];
foreach ($widths as $index => $width) {
$this->setColumnWidth($index, $width);
}

return $this;
}









public function setColumnMaxWidth(int $columnIndex, int $width): self
{
if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) {
throw new \LogicException(sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, \get_class($this->output->getFormatter())));
}

$this->columnMaxWidths[$columnIndex] = $width;

return $this;
}

public function setHeaders(array $headers)
{
$headers = array_values($headers);
if (!empty($headers) && !\is_array($headers[0])) {
$headers = [$headers];
}

$this->headers = $headers;

return $this;
}

public function setRows(array $rows)
{
$this->rows = [];

return $this->addRows($rows);
}

public function addRows(array $rows)
{
foreach ($rows as $row) {
$this->addRow($row);
}

return $this;
}

public function addRow($row)
{
if ($row instanceof TableSeparator) {
$this->rows[] = $row;

return $this;
}

if (!\is_array($row)) {
throw new InvalidArgumentException('A row must be an array or a TableSeparator instance.');
}

$this->rows[] = array_values($row);

return $this;
}




public function appendRow($row): self
{
if (!$this->output instanceof ConsoleSectionOutput) {
throw new RuntimeException(sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__));
}

if ($this->rendered) {
$this->output->clear($this->calculateRowCount());
}

$this->addRow($row);
$this->render();

return $this;
}

public function setRow($column, array $row)
{
$this->rows[$column] = $row;

return $this;
}

public function setHeaderTitle(?string $title): self
{
$this->headerTitle = $title;

return $this;
}

public function setFooterTitle(?string $title): self
{
$this->footerTitle = $title;

return $this;
}

public function setHorizontal(bool $horizontal = true): self
{
$this->horizontal = $horizontal;

return $this;
}














public function render()
{
$divider = new TableSeparator();
if ($this->horizontal) {
$rows = [];
foreach ($this->headers[0] ?? [] as $i => $header) {
$rows[$i] = [$header];
foreach ($this->rows as $row) {
if ($row instanceof TableSeparator) {
continue;
}
if (isset($row[$i])) {
$rows[$i][] = $row[$i];
} elseif ($rows[$i][0] instanceof TableCell && $rows[$i][0]->getColspan() >= 2) {

 } else {
$rows[$i][] = null;
}
}
}
} else {
$rows = array_merge($this->headers, [$divider], $this->rows);
}

$this->calculateNumberOfColumns($rows);

$rows = $this->buildTableRows($rows);
$this->calculateColumnsWidth($rows);

$isHeader = !$this->horizontal;
$isFirstRow = $this->horizontal;
$hasTitle = (bool) $this->headerTitle;
foreach ($rows as $row) {
if ($divider === $row) {
$isHeader = false;
$isFirstRow = true;

continue;
}
if ($row instanceof TableSeparator) {
$this->renderRowSeparator();

continue;
}
if (!$row) {
continue;
}

if ($isHeader || $isFirstRow) {
$this->renderRowSeparator(
$isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM,
$hasTitle ? $this->headerTitle : null,
$hasTitle ? $this->style->getHeaderTitleFormat() : null
);
$isFirstRow = false;
$hasTitle = false;
}
if ($this->horizontal) {
$this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat());
} else {
$this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat());
}
}
$this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat());

$this->cleanup();
$this->rendered = true;
}








private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $title = null, string $titleFormat = null)
{
if (0 === $count = $this->numberOfColumns) {
return;
}

$borders = $this->style->getBorderChars();
if (!$borders[0] && !$borders[2] && !$this->style->getCrossingChar()) {
return;
}

$crossings = $this->style->getCrossingChars();
if (self::SEPARATOR_MID === $type) {
[$horizontal, $leftChar, $midChar, $rightChar] = [$borders[2], $crossings[8], $crossings[0], $crossings[4]];
} elseif (self::SEPARATOR_TOP === $type) {
[$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[1], $crossings[2], $crossings[3]];
} elseif (self::SEPARATOR_TOP_BOTTOM === $type) {
[$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[9], $crossings[10], $crossings[11]];
} else {
[$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[7], $crossings[6], $crossings[5]];
}

$markup = $leftChar;
for ($column = 0; $column < $count; ++$column) {
$markup .= str_repeat($horizontal, $this->effectiveColumnWidths[$column]);
$markup .= $column === $count - 1 ? $rightChar : $midChar;
}

if (null !== $title) {
$titleLength = Helper::strlenWithoutDecoration($formatter = $this->output->getFormatter(), $formattedTitle = sprintf($titleFormat, $title));
$markupLength = Helper::strlen($markup);
if ($titleLength > $limit = $markupLength - 4) {
$titleLength = $limit;
$formatLength = Helper::strlenWithoutDecoration($formatter, sprintf($titleFormat, ''));
$formattedTitle = sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...');
}

$titleStart = intdiv($markupLength - $titleLength, 2);
if (false === mb_detect_encoding($markup, null, true)) {
$markup = substr_replace($markup, $formattedTitle, $titleStart, $titleLength);
} else {
$markup = mb_substr($markup, 0, $titleStart).$formattedTitle.mb_substr($markup, $titleStart + $titleLength);
}
}

$this->output->writeln(sprintf($this->style->getBorderFormat(), $markup));
}




private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE): string
{
$borders = $this->style->getBorderChars();

return sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]);
}








private function renderRow(array $row, string $cellFormat, string $firstCellFormat = null)
{
$rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE);
$columns = $this->getRowColumns($row);
$last = \count($columns) - 1;
foreach ($columns as $i => $column) {
if ($firstCellFormat && 0 === $i) {
$rowContent .= $this->renderCell($row, $column, $firstCellFormat);
} else {
$rowContent .= $this->renderCell($row, $column, $cellFormat);
}
$rowContent .= $this->renderColumnSeparator($last === $i ? self::BORDER_OUTSIDE : self::BORDER_INSIDE);
}
$this->output->writeln($rowContent);
}




private function renderCell(array $row, int $column, string $cellFormat): string
{
$cell = $row[$column] ?? '';
$width = $this->effectiveColumnWidths[$column];
if ($cell instanceof TableCell && $cell->getColspan() > 1) {

 foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) {
$width += $this->getColumnSeparatorWidth() + $this->effectiveColumnWidths[$nextColumn];
}
}


 if (false !== $encoding = mb_detect_encoding($cell, null, true)) {
$width += \strlen($cell) - mb_strwidth($cell, $encoding);
}

$style = $this->getColumnStyle($column);

if ($cell instanceof TableSeparator) {
return sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width));
}

$width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
$content = sprintf($style->getCellRowContentFormat(), $cell);

return sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $style->getPadType()));
}




private function calculateNumberOfColumns(array $rows)
{
$columns = [0];
foreach ($rows as $row) {
if ($row instanceof TableSeparator) {
continue;
}

$columns[] = $this->getNumberOfColumns($row);
}

$this->numberOfColumns = max($columns);
}

private function buildTableRows(array $rows): TableRows
{

$formatter = $this->output->getFormatter();
$unmergedRows = [];
for ($rowKey = 0; $rowKey < \count($rows); ++$rowKey) {
$rows = $this->fillNextRows($rows, $rowKey);


 foreach ($rows[$rowKey] as $column => $cell) {
$colspan = $cell instanceof TableCell ? $cell->getColspan() : 1;

if (isset($this->columnMaxWidths[$column]) && Helper::strlenWithoutDecoration($formatter, $cell) > $this->columnMaxWidths[$column]) {
$cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan);
}
if (!strstr($cell ?? '', "\n")) {
continue;
}
$escaped = implode("\n", array_map([OutputFormatter::class, 'escapeTrailingBackslash'], explode("\n", $cell)));
$cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped;
$lines = explode("\n", str_replace("\n", "<fg=default;bg=default>\n</>", $cell));
foreach ($lines as $lineKey => $line) {
if ($colspan > 1) {
$line = new TableCell($line, ['colspan' => $colspan]);
}
if (0 === $lineKey) {
$rows[$rowKey][$column] = $line;
} else {
if (!\array_key_exists($rowKey, $unmergedRows) || !\array_key_exists($lineKey, $unmergedRows[$rowKey])) {
$unmergedRows[$rowKey][$lineKey] = $this->copyRow($rows, $rowKey);
}
$unmergedRows[$rowKey][$lineKey][$column] = $line;
}
}
}
}

return new TableRows(function () use ($rows, $unmergedRows): \Traversable {
foreach ($rows as $rowKey => $row) {
yield $row instanceof TableSeparator ? $row : $this->fillCells($row);

if (isset($unmergedRows[$rowKey])) {
foreach ($unmergedRows[$rowKey] as $row) {
yield $row instanceof TableSeparator ? $row : $this->fillCells($row);
}
}
}
});
}

private function calculateRowCount(): int
{
$numberOfRows = \count(iterator_to_array($this->buildTableRows(array_merge($this->headers, [new TableSeparator()], $this->rows))));

if ($this->headers) {
++$numberOfRows; 
 }

if (\count($this->rows) > 0) {
++$numberOfRows; 
 }

return $numberOfRows;
}






private function fillNextRows(array $rows, int $line): array
{
$unmergedRows = [];
foreach ($rows[$line] as $column => $cell) {
if (null !== $cell && !$cell instanceof TableCell && !is_scalar($cell) && !(\is_object($cell) && method_exists($cell, '__toString'))) {
throw new InvalidArgumentException(sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', \gettype($cell)));
}
if ($cell instanceof TableCell && $cell->getRowspan() > 1) {
$nbLines = $cell->getRowspan() - 1;
$lines = [$cell];
if (strstr($cell, "\n")) {
$lines = explode("\n", str_replace("\n", "<fg=default;bg=default>\n</>", $cell));
$nbLines = \count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines;

$rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan()]);
unset($lines[0]);
}


 $unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, []), $unmergedRows);
foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
$value = $lines[$unmergedRowKey - $line] ?? '';
$unmergedRows[$unmergedRowKey][$column] = new TableCell($value, ['colspan' => $cell->getColspan()]);
if ($nbLines === $unmergedRowKey - $line) {
break;
}
}
}
}

foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {

 if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && ($this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns)) {
foreach ($unmergedRow as $cellKey => $cell) {

 array_splice($rows[$unmergedRowKey], $cellKey, 0, [$cell]);
}
} else {
$row = $this->copyRow($rows, $unmergedRowKey - 1);
foreach ($unmergedRow as $column => $cell) {
if (!empty($cell)) {
$row[$column] = $unmergedRow[$column];
}
}
array_splice($rows, $unmergedRowKey, 0, [$row]);
}
}

return $rows;
}




private function fillCells(iterable $row)
{
$newRow = [];

foreach ($row as $column => $cell) {
$newRow[] = $cell;
if ($cell instanceof TableCell && $cell->getColspan() > 1) {
foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) {

 $newRow[] = '';
}
}
}

return $newRow ?: $row;
}

private function copyRow(array $rows, int $line): array
{
$row = $rows[$line];
foreach ($row as $cellKey => $cellValue) {
$row[$cellKey] = '';
if ($cellValue instanceof TableCell) {
$row[$cellKey] = new TableCell('', ['colspan' => $cellValue->getColspan()]);
}
}

return $row;
}




private function getNumberOfColumns(array $row): int
{
$columns = \count($row);
foreach ($row as $column) {
$columns += $column instanceof TableCell ? ($column->getColspan() - 1) : 0;
}

return $columns;
}




private function getRowColumns(array $row): array
{
$columns = range(0, $this->numberOfColumns - 1);
foreach ($row as $cellKey => $cell) {
if ($cell instanceof TableCell && $cell->getColspan() > 1) {

 $columns = array_diff($columns, range($cellKey + 1, $cellKey + $cell->getColspan() - 1));
}
}

return $columns;
}




private function calculateColumnsWidth(iterable $rows)
{
for ($column = 0; $column < $this->numberOfColumns; ++$column) {
$lengths = [];
foreach ($rows as $row) {
if ($row instanceof TableSeparator) {
continue;
}

foreach ($row as $i => $cell) {
if ($cell instanceof TableCell) {
$textContent = Helper::removeDecoration($this->output->getFormatter(), $cell);
$textLength = Helper::strlen($textContent);
if ($textLength > 0) {
$contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan()));
foreach ($contentColumns as $position => $content) {
$row[$i + $position] = $content;
}
}
}
}

$lengths[] = $this->getCellWidth($row, $column);
}

$this->effectiveColumnWidths[$column] = max($lengths) + Helper::strlen($this->style->getCellRowContentFormat()) - 2;
}
}

private function getColumnSeparatorWidth(): int
{
return Helper::strlen(sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3]));
}

private function getCellWidth(array $row, int $column): int
{
$cellWidth = 0;

if (isset($row[$column])) {
$cell = $row[$column];
$cellWidth = Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
}

$columnWidth = $this->columnWidths[$column] ?? 0;
$cellWidth = max($cellWidth, $columnWidth);

return isset($this->columnMaxWidths[$column]) ? min($this->columnMaxWidths[$column], $cellWidth) : $cellWidth;
}




private function cleanup()
{
$this->effectiveColumnWidths = [];
$this->numberOfColumns = null;
}

private static function initStyles(): array
{
$borderless = new TableStyle();
$borderless
->setHorizontalBorderChars('=')
->setVerticalBorderChars(' ')
->setDefaultCrossingChar(' ')
;

$compact = new TableStyle();
$compact
->setHorizontalBorderChars('')
->setVerticalBorderChars(' ')
->setDefaultCrossingChar('')
->setCellRowContentFormat('%s')
;

$styleGuide = new TableStyle();
$styleGuide
->setHorizontalBorderChars('-')
->setVerticalBorderChars(' ')
->setDefaultCrossingChar(' ')
->setCellHeaderFormat('%s')
;

$box = (new TableStyle())
->setHorizontalBorderChars('─')
->setVerticalBorderChars('│')
->setCrossingChars('┼', '┌', '┬', '┐', '┤', '┘', '┴', '└', '├')
;

$boxDouble = (new TableStyle())
->setHorizontalBorderChars('═', '─')
->setVerticalBorderChars('║', '│')
->setCrossingChars('┼', '╔', '╤', '╗', '╢', '╝', '╧', '╚', '╟', '╠', '╪', '╣')
;

return [
'default' => new TableStyle(),
'borderless' => $borderless,
'compact' => $compact,
'symfony-style-guide' => $styleGuide,
'box' => $box,
'box-double' => $boxDouble,
];
}

private function resolveStyle($name): TableStyle
{
if ($name instanceof TableStyle) {
return $name;
}

if (isset(self::$styles[$name])) {
return self::$styles[$name];
}

throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
}
}
<?php










namespace Symfony\Component\Console\Helper;






class TableSeparator extends TableCell
{
public function __construct(array $options = [])
{
parent::__construct('', $options);
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Descriptor\DescriptorInterface;
use Symfony\Component\Console\Descriptor\JsonDescriptor;
use Symfony\Component\Console\Descriptor\MarkdownDescriptor;
use Symfony\Component\Console\Descriptor\TextDescriptor;
use Symfony\Component\Console\Descriptor\XmlDescriptor;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Output\OutputInterface;






class DescriptorHelper extends Helper
{



private $descriptors = [];

public function __construct()
{
$this
->register('txt', new TextDescriptor())
->register('xml', new XmlDescriptor())
->register('json', new JsonDescriptor())
->register('md', new MarkdownDescriptor())
;
}












public function describe(OutputInterface $output, $object, array $options = [])
{
$options = array_merge([
'raw_text' => false,
'format' => 'txt',
], $options);

if (!isset($this->descriptors[$options['format']])) {
throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format']));
}

$descriptor = $this->descriptors[$options['format']];
$descriptor->describe($output, $object, $options);
}








public function register($format, DescriptorInterface $descriptor)
{
$this->descriptors[$format] = $descriptor;

return $this;
}




public function getName()
{
return 'descriptor';
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\ConsoleSectionOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Terminal;







final class ProgressBar
{
private $barWidth = 28;
private $barChar;
private $emptyBarChar = '-';
private $progressChar = '>';
private $format;
private $internalFormat;
private $redrawFreq = 1;
private $writeCount;
private $lastWriteTime;
private $minSecondsBetweenRedraws = 0;
private $maxSecondsBetweenRedraws = 1;
private $output;
private $step = 0;
private $max;
private $startTime;
private $stepWidth;
private $percent = 0.0;
private $formatLineCount;
private $messages = [];
private $overwrite = true;
private $terminal;
private $previousMessage;

private static $formatters;
private static $formats;




public function __construct(OutputInterface $output, int $max = 0, float $minSecondsBetweenRedraws = 0.1)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}

$this->output = $output;
$this->setMaxSteps($max);
$this->terminal = new Terminal();

if (0 < $minSecondsBetweenRedraws) {
$this->redrawFreq = null;
$this->minSecondsBetweenRedraws = $minSecondsBetweenRedraws;
}

if (!$this->output->isDecorated()) {

 $this->overwrite = false;


 $this->redrawFreq = null;
}

$this->startTime = time();
}









public static function setPlaceholderFormatterDefinition(string $name, callable $callable): void
{
if (!self::$formatters) {
self::$formatters = self::initPlaceholderFormatters();
}

self::$formatters[$name] = $callable;
}








public static function getPlaceholderFormatterDefinition(string $name): ?callable
{
if (!self::$formatters) {
self::$formatters = self::initPlaceholderFormatters();
}

return self::$formatters[$name] ?? null;
}









public static function setFormatDefinition(string $name, string $format): void
{
if (!self::$formats) {
self::$formats = self::initFormats();
}

self::$formats[$name] = $format;
}








public static function getFormatDefinition(string $name): ?string
{
if (!self::$formats) {
self::$formats = self::initFormats();
}

return self::$formats[$name] ?? null;
}











public function setMessage(string $message, string $name = 'message')
{
$this->messages[$name] = $message;
}

public function getMessage(string $name = 'message')
{
return $this->messages[$name];
}

public function getStartTime(): int
{
return $this->startTime;
}

public function getMaxSteps(): int
{
return $this->max;
}

public function getProgress(): int
{
return $this->step;
}

private function getStepWidth(): int
{
return $this->stepWidth;
}

public function getProgressPercent(): float
{
return $this->percent;
}

public function getBarOffset(): int
{
return floor($this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth);
}

public function setBarWidth(int $size)
{
$this->barWidth = max(1, $size);
}

public function getBarWidth(): int
{
return $this->barWidth;
}

public function setBarCharacter(string $char)
{
$this->barChar = $char;
}

public function getBarCharacter(): string
{
if (null === $this->barChar) {
return $this->max ? '=' : $this->emptyBarChar;
}

return $this->barChar;
}

public function setEmptyBarCharacter(string $char)
{
$this->emptyBarChar = $char;
}

public function getEmptyBarCharacter(): string
{
return $this->emptyBarChar;
}

public function setProgressCharacter(string $char)
{
$this->progressChar = $char;
}

public function getProgressCharacter(): string
{
return $this->progressChar;
}

public function setFormat(string $format)
{
$this->format = null;
$this->internalFormat = $format;
}






public function setRedrawFrequency(?int $freq)
{
$this->redrawFreq = null !== $freq ? max(1, $freq) : null;
}

public function minSecondsBetweenRedraws(float $seconds): void
{
$this->minSecondsBetweenRedraws = $seconds;
}

public function maxSecondsBetweenRedraws(float $seconds): void
{
$this->maxSecondsBetweenRedraws = $seconds;
}






public function iterate(iterable $iterable, int $max = null): iterable
{
$this->start($max ?? (is_countable($iterable) ? \count($iterable) : 0));

foreach ($iterable as $key => $value) {
yield $key => $value;

$this->advance();
}

$this->finish();
}






public function start(int $max = null)
{
$this->startTime = time();
$this->step = 0;
$this->percent = 0.0;

if (null !== $max) {
$this->setMaxSteps($max);
}

$this->display();
}






public function advance(int $step = 1)
{
$this->setProgress($this->step + $step);
}




public function setOverwrite(bool $overwrite)
{
$this->overwrite = $overwrite;
}

public function setProgress(int $step)
{
if ($this->max && $step > $this->max) {
$this->max = $step;
} elseif ($step < 0) {
$step = 0;
}

$redrawFreq = $this->redrawFreq ?? (($this->max ?: 10) / 10);
$prevPeriod = (int) ($this->step / $redrawFreq);
$currPeriod = (int) ($step / $redrawFreq);
$this->step = $step;
$this->percent = $this->max ? (float) $this->step / $this->max : 0;
$timeInterval = microtime(true) - $this->lastWriteTime;


 if ($this->max === $step) {
$this->display();

return;
}


 if ($timeInterval < $this->minSecondsBetweenRedraws) {
return;
}


 if ($prevPeriod !== $currPeriod || $timeInterval >= $this->maxSecondsBetweenRedraws) {
$this->display();
}
}

public function setMaxSteps(int $max)
{
$this->format = null;
$this->max = max(0, $max);
$this->stepWidth = $this->max ? Helper::strlen((string) $this->max) : 4;
}




public function finish(): void
{
if (!$this->max) {
$this->max = $this->step;
}

if ($this->step === $this->max && !$this->overwrite) {

 return;
}

$this->setProgress($this->max);
}




public function display(): void
{
if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
return;
}

if (null === $this->format) {
$this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
}

$this->overwrite($this->buildLine());
}








public function clear(): void
{
if (!$this->overwrite) {
return;
}

if (null === $this->format) {
$this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
}

$this->overwrite('');
}

private function setRealFormat(string $format)
{

 if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) {
$this->format = self::getFormatDefinition($format.'_nomax');
} elseif (null !== self::getFormatDefinition($format)) {
$this->format = self::getFormatDefinition($format);
} else {
$this->format = $format;
}

$this->formatLineCount = substr_count($this->format, "\n");
}




private function overwrite(string $message): void
{
if ($this->previousMessage === $message) {
return;
}

$originalMessage = $message;

if ($this->overwrite) {
if (null !== $this->previousMessage) {
if ($this->output instanceof ConsoleSectionOutput) {
$messageLines = explode("\n", $message);
$lineCount = \count($messageLines);
foreach ($messageLines as $messageLine) {
$messageLineLength = Helper::strlenWithoutDecoration($this->output->getFormatter(), $messageLine);
if ($messageLineLength > $this->terminal->getWidth()) {
$lineCount += floor($messageLineLength / $this->terminal->getWidth());
}
}
$this->output->clear($lineCount);
} else {

 if ($this->formatLineCount > 0) {
$message = str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount).$message;
}


 $message = "\x0D\x1B[2K$message";
}
}
} elseif ($this->step > 0) {
$message = \PHP_EOL.$message;
}

$this->previousMessage = $originalMessage;
$this->lastWriteTime = microtime(true);

$this->output->write($message);
++$this->writeCount;
}

private function determineBestFormat(): string
{
switch ($this->output->getVerbosity()) {

 case OutputInterface::VERBOSITY_VERBOSE:
return $this->max ? 'verbose' : 'verbose_nomax';
case OutputInterface::VERBOSITY_VERY_VERBOSE:
return $this->max ? 'very_verbose' : 'very_verbose_nomax';
case OutputInterface::VERBOSITY_DEBUG:
return $this->max ? 'debug' : 'debug_nomax';
default:
return $this->max ? 'normal' : 'normal_nomax';
}
}

private static function initPlaceholderFormatters(): array
{
return [
'bar' => function (self $bar, OutputInterface $output) {
$completeBars = $bar->getBarOffset();
$display = str_repeat($bar->getBarCharacter(), $completeBars);
if ($completeBars < $bar->getBarWidth()) {
$emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlenWithoutDecoration($output->getFormatter(), $bar->getProgressCharacter());
$display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars);
}

return $display;
},
'elapsed' => function (self $bar) {
return Helper::formatTime(time() - $bar->getStartTime());
},
'remaining' => function (self $bar) {
if (!$bar->getMaxSteps()) {
throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
}

if (!$bar->getProgress()) {
$remaining = 0;
} else {
$remaining = round((time() - $bar->getStartTime()) / $bar->getProgress() * ($bar->getMaxSteps() - $bar->getProgress()));
}

return Helper::formatTime($remaining);
},
'estimated' => function (self $bar) {
if (!$bar->getMaxSteps()) {
throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
}

if (!$bar->getProgress()) {
$estimated = 0;
} else {
$estimated = round((time() - $bar->getStartTime()) / $bar->getProgress() * $bar->getMaxSteps());
}

return Helper::formatTime($estimated);
},
'memory' => function (self $bar) {
return Helper::formatMemory(memory_get_usage(true));
},
'current' => function (self $bar) {
return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT);
},
'max' => function (self $bar) {
return $bar->getMaxSteps();
},
'percent' => function (self $bar) {
return floor($bar->getProgressPercent() * 100);
},
];
}

private static function initFormats(): array
{
return [
'normal' => ' %current%/%max% [%bar%] %percent:3s%%',
'normal_nomax' => ' %current% [%bar%]',

'verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%',
'verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',

'very_verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%',
'very_verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',

'debug' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%',
'debug_nomax' => ' %current% [%bar%] %elapsed:6s% %memory:6s%',
];
}

private function buildLine(): string
{
$regex = "{%([a-z\-_]+)(?:\:([^%]+))?%}i";
$callback = function ($matches) {
if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) {
$text = $formatter($this, $this->output);
} elseif (isset($this->messages[$matches[1]])) {
$text = $this->messages[$matches[1]];
} else {
return $matches[0];
}

if (isset($matches[2])) {
$text = sprintf('%'.$matches[2], $text);
}

return $text;
};
$line = preg_replace_callback($regex, $callback, $this->format);


 $linesLength = array_map(function ($subLine) {
return Helper::strlenWithoutDecoration($this->output->getFormatter(), rtrim($subLine, "\r"));
}, explode("\n", $line));

$linesWidth = max($linesLength);

$terminalWidth = $this->terminal->getWidth();
if ($linesWidth <= $terminalWidth) {
return $line;
}

$this->setBarWidth($this->barWidth - $linesWidth + $terminalWidth);

return preg_replace_callback($regex, $callback, $this->format);
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\VarDumper\Cloner\ClonerInterface;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;




final class Dumper
{
private $output;
private $dumper;
private $cloner;
private $handler;

public function __construct(OutputInterface $output, CliDumper $dumper = null, ClonerInterface $cloner = null)
{
$this->output = $output;
$this->dumper = $dumper;
$this->cloner = $cloner;

if (class_exists(CliDumper::class)) {
$this->handler = function ($var): string {
$dumper = $this->dumper ?? $this->dumper = new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR);
$dumper->setColors($this->output->isDecorated());

return rtrim($dumper->dump(($this->cloner ?? $this->cloner = new VarCloner())->cloneVar($var)->withRefHandles(false), true));
};
} else {
$this->handler = function ($var): string {
switch (true) {
case null === $var:
return 'null';
case true === $var:
return 'true';
case false === $var:
return 'false';
case \is_string($var):
return '"'.$var.'"';
default:
return rtrim(print_r($var, true));
}
};
}
}

public function __invoke($var): string
{
return ($this->handler)($var);
}
}
<?php










namespace Symfony\Component\Console\Helper;




class TableRows implements \IteratorAggregate
{
private $generator;

public function __construct(callable $generator)
{
$this->generator = $generator;
}

public function getIterator(): \Traversable
{
$g = $this->generator;

return $g();
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;






class HelperSet implements \IteratorAggregate
{



private $helpers = [];
private $command;




public function __construct(array $helpers = [])
{
foreach ($helpers as $alias => $helper) {
$this->set($helper, \is_int($alias) ? null : $alias);
}
}






public function set(HelperInterface $helper, $alias = null)
{
$this->helpers[$helper->getName()] = $helper;
if (null !== $alias) {
$this->helpers[$alias] = $helper;
}

$helper->setHelperSet($this);
}








public function has($name)
{
return isset($this->helpers[$name]);
}










public function get($name)
{
if (!$this->has($name)) {
throw new InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
}

return $this->helpers[$name];
}

public function setCommand(Command $command = null)
{
$this->command = $command;
}






public function getCommand()
{
return $this->command;
}





 public function getIterator()
{
return new \ArrayIterator($this->helpers);
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Formatter\OutputFormatterInterface;






abstract class Helper implements HelperInterface
{
protected $helperSet = null;




public function setHelperSet(HelperSet $helperSet = null)
{
$this->helperSet = $helperSet;
}




public function getHelperSet()
{
return $this->helperSet;
}








public static function strlen($string)
{
$string = (string) $string;

if (false === $encoding = mb_detect_encoding($string, null, true)) {
return \strlen($string);
}

return mb_strwidth($string, $encoding);
}










public static function substr($string, $from, $length = null)
{
$string = (string) $string;

if (false === $encoding = mb_detect_encoding($string, null, true)) {
return substr($string, $from, $length);
}

return mb_substr($string, $from, $length, $encoding);
}

public static function formatTime($secs)
{
static $timeFormats = [
[0, '< 1 sec'],
[1, '1 sec'],
[2, 'secs', 1],
[60, '1 min'],
[120, 'mins', 60],
[3600, '1 hr'],
[7200, 'hrs', 3600],
[86400, '1 day'],
[172800, 'days', 86400],
];

foreach ($timeFormats as $index => $format) {
if ($secs >= $format[0]) {
if ((isset($timeFormats[$index + 1]) && $secs < $timeFormats[$index + 1][0])
|| $index == \count($timeFormats) - 1
) {
if (2 == \count($format)) {
return $format[1];
}

return floor($secs / $format[2]).' '.$format[1];
}
}
}
}

public static function formatMemory($memory)
{
if ($memory >= 1024 * 1024 * 1024) {
return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024);
}

if ($memory >= 1024 * 1024) {
return sprintf('%.1f MiB', $memory / 1024 / 1024);
}

if ($memory >= 1024) {
return sprintf('%d KiB', $memory / 1024);
}

return sprintf('%d B', $memory);
}

public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, $string)
{
return self::strlen(self::removeDecoration($formatter, $string));
}

public static function removeDecoration(OutputFormatterInterface $formatter, $string)
{
$isDecorated = $formatter->isDecorated();
$formatter->setDecorated(false);

 $string = $formatter->format($string);

 $string = preg_replace("/\033\[[^m]*m/", '', $string);
$formatter->setDecorated($isDecorated);

return $string;
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Formatter\OutputFormatter;






class FormatterHelper extends Helper
{









public function formatSection($section, $message, $style = 'info')
{
return sprintf('<%s>[%s]</%s> %s', $style, $section, $style, $message);
}










public function formatBlock($messages, $style, $large = false)
{
if (!\is_array($messages)) {
$messages = [$messages];
}

$len = 0;
$lines = [];
foreach ($messages as $message) {
$message = OutputFormatter::escape($message);
$lines[] = sprintf($large ? '  %s  ' : ' %s ', $message);
$len = max(self::strlen($message) + ($large ? 4 : 2), $len);
}

$messages = $large ? [str_repeat(' ', $len)] : [];
for ($i = 0; isset($lines[$i]); ++$i) {
$messages[] = $lines[$i].str_repeat(' ', $len - self::strlen($lines[$i]));
}
if ($large) {
$messages[] = str_repeat(' ', $len);
}

for ($i = 0; isset($messages[$i]); ++$i) {
$messages[$i] = sprintf('<%s>%s</%s>', $style, $messages[$i], $style);
}

return implode("\n", $messages);
}










public function truncate($message, $length, $suffix = '...')
{
$computedLength = $length - self::strlen($suffix);

if ($computedLength > self::strlen($message)) {
return $message;
}

return self::substr($message, 0, $length).$suffix;
}




public function getName()
{
return 'formatter';
}
}
<?php










namespace Symfony\Component\Console\Helper;








class DebugFormatterHelper extends Helper
{
private $colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default'];
private $started = [];
private $count = -1;










public function start($id, $message, $prefix = 'RUN')
{
$this->started[$id] = ['border' => ++$this->count % \count($this->colors)];

return sprintf("%s<bg=blue;fg=white> %s </> <fg=blue>%s</>\n", $this->getBorder($id), $prefix, $message);
}












public function progress($id, $buffer, $error = false, $prefix = 'OUT', $errorPrefix = 'ERR')
{
$message = '';

if ($error) {
if (isset($this->started[$id]['out'])) {
$message .= "\n";
unset($this->started[$id]['out']);
}
if (!isset($this->started[$id]['err'])) {
$message .= sprintf('%s<bg=red;fg=white> %s </> ', $this->getBorder($id), $errorPrefix);
$this->started[$id]['err'] = true;
}

$message .= str_replace("\n", sprintf("\n%s<bg=red;fg=white> %s </> ", $this->getBorder($id), $errorPrefix), $buffer);
} else {
if (isset($this->started[$id]['err'])) {
$message .= "\n";
unset($this->started[$id]['err']);
}
if (!isset($this->started[$id]['out'])) {
$message .= sprintf('%s<bg=green;fg=white> %s </> ', $this->getBorder($id), $prefix);
$this->started[$id]['out'] = true;
}

$message .= str_replace("\n", sprintf("\n%s<bg=green;fg=white> %s </> ", $this->getBorder($id), $prefix), $buffer);
}

return $message;
}











public function stop($id, $message, $successful, $prefix = 'RES')
{
$trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : '';

if ($successful) {
return sprintf("%s%s<bg=green;fg=white> %s </> <fg=green>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
}

$message = sprintf("%s%s<bg=red;fg=white> %s </> <fg=red>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);

unset($this->started[$id]['out'], $this->started[$id]['err']);

return $message;
}

private function getBorder(string $id): string
{
return sprintf('<bg=%s> </>', $this->colors[$this->started[$id]['border']]);
}




public function getName()
{
return 'debug_formatter';
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Output\OutputInterface;




class ProgressIndicator
{
private $output;
private $startTime;
private $format;
private $message;
private $indicatorValues;
private $indicatorCurrent;
private $indicatorChangeInterval;
private $indicatorUpdateTime;
private $started = false;

private static $formatters;
private static $formats;






public function __construct(OutputInterface $output, string $format = null, int $indicatorChangeInterval = 100, array $indicatorValues = null)
{
$this->output = $output;

if (null === $format) {
$format = $this->determineBestFormat();
}

if (null === $indicatorValues) {
$indicatorValues = ['-', '\\', '|', '/'];
}

$indicatorValues = array_values($indicatorValues);

if (2 > \count($indicatorValues)) {
throw new InvalidArgumentException('Must have at least 2 indicator value characters.');
}

$this->format = self::getFormatDefinition($format);
$this->indicatorChangeInterval = $indicatorChangeInterval;
$this->indicatorValues = $indicatorValues;
$this->startTime = time();
}






public function setMessage($message)
{
$this->message = $message;

$this->display();
}






public function start($message)
{
if ($this->started) {
throw new LogicException('Progress indicator already started.');
}

$this->message = $message;
$this->started = true;
$this->startTime = time();
$this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval;
$this->indicatorCurrent = 0;

$this->display();
}




public function advance()
{
if (!$this->started) {
throw new LogicException('Progress indicator has not yet been started.');
}

if (!$this->output->isDecorated()) {
return;
}

$currentTime = $this->getCurrentTimeInMilliseconds();

if ($currentTime < $this->indicatorUpdateTime) {
return;
}

$this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval;
++$this->indicatorCurrent;

$this->display();
}






public function finish($message)
{
if (!$this->started) {
throw new LogicException('Progress indicator has not yet been started.');
}

$this->message = $message;
$this->display();
$this->output->writeln('');
$this->started = false;
}








public static function getFormatDefinition($name)
{
if (!self::$formats) {
self::$formats = self::initFormats();
}

return self::$formats[$name] ?? null;
}









public static function setPlaceholderFormatterDefinition($name, $callable)
{
if (!self::$formatters) {
self::$formatters = self::initPlaceholderFormatters();
}

self::$formatters[$name] = $callable;
}








public static function getPlaceholderFormatterDefinition($name)
{
if (!self::$formatters) {
self::$formatters = self::initPlaceholderFormatters();
}

return self::$formatters[$name] ?? null;
}

private function display()
{
if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
return;
}

$this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) {
if ($formatter = self::getPlaceholderFormatterDefinition($matches[1])) {
return $formatter($this);
}

return $matches[0];
}, $this->format ?? ''));
}

private function determineBestFormat(): string
{
switch ($this->output->getVerbosity()) {

 case OutputInterface::VERBOSITY_VERBOSE:
return $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi';
case OutputInterface::VERBOSITY_VERY_VERBOSE:
case OutputInterface::VERBOSITY_DEBUG:
return $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi';
default:
return $this->output->isDecorated() ? 'normal' : 'normal_no_ansi';
}
}




private function overwrite(string $message)
{
if ($this->output->isDecorated()) {
$this->output->write("\x0D\x1B[2K");
$this->output->write($message);
} else {
$this->output->writeln($message);
}
}

private function getCurrentTimeInMilliseconds(): float
{
return round(microtime(true) * 1000);
}

private static function initPlaceholderFormatters(): array
{
return [
'indicator' => function (self $indicator) {
return $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)];
},
'message' => function (self $indicator) {
return $indicator->message;
},
'elapsed' => function (self $indicator) {
return Helper::formatTime(time() - $indicator->startTime);
},
'memory' => function () {
return Helper::formatMemory(memory_get_usage(true));
},
];
}

private static function initFormats(): array
{
return [
'normal' => ' %indicator% %message%',
'normal_no_ansi' => ' %message%',

'verbose' => ' %indicator% %message% (%elapsed:6s%)',
'verbose_no_ansi' => ' %message% (%elapsed:6s%)',

'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)',
'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)',
];
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Exception\InvalidArgumentException;




class TableCell
{
private $value;
private $options = [
'rowspan' => 1,
'colspan' => 1,
];

public function __construct(string $value = '', array $options = [])
{
$this->value = $value;


 if ($diff = array_diff(array_keys($options), array_keys($this->options))) {
throw new InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff)));
}

$this->options = array_merge($this->options, $options);
}






public function __toString()
{
return $this->value;
}






public function getColspan()
{
return (int) $this->options['colspan'];
}






public function getRowspan()
{
return (int) $this->options['rowspan'];
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;








class TableStyle
{
private $paddingChar = ' ';
private $horizontalOutsideBorderChar = '-';
private $horizontalInsideBorderChar = '-';
private $verticalOutsideBorderChar = '|';
private $verticalInsideBorderChar = '|';
private $crossingChar = '+';
private $crossingTopRightChar = '+';
private $crossingTopMidChar = '+';
private $crossingTopLeftChar = '+';
private $crossingMidRightChar = '+';
private $crossingBottomRightChar = '+';
private $crossingBottomMidChar = '+';
private $crossingBottomLeftChar = '+';
private $crossingMidLeftChar = '+';
private $crossingTopLeftBottomChar = '+';
private $crossingTopMidBottomChar = '+';
private $crossingTopRightBottomChar = '+';
private $headerTitleFormat = '<fg=black;bg=white;options=bold> %s </>';
private $footerTitleFormat = '<fg=black;bg=white;options=bold> %s </>';
private $cellHeaderFormat = '<info>%s</info>';
private $cellRowFormat = '%s';
private $cellRowContentFormat = ' %s ';
private $borderFormat = '%s';
private $padType = \STR_PAD_RIGHT;








public function setPaddingChar($paddingChar)
{
if (!$paddingChar) {
throw new LogicException('The padding char must not be empty.');
}

$this->paddingChar = $paddingChar;

return $this;
}






public function getPaddingChar()
{
return $this->paddingChar;
}


















public function setHorizontalBorderChars(string $outside, string $inside = null): self
{
$this->horizontalOutsideBorderChar = $outside;
$this->horizontalInsideBorderChar = $inside ?? $outside;

return $this;
}










public function setHorizontalBorderChar($horizontalBorderChar)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use setHorizontalBorderChars() instead.', __METHOD__), \E_USER_DEPRECATED);

return $this->setHorizontalBorderChars($horizontalBorderChar, $horizontalBorderChar);
}








public function getHorizontalBorderChar()
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use getBorderChars() instead.', __METHOD__), \E_USER_DEPRECATED);

return $this->horizontalOutsideBorderChar;
}



















public function setVerticalBorderChars(string $outside, string $inside = null): self
{
$this->verticalOutsideBorderChar = $outside;
$this->verticalInsideBorderChar = $inside ?? $outside;

return $this;
}










public function setVerticalBorderChar($verticalBorderChar)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use setVerticalBorderChars() instead.', __METHOD__), \E_USER_DEPRECATED);

return $this->setVerticalBorderChars($verticalBorderChar, $verticalBorderChar);
}








public function getVerticalBorderChar()
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use getBorderChars() instead.', __METHOD__), \E_USER_DEPRECATED);

return $this->verticalOutsideBorderChar;
}






public function getBorderChars(): array
{
return [
$this->horizontalOutsideBorderChar,
$this->verticalOutsideBorderChar,
$this->horizontalInsideBorderChar,
$this->verticalInsideBorderChar,
];
}






























public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, string $topLeftBottom = null, string $topMidBottom = null, string $topRightBottom = null): self
{
$this->crossingChar = $cross;
$this->crossingTopLeftChar = $topLeft;
$this->crossingTopMidChar = $topMid;
$this->crossingTopRightChar = $topRight;
$this->crossingMidRightChar = $midRight;
$this->crossingBottomRightChar = $bottomRight;
$this->crossingBottomMidChar = $bottomMid;
$this->crossingBottomLeftChar = $bottomLeft;
$this->crossingMidLeftChar = $midLeft;
$this->crossingTopLeftBottomChar = $topLeftBottom ?? $midLeft;
$this->crossingTopMidBottomChar = $topMidBottom ?? $cross;
$this->crossingTopRightBottomChar = $topRightBottom ?? $midRight;

return $this;
}






public function setDefaultCrossingChar(string $char): self
{
return $this->setCrossingChars($char, $char, $char, $char, $char, $char, $char, $char, $char);
}










public function setCrossingChar($crossingChar)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1. Use setDefaultCrossingChar() instead.', __METHOD__), \E_USER_DEPRECATED);

return $this->setDefaultCrossingChar($crossingChar);
}






public function getCrossingChar()
{
return $this->crossingChar;
}






public function getCrossingChars(): array
{
return [
$this->crossingChar,
$this->crossingTopLeftChar,
$this->crossingTopMidChar,
$this->crossingTopRightChar,
$this->crossingMidRightChar,
$this->crossingBottomRightChar,
$this->crossingBottomMidChar,
$this->crossingBottomLeftChar,
$this->crossingMidLeftChar,
$this->crossingTopLeftBottomChar,
$this->crossingTopMidBottomChar,
$this->crossingTopRightBottomChar,
];
}








public function setCellHeaderFormat($cellHeaderFormat)
{
$this->cellHeaderFormat = $cellHeaderFormat;

return $this;
}






public function getCellHeaderFormat()
{
return $this->cellHeaderFormat;
}








public function setCellRowFormat($cellRowFormat)
{
$this->cellRowFormat = $cellRowFormat;

return $this;
}






public function getCellRowFormat()
{
return $this->cellRowFormat;
}








public function setCellRowContentFormat($cellRowContentFormat)
{
$this->cellRowContentFormat = $cellRowContentFormat;

return $this;
}






public function getCellRowContentFormat()
{
return $this->cellRowContentFormat;
}








public function setBorderFormat($borderFormat)
{
$this->borderFormat = $borderFormat;

return $this;
}






public function getBorderFormat()
{
return $this->borderFormat;
}








public function setPadType($padType)
{
if (!\in_array($padType, [\STR_PAD_LEFT, \STR_PAD_RIGHT, \STR_PAD_BOTH], true)) {
throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).');
}

$this->padType = $padType;

return $this;
}






public function getPadType()
{
return $this->padType;
}

public function getHeaderTitleFormat(): string
{
return $this->headerTitleFormat;
}

public function setHeaderTitleFormat(string $format): self
{
$this->headerTitleFormat = $format;

return $this;
}

public function getFooterTitleFormat(): string
{
return $this->footerTitleFormat;
}

public function setFooterTitleFormat(string $format): self
{
$this->footerTitleFormat = $format;

return $this;
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Exception\MissingInputException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\StreamableInputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\ConsoleSectionOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Terminal;






class QuestionHelper extends Helper
{
private $inputStream;
private static $shell;
private static $stty = true;
private static $stdinIsInteractive;








public function ask(InputInterface $input, OutputInterface $output, Question $question)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}

if (!$input->isInteractive()) {
return $this->getDefaultAnswer($question);
}

if ($input instanceof StreamableInputInterface && $stream = $input->getStream()) {
$this->inputStream = $stream;
}

try {
if (!$question->getValidator()) {
return $this->doAsk($output, $question);
}

$interviewer = function () use ($output, $question) {
return $this->doAsk($output, $question);
};

return $this->validateAttempts($interviewer, $output, $question);
} catch (MissingInputException $exception) {
$input->setInteractive(false);

if (null === $fallbackOutput = $this->getDefaultAnswer($question)) {
throw $exception;
}

return $fallbackOutput;
}
}




public function getName()
{
return 'question';
}




public static function disableStty()
{
self::$stty = false;
}








private function doAsk(OutputInterface $output, Question $question)
{
$this->writePrompt($output, $question);

$inputStream = $this->inputStream ?: \STDIN;
$autocomplete = $question->getAutocompleterCallback();

if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) {
$ret = false;
if ($question->isHidden()) {
try {
$hiddenResponse = $this->getHiddenResponse($output, $inputStream, $question->isTrimmable());
$ret = $question->isTrimmable() ? trim($hiddenResponse) : $hiddenResponse;
} catch (RuntimeException $e) {
if (!$question->isHiddenFallback()) {
throw $e;
}
}
}

if (false === $ret) {
$cp = $this->setIOCodepage();
$ret = fgets($inputStream, 4096);
$ret = $this->resetIOCodepage($cp, $ret);
if (false === $ret) {
throw new MissingInputException('Aborted.');
}
if ($question->isTrimmable()) {
$ret = trim($ret);
}
}
} else {
$autocomplete = $this->autocomplete($output, $question, $inputStream, $autocomplete);
$ret = $question->isTrimmable() ? trim($autocomplete) : $autocomplete;
}

if ($output instanceof ConsoleSectionOutput) {
$output->addContent($ret);
}

$ret = \strlen($ret) > 0 ? $ret : $question->getDefault();

if ($normalizer = $question->getNormalizer()) {
return $normalizer($ret);
}

return $ret;
}




private function getDefaultAnswer(Question $question)
{
$default = $question->getDefault();

if (null === $default) {
return $default;
}

if ($validator = $question->getValidator()) {
return \call_user_func($question->getValidator(), $default);
} elseif ($question instanceof ChoiceQuestion) {
$choices = $question->getChoices();

if (!$question->isMultiselect()) {
return $choices[$default] ?? $default;
}

$default = explode(',', $default);
foreach ($default as $k => $v) {
$v = $question->isTrimmable() ? trim($v) : $v;
$default[$k] = $choices[$v] ?? $v;
}
}

return $default;
}




protected function writePrompt(OutputInterface $output, Question $question)
{
$message = $question->getQuestion();

if ($question instanceof ChoiceQuestion) {
$output->writeln(array_merge([
$question->getQuestion(),
], $this->formatChoiceQuestionChoices($question, 'info')));

$message = $question->getPrompt();
}

$output->write($message);
}






protected function formatChoiceQuestionChoices(ChoiceQuestion $question, $tag)
{
$messages = [];

$maxWidth = max(array_map([__CLASS__, 'strlen'], array_keys($choices = $question->getChoices())));

foreach ($choices as $key => $value) {
$padding = str_repeat(' ', $maxWidth - self::strlen($key));

$messages[] = sprintf("  [<$tag>%s$padding</$tag>] %s", $key, $value);
}

return $messages;
}




protected function writeError(OutputInterface $output, \Exception $error)
{
if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) {
$message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error');
} else {
$message = '<error>'.$error->getMessage().'</error>';
}

$output->writeln($message);
}






private function autocomplete(OutputInterface $output, Question $question, $inputStream, callable $autocomplete): string
{
$fullChoice = '';
$ret = '';

$i = 0;
$ofs = -1;
$matches = $autocomplete($ret);
$numMatches = \count($matches);

$sttyMode = shell_exec('stty -g');


 shell_exec('stty -icanon -echo');


 $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white'));


 while (!feof($inputStream)) {
$c = fread($inputStream, 1);


 if (false === $c || ('' === $ret && '' === $c && null === $question->getDefault())) {
shell_exec(sprintf('stty %s', $sttyMode));
throw new MissingInputException('Aborted.');
} elseif ("\177" === $c) { 
 if (0 === $numMatches && 0 !== $i) {
--$i;
$fullChoice = self::substr($fullChoice, 0, $i);

 $output->write("\033[1D");
}

if (0 === $i) {
$ofs = -1;
$matches = $autocomplete($ret);
$numMatches = \count($matches);
} else {
$numMatches = 0;
}


 $ret = self::substr($ret, 0, $i);
} elseif ("\033" === $c) {

 $c .= fread($inputStream, 2);


 if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {
if ('A' === $c[2] && -1 === $ofs) {
$ofs = 0;
}

if (0 === $numMatches) {
continue;
}

$ofs += ('A' === $c[2]) ? -1 : 1;
$ofs = ($numMatches + $ofs) % $numMatches;
}
} elseif (\ord($c) < 32) {
if ("\t" === $c || "\n" === $c) {
if ($numMatches > 0 && -1 !== $ofs) {
$ret = (string) $matches[$ofs];

 $remainingCharacters = substr($ret, \strlen(trim($this->mostRecentlyEnteredValue($fullChoice))));
$output->write($remainingCharacters);
$fullChoice .= $remainingCharacters;
$i = (false === $encoding = mb_detect_encoding($fullChoice, null, true)) ? \strlen($fullChoice) : mb_strlen($fullChoice, $encoding);

$matches = array_filter(
$autocomplete($ret),
function ($match) use ($ret) {
return '' === $ret || str_starts_with($match, $ret);
}
);
$numMatches = \count($matches);
$ofs = -1;
}

if ("\n" === $c) {
$output->write($c);
break;
}

$numMatches = 0;
}

continue;
} else {
if ("\x80" <= $c) {
$c .= fread($inputStream, ["\xC0" => 1, "\xD0" => 1, "\xE0" => 2, "\xF0" => 3][$c & "\xF0"]);
}

$output->write($c);
$ret .= $c;
$fullChoice .= $c;
++$i;

$tempRet = $ret;

if ($question instanceof ChoiceQuestion && $question->isMultiselect()) {
$tempRet = $this->mostRecentlyEnteredValue($fullChoice);
}

$numMatches = 0;
$ofs = 0;

foreach ($autocomplete($ret) as $value) {

 if (str_starts_with($value, $tempRet)) {
$matches[$numMatches++] = $value;
}
}
}


 $output->write("\033[K");

if ($numMatches > 0 && -1 !== $ofs) {

 $output->write("\0337");

 $charactersEntered = \strlen(trim($this->mostRecentlyEnteredValue($fullChoice)));
$output->write('<hl>'.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $charactersEntered)).'</hl>');

 $output->write("\0338");
}
}


 shell_exec(sprintf('stty %s', $sttyMode));

return $fullChoice;
}

private function mostRecentlyEnteredValue(string $entered): string
{

 if (!str_contains($entered, ',')) {
return $entered;
}

$choices = explode(',', $entered);
if ('' !== $lastChoice = trim($choices[\count($choices) - 1])) {
return $lastChoice;
}

return $entered;
}









private function getHiddenResponse(OutputInterface $output, $inputStream, bool $trimmable = true): string
{
if ('\\' === \DIRECTORY_SEPARATOR) {
$exe = __DIR__.'/../Resources/bin/hiddeninput.exe';


 if ('phar:' === substr(__FILE__, 0, 5)) {
$tmpExe = sys_get_temp_dir().'/hiddeninput.exe';
copy($exe, $tmpExe);
$exe = $tmpExe;
}

$sExec = shell_exec('"'.$exe.'"');
$value = $trimmable ? rtrim($sExec) : $sExec;
$output->writeln('');

if (isset($tmpExe)) {
unlink($tmpExe);
}

return $value;
}

if (self::$stty && Terminal::hasSttyAvailable()) {
$sttyMode = shell_exec('stty -g');
shell_exec('stty -echo');
} elseif ($this->isInteractiveInput($inputStream)) {
throw new RuntimeException('Unable to hide the response.');
}

$value = fgets($inputStream, 4096);

if (self::$stty && Terminal::hasSttyAvailable()) {
shell_exec(sprintf('stty %s', $sttyMode));
}

if (false === $value) {
throw new MissingInputException('Aborted.');
}
if ($trimmable) {
$value = trim($value);
}
$output->writeln('');

return $value;
}










private function validateAttempts(callable $interviewer, OutputInterface $output, Question $question)
{
$error = null;
$attempts = $question->getMaxAttempts();

while (null === $attempts || $attempts--) {
if (null !== $error) {
$this->writeError($output, $error);
}

try {
return $question->getValidator()($interviewer());
} catch (RuntimeException $e) {
throw $e;
} catch (\Exception $error) {
}
}

throw $error;
}

private function isInteractiveInput($inputStream): bool
{
if ('php://stdin' !== (stream_get_meta_data($inputStream)['uri'] ?? null)) {
return false;
}

if (null !== self::$stdinIsInteractive) {
return self::$stdinIsInteractive;
}

if (\function_exists('stream_isatty')) {
return self::$stdinIsInteractive = stream_isatty(fopen('php://stdin', 'r'));
}

if (\function_exists('posix_isatty')) {
return self::$stdinIsInteractive = posix_isatty(fopen('php://stdin', 'r'));
}

if (!\function_exists('exec')) {
return self::$stdinIsInteractive = true;
}

exec('stty 2> /dev/null', $output, $status);

return self::$stdinIsInteractive = 1 !== $status;
}






private function setIOCodepage(): int
{
if (\function_exists('sapi_windows_cp_set')) {
$cp = sapi_windows_cp_get();
sapi_windows_cp_set(sapi_windows_cp_get('oem'));

return $cp;
}

return 0;
}








private function resetIOCodepage(int $cp, $input)
{
if (0 !== $cp) {
sapi_windows_cp_set($cp);

if (false !== $input && '' !== $input) {
$input = sapi_windows_cp_conv(sapi_windows_cp_get('oem'), $cp, $input);
}
}

return $input;
}
}
<?php










namespace Symfony\Component\Console\Helper;






interface HelperInterface
{



public function setHelperSet(HelperSet $helperSet = null);






public function getHelperSet();






public function getName();
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;








class ProcessHelper extends Helper
{











public function run(OutputInterface $output, $cmd, $error = null, callable $callback = null, $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE)
{
if (!class_exists(Process::class)) {
throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".');
}

if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}

$formatter = $this->getHelperSet()->get('debug_formatter');

if ($cmd instanceof Process) {
$cmd = [$cmd];
}

if (!\is_array($cmd)) {
@trigger_error(sprintf('Passing a command as a string to "%s()" is deprecated since Symfony 4.2, pass it the command as an array of arguments instead.', __METHOD__), \E_USER_DEPRECATED);
$cmd = [method_exists(Process::class, 'fromShellCommandline') ? Process::fromShellCommandline($cmd) : new Process($cmd)];
}

if (\is_string($cmd[0] ?? null)) {
$process = new Process($cmd);
$cmd = [];
} elseif (($cmd[0] ?? null) instanceof Process) {
$process = $cmd[0];
unset($cmd[0]);
} else {
throw new \InvalidArgumentException(sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__));
}

if ($verbosity <= $output->getVerbosity()) {
$output->write($formatter->start(spl_object_hash($process), $this->escapeString($process->getCommandLine())));
}

if ($output->isDebug()) {
$callback = $this->wrapCallback($output, $process, $callback);
}

$process->run($callback, $cmd);

if ($verbosity <= $output->getVerbosity()) {
$message = $process->isSuccessful() ? 'Command ran successfully' : sprintf('%s Command did not run successfully', $process->getExitCode());
$output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful()));
}

if (!$process->isSuccessful() && null !== $error) {
$output->writeln(sprintf('<error>%s</error>', $this->escapeString($error)));
}

return $process;
}


















public function mustRun(OutputInterface $output, $cmd, $error = null, callable $callback = null)
{
$process = $this->run($output, $cmd, $error, $callback);

if (!$process->isSuccessful()) {
throw new ProcessFailedException($process);
}

return $process;
}






public function wrapCallback(OutputInterface $output, Process $process, callable $callback = null)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}

$formatter = $this->getHelperSet()->get('debug_formatter');

return function ($type, $buffer) use ($output, $process, $callback, $formatter) {
$output->write($formatter->progress(spl_object_hash($process), $this->escapeString($buffer), Process::ERR === $type));

if (null !== $callback) {
$callback($type, $buffer);
}
};
}

private function escapeString(string $str): string
{
return str_replace('<', '\\<', $str);
}




public function getName()
{
return 'process';
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Style\SymfonyStyle;






class SymfonyQuestionHelper extends QuestionHelper
{



protected function writePrompt(OutputInterface $output, Question $question)
{
$text = OutputFormatter::escapeTrailingBackslash($question->getQuestion());
$default = $question->getDefault();

switch (true) {
case null === $default:
$text = sprintf(' <info>%s</info>:', $text);

break;

case $question instanceof ConfirmationQuestion:
$text = sprintf(' <info>%s (yes/no)</info> [<comment>%s</comment>]:', $text, $default ? 'yes' : 'no');

break;

case $question instanceof ChoiceQuestion && $question->isMultiselect():
$choices = $question->getChoices();
$default = explode(',', $default);

foreach ($default as $key => $value) {
$default[$key] = $choices[trim($value)];
}

$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape(implode(', ', $default)));

break;

case $question instanceof ChoiceQuestion:
$choices = $question->getChoices();
$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape($choices[$default] ?? $default));

break;

default:
$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape($default));
}

$output->writeln($text);

$prompt = ' > ';

if ($question instanceof ChoiceQuestion) {
$output->writeln($this->formatChoiceQuestionChoices($question, 'comment'));

$prompt = $question->getPrompt();
}

$output->write($prompt);
}




protected function writeError(OutputInterface $output, \Exception $error)
{
if ($output instanceof SymfonyStyle) {
$output->newLine();
$output->error($error->getMessage());

return;
}

parent::writeError($output, $error);
}
}
<?php










namespace Symfony\Component\Console\Question;

use Symfony\Component\Console\Exception\InvalidArgumentException;






class ChoiceQuestion extends Question
{
private $choices;
private $multiselect = false;
private $prompt = ' > ';
private $errorMessage = 'Value "%s" is invalid';






public function __construct(string $question, array $choices, $default = null)
{
if (!$choices) {
throw new \LogicException('Choice question must have at least 1 choice available.');
}

parent::__construct($question, $default);

$this->choices = $choices;
$this->setValidator($this->getDefaultValidator());
$this->setAutocompleterValues($choices);
}






public function getChoices()
{
return $this->choices;
}










public function setMultiselect($multiselect)
{
$this->multiselect = $multiselect;
$this->setValidator($this->getDefaultValidator());

return $this;
}






public function isMultiselect()
{
return $this->multiselect;
}






public function getPrompt()
{
return $this->prompt;
}








public function setPrompt($prompt)
{
$this->prompt = $prompt;

return $this;
}










public function setErrorMessage($errorMessage)
{
$this->errorMessage = $errorMessage;
$this->setValidator($this->getDefaultValidator());

return $this;
}

private function getDefaultValidator(): callable
{
$choices = $this->choices;
$errorMessage = $this->errorMessage;
$multiselect = $this->multiselect;
$isAssoc = $this->isAssoc($choices);

return function ($selected) use ($choices, $errorMessage, $multiselect, $isAssoc) {
if ($multiselect) {

 if (!preg_match('/^[^,]+(?:,[^,]+)*$/', $selected, $matches)) {
throw new InvalidArgumentException(sprintf($errorMessage, $selected));
}

$selectedChoices = explode(',', $selected);
} else {
$selectedChoices = [$selected];
}

if ($this->isTrimmable()) {
foreach ($selectedChoices as $k => $v) {
$selectedChoices[$k] = trim($v);
}
}

$multiselectChoices = [];
foreach ($selectedChoices as $value) {
$results = [];
foreach ($choices as $key => $choice) {
if ($choice === $value) {
$results[] = $key;
}
}

if (\count($results) > 1) {
throw new InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of "%s".', implode('" or "', $results)));
}

$result = array_search($value, $choices);

if (!$isAssoc) {
if (false !== $result) {
$result = $choices[$result];
} elseif (isset($choices[$value])) {
$result = $choices[$value];
}
} elseif (false === $result && isset($choices[$value])) {
$result = $value;
}

if (false === $result) {
throw new InvalidArgumentException(sprintf($errorMessage, $value));
}

$multiselectChoices[] = (string) $result;
}

if ($multiselect) {
return $multiselectChoices;
}

return current($multiselectChoices);
};
}
}
<?php










namespace Symfony\Component\Console\Question;






class ConfirmationQuestion extends Question
{
private $trueAnswerRegex;






public function __construct(string $question, bool $default = true, string $trueAnswerRegex = '/^y/i')
{
parent::__construct($question, $default);

$this->trueAnswerRegex = $trueAnswerRegex;
$this->setNormalizer($this->getDefaultNormalizer());
}




private function getDefaultNormalizer(): callable
{
$default = $this->getDefault();
$regex = $this->trueAnswerRegex;

return function ($answer) use ($default, $regex) {
if (\is_bool($answer)) {
return $answer;
}

$answerIsTrue = (bool) preg_match($regex, $answer);
if (false === $default) {
return $answer && $answerIsTrue;
}

return '' === $answer || $answerIsTrue;
};
}
}
<?php










namespace Symfony\Component\Console\Question;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;






class Question
{
private $question;
private $attempts;
private $hidden = false;
private $hiddenFallback = true;
private $autocompleterCallback;
private $validator;
private $default;
private $normalizer;
private $trimmable = true;





public function __construct(string $question, $default = null)
{
$this->question = $question;
$this->default = $default;
}






public function getQuestion()
{
return $this->question;
}






public function getDefault()
{
return $this->default;
}






public function isHidden()
{
return $this->hidden;
}










public function setHidden($hidden)
{
if ($this->autocompleterCallback) {
throw new LogicException('A hidden question cannot use the autocompleter.');
}

$this->hidden = (bool) $hidden;

return $this;
}






public function isHiddenFallback()
{
return $this->hiddenFallback;
}








public function setHiddenFallback($fallback)
{
$this->hiddenFallback = (bool) $fallback;

return $this;
}






public function getAutocompleterValues()
{
$callback = $this->getAutocompleterCallback();

return $callback ? $callback('') : null;
}











public function setAutocompleterValues($values)
{
if (\is_array($values)) {
$values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values);

$callback = static function () use ($values) {
return $values;
};
} elseif ($values instanceof \Traversable) {
$valueCache = null;
$callback = static function () use ($values, &$valueCache) {
return $valueCache ?? $valueCache = iterator_to_array($values, false);
};
} elseif (null === $values) {
$callback = null;
} else {
throw new InvalidArgumentException('Autocompleter values can be either an array, "null" or a "Traversable" object.');
}

return $this->setAutocompleterCallback($callback);
}




public function getAutocompleterCallback(): ?callable
{
return $this->autocompleterCallback;
}








public function setAutocompleterCallback(callable $callback = null): self
{
if ($this->hidden && null !== $callback) {
throw new LogicException('A hidden question cannot use the autocompleter.');
}

$this->autocompleterCallback = $callback;

return $this;
}






public function setValidator(callable $validator = null)
{
$this->validator = $validator;

return $this;
}






public function getValidator()
{
return $this->validator;
}












public function setMaxAttempts($attempts)
{
if (null !== $attempts) {
$attempts = (int) $attempts;
if ($attempts < 1) {
throw new InvalidArgumentException('Maximum number of attempts must be a positive value.');
}
}

$this->attempts = $attempts;

return $this;
}








public function getMaxAttempts()
{
return $this->attempts;
}








public function setNormalizer(callable $normalizer)
{
$this->normalizer = $normalizer;

return $this;
}








public function getNormalizer()
{
return $this->normalizer;
}

protected function isAssoc($array)
{
return (bool) \count(array_filter(array_keys($array), 'is_string'));
}

public function isTrimmable(): bool
{
return $this->trimmable;
}




public function setTrimmable(bool $trimmable): self
{
$this->trimmable = $trimmable;

return $this;
}
}
<?php










namespace Symfony\Component\Console\EventListener;

use Psr\Log\LoggerInterface;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleErrorEvent;
use Symfony\Component\Console\Event\ConsoleEvent;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;





class ErrorListener implements EventSubscriberInterface
{
private $logger;

public function __construct(LoggerInterface $logger = null)
{
$this->logger = $logger;
}

public function onConsoleError(ConsoleErrorEvent $event)
{
if (null === $this->logger) {
return;
}

$error = $event->getError();

if (!$inputString = $this->getInputString($event)) {
$this->logger->critical('An error occurred while using the console. Message: "{message}"', ['exception' => $error, 'message' => $error->getMessage()]);

return;
}

$this->logger->critical('Error thrown while running command "{command}". Message: "{message}"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]);
}

public function onConsoleTerminate(ConsoleTerminateEvent $event)
{
if (null === $this->logger) {
return;
}

$exitCode = $event->getExitCode();

if (0 === $exitCode) {
return;
}

if (!$inputString = $this->getInputString($event)) {
$this->logger->debug('The console exited with code "{code}"', ['code' => $exitCode]);

return;
}

$this->logger->debug('Command "{command}" exited with code "{code}"', ['command' => $inputString, 'code' => $exitCode]);
}

public static function getSubscribedEvents()
{
return [
ConsoleEvents::ERROR => ['onConsoleError', -128],
ConsoleEvents::TERMINATE => ['onConsoleTerminate', -128],
];
}

private static function getInputString(ConsoleEvent $event): ?string
{
$commandName = $event->getCommand() ? $event->getCommand()->getName() : null;
$input = $event->getInput();

if (method_exists($input, '__toString')) {
if ($commandName) {
return str_replace(["'$commandName'", "\"$commandName\""], $commandName, (string) $input);
}

return (string) $input;
}

return $commandName;
}
}
<?php










namespace Symfony\Component\Console;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Command\HelpCommand;
use Symfony\Component\Console\Command\ListCommand;
use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Event\ConsoleErrorEvent;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\Console\Exception\CommandNotFoundException;
use Symfony\Component\Console\Exception\ExceptionInterface;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Exception\NamespaceNotFoundException;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\DebugFormatterHelper;
use Symfony\Component\Console\Helper\FormatterHelper;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Helper\ProcessHelper;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputAwareInterface;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Debug\ErrorHandler as LegacyErrorHandler;
use Symfony\Component\Debug\Exception\FatalThrowableError;
use Symfony\Component\ErrorHandler\ErrorHandler;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
use Symfony\Contracts\Service\ResetInterface;
















class Application implements ResetInterface
{
private $commands = [];
private $wantHelps = false;
private $runningCommand;
private $name;
private $version;
private $commandLoader;
private $catchExceptions = true;
private $autoExit = true;
private $definition;
private $helperSet;
private $dispatcher;
private $terminal;
private $defaultCommand;
private $singleCommand = false;
private $initialized;





public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN')
{
$this->name = $name;
$this->version = $version;
$this->terminal = new Terminal();
$this->defaultCommand = 'list';
}




public function setDispatcher(EventDispatcherInterface $dispatcher)
{
$this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
}

public function setCommandLoader(CommandLoaderInterface $commandLoader)
{
$this->commandLoader = $commandLoader;
}








public function run(InputInterface $input = null, OutputInterface $output = null)
{
if (\function_exists('putenv')) {
@putenv('LINES='.$this->terminal->getHeight());
@putenv('COLUMNS='.$this->terminal->getWidth());
}

if (null === $input) {
$input = new ArgvInput();
}

if (null === $output) {
$output = new ConsoleOutput();
}

$renderException = function (\Throwable $e) use ($output) {
if ($output instanceof ConsoleOutputInterface) {
$this->renderThrowable($e, $output->getErrorOutput());
} else {
$this->renderThrowable($e, $output);
}
};
if ($phpHandler = set_exception_handler($renderException)) {
restore_exception_handler();
if (!\is_array($phpHandler) || (!$phpHandler[0] instanceof ErrorHandler && !$phpHandler[0] instanceof LegacyErrorHandler)) {
$errorHandler = true;
} elseif ($errorHandler = $phpHandler[0]->setExceptionHandler($renderException)) {
$phpHandler[0]->setExceptionHandler($errorHandler);
}
}

$this->configureIO($input, $output);

try {
$exitCode = $this->doRun($input, $output);
} catch (\Exception $e) {
if (!$this->catchExceptions) {
throw $e;
}

$renderException($e);

$exitCode = $e->getCode();
if (is_numeric($exitCode)) {
$exitCode = (int) $exitCode;
if (0 === $exitCode) {
$exitCode = 1;
}
} else {
$exitCode = 1;
}
} finally {

 
 if (!$phpHandler) {
if (set_exception_handler($renderException) === $renderException) {
restore_exception_handler();
}
restore_exception_handler();
} elseif (!$errorHandler) {
$finalHandler = $phpHandler[0]->setExceptionHandler(null);
if ($finalHandler !== $renderException) {
$phpHandler[0]->setExceptionHandler($finalHandler);
}
}
}

if ($this->autoExit) {
if ($exitCode > 255) {
$exitCode = 255;
}

exit($exitCode);
}

return $exitCode;
}






public function doRun(InputInterface $input, OutputInterface $output)
{
if (true === $input->hasParameterOption(['--version', '-V'], true)) {
$output->writeln($this->getLongVersion());

return 0;
}

try {

 $input->bind($this->getDefinition());
} catch (ExceptionInterface $e) {

 }

$name = $this->getCommandName($input);
if (true === $input->hasParameterOption(['--help', '-h'], true)) {
if (!$name) {
$name = 'help';
$input = new ArrayInput(['command_name' => $this->defaultCommand]);
} else {
$this->wantHelps = true;
}
}

if (!$name) {
$name = $this->defaultCommand;
$definition = $this->getDefinition();
$definition->setArguments(array_merge(
$definition->getArguments(),
[
'command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name),
]
));
}

try {
$this->runningCommand = null;

 $command = $this->find($name);
} catch (\Throwable $e) {
if (!($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException) || 1 !== \count($alternatives = $e->getAlternatives()) || !$input->isInteractive()) {
if (null !== $this->dispatcher) {
$event = new ConsoleErrorEvent($input, $output, $e);
$this->dispatcher->dispatch($event, ConsoleEvents::ERROR);

if (0 === $event->getExitCode()) {
return 0;
}

$e = $event->getError();
}

throw $e;
}

$alternative = $alternatives[0];

$style = new SymfonyStyle($input, $output);
$style->block(sprintf("\nCommand \"%s\" is not defined.\n", $name), null, 'error');
if (!$style->confirm(sprintf('Do you want to run "%s" instead? ', $alternative), false)) {
if (null !== $this->dispatcher) {
$event = new ConsoleErrorEvent($input, $output, $e);
$this->dispatcher->dispatch($event, ConsoleEvents::ERROR);

return $event->getExitCode();
}

return 1;
}

$command = $this->find($alternative);
}

$this->runningCommand = $command;
$exitCode = $this->doRunCommand($command, $input, $output);
$this->runningCommand = null;

return $exitCode;
}




public function reset()
{
}

public function setHelperSet(HelperSet $helperSet)
{
$this->helperSet = $helperSet;
}






public function getHelperSet()
{
if (!$this->helperSet) {
$this->helperSet = $this->getDefaultHelperSet();
}

return $this->helperSet;
}

public function setDefinition(InputDefinition $definition)
{
$this->definition = $definition;
}






public function getDefinition()
{
if (!$this->definition) {
$this->definition = $this->getDefaultInputDefinition();
}

if ($this->singleCommand) {
$inputDefinition = $this->definition;
$inputDefinition->setArguments();

return $inputDefinition;
}

return $this->definition;
}






public function getHelp()
{
return $this->getLongVersion();
}






public function areExceptionsCaught()
{
return $this->catchExceptions;
}






public function setCatchExceptions($boolean)
{
$this->catchExceptions = (bool) $boolean;
}






public function isAutoExitEnabled()
{
return $this->autoExit;
}






public function setAutoExit($boolean)
{
$this->autoExit = (bool) $boolean;
}






public function getName()
{
return $this->name;
}






public function setName($name)
{
$this->name = $name;
}






public function getVersion()
{
return $this->version;
}






public function setVersion($version)
{
$this->version = $version;
}






public function getLongVersion()
{
if ('UNKNOWN' !== $this->getName()) {
if ('UNKNOWN' !== $this->getVersion()) {
return sprintf('%s <info>%s</info>', $this->getName(), $this->getVersion());
}

return $this->getName();
}

return 'Console Tool';
}








public function register($name)
{
return $this->add(new Command($name));
}








public function addCommands(array $commands)
{
foreach ($commands as $command) {
$this->add($command);
}
}









public function add(Command $command)
{
$this->init();

$command->setApplication($this);

if (!$command->isEnabled()) {
$command->setApplication(null);

return null;
}


 $command->getDefinition();

if (!$command->getName()) {
throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', \get_class($command)));
}

$this->commands[$command->getName()] = $command;

foreach ($command->getAliases() as $alias) {
$this->commands[$alias] = $command;
}

return $command;
}










public function get($name)
{
$this->init();

if (!$this->has($name)) {
throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name));
}


 if (!isset($this->commands[$name])) {
throw new CommandNotFoundException(sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name));
}

$command = $this->commands[$name];

if ($this->wantHelps) {
$this->wantHelps = false;

$helpCommand = $this->get('help');
$helpCommand->setCommand($command);

return $helpCommand;
}

return $command;
}








public function has($name)
{
$this->init();

return isset($this->commands[$name]) || ($this->commandLoader && $this->commandLoader->has($name) && $this->add($this->commandLoader->get($name)));
}








public function getNamespaces()
{
$namespaces = [];
foreach ($this->all() as $command) {
if ($command->isHidden()) {
continue;
}

$namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));

foreach ($command->getAliases() as $alias) {
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias));
}
}

return array_values(array_unique(array_filter($namespaces)));
}










public function findNamespace($namespace)
{
$allNamespaces = $this->getNamespaces();
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $namespace);
$namespaces = preg_grep('{^'.$expr.'}', $allNamespaces);

if (empty($namespaces)) {
$message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);

if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {
if (1 == \count($alternatives)) {
$message .= "\n\nDid you mean this?\n    ";
} else {
$message .= "\n\nDid you mean one of these?\n    ";
}

$message .= implode("\n    ", $alternatives);
}

throw new NamespaceNotFoundException($message, $alternatives);
}

$exact = \in_array($namespace, $namespaces, true);
if (\count($namespaces) > 1 && !$exact) {
throw new NamespaceNotFoundException(sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
}

return $exact ? $namespace : reset($namespaces);
}













public function find($name)
{
$this->init();

$aliases = [];

foreach ($this->commands as $command) {
foreach ($command->getAliases() as $alias) {
if (!$this->has($alias)) {
$this->commands[$alias] = $command;
}
}
}

if ($this->has($name)) {
return $this->get($name);
}

$allCommands = $this->commandLoader ? array_merge($this->commandLoader->getNames(), array_keys($this->commands)) : array_keys($this->commands);
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name);
$commands = preg_grep('{^'.$expr.'}', $allCommands);

if (empty($commands)) {
$commands = preg_grep('{^'.$expr.'}i', $allCommands);
}


 if (empty($commands) || \count(preg_grep('{^'.$expr.'$}i', $commands)) < 1) {
if (false !== $pos = strrpos($name, ':')) {

 $this->findNamespace(substr($name, 0, $pos));
}

$message = sprintf('Command "%s" is not defined.', $name);

if ($alternatives = $this->findAlternatives($name, $allCommands)) {

 $alternatives = array_filter($alternatives, function ($name) {
return !$this->get($name)->isHidden();
});

if (1 == \count($alternatives)) {
$message .= "\n\nDid you mean this?\n    ";
} else {
$message .= "\n\nDid you mean one of these?\n    ";
}
$message .= implode("\n    ", $alternatives);
}

throw new CommandNotFoundException($message, array_values($alternatives));
}


 if (\count($commands) > 1) {
$commandList = $this->commandLoader ? array_merge(array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands;
$commands = array_unique(array_filter($commands, function ($nameOrAlias) use (&$commandList, $commands, &$aliases) {
if (!$commandList[$nameOrAlias] instanceof Command) {
$commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias);
}

$commandName = $commandList[$nameOrAlias]->getName();

$aliases[$nameOrAlias] = $commandName;

return $commandName === $nameOrAlias || !\in_array($commandName, $commands);
}));
}

if (\count($commands) > 1) {
$usableWidth = $this->terminal->getWidth() - 10;
$abbrevs = array_values($commands);
$maxLen = 0;
foreach ($abbrevs as $abbrev) {
$maxLen = max(Helper::strlen($abbrev), $maxLen);
}
$abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen, &$commands) {
if ($commandList[$cmd]->isHidden()) {
unset($commands[array_search($cmd, $commands)]);

return false;
}

$abbrev = str_pad($cmd, $maxLen, ' ').' '.$commandList[$cmd]->getDescription();

return Helper::strlen($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3).'...' : $abbrev;
}, array_values($commands));

if (\count($commands) > 1) {
$suggestions = $this->getAbbreviationSuggestions(array_filter($abbrevs));

throw new CommandNotFoundException(sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), array_values($commands));
}
}

$command = $this->get(reset($commands));

if ($command->isHidden()) {
@trigger_error(sprintf('Command "%s" is hidden, finding it using an abbreviation is deprecated since Symfony 4.4, use its full name instead.', $command->getName()), \E_USER_DEPRECATED);
}

return $command;
}










public function all($namespace = null)
{
$this->init();

if (null === $namespace) {
if (!$this->commandLoader) {
return $this->commands;
}

$commands = $this->commands;
foreach ($this->commandLoader->getNames() as $name) {
if (!isset($commands[$name]) && $this->has($name)) {
$commands[$name] = $this->get($name);
}
}

return $commands;
}

$commands = [];
foreach ($this->commands as $name => $command) {
if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) {
$commands[$name] = $command;
}
}

if ($this->commandLoader) {
foreach ($this->commandLoader->getNames() as $name) {
if (!isset($commands[$name]) && $namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1) && $this->has($name)) {
$commands[$name] = $this->get($name);
}
}
}

return $commands;
}








public static function getAbbreviations($names)
{
$abbrevs = [];
foreach ($names as $name) {
for ($len = \strlen($name); $len > 0; --$len) {
$abbrev = substr($name, 0, $len);
$abbrevs[$abbrev][] = $name;
}
}

return $abbrevs;
}






public function renderException(\Exception $e, OutputInterface $output)
{
@trigger_error(sprintf('The "%s::renderException()" method is deprecated since Symfony 4.4, use "renderThrowable()" instead.', __CLASS__), \E_USER_DEPRECATED);

$output->writeln('', OutputInterface::VERBOSITY_QUIET);

$this->doRenderException($e, $output);

$this->finishRenderThrowableOrException($output);
}

public function renderThrowable(\Throwable $e, OutputInterface $output): void
{
if (__CLASS__ !== static::class && __CLASS__ === (new \ReflectionMethod($this, 'renderThrowable'))->getDeclaringClass()->getName() && __CLASS__ !== (new \ReflectionMethod($this, 'renderException'))->getDeclaringClass()->getName()) {
@trigger_error(sprintf('The "%s::renderException()" method is deprecated since Symfony 4.4, use "renderThrowable()" instead.', __CLASS__), \E_USER_DEPRECATED);

if (!$e instanceof \Exception) {
$e = class_exists(FatalThrowableError::class) ? new FatalThrowableError($e) : new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
}

$this->renderException($e, $output);

return;
}

$output->writeln('', OutputInterface::VERBOSITY_QUIET);

$this->doRenderThrowable($e, $output);

$this->finishRenderThrowableOrException($output);
}

private function finishRenderThrowableOrException(OutputInterface $output): void
{
if (null !== $this->runningCommand) {
$output->writeln(sprintf('<info>%s</info>', OutputFormatter::escape(sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET);
$output->writeln('', OutputInterface::VERBOSITY_QUIET);
}
}




protected function doRenderException(\Exception $e, OutputInterface $output)
{
@trigger_error(sprintf('The "%s::doRenderException()" method is deprecated since Symfony 4.4, use "doRenderThrowable()" instead.', __CLASS__), \E_USER_DEPRECATED);

$this->doActuallyRenderThrowable($e, $output);
}

protected function doRenderThrowable(\Throwable $e, OutputInterface $output): void
{
if (__CLASS__ !== static::class && __CLASS__ === (new \ReflectionMethod($this, 'doRenderThrowable'))->getDeclaringClass()->getName() && __CLASS__ !== (new \ReflectionMethod($this, 'doRenderException'))->getDeclaringClass()->getName()) {
@trigger_error(sprintf('The "%s::doRenderException()" method is deprecated since Symfony 4.4, use "doRenderThrowable()" instead.', __CLASS__), \E_USER_DEPRECATED);

if (!$e instanceof \Exception) {
$e = class_exists(FatalThrowableError::class) ? new FatalThrowableError($e) : new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
}

$this->doRenderException($e, $output);

return;
}

$this->doActuallyRenderThrowable($e, $output);
}

private function doActuallyRenderThrowable(\Throwable $e, OutputInterface $output): void
{
do {
$message = trim($e->getMessage());
if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
$class = get_debug_type($e);
$title = sprintf('  [%s%s]  ', $class, 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : '');
$len = Helper::strlen($title);
} else {
$len = 0;
}

if (str_contains($message, "@anonymous\0")) {
$message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) {
return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0];
}, $message);
}

$width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : \PHP_INT_MAX;
$lines = [];
foreach ('' !== $message ? preg_split('/\r?\n/', $message) : [] as $line) {
foreach ($this->splitStringByWidth($line, $width - 4) as $line) {

 $lineLength = Helper::strlen($line) + 4;
$lines[] = [$line, $lineLength];

$len = max($lineLength, $len);
}
}

$messages = [];
if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
$messages[] = sprintf('<comment>%s</comment>', OutputFormatter::escape(sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a')));
}
$messages[] = $emptyLine = sprintf('<error>%s</error>', str_repeat(' ', $len));
if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
$messages[] = sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - Helper::strlen($title))));
}
foreach ($lines as $line) {
$messages[] = sprintf('<error>  %s  %s</error>', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1]));
}
$messages[] = $emptyLine;
$messages[] = '';

$output->writeln($messages, OutputInterface::VERBOSITY_QUIET);

if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
$output->writeln('<comment>Exception trace:</comment>', OutputInterface::VERBOSITY_QUIET);


 $trace = $e->getTrace();

array_unshift($trace, [
'function' => '',
'file' => $e->getFile() ?: 'n/a',
'line' => $e->getLine() ?: 'n/a',
'args' => [],
]);

for ($i = 0, $count = \count($trace); $i < $count; ++$i) {
$class = $trace[$i]['class'] ?? '';
$type = $trace[$i]['type'] ?? '';
$function = $trace[$i]['function'] ?? '';
$file = $trace[$i]['file'] ?? 'n/a';
$line = $trace[$i]['line'] ?? 'n/a';

$output->writeln(sprintf(' %s%s at <info>%s:%s</info>', $class, $function ? $type.$function.'()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET);
}

$output->writeln('', OutputInterface::VERBOSITY_QUIET);
}
} while ($e = $e->getPrevious());
}




protected function configureIO(InputInterface $input, OutputInterface $output)
{
if (true === $input->hasParameterOption(['--ansi'], true)) {
$output->setDecorated(true);
} elseif (true === $input->hasParameterOption(['--no-ansi'], true)) {
$output->setDecorated(false);
}

if (true === $input->hasParameterOption(['--no-interaction', '-n'], true)) {
$input->setInteractive(false);
}

switch ($shellVerbosity = (int) getenv('SHELL_VERBOSITY')) {
case -1: $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); break;
case 1: $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); break;
case 2: $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); break;
case 3: $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); break;
default: $shellVerbosity = 0; break;
}

if (true === $input->hasParameterOption(['--quiet', '-q'], true)) {
$output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
$shellVerbosity = -1;
} else {
if ($input->hasParameterOption('-vvv', true) || $input->hasParameterOption('--verbose=3', true) || 3 === $input->getParameterOption('--verbose', false, true)) {
$output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
$shellVerbosity = 3;
} elseif ($input->hasParameterOption('-vv', true) || $input->hasParameterOption('--verbose=2', true) || 2 === $input->getParameterOption('--verbose', false, true)) {
$output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
$shellVerbosity = 2;
} elseif ($input->hasParameterOption('-v', true) || $input->hasParameterOption('--verbose=1', true) || $input->hasParameterOption('--verbose', true) || $input->getParameterOption('--verbose', false, true)) {
$output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
$shellVerbosity = 1;
}
}

if (-1 === $shellVerbosity) {
$input->setInteractive(false);
}

if (\function_exists('putenv')) {
@putenv('SHELL_VERBOSITY='.$shellVerbosity);
}
$_ENV['SHELL_VERBOSITY'] = $shellVerbosity;
$_SERVER['SHELL_VERBOSITY'] = $shellVerbosity;
}









protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output)
{
foreach ($command->getHelperSet() as $helper) {
if ($helper instanceof InputAwareInterface) {
$helper->setInput($input);
}
}

if (null === $this->dispatcher) {
return $command->run($input, $output);
}


 try {
$command->mergeApplicationDefinition();
$input->bind($command->getDefinition());
} catch (ExceptionInterface $e) {

 }

$event = new ConsoleCommandEvent($command, $input, $output);
$e = null;

try {
$this->dispatcher->dispatch($event, ConsoleEvents::COMMAND);

if ($event->commandShouldRun()) {
$exitCode = $command->run($input, $output);
} else {
$exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
}
} catch (\Throwable $e) {
$event = new ConsoleErrorEvent($input, $output, $e, $command);
$this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
$e = $event->getError();

if (0 === $exitCode = $event->getExitCode()) {
$e = null;
}
}

$event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
$this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE);

if (null !== $e) {
throw $e;
}

return $event->getExitCode();
}






protected function getCommandName(InputInterface $input)
{
return $this->singleCommand ? $this->defaultCommand : $input->getFirstArgument();
}






protected function getDefaultInputDefinition()
{
return new InputDefinition([
new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),

new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message'),
new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'),
new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'),
new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'),
new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'),
new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'),
new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'),
]);
}






protected function getDefaultCommands()
{
return [new HelpCommand(), new ListCommand()];
}






protected function getDefaultHelperSet()
{
return new HelperSet([
new FormatterHelper(),
new DebugFormatterHelper(),
new ProcessHelper(),
new QuestionHelper(),
]);
}




private function getAbbreviationSuggestions(array $abbrevs): string
{
return '    '.implode("\n    ", $abbrevs);
}











public function extractNamespace($name, $limit = null)
{
$parts = explode(':', $name, -1);

return implode(':', null === $limit ? $parts : \array_slice($parts, 0, $limit));
}







private function findAlternatives(string $name, iterable $collection): array
{
$threshold = 1e3;
$alternatives = [];

$collectionParts = [];
foreach ($collection as $item) {
$collectionParts[$item] = explode(':', $item);
}

foreach (explode(':', $name) as $i => $subname) {
foreach ($collectionParts as $collectionName => $parts) {
$exists = isset($alternatives[$collectionName]);
if (!isset($parts[$i]) && $exists) {
$alternatives[$collectionName] += $threshold;
continue;
} elseif (!isset($parts[$i])) {
continue;
}

$lev = levenshtein($subname, $parts[$i]);
if ($lev <= \strlen($subname) / 3 || '' !== $subname && str_contains($parts[$i], $subname)) {
$alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
} elseif ($exists) {
$alternatives[$collectionName] += $threshold;
}
}
}

foreach ($collection as $item) {
$lev = levenshtein($name, $item);
if ($lev <= \strlen($name) / 3 || str_contains($item, $name)) {
$alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
}
}

$alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; });
ksort($alternatives, \SORT_NATURAL | \SORT_FLAG_CASE);

return array_keys($alternatives);
}









public function setDefaultCommand($commandName, $isSingleCommand = false)
{
$this->defaultCommand = $commandName;

if ($isSingleCommand) {

 $this->find($commandName);

$this->singleCommand = true;
}

return $this;
}




public function isSingleCommand(): bool
{
return $this->singleCommand;
}

private function splitStringByWidth(string $string, int $width): array
{

 
 
 if (false === $encoding = mb_detect_encoding($string, null, true)) {
return str_split($string, $width);
}

$utf8String = mb_convert_encoding($string, 'utf8', $encoding);
$lines = [];
$line = '';

$offset = 0;
while (preg_match('/.{1,10000}/u', $utf8String, $m, 0, $offset)) {
$offset += \strlen($m[0]);

foreach (preg_split('//u', $m[0]) as $char) {

 if (mb_strwidth($line.$char, 'utf8') <= $width) {
$line .= $char;
continue;
}

 $lines[] = str_pad($line, $width);
$line = $char;
}
}

$lines[] = \count($lines) ? str_pad($line, $width) : $line;

mb_convert_variables($encoding, 'utf8', $lines);

return $lines;
}






private function extractAllNamespaces(string $name): array
{

 $parts = explode(':', $name, -1);
$namespaces = [];

foreach ($parts as $part) {
if (\count($namespaces)) {
$namespaces[] = end($namespaces).':'.$part;
} else {
$namespaces[] = $part;
}
}

return $namespaces;
}

private function init()
{
if ($this->initialized) {
return;
}
$this->initialized = true;

foreach ($this->getDefaultCommands() as $command) {
$this->add($command);
}
}
}
<?php










namespace Symfony\Component\Console\Style;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Helper\SymfonyQuestionHelper;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableCell;
use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\TrimmedBufferOutput;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Terminal;






class SymfonyStyle extends OutputStyle
{
public const MAX_LINE_LENGTH = 120;

private $input;
private $questionHelper;
private $progressBar;
private $lineLength;
private $bufferedOutput;

public function __construct(InputInterface $input, OutputInterface $output)
{
$this->input = $input;
$this->bufferedOutput = new TrimmedBufferOutput(\DIRECTORY_SEPARATOR === '\\' ? 4 : 2, $output->getVerbosity(), false, clone $output->getFormatter());

 $width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH;
$this->lineLength = min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH);

parent::__construct($output);
}











public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false, $escape = true)
{
$messages = \is_array($messages) ? array_values($messages) : [$messages];

$this->autoPrependBlock();
$this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, $escape));
$this->newLine();
}




public function title($message)
{
$this->autoPrependBlock();
$this->writeln([
sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
sprintf('<comment>%s</>', str_repeat('=', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
]);
$this->newLine();
}




public function section($message)
{
$this->autoPrependBlock();
$this->writeln([
sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
sprintf('<comment>%s</>', str_repeat('-', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
]);
$this->newLine();
}




public function listing(array $elements)
{
$this->autoPrependText();
$elements = array_map(function ($element) {
return sprintf(' * %s', $element);
}, $elements);

$this->writeln($elements);
$this->newLine();
}




public function text($message)
{
$this->autoPrependText();

$messages = \is_array($message) ? array_values($message) : [$message];
foreach ($messages as $message) {
$this->writeln(sprintf(' %s', $message));
}
}






public function comment($message)
{
$this->block($message, null, null, '<fg=default;bg=default> // </>', false, false);
}




public function success($message)
{
$this->block($message, 'OK', 'fg=black;bg=green', ' ', true);
}




public function error($message)
{
$this->block($message, 'ERROR', 'fg=white;bg=red', ' ', true);
}




public function warning($message)
{
$this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', true);
}




public function note($message)
{
$this->block($message, 'NOTE', 'fg=yellow', ' ! ');
}




public function caution($message)
{
$this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', true);
}




public function table(array $headers, array $rows)
{
$style = clone Table::getStyleDefinition('symfony-style-guide');
$style->setCellHeaderFormat('<info>%s</info>');

$table = new Table($this);
$table->setHeaders($headers);
$table->setRows($rows);
$table->setStyle($style);

$table->render();
$this->newLine();
}




public function horizontalTable(array $headers, array $rows)
{
$style = clone Table::getStyleDefinition('symfony-style-guide');
$style->setCellHeaderFormat('<info>%s</info>');

$table = new Table($this);
$table->setHeaders($headers);
$table->setRows($rows);
$table->setStyle($style);
$table->setHorizontal(true);

$table->render();
$this->newLine();
}











public function definitionList(...$list)
{
$style = clone Table::getStyleDefinition('symfony-style-guide');
$style->setCellHeaderFormat('<info>%s</info>');

$table = new Table($this);
$headers = [];
$row = [];
foreach ($list as $value) {
if ($value instanceof TableSeparator) {
$headers[] = $value;
$row[] = $value;
continue;
}
if (\is_string($value)) {
$headers[] = new TableCell($value, ['colspan' => 2]);
$row[] = null;
continue;
}
if (!\is_array($value)) {
throw new InvalidArgumentException('Value should be an array, string, or an instance of TableSeparator.');
}
$headers[] = key($value);
$row[] = current($value);
}

$table->setHeaders($headers);
$table->setRows([$row]);
$table->setHorizontal();
$table->setStyle($style);

$table->render();
$this->newLine();
}




public function ask($question, $default = null, $validator = null)
{
$question = new Question($question, $default);
$question->setValidator($validator);

return $this->askQuestion($question);
}




public function askHidden($question, $validator = null)
{
$question = new Question($question);

$question->setHidden(true);
$question->setValidator($validator);

return $this->askQuestion($question);
}




public function confirm($question, $default = true)
{
return $this->askQuestion(new ConfirmationQuestion($question, $default));
}




public function choice($question, array $choices, $default = null)
{
if (null !== $default) {
$values = array_flip($choices);
$default = $values[$default] ?? $default;
}

return $this->askQuestion(new ChoiceQuestion($question, $choices, $default));
}




public function progressStart($max = 0)
{
$this->progressBar = $this->createProgressBar($max);
$this->progressBar->start();
}




public function progressAdvance($step = 1)
{
$this->getProgressBar()->advance($step);
}




public function progressFinish()
{
$this->getProgressBar()->finish();
$this->newLine(2);
$this->progressBar = null;
}




public function createProgressBar($max = 0)
{
$progressBar = parent::createProgressBar($max);

if ('\\' !== \DIRECTORY_SEPARATOR || 'Hyper' === getenv('TERM_PROGRAM')) {
$progressBar->setEmptyBarCharacter('░'); 
 $progressBar->setProgressCharacter('');
$progressBar->setBarCharacter('▓'); 
 }

return $progressBar;
}




public function askQuestion(Question $question)
{
if ($this->input->isInteractive()) {
$this->autoPrependBlock();
}

if (!$this->questionHelper) {
$this->questionHelper = new SymfonyQuestionHelper();
}

$answer = $this->questionHelper->ask($this->input, $this, $question);

if ($this->input->isInteractive()) {
$this->newLine();
$this->bufferedOutput->write("\n");
}

return $answer;
}




public function writeln($messages, $type = self::OUTPUT_NORMAL)
{
if (!is_iterable($messages)) {
$messages = [$messages];
}

foreach ($messages as $message) {
parent::writeln($message, $type);
$this->writeBuffer($message, true, $type);
}
}




public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
{
if (!is_iterable($messages)) {
$messages = [$messages];
}

foreach ($messages as $message) {
parent::write($message, $newline, $type);
$this->writeBuffer($message, $newline, $type);
}
}




public function newLine($count = 1)
{
parent::newLine($count);
$this->bufferedOutput->write(str_repeat("\n", $count));
}






public function getErrorStyle()
{
return new self($this->input, $this->getErrorOutput());
}

private function getProgressBar(): ProgressBar
{
if (!$this->progressBar) {
throw new RuntimeException('The ProgressBar is not started.');
}

return $this->progressBar;
}

private function autoPrependBlock(): void
{
$chars = substr(str_replace(\PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2);

if (!isset($chars[0])) {
$this->newLine(); 

return;
}

 $this->newLine(2 - substr_count($chars, "\n"));
}

private function autoPrependText(): void
{
$fetched = $this->bufferedOutput->fetch();

 if (!str_ends_with($fetched, "\n")) {
$this->newLine();
}
}

private function writeBuffer(string $message, bool $newLine, int $type): void
{

 $this->bufferedOutput->write($message, $newLine, $type);
}

private function createBlock(iterable $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array
{
$indentLength = 0;
$prefixLength = Helper::strlenWithoutDecoration($this->getFormatter(), $prefix);
$lines = [];

if (null !== $type) {
$type = sprintf('[%s] ', $type);
$indentLength = \strlen($type);
$lineIndentation = str_repeat(' ', $indentLength);
}


 foreach ($messages as $key => $message) {
if ($escape) {
$message = OutputFormatter::escape($message);
}

$decorationLength = Helper::strlen($message) - Helper::strlenWithoutDecoration($this->getFormatter(), $message);
$messageLineLength = min($this->lineLength - $prefixLength - $indentLength + $decorationLength, $this->lineLength);
$messageLines = explode(\PHP_EOL, wordwrap($message, $messageLineLength, \PHP_EOL, true));
foreach ($messageLines as $messageLine) {
$lines[] = $messageLine;
}

if (\count($messages) > 1 && $key < \count($messages) - 1) {
$lines[] = '';
}
}

$firstLineIndex = 0;
if ($padding && $this->isDecorated()) {
$firstLineIndex = 1;
array_unshift($lines, '');
$lines[] = '';
}

foreach ($lines as $i => &$line) {
if (null !== $type) {
$line = $firstLineIndex === $i ? $type.$line : $lineIndentation.$line;
}

$line = $prefix.$line;
$line .= str_repeat(' ', max($this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line), 0));

if ($style) {
$line = sprintf('<%s>%s</>', $style, $line);
}
}

return $lines;
}
}
<?php










namespace Symfony\Component\Console\Style;

use Symfony\Component\Console\Formatter\OutputFormatterInterface;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;






abstract class OutputStyle implements OutputInterface, StyleInterface
{
private $output;

public function __construct(OutputInterface $output)
{
$this->output = $output;
}




public function newLine($count = 1)
{
$this->output->write(str_repeat(\PHP_EOL, $count));
}






public function createProgressBar($max = 0)
{
return new ProgressBar($this->output, $max);
}




public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
{
$this->output->write($messages, $newline, $type);
}




public function writeln($messages, $type = self::OUTPUT_NORMAL)
{
$this->output->writeln($messages, $type);
}




public function setVerbosity($level)
{
$this->output->setVerbosity($level);
}




public function getVerbosity()
{
return $this->output->getVerbosity();
}




public function setDecorated($decorated)
{
$this->output->setDecorated($decorated);
}




public function isDecorated()
{
return $this->output->isDecorated();
}




public function setFormatter(OutputFormatterInterface $formatter)
{
$this->output->setFormatter($formatter);
}




public function getFormatter()
{
return $this->output->getFormatter();
}




public function isQuiet()
{
return $this->output->isQuiet();
}




public function isVerbose()
{
return $this->output->isVerbose();
}




public function isVeryVerbose()
{
return $this->output->isVeryVerbose();
}




public function isDebug()
{
return $this->output->isDebug();
}

protected function getErrorOutput()
{
if (!$this->output instanceof ConsoleOutputInterface) {
return $this->output;
}

return $this->output->getErrorOutput();
}
}
<?php










namespace Symfony\Component\Console\Style;






interface StyleInterface
{





public function title($message);






public function section($message);




public function listing(array $elements);






public function text($message);






public function success($message);






public function error($message);






public function warning($message);






public function note($message);






public function caution($message);




public function table(array $headers, array $rows);










public function ask($question, $default = null, $validator = null);









public function askHidden($question, $validator = null);









public function confirm($question, $default = true);









public function choice($question, array $choices, $default = null);






public function newLine($count = 1);






public function progressStart($max = 0);






public function progressAdvance($step = 1);




public function progressFinish();
}
<?php










namespace Symfony\Component\Console\Tester;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;







class CommandTester
{
use TesterTrait;

private $command;
private $input;
private $statusCode;

public function __construct(Command $command)
{
$this->command = $command;
}
















public function execute(array $input, array $options = [])
{

 
 if (!isset($input['command'])
&& (null !== $application = $this->command->getApplication())
&& $application->getDefinition()->hasArgument('command')
) {
$input = array_merge(['command' => $this->command->getName()], $input);
}

$this->input = new ArrayInput($input);

 $this->input->setStream(self::createStream($this->inputs));

if (isset($options['interactive'])) {
$this->input->setInteractive($options['interactive']);
}

if (!isset($options['decorated'])) {
$options['decorated'] = false;
}

$this->initOutput($options);

return $this->statusCode = $this->command->run($this->input, $this->output);
}
}
<?php










namespace Symfony\Component\Console\Tester;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;











class ApplicationTester
{
use TesterTrait;

private $application;
private $input;
private $statusCode;

public function __construct(Application $application)
{
$this->application = $application;
}
















public function run(array $input, $options = [])
{
$this->input = new ArrayInput($input);
if (isset($options['interactive'])) {
$this->input->setInteractive($options['interactive']);
}

if ($this->inputs) {
$this->input->setStream(self::createStream($this->inputs));
}

$this->initOutput($options);

return $this->statusCode = $this->application->run($this->input, $this->output);
}
}
<?php










namespace Symfony\Component\Console\Tester;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\StreamOutput;




trait TesterTrait
{

private $output;
private $inputs = [];
private $captureStreamsIndependently = false;








public function getDisplay($normalize = false)
{
if (null === $this->output) {
throw new \RuntimeException('Output not initialized, did you execute the command before requesting the display?');
}

rewind($this->output->getStream());

$display = stream_get_contents($this->output->getStream());

if ($normalize) {
$display = str_replace(\PHP_EOL, "\n", $display);
}

return $display;
}








public function getErrorOutput($normalize = false)
{
if (!$this->captureStreamsIndependently) {
throw new \LogicException('The error output is not available when the tester is run without "capture_stderr_separately" option set.');
}

rewind($this->output->getErrorOutput()->getStream());

$display = stream_get_contents($this->output->getErrorOutput()->getStream());

if ($normalize) {
$display = str_replace(\PHP_EOL, "\n", $display);
}

return $display;
}






public function getInput()
{
return $this->input;
}






public function getOutput()
{
return $this->output;
}






public function getStatusCode()
{
return $this->statusCode;
}









public function setInputs(array $inputs)
{
$this->inputs = $inputs;

return $this;
}










private function initOutput(array $options)
{
$this->captureStreamsIndependently = \array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately'];
if (!$this->captureStreamsIndependently) {
$this->output = new StreamOutput(fopen('php://memory', 'w', false));
if (isset($options['decorated'])) {
$this->output->setDecorated($options['decorated']);
}
if (isset($options['verbosity'])) {
$this->output->setVerbosity($options['verbosity']);
}
} else {
$this->output = new ConsoleOutput(
$options['verbosity'] ?? ConsoleOutput::VERBOSITY_NORMAL,
$options['decorated'] ?? null
);

$errorOutput = new StreamOutput(fopen('php://memory', 'w', false));
$errorOutput->setFormatter($this->output->getFormatter());
$errorOutput->setVerbosity($this->output->getVerbosity());
$errorOutput->setDecorated($this->output->isDecorated());

$reflectedOutput = new \ReflectionObject($this->output);
$strErrProperty = $reflectedOutput->getProperty('stderr');
$strErrProperty->setAccessible(true);
$strErrProperty->setValue($this->output, $errorOutput);

$reflectedParent = $reflectedOutput->getParentClass();
$streamProperty = $reflectedParent->getProperty('stream');
$streamProperty->setAccessible(true);
$streamProperty->setValue($this->output, fopen('php://memory', 'w', false));
}
}




private static function createStream(array $inputs)
{
$stream = fopen('php://memory', 'r+', false);

foreach ($inputs as $input) {
fwrite($stream, $input.\PHP_EOL);
}

rewind($stream);

return $stream;
}
}
<?php










namespace Symfony\Component\Console\Logger;

use Psr\Log\AbstractLogger;
use Psr\Log\InvalidArgumentException;
use Psr\Log\LogLevel;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;








class ConsoleLogger extends AbstractLogger
{
public const INFO = 'info';
public const ERROR = 'error';

private $output;
private $verbosityLevelMap = [
LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL,
LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL,
LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL,
LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL,
LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL,
LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE,
LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE,
LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG,
];
private $formatLevelMap = [
LogLevel::EMERGENCY => self::ERROR,
LogLevel::ALERT => self::ERROR,
LogLevel::CRITICAL => self::ERROR,
LogLevel::ERROR => self::ERROR,
LogLevel::WARNING => self::INFO,
LogLevel::NOTICE => self::INFO,
LogLevel::INFO => self::INFO,
LogLevel::DEBUG => self::INFO,
];
private $errored = false;

public function __construct(OutputInterface $output, array $verbosityLevelMap = [], array $formatLevelMap = [])
{
$this->output = $output;
$this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap;
$this->formatLevelMap = $formatLevelMap + $this->formatLevelMap;
}






public function log($level, $message, array $context = [])
{
if (!isset($this->verbosityLevelMap[$level])) {
throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level));
}

$output = $this->output;


 if (self::ERROR === $this->formatLevelMap[$level]) {
if ($this->output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}
$this->errored = true;
}


 
 if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) {
$output->writeln(sprintf('<%1$s>[%2$s] %3$s</%1$s>', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]);
}
}






public function hasErrored()
{
return $this->errored;
}






private function interpolate(string $message, array $context): string
{
if (!str_contains($message, '{')) {
return $message;
}

$replacements = [];
foreach ($context as $key => $val) {
if (null === $val || is_scalar($val) || (\is_object($val) && method_exists($val, '__toString'))) {
$replacements["{{$key}}"] = $val;
} elseif ($val instanceof \DateTimeInterface) {
$replacements["{{$key}}"] = $val->format(\DateTime::RFC3339);
} elseif (\is_object($val)) {
$replacements["{{$key}}"] = '[object '.\get_class($val).']';
} else {
$replacements["{{$key}}"] = '['.\gettype($val).']';
}
}

return strtr($message, $replacements);
}
}
<?php










namespace Symfony\Component\Console\Command;

use Symfony\Component\Console\Helper\DescriptorHelper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;






class ListCommand extends Command
{



protected function configure()
{
$this
->setName('list')
->setDefinition($this->createDefinition())
->setDescription('List commands')
->setHelp(<<<'EOF'
The <info>%command.name%</info> command lists all commands:

  <info>php %command.full_name%</info>

You can also display the commands for a specific namespace:

  <info>php %command.full_name% test</info>

You can also output the information in other formats by using the <comment>--format</comment> option:

  <info>php %command.full_name% --format=xml</info>

It's also possible to get raw list of commands (useful for embedding command runner):

  <info>php %command.full_name% --raw</info>
EOF
)
;
}




public function getNativeDefinition()
{
return $this->createDefinition();
}




protected function execute(InputInterface $input, OutputInterface $output)
{
$helper = new DescriptorHelper();
$helper->describe($output, $this->getApplication(), [
'format' => $input->getOption('format'),
'raw_text' => $input->getOption('raw'),
'namespace' => $input->getArgument('namespace'),
]);

return 0;
}

private function createDefinition(): InputDefinition
{
return new InputDefinition([
new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
]);
}
}
<?php










namespace Symfony\Component\Console\Command;

use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Lock\Lock;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\Store\FlockStore;
use Symfony\Component\Lock\Store\SemaphoreStore;






trait LockableTrait
{

private $lock;




private function lock(string $name = null, bool $blocking = false): bool
{
if (!class_exists(SemaphoreStore::class)) {
throw new LogicException('To enable the locking feature you must install the symfony/lock component.');
}

if (null !== $this->lock) {
throw new LogicException('A lock is already in place.');
}

if (SemaphoreStore::isSupported()) {
$store = new SemaphoreStore();
} else {
$store = new FlockStore();
}

$this->lock = (new LockFactory($store))->createLock($name ?: $this->getName());
if (!$this->lock->acquire($blocking)) {
$this->lock = null;

return false;
}

return true;
}




private function release()
{
if ($this->lock) {
$this->lock->release();
$this->lock = null;
}
}
}
<?php










namespace Symfony\Component\Console\Command;

use Symfony\Component\Console\Helper\DescriptorHelper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;






class HelpCommand extends Command
{
private $command;




protected function configure()
{
$this->ignoreValidationErrors();

$this
->setName('help')
->setDefinition([
new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),
])
->setDescription('Display help for a command')
->setHelp(<<<'EOF'
The <info>%command.name%</info> command displays help for a given command:

  <info>php %command.full_name% list</info>

You can also output the help in other formats by using the <comment>--format</comment> option:

  <info>php %command.full_name% --format=xml list</info>

To display the list of available commands, please use the <info>list</info> command.
EOF
)
;
}

public function setCommand(Command $command)
{
$this->command = $command;
}




protected function execute(InputInterface $input, OutputInterface $output)
{
if (null === $this->command) {
$this->command = $this->getApplication()->find($input->getArgument('command_name'));
}

$helper = new DescriptorHelper();
$helper->describe($output, $this->command, [
'format' => $input->getOption('format'),
'raw_text' => $input->getOption('raw'),
]);

$this->command = null;

return 0;
}
}
<?php










namespace Symfony\Component\Console\Command;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Exception\ExceptionInterface;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;






class Command
{



protected static $defaultName;

private $application;
private $name;
private $processTitle;
private $aliases = [];
private $definition;
private $hidden = false;
private $help = '';
private $description = '';
private $ignoreValidationErrors = false;
private $applicationDefinitionMerged = false;
private $applicationDefinitionMergedWithArgs = false;
private $code;
private $synopsis = [];
private $usages = [];
private $helperSet;




public static function getDefaultName()
{
$class = static::class;
$r = new \ReflectionProperty($class, 'defaultName');

return $class === $r->class ? static::$defaultName : null;
}






public function __construct(string $name = null)
{
$this->definition = new InputDefinition();

if (null !== $name || null !== $name = static::getDefaultName()) {
$this->setName($name);
}

$this->configure();
}






public function ignoreValidationErrors()
{
$this->ignoreValidationErrors = true;
}

public function setApplication(Application $application = null)
{
$this->application = $application;
if ($application) {
$this->setHelperSet($application->getHelperSet());
} else {
$this->helperSet = null;
}
}

public function setHelperSet(HelperSet $helperSet)
{
$this->helperSet = $helperSet;
}






public function getHelperSet()
{
return $this->helperSet;
}






public function getApplication()
{
return $this->application;
}









public function isEnabled()
{
return true;
}




protected function configure()
{
}















protected function execute(InputInterface $input, OutputInterface $output)
{
throw new LogicException('You must override the execute() method in the concrete command class.');
}








protected function interact(InputInterface $input, OutputInterface $output)
{
}











protected function initialize(InputInterface $input, OutputInterface $output)
{
}















public function run(InputInterface $input, OutputInterface $output)
{

 $this->getSynopsis(true);
$this->getSynopsis(false);


 $this->mergeApplicationDefinition();


 try {
$input->bind($this->definition);
} catch (ExceptionInterface $e) {
if (!$this->ignoreValidationErrors) {
throw $e;
}
}

$this->initialize($input, $output);

if (null !== $this->processTitle) {
if (\function_exists('cli_set_process_title')) {
if (!@cli_set_process_title($this->processTitle)) {
if ('Darwin' === \PHP_OS) {
$output->writeln('<comment>Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.</comment>', OutputInterface::VERBOSITY_VERY_VERBOSE);
} else {
cli_set_process_title($this->processTitle);
}
}
} elseif (\function_exists('setproctitle')) {
setproctitle($this->processTitle);
} elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) {
$output->writeln('<comment>Install the proctitle PECL to be able to change the process title.</comment>');
}
}

if ($input->isInteractive()) {
$this->interact($input, $output);
}


 
 
 if ($input->hasArgument('command') && null === $input->getArgument('command')) {
$input->setArgument('command', $this->getName());
}

$input->validate();

if ($this->code) {
$statusCode = ($this->code)($input, $output);
} else {
$statusCode = $this->execute($input, $output);

if (!\is_int($statusCode)) {
@trigger_error(sprintf('Return value of "%s::execute()" should always be of the type int since Symfony 4.4, %s returned.', static::class, \gettype($statusCode)), \E_USER_DEPRECATED);
}
}

return is_numeric($statusCode) ? (int) $statusCode : 0;
}















public function setCode(callable $code)
{
if ($code instanceof \Closure) {
$r = new \ReflectionFunction($code);
if (null === $r->getClosureThis()) {
set_error_handler(static function () {});
try {
if ($c = \Closure::bind($code, $this)) {
$code = $c;
}
} finally {
restore_error_handler();
}
}
}

$this->code = $code;

return $this;
}








public function mergeApplicationDefinition($mergeArgs = true)
{
if (null === $this->application || (true === $this->applicationDefinitionMerged && ($this->applicationDefinitionMergedWithArgs || !$mergeArgs))) {
return;
}

$this->definition->addOptions($this->application->getDefinition()->getOptions());

$this->applicationDefinitionMerged = true;

if ($mergeArgs) {
$currentArguments = $this->definition->getArguments();
$this->definition->setArguments($this->application->getDefinition()->getArguments());
$this->definition->addArguments($currentArguments);

$this->applicationDefinitionMergedWithArgs = true;
}
}








public function setDefinition($definition)
{
if ($definition instanceof InputDefinition) {
$this->definition = $definition;
} else {
$this->definition->setDefinition($definition);
}

$this->applicationDefinitionMerged = false;

return $this;
}






public function getDefinition()
{
if (null === $this->definition) {
throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class));
}

return $this->definition;
}











public function getNativeDefinition()
{
return $this->getDefinition();
}













public function addArgument($name, $mode = null, $description = '', $default = null)
{
$this->definition->addArgument(new InputArgument($name, $mode, $description, $default));

return $this;
}














public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
{
$this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));

return $this;
}















public function setName($name)
{
$this->validateName($name);

$this->name = $name;

return $this;
}











public function setProcessTitle($title)
{
$this->processTitle = $title;

return $this;
}






public function getName()
{
return $this->name;
}






public function setHidden($hidden)
{
$this->hidden = (bool) $hidden;

return $this;
}




public function isHidden()
{
return $this->hidden;
}








public function setDescription($description)
{
$this->description = $description;

return $this;
}






public function getDescription()
{
return $this->description;
}








public function setHelp($help)
{
$this->help = $help;

return $this;
}






public function getHelp()
{
return $this->help;
}







public function getProcessedHelp()
{
$name = $this->name;
$isSingleCommand = $this->application && $this->application->isSingleCommand();

$placeholders = [
'%command.name%',
'%command.full_name%',
];
$replacements = [
$name,
$isSingleCommand ? $_SERVER['PHP_SELF'] : $_SERVER['PHP_SELF'].' '.$name,
];

return str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription());
}










public function setAliases($aliases)
{
if (!\is_array($aliases) && !$aliases instanceof \Traversable) {
throw new InvalidArgumentException('$aliases must be an array or an instance of \Traversable.');
}

foreach ($aliases as $alias) {
$this->validateName($alias);
}

$this->aliases = $aliases;

return $this;
}






public function getAliases()
{
return $this->aliases;
}








public function getSynopsis($short = false)
{
$key = $short ? 'short' : 'long';

if (!isset($this->synopsis[$key])) {
$this->synopsis[$key] = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis($short)));
}

return $this->synopsis[$key];
}








public function addUsage($usage)
{
if (!str_starts_with($usage, $this->name)) {
$usage = sprintf('%s %s', $this->name, $usage);
}

$this->usages[] = $usage;

return $this;
}






public function getUsages()
{
return $this->usages;
}











public function getHelper($name)
{
if (null === $this->helperSet) {
throw new LogicException(sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name));
}

return $this->helperSet->get($name);
}








private function validateName(string $name)
{
if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) {
throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
}
}
}
<?php










namespace Symfony\Component\Console\CommandLoader;

use Symfony\Component\Console\Exception\CommandNotFoundException;






class FactoryCommandLoader implements CommandLoaderInterface
{
private $factories;




public function __construct(array $factories)
{
$this->factories = $factories;
}




public function has($name)
{
return isset($this->factories[$name]);
}




public function get($name)
{
if (!isset($this->factories[$name])) {
throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));
}

$factory = $this->factories[$name];

return $factory();
}




public function getNames()
{
return array_keys($this->factories);
}
}
<?php










namespace Symfony\Component\Console\CommandLoader;

use Psr\Container\ContainerInterface;
use Symfony\Component\Console\Exception\CommandNotFoundException;






class ContainerCommandLoader implements CommandLoaderInterface
{
private $container;
private $commandMap;




public function __construct(ContainerInterface $container, array $commandMap)
{
$this->container = $container;
$this->commandMap = $commandMap;
}




public function get($name)
{
if (!$this->has($name)) {
throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));
}

return $this->container->get($this->commandMap[$name]);
}




public function has($name)
{
return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]);
}




public function getNames()
{
return array_keys($this->commandMap);
}
}
<?php










namespace Symfony\Component\Console\CommandLoader;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\CommandNotFoundException;




interface CommandLoaderInterface
{









public function get($name);








public function has($name);




public function getNames();
}
<?php










namespace Symfony\Component\Console\DependencyInjection;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\TypedReference;






class AddConsoleCommandPass implements CompilerPassInterface
{
private $commandLoaderServiceId;
private $commandTag;

public function __construct(string $commandLoaderServiceId = 'console.command_loader', string $commandTag = 'console.command')
{
$this->commandLoaderServiceId = $commandLoaderServiceId;
$this->commandTag = $commandTag;
}

public function process(ContainerBuilder $container)
{
$commandServices = $container->findTaggedServiceIds($this->commandTag, true);
$lazyCommandMap = [];
$lazyCommandRefs = [];
$serviceIds = [];

foreach ($commandServices as $id => $tags) {
$definition = $container->getDefinition($id);
$class = $container->getParameterBag()->resolveValue($definition->getClass());

if (isset($tags[0]['command'])) {
$commandName = $tags[0]['command'];
} else {
if (!$r = $container->getReflectionClass($class)) {
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
}
if (!$r->isSubclassOf(Command::class)) {
throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, $this->commandTag, Command::class));
}
$commandName = $class::getDefaultName();
}

if (null === $commandName) {
if (!$definition->isPublic() || $definition->isPrivate()) {
$commandId = 'console.command.public_alias.'.$id;
$container->setAlias($commandId, $id)->setPublic(true);
$id = $commandId;
}
$serviceIds[] = $id;

continue;
}

unset($tags[0]);
$lazyCommandMap[$commandName] = $id;
$lazyCommandRefs[$id] = new TypedReference($id, $class);
$aliases = [];

foreach ($tags as $tag) {
if (isset($tag['command'])) {
$aliases[] = $tag['command'];
$lazyCommandMap[$tag['command']] = $id;
}
}

$definition->addMethodCall('setName', [$commandName]);

if ($aliases) {
$definition->addMethodCall('setAliases', [$aliases]);
}
}

$container
->register($this->commandLoaderServiceId, ContainerCommandLoader::class)
->setPublic(true)
->setArguments([ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap]);

$container->setParameter('console.command.ids', $serviceIds);
}
}
<?php










namespace Symfony\Component\Console\Exception;






class MissingInputException extends RuntimeException implements ExceptionInterface
{
}
<?php










namespace Symfony\Component\Console\Exception;






class NamespaceNotFoundException extends CommandNotFoundException
{
}
<?php










namespace Symfony\Component\Console\Exception;






class InvalidOptionException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?php










namespace Symfony\Component\Console\Exception;




class LogicException extends \LogicException implements ExceptionInterface
{
}
<?php










namespace Symfony\Component\Console\Exception;




class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
<?php










namespace Symfony\Component\Console\Exception;






class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface
{
private $alternatives;







public function __construct(string $message, array $alternatives = [], int $code = 0, \Throwable $previous = null)
{
parent::__construct($message, $code, $previous);

$this->alternatives = $alternatives;
}




public function getAlternatives()
{
return $this->alternatives;
}
}
<?php










namespace Symfony\Component\Console\Exception;




class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?php










namespace Symfony\Component\Console\Exception;






interface ExceptionInterface extends \Throwable
{
}
<?php










namespace Symfony\Component\Console\Formatter;






interface WrappableOutputFormatterInterface extends OutputFormatterInterface
{



public function formatAndWrap(string $message, int $width);
}
<?php










namespace Symfony\Component\Console\Formatter;

use Symfony\Component\Console\Exception\InvalidArgumentException;







class OutputFormatter implements WrappableOutputFormatterInterface
{
private $decorated;
private $styles = [];
private $styleStack;

public function __clone()
{
$this->styleStack = clone $this->styleStack;
foreach ($this->styles as $key => $value) {
$this->styles[$key] = clone $value;
}
}








public static function escape($text)
{
$text = preg_replace('/([^\\\\]?)</', '$1\\<', $text);

return self::escapeTrailingBackslash($text);
}






public static function escapeTrailingBackslash(string $text): string
{
if (str_ends_with($text, '\\')) {
$len = \strlen($text);
$text = rtrim($text, '\\');
$text = str_replace("\0", '', $text);
$text .= str_repeat("\0", $len - \strlen($text));
}

return $text;
}






public function __construct(bool $decorated = false, array $styles = [])
{
$this->decorated = $decorated;

$this->setStyle('error', new OutputFormatterStyle('white', 'red'));
$this->setStyle('info', new OutputFormatterStyle('green'));
$this->setStyle('comment', new OutputFormatterStyle('yellow'));
$this->setStyle('question', new OutputFormatterStyle('black', 'cyan'));

foreach ($styles as $name => $style) {
$this->setStyle($name, $style);
}

$this->styleStack = new OutputFormatterStyleStack();
}




public function setDecorated($decorated)
{
$this->decorated = (bool) $decorated;
}




public function isDecorated()
{
return $this->decorated;
}




public function setStyle($name, OutputFormatterStyleInterface $style)
{
$this->styles[strtolower($name)] = $style;
}




public function hasStyle($name)
{
return isset($this->styles[strtolower($name)]);
}




public function getStyle($name)
{
if (!$this->hasStyle($name)) {
throw new InvalidArgumentException(sprintf('Undefined style: "%s".', $name));
}

return $this->styles[strtolower($name)];
}




public function format($message)
{
return $this->formatAndWrap((string) $message, 0);
}




public function formatAndWrap(string $message, int $width)
{
$offset = 0;
$output = '';
$tagRegex = '[a-z][^<>]*+';
$currentLineLength = 0;
preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#ix", $message, $matches, \PREG_OFFSET_CAPTURE);
foreach ($matches[0] as $i => $match) {
$pos = $match[1];
$text = $match[0];

if (0 != $pos && '\\' == $message[$pos - 1]) {
continue;
}


 $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength);
$offset = $pos + \strlen($text);


 if ($open = '/' != $text[1]) {
$tag = $matches[1][$i][0];
} else {
$tag = $matches[3][$i][0] ?? '';
}

if (!$open && !$tag) {

 $this->styleStack->pop();
} elseif (null === $style = $this->createStyleFromString($tag)) {
$output .= $this->applyCurrentStyle($text, $output, $width, $currentLineLength);
} elseif ($open) {
$this->styleStack->push($style);
} else {
$this->styleStack->pop($style);
}
}

$output .= $this->applyCurrentStyle(substr($message, $offset), $output, $width, $currentLineLength);

if (str_contains($output, "\0")) {
return strtr($output, ["\0" => '\\', '\\<' => '<']);
}

return str_replace('\\<', '<', $output);
}




public function getStyleStack()
{
return $this->styleStack;
}




private function createStyleFromString(string $string): ?OutputFormatterStyleInterface
{
if (isset($this->styles[$string])) {
return $this->styles[$string];
}

if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, \PREG_SET_ORDER)) {
return null;
}

$style = new OutputFormatterStyle();
foreach ($matches as $match) {
array_shift($match);
$match[0] = strtolower($match[0]);

if ('fg' == $match[0]) {
$style->setForeground(strtolower($match[1]));
} elseif ('bg' == $match[0]) {
$style->setBackground(strtolower($match[1]));
} elseif ('href' === $match[0]) {
$style->setHref($match[1]);
} elseif ('options' === $match[0]) {
preg_match_all('([^,;]+)', strtolower($match[1]), $options);
$options = array_shift($options);
foreach ($options as $option) {
$style->setOption($option);
}
} else {
return null;
}
}

return $style;
}




private function applyCurrentStyle(string $text, string $current, int $width, int &$currentLineLength): string
{
if ('' === $text) {
return '';
}

if (!$width) {
return $this->isDecorated() ? $this->styleStack->getCurrent()->apply($text) : $text;
}

if (!$currentLineLength && '' !== $current) {
$text = ltrim($text);
}

if ($currentLineLength) {
$prefix = substr($text, 0, $i = $width - $currentLineLength)."\n";
$text = substr($text, $i);
} else {
$prefix = '';
}

preg_match('~(\\n)$~', $text, $matches);
$text = $prefix.preg_replace('~([^\\n]{'.$width.'})\\ *~', "\$1\n", $text);
$text = rtrim($text, "\n").($matches[1] ?? '');

if (!$currentLineLength && '' !== $current && "\n" !== substr($current, -1)) {
$text = "\n".$text;
}

$lines = explode("\n", $text);

foreach ($lines as $line) {
$currentLineLength += \strlen($line);
if ($width <= $currentLineLength) {
$currentLineLength = 0;
}
}

if ($this->isDecorated()) {
foreach ($lines as $i => $line) {
$lines[$i] = $this->styleStack->getCurrent()->apply($line);
}
}

return implode("\n", $lines);
}
}
<?php










namespace Symfony\Component\Console\Formatter;






interface OutputFormatterInterface
{





public function setDecorated($decorated);






public function isDecorated();






public function setStyle($name, OutputFormatterStyleInterface $style);








public function hasStyle($name);










public function getStyle($name);








public function format($message);
}
<?php










namespace Symfony\Component\Console\Formatter;






interface OutputFormatterStyleInterface
{





public function setForeground($color = null);






public function setBackground($color = null);






public function setOption($option);






public function unsetOption($option);




public function setOptions(array $options);








public function apply($text);
}
<?php










namespace Symfony\Component\Console\Formatter;

use Symfony\Component\Console\Exception\InvalidArgumentException;






class OutputFormatterStyle implements OutputFormatterStyleInterface
{
private static $availableForegroundColors = [
'black' => ['set' => 30, 'unset' => 39],
'red' => ['set' => 31, 'unset' => 39],
'green' => ['set' => 32, 'unset' => 39],
'yellow' => ['set' => 33, 'unset' => 39],
'blue' => ['set' => 34, 'unset' => 39],
'magenta' => ['set' => 35, 'unset' => 39],
'cyan' => ['set' => 36, 'unset' => 39],
'white' => ['set' => 37, 'unset' => 39],
'default' => ['set' => 39, 'unset' => 39],
];
private static $availableBackgroundColors = [
'black' => ['set' => 40, 'unset' => 49],
'red' => ['set' => 41, 'unset' => 49],
'green' => ['set' => 42, 'unset' => 49],
'yellow' => ['set' => 43, 'unset' => 49],
'blue' => ['set' => 44, 'unset' => 49],
'magenta' => ['set' => 45, 'unset' => 49],
'cyan' => ['set' => 46, 'unset' => 49],
'white' => ['set' => 47, 'unset' => 49],
'default' => ['set' => 49, 'unset' => 49],
];
private static $availableOptions = [
'bold' => ['set' => 1, 'unset' => 22],
'underscore' => ['set' => 4, 'unset' => 24],
'blink' => ['set' => 5, 'unset' => 25],
'reverse' => ['set' => 7, 'unset' => 27],
'conceal' => ['set' => 8, 'unset' => 28],
];

private $foreground;
private $background;
private $href;
private $options = [];
private $handlesHrefGracefully;







public function __construct(string $foreground = null, string $background = null, array $options = [])
{
if (null !== $foreground) {
$this->setForeground($foreground);
}
if (null !== $background) {
$this->setBackground($background);
}
if (\count($options)) {
$this->setOptions($options);
}
}




public function setForeground($color = null)
{
if (null === $color) {
$this->foreground = null;

return;
}

if (!isset(static::$availableForegroundColors[$color])) {
throw new InvalidArgumentException(sprintf('Invalid foreground color specified: "%s". Expected one of (%s).', $color, implode(', ', array_keys(static::$availableForegroundColors))));
}

$this->foreground = static::$availableForegroundColors[$color];
}




public function setBackground($color = null)
{
if (null === $color) {
$this->background = null;

return;
}

if (!isset(static::$availableBackgroundColors[$color])) {
throw new InvalidArgumentException(sprintf('Invalid background color specified: "%s". Expected one of (%s).', $color, implode(', ', array_keys(static::$availableBackgroundColors))));
}

$this->background = static::$availableBackgroundColors[$color];
}

public function setHref(string $url): void
{
$this->href = $url;
}




public function setOption($option)
{
if (!isset(static::$availableOptions[$option])) {
throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(static::$availableOptions))));
}

if (!\in_array(static::$availableOptions[$option], $this->options)) {
$this->options[] = static::$availableOptions[$option];
}
}




public function unsetOption($option)
{
if (!isset(static::$availableOptions[$option])) {
throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(static::$availableOptions))));
}

$pos = array_search(static::$availableOptions[$option], $this->options);
if (false !== $pos) {
unset($this->options[$pos]);
}
}




public function setOptions(array $options)
{
$this->options = [];

foreach ($options as $option) {
$this->setOption($option);
}
}




public function apply($text)
{
$setCodes = [];
$unsetCodes = [];

if (null === $this->handlesHrefGracefully) {
$this->handlesHrefGracefully = 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR')
&& (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100);
}

if (null !== $this->foreground) {
$setCodes[] = $this->foreground['set'];
$unsetCodes[] = $this->foreground['unset'];
}
if (null !== $this->background) {
$setCodes[] = $this->background['set'];
$unsetCodes[] = $this->background['unset'];
}

foreach ($this->options as $option) {
$setCodes[] = $option['set'];
$unsetCodes[] = $option['unset'];
}

if (null !== $this->href && $this->handlesHrefGracefully) {
$text = "\033]8;;$this->href\033\\$text\033]8;;\033\\";
}

if (0 === \count($setCodes)) {
return $text;
}

return sprintf("\033[%sm%s\033[%sm", implode(';', $setCodes), $text, implode(';', $unsetCodes));
}
}
<?php










namespace Symfony\Component\Console\Formatter;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Contracts\Service\ResetInterface;




class OutputFormatterStyleStack implements ResetInterface
{



private $styles;

private $emptyStyle;

public function __construct(OutputFormatterStyleInterface $emptyStyle = null)
{
$this->emptyStyle = $emptyStyle ?? new OutputFormatterStyle();
$this->reset();
}




public function reset()
{
$this->styles = [];
}




public function push(OutputFormatterStyleInterface $style)
{
$this->styles[] = $style;
}








public function pop(OutputFormatterStyleInterface $style = null)
{
if (empty($this->styles)) {
return $this->emptyStyle;
}

if (null === $style) {
return array_pop($this->styles);
}

foreach (array_reverse($this->styles, true) as $index => $stackedStyle) {
if ($style->apply('') === $stackedStyle->apply('')) {
$this->styles = \array_slice($this->styles, 0, $index);

return $stackedStyle;
}
}

throw new InvalidArgumentException('Incorrectly nested style tag found.');
}






public function getCurrent()
{
if (empty($this->styles)) {
return $this->emptyStyle;
}

return $this->styles[\count($this->styles) - 1];
}




public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle)
{
$this->emptyStyle = $emptyStyle;

return $this;
}




public function getEmptyStyle()
{
return $this->emptyStyle;
}
}
<?php










namespace Symfony\Component\Console\Descriptor;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;








class TextDescriptor extends Descriptor
{



protected function describeInputArgument(InputArgument $argument, array $options = [])
{
if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) {
$default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($argument->getDefault()));
} else {
$default = '';
}

$totalWidth = $options['total_width'] ?? Helper::strlen($argument->getName());
$spacingWidth = $totalWidth - \strlen($argument->getName());

$this->writeText(sprintf('  <info>%s</info>  %s%s%s',
$argument->getName(),
str_repeat(' ', $spacingWidth),

 preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $argument->getDescription()),
$default
), $options);
}




protected function describeInputOption(InputOption $option, array $options = [])
{
if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) {
$default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($option->getDefault()));
} else {
$default = '';
}

$value = '';
if ($option->acceptValue()) {
$value = '='.strtoupper($option->getName());

if ($option->isValueOptional()) {
$value = '['.$value.']';
}
}

$totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]);
$synopsis = sprintf('%s%s',
$option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : '    ',
sprintf('--%s%s', $option->getName(), $value)
);

$spacingWidth = $totalWidth - Helper::strlen($synopsis);

$this->writeText(sprintf('  <info>%s</info>  %s%s%s%s',
$synopsis,
str_repeat(' ', $spacingWidth),

 preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $option->getDescription()),
$default,
$option->isArray() ? '<comment> (multiple values allowed)</comment>' : ''
), $options);
}




protected function describeInputDefinition(InputDefinition $definition, array $options = [])
{
$totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());
foreach ($definition->getArguments() as $argument) {
$totalWidth = max($totalWidth, Helper::strlen($argument->getName()));
}

if ($definition->getArguments()) {
$this->writeText('<comment>Arguments:</comment>', $options);
$this->writeText("\n");
foreach ($definition->getArguments() as $argument) {
$this->describeInputArgument($argument, array_merge($options, ['total_width' => $totalWidth]));
$this->writeText("\n");
}
}

if ($definition->getArguments() && $definition->getOptions()) {
$this->writeText("\n");
}

if ($definition->getOptions()) {
$laterOptions = [];

$this->writeText('<comment>Options:</comment>', $options);
foreach ($definition->getOptions() as $option) {
if (\strlen($option->getShortcut() ?? '') > 1) {
$laterOptions[] = $option;
continue;
}
$this->writeText("\n");
$this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));
}
foreach ($laterOptions as $option) {
$this->writeText("\n");
$this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));
}
}
}




protected function describeCommand(Command $command, array $options = [])
{
$command->getSynopsis(true);
$command->getSynopsis(false);
$command->mergeApplicationDefinition(false);

if ($description = $command->getDescription()) {
$this->writeText('<comment>Description:</comment>', $options);
$this->writeText("\n");
$this->writeText('  '.$description);
$this->writeText("\n\n");
}

$this->writeText('<comment>Usage:</comment>', $options);
foreach (array_merge([$command->getSynopsis(true)], $command->getAliases(), $command->getUsages()) as $usage) {
$this->writeText("\n");
$this->writeText('  '.OutputFormatter::escape($usage), $options);
}
$this->writeText("\n");

$definition = $command->getNativeDefinition();
if ($definition->getOptions() || $definition->getArguments()) {
$this->writeText("\n");
$this->describeInputDefinition($definition, $options);
$this->writeText("\n");
}

$help = $command->getProcessedHelp();
if ($help && $help !== $description) {
$this->writeText("\n");
$this->writeText('<comment>Help:</comment>', $options);
$this->writeText("\n");
$this->writeText('  '.str_replace("\n", "\n  ", $help), $options);
$this->writeText("\n");
}
}




protected function describeApplication(Application $application, array $options = [])
{
$describedNamespace = $options['namespace'] ?? null;
$description = new ApplicationDescription($application, $describedNamespace);

if (isset($options['raw_text']) && $options['raw_text']) {
$width = $this->getColumnWidth($description->getCommands());

foreach ($description->getCommands() as $command) {
$this->writeText(sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options);
$this->writeText("\n");
}
} else {
if ('' != $help = $application->getHelp()) {
$this->writeText("$help\n\n", $options);
}

$this->writeText("<comment>Usage:</comment>\n", $options);
$this->writeText("  command [options] [arguments]\n\n", $options);

$this->describeInputDefinition(new InputDefinition($application->getDefinition()->getOptions()), $options);

$this->writeText("\n");
$this->writeText("\n");

$commands = $description->getCommands();
$namespaces = $description->getNamespaces();
if ($describedNamespace && $namespaces) {

 $describedNamespaceInfo = reset($namespaces);
foreach ($describedNamespaceInfo['commands'] as $name) {
$commands[$name] = $description->getCommand($name);
}
}


 $width = $this->getColumnWidth(array_merge(...array_values(array_map(function ($namespace) use ($commands) {
return array_intersect($namespace['commands'], array_keys($commands));
}, array_values($namespaces)))));

if ($describedNamespace) {
$this->writeText(sprintf('<comment>Available commands for the "%s" namespace:</comment>', $describedNamespace), $options);
} else {
$this->writeText('<comment>Available commands:</comment>', $options);
}

foreach ($namespaces as $namespace) {
$namespace['commands'] = array_filter($namespace['commands'], function ($name) use ($commands) {
return isset($commands[$name]);
});

if (!$namespace['commands']) {
continue;
}

if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
$this->writeText("\n");
$this->writeText(' <comment>'.$namespace['id'].'</comment>', $options);
}

foreach ($namespace['commands'] as $name) {
$this->writeText("\n");
$spacingWidth = $width - Helper::strlen($name);
$command = $commands[$name];
$commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : '';
$this->writeText(sprintf('  <info>%s</info>%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options);
}
}

$this->writeText("\n");
}
}




private function writeText(string $content, array $options = [])
{
$this->write(
isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content,
isset($options['raw_output']) ? !$options['raw_output'] : true
);
}




private function getCommandAliasesText(Command $command): string
{
$text = '';
$aliases = $command->getAliases();

if ($aliases) {
$text = '['.implode('|', $aliases).'] ';
}

return $text;
}






private function formatDefaultValue($default): string
{
if (\INF === $default) {
return 'INF';
}

if (\is_string($default)) {
$default = OutputFormatter::escape($default);
} elseif (\is_array($default)) {
foreach ($default as $key => $value) {
if (\is_string($value)) {
$default[$key] = OutputFormatter::escape($value);
}
}
}

return str_replace('\\\\', '\\', json_encode($default, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE));
}




private function getColumnWidth(array $commands): int
{
$widths = [];

foreach ($commands as $command) {
if ($command instanceof Command) {
$widths[] = Helper::strlen($command->getName());
foreach ($command->getAliases() as $alias) {
$widths[] = Helper::strlen($alias);
}
} else {
$widths[] = Helper::strlen($command);
}
}

return $widths ? max($widths) + 2 : 0;
}




private function calculateTotalWidthForOptions(array $options): int
{
$totalWidth = 0;
foreach ($options as $option) {

 $nameLength = 1 + max(Helper::strlen($option->getShortcut()), 1) + 4 + Helper::strlen($option->getName());

if ($option->acceptValue()) {
$valueLength = 1 + Helper::strlen($option->getName()); 
 $valueLength += $option->isValueOptional() ? 2 : 0; 

$nameLength += $valueLength;
}
$totalWidth = max($totalWidth, $nameLength);
}

return $totalWidth;
}
}
<?php










namespace Symfony\Component\Console\Descriptor;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;








class XmlDescriptor extends Descriptor
{
public function getInputDefinitionDocument(InputDefinition $definition): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($definitionXML = $dom->createElement('definition'));

$definitionXML->appendChild($argumentsXML = $dom->createElement('arguments'));
foreach ($definition->getArguments() as $argument) {
$this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument));
}

$definitionXML->appendChild($optionsXML = $dom->createElement('options'));
foreach ($definition->getOptions() as $option) {
$this->appendDocument($optionsXML, $this->getInputOptionDocument($option));
}

return $dom;
}

public function getCommandDocument(Command $command): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($commandXML = $dom->createElement('command'));

$command->getSynopsis();
$command->mergeApplicationDefinition(false);

$commandXML->setAttribute('id', $command->getName());
$commandXML->setAttribute('name', $command->getName());
$commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0);

$commandXML->appendChild($usagesXML = $dom->createElement('usages'));

foreach (array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) {
$usagesXML->appendChild($dom->createElement('usage', $usage));
}

$commandXML->appendChild($descriptionXML = $dom->createElement('description'));
$descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getDescription())));

$commandXML->appendChild($helpXML = $dom->createElement('help'));
$helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getProcessedHelp())));

$definitionXML = $this->getInputDefinitionDocument($command->getNativeDefinition());
$this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0));

return $dom;
}

public function getApplicationDocument(Application $application, string $namespace = null): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($rootXml = $dom->createElement('symfony'));

if ('UNKNOWN' !== $application->getName()) {
$rootXml->setAttribute('name', $application->getName());
if ('UNKNOWN' !== $application->getVersion()) {
$rootXml->setAttribute('version', $application->getVersion());
}
}

$rootXml->appendChild($commandsXML = $dom->createElement('commands'));

$description = new ApplicationDescription($application, $namespace, true);

if ($namespace) {
$commandsXML->setAttribute('namespace', $namespace);
}

foreach ($description->getCommands() as $command) {
$this->appendDocument($commandsXML, $this->getCommandDocument($command));
}

if (!$namespace) {
$rootXml->appendChild($namespacesXML = $dom->createElement('namespaces'));

foreach ($description->getNamespaces() as $namespaceDescription) {
$namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace'));
$namespaceArrayXML->setAttribute('id', $namespaceDescription['id']);

foreach ($namespaceDescription['commands'] as $name) {
$namespaceArrayXML->appendChild($commandXML = $dom->createElement('command'));
$commandXML->appendChild($dom->createTextNode($name));
}
}
}

return $dom;
}




protected function describeInputArgument(InputArgument $argument, array $options = [])
{
$this->writeDocument($this->getInputArgumentDocument($argument));
}




protected function describeInputOption(InputOption $option, array $options = [])
{
$this->writeDocument($this->getInputOptionDocument($option));
}




protected function describeInputDefinition(InputDefinition $definition, array $options = [])
{
$this->writeDocument($this->getInputDefinitionDocument($definition));
}




protected function describeCommand(Command $command, array $options = [])
{
$this->writeDocument($this->getCommandDocument($command));
}




protected function describeApplication(Application $application, array $options = [])
{
$this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null));
}




private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent)
{
foreach ($importedParent->childNodes as $childNode) {
$parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, true));
}
}




private function writeDocument(\DOMDocument $dom)
{
$dom->formatOutput = true;
$this->write($dom->saveXML());
}

private function getInputArgumentDocument(InputArgument $argument): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');

$dom->appendChild($objectXML = $dom->createElement('argument'));
$objectXML->setAttribute('name', $argument->getName());
$objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0);
$objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0);
$objectXML->appendChild($descriptionXML = $dom->createElement('description'));
$descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));

$objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
$defaults = \is_array($argument->getDefault()) ? $argument->getDefault() : (\is_bool($argument->getDefault()) ? [var_export($argument->getDefault(), true)] : ($argument->getDefault() ? [$argument->getDefault()] : []));
foreach ($defaults as $default) {
$defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
$defaultXML->appendChild($dom->createTextNode($default));
}

return $dom;
}

private function getInputOptionDocument(InputOption $option): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');

$dom->appendChild($objectXML = $dom->createElement('option'));
$objectXML->setAttribute('name', '--'.$option->getName());
$pos = strpos($option->getShortcut() ?? '', '|');
if (false !== $pos) {
$objectXML->setAttribute('shortcut', '-'.substr($option->getShortcut(), 0, $pos));
$objectXML->setAttribute('shortcuts', '-'.str_replace('|', '|-', $option->getShortcut()));
} else {
$objectXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : '');
}
$objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0);
$objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0);
$objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0);
$objectXML->appendChild($descriptionXML = $dom->createElement('description'));
$descriptionXML->appendChild($dom->createTextNode($option->getDescription()));

if ($option->acceptValue()) {
$defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? [var_export($option->getDefault(), true)] : ($option->getDefault() ? [$option->getDefault()] : []));
$objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));

if (!empty($defaults)) {
foreach ($defaults as $default) {
$defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
$defaultXML->appendChild($dom->createTextNode($default));
}
}
}

return $dom;
}
}
<?php










namespace Symfony\Component\Console\Descriptor;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;






abstract class Descriptor implements DescriptorInterface
{



protected $output;




public function describe(OutputInterface $output, $object, array $options = [])
{
$this->output = $output;

switch (true) {
case $object instanceof InputArgument:
$this->describeInputArgument($object, $options);
break;
case $object instanceof InputOption:
$this->describeInputOption($object, $options);
break;
case $object instanceof InputDefinition:
$this->describeInputDefinition($object, $options);
break;
case $object instanceof Command:
$this->describeCommand($object, $options);
break;
case $object instanceof Application:
$this->describeApplication($object, $options);
break;
default:
throw new InvalidArgumentException(sprintf('Object of type "%s" is not describable.', \get_class($object)));
}
}







protected function write($content, $decorated = false)
{
$this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW);
}




abstract protected function describeInputArgument(InputArgument $argument, array $options = []);




abstract protected function describeInputOption(InputOption $option, array $options = []);




abstract protected function describeInputDefinition(InputDefinition $definition, array $options = []);




abstract protected function describeCommand(Command $command, array $options = []);




abstract protected function describeApplication(Application $application, array $options = []);
}
<?php










namespace Symfony\Component\Console\Descriptor;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;








class MarkdownDescriptor extends Descriptor
{



public function describe(OutputInterface $output, $object, array $options = [])
{
$decorated = $output->isDecorated();
$output->setDecorated(false);

parent::describe($output, $object, $options);

$output->setDecorated($decorated);
}




protected function write($content, $decorated = true)
{
parent::write($content, $decorated);
}




protected function describeInputArgument(InputArgument $argument, array $options = [])
{
$this->write(
'#### `'.($argument->getName() ?: '<none>')."`\n\n"
.($argument->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $argument->getDescription())."\n\n" : '')
.'* Is required: '.($argument->isRequired() ? 'yes' : 'no')."\n"
.'* Is array: '.($argument->isArray() ? 'yes' : 'no')."\n"
.'* Default: `'.str_replace("\n", '', var_export($argument->getDefault(), true)).'`'
);
}




protected function describeInputOption(InputOption $option, array $options = [])
{
$name = '--'.$option->getName();
if ($option->getShortcut()) {
$name .= '|-'.str_replace('|', '|-', $option->getShortcut()).'';
}

$this->write(
'#### `'.$name.'`'."\n\n"
.($option->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $option->getDescription())."\n\n" : '')
.'* Accept value: '.($option->acceptValue() ? 'yes' : 'no')."\n"
.'* Is value required: '.($option->isValueRequired() ? 'yes' : 'no')."\n"
.'* Is multiple: '.($option->isArray() ? 'yes' : 'no')."\n"
.'* Default: `'.str_replace("\n", '', var_export($option->getDefault(), true)).'`'
);
}




protected function describeInputDefinition(InputDefinition $definition, array $options = [])
{
if ($showArguments = \count($definition->getArguments()) > 0) {
$this->write('### Arguments');
foreach ($definition->getArguments() as $argument) {
$this->write("\n\n");
$this->write($this->describeInputArgument($argument));
}
}

if (\count($definition->getOptions()) > 0) {
if ($showArguments) {
$this->write("\n\n");
}

$this->write('### Options');
foreach ($definition->getOptions() as $option) {
$this->write("\n\n");
$this->write($this->describeInputOption($option));
}
}
}




protected function describeCommand(Command $command, array $options = [])
{
$command->getSynopsis();
$command->mergeApplicationDefinition(false);

$this->write(
'`'.$command->getName()."`\n"
.str_repeat('-', Helper::strlen($command->getName()) + 2)."\n\n"
.($command->getDescription() ? $command->getDescription()."\n\n" : '')
.'### Usage'."\n\n"
.array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), function ($carry, $usage) {
return $carry.'* `'.$usage.'`'."\n";
})
);

if ($help = $command->getProcessedHelp()) {
$this->write("\n");
$this->write($help);
}

if ($command->getNativeDefinition()) {
$this->write("\n\n");
$this->describeInputDefinition($command->getNativeDefinition());
}
}




protected function describeApplication(Application $application, array $options = [])
{
$describedNamespace = $options['namespace'] ?? null;
$description = new ApplicationDescription($application, $describedNamespace);
$title = $this->getApplicationTitle($application);

$this->write($title."\n".str_repeat('=', Helper::strlen($title)));

foreach ($description->getNamespaces() as $namespace) {
if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
$this->write("\n\n");
$this->write('**'.$namespace['id'].':**');
}

$this->write("\n\n");
$this->write(implode("\n", array_map(function ($commandName) use ($description) {
return sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName()));
}, $namespace['commands'])));
}

foreach ($description->getCommands() as $command) {
$this->write("\n\n");
$this->write($this->describeCommand($command));
}
}

private function getApplicationTitle(Application $application): string
{
if ('UNKNOWN' !== $application->getName()) {
if ('UNKNOWN' !== $application->getVersion()) {
return sprintf('%s %s', $application->getName(), $application->getVersion());
}

return $application->getName();
}

return 'Console Tool';
}
}
<?php










namespace Symfony\Component\Console\Descriptor;

use Symfony\Component\Console\Output\OutputInterface;






interface DescriptorInterface
{





public function describe(OutputInterface $output, $object, array $options = []);
}
<?php










namespace Symfony\Component\Console\Descriptor;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\CommandNotFoundException;






class ApplicationDescription
{
public const GLOBAL_NAMESPACE = '_global';

private $application;
private $namespace;
private $showHidden;




private $namespaces;




private $commands;




private $aliases;

public function __construct(Application $application, string $namespace = null, bool $showHidden = false)
{
$this->application = $application;
$this->namespace = $namespace;
$this->showHidden = $showHidden;
}

public function getNamespaces(): array
{
if (null === $this->namespaces) {
$this->inspectApplication();
}

return $this->namespaces;
}




public function getCommands(): array
{
if (null === $this->commands) {
$this->inspectApplication();
}

return $this->commands;
}




public function getCommand(string $name): Command
{
if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {
throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));
}

return $this->commands[$name] ?? $this->aliases[$name];
}

private function inspectApplication()
{
$this->commands = [];
$this->namespaces = [];

$all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null);
foreach ($this->sortCommands($all) as $namespace => $commands) {
$names = [];


foreach ($commands as $name => $command) {
if (!$command->getName() || (!$this->showHidden && $command->isHidden())) {
continue;
}

if ($command->getName() === $name) {
$this->commands[$name] = $command;
} else {
$this->aliases[$name] = $command;
}

$names[] = $name;
}

$this->namespaces[$namespace] = ['id' => $namespace, 'commands' => $names];
}
}

private function sortCommands(array $commands): array
{
$namespacedCommands = [];
$globalCommands = [];
$sortedCommands = [];
foreach ($commands as $name => $command) {
$key = $this->application->extractNamespace($name, 1);
if (\in_array($key, ['', self::GLOBAL_NAMESPACE], true)) {
$globalCommands[$name] = $command;
} else {
$namespacedCommands[$key][$name] = $command;
}
}

if ($globalCommands) {
ksort($globalCommands);
$sortedCommands[self::GLOBAL_NAMESPACE] = $globalCommands;
}

if ($namespacedCommands) {
ksort($namespacedCommands);
foreach ($namespacedCommands as $key => $commandsSet) {
ksort($commandsSet);
$sortedCommands[$key] = $commandsSet;
}
}

return $sortedCommands;
}
}
<?php










namespace Symfony\Component\Console\Descriptor;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;








class JsonDescriptor extends Descriptor
{



protected function describeInputArgument(InputArgument $argument, array $options = [])
{
$this->writeData($this->getInputArgumentData($argument), $options);
}




protected function describeInputOption(InputOption $option, array $options = [])
{
$this->writeData($this->getInputOptionData($option), $options);
}




protected function describeInputDefinition(InputDefinition $definition, array $options = [])
{
$this->writeData($this->getInputDefinitionData($definition), $options);
}




protected function describeCommand(Command $command, array $options = [])
{
$this->writeData($this->getCommandData($command), $options);
}




protected function describeApplication(Application $application, array $options = [])
{
$describedNamespace = $options['namespace'] ?? null;
$description = new ApplicationDescription($application, $describedNamespace, true);
$commands = [];

foreach ($description->getCommands() as $command) {
$commands[] = $this->getCommandData($command);
}

$data = [];
if ('UNKNOWN' !== $application->getName()) {
$data['application']['name'] = $application->getName();
if ('UNKNOWN' !== $application->getVersion()) {
$data['application']['version'] = $application->getVersion();
}
}

$data['commands'] = $commands;

if ($describedNamespace) {
$data['namespace'] = $describedNamespace;
} else {
$data['namespaces'] = array_values($description->getNamespaces());
}

$this->writeData($data, $options);
}




private function writeData(array $data, array $options)
{
$flags = $options['json_encoding'] ?? 0;

$this->write(json_encode($data, $flags));
}

private function getInputArgumentData(InputArgument $argument): array
{
return [
'name' => $argument->getName(),
'is_required' => $argument->isRequired(),
'is_array' => $argument->isArray(),
'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $argument->getDescription()),
'default' => \INF === $argument->getDefault() ? 'INF' : $argument->getDefault(),
];
}

private function getInputOptionData(InputOption $option): array
{
return [
'name' => '--'.$option->getName(),
'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '',
'accept_value' => $option->acceptValue(),
'is_value_required' => $option->isValueRequired(),
'is_multiple' => $option->isArray(),
'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $option->getDescription()),
'default' => \INF === $option->getDefault() ? 'INF' : $option->getDefault(),
];
}

private function getInputDefinitionData(InputDefinition $definition): array
{
$inputArguments = [];
foreach ($definition->getArguments() as $name => $argument) {
$inputArguments[$name] = $this->getInputArgumentData($argument);
}

$inputOptions = [];
foreach ($definition->getOptions() as $name => $option) {
$inputOptions[$name] = $this->getInputOptionData($option);
}

return ['arguments' => $inputArguments, 'options' => $inputOptions];
}

private function getCommandData(Command $command): array
{
$command->getSynopsis();
$command->mergeApplicationDefinition(false);

return [
'name' => $command->getName(),
'usage' => array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()),
'description' => $command->getDescription(),
'help' => $command->getProcessedHelp(),
'definition' => $this->getInputDefinitionData($command->getNativeDefinition()),
'hidden' => $command->isHidden(),
];
}
}
<?php










namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Exception\InvalidArgumentException;










class StringInput extends ArgvInput
{
public const REGEX_STRING = '([^\s]+?)(?:\s|(?<!\\\\)"|(?<!\\\\)\'|$)';
public const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';




public function __construct(string $input)
{
parent::__construct([]);

$this->setTokens($this->tokenize($input));
}






private function tokenize(string $input): array
{
$tokens = [];
$length = \strlen($input);
$cursor = 0;
while ($cursor < $length) {
if (preg_match('/\s+/A', $input, $match, 0, $cursor)) {
} elseif (preg_match('/([^="\'\s]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, 0, $cursor)) {
$tokens[] = $match[1].$match[2].stripcslashes(str_replace(['"\'', '\'"', '\'\'', '""'], '', substr($match[3], 1, -1)));
} elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, 0, $cursor)) {
$tokens[] = stripcslashes(substr($match[0], 1, -1));
} elseif (preg_match('/'.self::REGEX_STRING.'/A', $input, $match, 0, $cursor)) {
$tokens[] = stripcslashes($match[1]);
} else {

 throw new InvalidArgumentException(sprintf('Unable to parse input near "... %s ...".', substr($input, $cursor, 10)));
}

$cursor += \strlen($match[0]);
}

return $tokens;
}
}
<?php










namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;






class InputArgument
{
public const REQUIRED = 1;
public const OPTIONAL = 2;
public const IS_ARRAY = 4;

private $name;
private $mode;
private $default;
private $description;









public function __construct(string $name, int $mode = null, string $description = '', $default = null)
{
if (null === $mode) {
$mode = self::OPTIONAL;
} elseif ($mode > 7 || $mode < 1) {
throw new InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode));
}

$this->name = $name;
$this->mode = $mode;
$this->description = $description;

$this->setDefault($default);
}






public function getName()
{
return $this->name;
}






public function isRequired()
{
return self::REQUIRED === (self::REQUIRED & $this->mode);
}






public function isArray()
{
return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);
}








public function setDefault($default = null)
{
if (self::REQUIRED === $this->mode && null !== $default) {
throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.');
}

if ($this->isArray()) {
if (null === $default) {
$default = [];
} elseif (!\is_array($default)) {
throw new LogicException('A default value for an array argument must be an array.');
}
}

$this->default = $default;
}






public function getDefault()
{
return $this->default;
}






public function getDescription()
{
return $this->description;
}
}
<?php










namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\InvalidOptionException;










class ArrayInput extends Input
{
private $parameters;

public function __construct(array $parameters, InputDefinition $definition = null)
{
$this->parameters = $parameters;

parent::__construct($definition);
}




public function getFirstArgument()
{
foreach ($this->parameters as $param => $value) {
if ($param && \is_string($param) && '-' === $param[0]) {
continue;
}

return $value;
}

return null;
}




public function hasParameterOption($values, $onlyParams = false)
{
$values = (array) $values;

foreach ($this->parameters as $k => $v) {
if (!\is_int($k)) {
$v = $k;
}

if ($onlyParams && '--' === $v) {
return false;
}

if (\in_array($v, $values)) {
return true;
}
}

return false;
}




public function getParameterOption($values, $default = false, $onlyParams = false)
{
$values = (array) $values;

foreach ($this->parameters as $k => $v) {
if ($onlyParams && ('--' === $k || (\is_int($k) && '--' === $v))) {
return $default;
}

if (\is_int($k)) {
if (\in_array($v, $values)) {
return true;
}
} elseif (\in_array($k, $values)) {
return $v;
}
}

return $default;
}






public function __toString()
{
$params = [];
foreach ($this->parameters as $param => $val) {
if ($param && \is_string($param) && '-' === $param[0]) {
$glue = ('-' === $param[1]) ? '=' : ' ';
if (\is_array($val)) {
foreach ($val as $v) {
$params[] = $param.('' != $v ? $glue.$this->escapeToken($v) : '');
}
} else {
$params[] = $param.('' != $val ? $glue.$this->escapeToken($val) : '');
}
} else {
$params[] = \is_array($val) ? implode(' ', array_map([$this, 'escapeToken'], $val)) : $this->escapeToken($val);
}
}

return implode(' ', $params);
}




protected function parse()
{
foreach ($this->parameters as $key => $value) {
if ('--' === $key) {
return;
}
if (str_starts_with($key, '--')) {
$this->addLongOption(substr($key, 2), $value);
} elseif (str_starts_with($key, '-')) {
$this->addShortOption(substr($key, 1), $value);
} else {
$this->addArgument($key, $value);
}
}
}






private function addShortOption(string $shortcut, $value)
{
if (!$this->definition->hasShortcut($shortcut)) {
throw new InvalidOptionException(sprintf('The "-%s" option does not exist.', $shortcut));
}

$this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
}







private function addLongOption(string $name, $value)
{
if (!$this->definition->hasOption($name)) {
throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name));
}

$option = $this->definition->getOption($name);

if (null === $value) {
if ($option->isValueRequired()) {
throw new InvalidOptionException(sprintf('The "--%s" option requires a value.', $name));
}

if (!$option->isValueOptional()) {
$value = true;
}
}

$this->options[$name] = $value;
}









private function addArgument($name, $value)
{
if (!$this->definition->hasArgument($name)) {
throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
}

$this->arguments[$name] = $value;
}
}
<?php










namespace Symfony\Component\Console\Input;







interface StreamableInputInterface extends InputInterface
{







public function setStream($stream);






public function getStream();
}
<?php










namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Exception\RuntimeException;


























class ArgvInput extends Input
{
private $tokens;
private $parsed;




public function __construct(array $argv = null, InputDefinition $definition = null)
{
$argv = $argv ?? $_SERVER['argv'] ?? [];


 array_shift($argv);

$this->tokens = $argv;

parent::__construct($definition);
}

protected function setTokens(array $tokens)
{
$this->tokens = $tokens;
}




protected function parse()
{
$parseOptions = true;
$this->parsed = $this->tokens;
while (null !== $token = array_shift($this->parsed)) {
if ($parseOptions && '' == $token) {
$this->parseArgument($token);
} elseif ($parseOptions && '--' == $token) {
$parseOptions = false;
} elseif ($parseOptions && str_starts_with($token, '--')) {
$this->parseLongOption($token);
} elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
$this->parseShortOption($token);
} else {
$this->parseArgument($token);
}
}
}




private function parseShortOption(string $token)
{
$name = substr($token, 1);

if (\strlen($name) > 1) {
if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {

 $this->addShortOption($name[0], substr($name, 1));
} else {
$this->parseShortOptionSet($name);
}
} else {
$this->addShortOption($name, null);
}
}






private function parseShortOptionSet(string $name)
{
$len = \strlen($name);
for ($i = 0; $i < $len; ++$i) {
if (!$this->definition->hasShortcut($name[$i])) {
$encoding = mb_detect_encoding($name, null, true);
throw new RuntimeException(sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding)));
}

$option = $this->definition->getOptionForShortcut($name[$i]);
if ($option->acceptValue()) {
$this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));

break;
} else {
$this->addLongOption($option->getName(), null);
}
}
}




private function parseLongOption(string $token)
{
$name = substr($token, 2);

if (false !== $pos = strpos($name, '=')) {
if ('' === $value = substr($name, $pos + 1)) {
array_unshift($this->parsed, $value);
}
$this->addLongOption(substr($name, 0, $pos), $value);
} else {
$this->addLongOption($name, null);
}
}






private function parseArgument(string $token)
{
$c = \count($this->arguments);


 if ($this->definition->hasArgument($c)) {
$arg = $this->definition->getArgument($c);
$this->arguments[$arg->getName()] = $arg->isArray() ? [$token] : $token;


 } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
$arg = $this->definition->getArgument($c - 1);
$this->arguments[$arg->getName()][] = $token;


 } else {
$all = $this->definition->getArguments();
if (\count($all)) {
throw new RuntimeException(sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))));
}

throw new RuntimeException(sprintf('No arguments expected, got "%s".', $token));
}
}






private function addShortOption(string $shortcut, $value)
{
if (!$this->definition->hasShortcut($shortcut)) {
throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
}

$this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
}






private function addLongOption(string $name, $value)
{
if (!$this->definition->hasOption($name)) {
throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name));
}

$option = $this->definition->getOption($name);

if (null !== $value && !$option->acceptValue()) {
throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name));
}

if (\in_array($value, ['', null], true) && $option->acceptValue() && \count($this->parsed)) {

 
 $next = array_shift($this->parsed);
if ((isset($next[0]) && '-' !== $next[0]) || \in_array($next, ['', null], true)) {
$value = $next;
} else {
array_unshift($this->parsed, $next);
}
}

if (null === $value) {
if ($option->isValueRequired()) {
throw new RuntimeException(sprintf('The "--%s" option requires a value.', $name));
}

if (!$option->isArray() && !$option->isValueOptional()) {
$value = true;
}
}

if ($option->isArray()) {
$this->options[$name][] = $value;
} else {
$this->options[$name] = $value;
}
}




public function getFirstArgument()
{
$isOption = false;
foreach ($this->tokens as $i => $token) {
if ($token && '-' === $token[0]) {
if (str_contains($token, '=') || !isset($this->tokens[$i + 1])) {
continue;
}


 
 $name = '-' === $token[1] ? substr($token, 2) : substr($token, -1);
if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) {

 } elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) {
$isOption = true;
}

continue;
}

if ($isOption) {
$isOption = false;
continue;
}

return $token;
}

return null;
}




public function hasParameterOption($values, $onlyParams = false)
{
$values = (array) $values;

foreach ($this->tokens as $token) {
if ($onlyParams && '--' === $token) {
return false;
}
foreach ($values as $value) {

 
 
 $leading = str_starts_with($value, '--') ? $value.'=' : $value;
if ($token === $value || '' !== $leading && str_starts_with($token, $leading)) {
return true;
}
}
}

return false;
}




public function getParameterOption($values, $default = false, $onlyParams = false)
{
$values = (array) $values;
$tokens = $this->tokens;

while (0 < \count($tokens)) {
$token = array_shift($tokens);
if ($onlyParams && '--' === $token) {
return $default;
}

foreach ($values as $value) {
if ($token === $value) {
return array_shift($tokens);
}

 
 
 $leading = str_starts_with($value, '--') ? $value.'=' : $value;
if ('' !== $leading && str_starts_with($token, $leading)) {
return substr($token, \strlen($leading));
}
}
}

return $default;
}






public function __toString()
{
$tokens = array_map(function ($token) {
if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) {
return $match[1].$this->escapeToken($match[2]);
}

if ($token && '-' !== $token[0]) {
return $this->escapeToken($token);
}

return $token;
}, $this->tokens);

return implode(' ', $tokens);
}
}
<?php










namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;












abstract class Input implements InputInterface, StreamableInputInterface
{
protected $definition;
protected $stream;
protected $options = [];
protected $arguments = [];
protected $interactive = true;

public function __construct(InputDefinition $definition = null)
{
if (null === $definition) {
$this->definition = new InputDefinition();
} else {
$this->bind($definition);
$this->validate();
}
}




public function bind(InputDefinition $definition)
{
$this->arguments = [];
$this->options = [];
$this->definition = $definition;

$this->parse();
}




abstract protected function parse();




public function validate()
{
$definition = $this->definition;
$givenArguments = $this->arguments;

$missingArguments = array_filter(array_keys($definition->getArguments()), function ($argument) use ($definition, $givenArguments) {
return !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired();
});

if (\count($missingArguments) > 0) {
throw new RuntimeException(sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments)));
}
}




public function isInteractive()
{
return $this->interactive;
}




public function setInteractive($interactive)
{
$this->interactive = (bool) $interactive;
}




public function getArguments()
{
return array_merge($this->definition->getArgumentDefaults(), $this->arguments);
}




public function getArgument($name)
{
if (!$this->definition->hasArgument((string) $name)) {
throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
}

return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault();
}




public function setArgument($name, $value)
{
if (!$this->definition->hasArgument((string) $name)) {
throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
}

$this->arguments[$name] = $value;
}




public function hasArgument($name)
{
return $this->definition->hasArgument((string) $name);
}




public function getOptions()
{
return array_merge($this->definition->getOptionDefaults(), $this->options);
}




public function getOption($name)
{
if (!$this->definition->hasOption($name)) {
throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
}

return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
}




public function setOption($name, $value)
{
if (!$this->definition->hasOption($name)) {
throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
}

$this->options[$name] = $value;
}




public function hasOption($name)
{
return $this->definition->hasOption($name);
}








public function escapeToken($token)
{
return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token);
}




public function setStream($stream)
{
$this->stream = $stream;
}




public function getStream()
{
return $this->stream;
}
}
<?php










namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;






interface InputInterface
{





public function getFirstArgument();














public function hasParameterOption($values, $onlyParams = false);















public function getParameterOption($values, $default = false, $onlyParams = false);






public function bind(InputDefinition $definition);






public function validate();






public function getArguments();










public function getArgument($name);









public function setArgument($name, $value);








public function hasArgument($name);






public function getOptions();










public function getOption($name);









public function setOption($name, $value);








public function hasOption($name);






public function isInteractive();






public function setInteractive($interactive);
}
<?php










namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;













class InputDefinition
{
private $arguments;
private $requiredCount;
private $hasAnArrayArgument = false;
private $hasOptional;
private $options;
private $shortcuts;




public function __construct(array $definition = [])
{
$this->setDefinition($definition);
}




public function setDefinition(array $definition)
{
$arguments = [];
$options = [];
foreach ($definition as $item) {
if ($item instanceof InputOption) {
$options[] = $item;
} else {
$arguments[] = $item;
}
}

$this->setArguments($arguments);
$this->setOptions($options);
}






public function setArguments($arguments = [])
{
$this->arguments = [];
$this->requiredCount = 0;
$this->hasOptional = false;
$this->hasAnArrayArgument = false;
$this->addArguments($arguments);
}






public function addArguments($arguments = [])
{
if (null !== $arguments) {
foreach ($arguments as $argument) {
$this->addArgument($argument);
}
}
}




public function addArgument(InputArgument $argument)
{
if (isset($this->arguments[$argument->getName()])) {
throw new LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName()));
}

if ($this->hasAnArrayArgument) {
throw new LogicException('Cannot add an argument after an array argument.');
}

if ($argument->isRequired() && $this->hasOptional) {
throw new LogicException('Cannot add a required argument after an optional one.');
}

if ($argument->isArray()) {
$this->hasAnArrayArgument = true;
}

if ($argument->isRequired()) {
++$this->requiredCount;
} else {
$this->hasOptional = true;
}

$this->arguments[$argument->getName()] = $argument;
}










public function getArgument($name)
{
if (!$this->hasArgument($name)) {
throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
}

$arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments;

return $arguments[$name];
}








public function hasArgument($name)
{
$arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments;

return isset($arguments[$name]);
}






public function getArguments()
{
return $this->arguments;
}






public function getArgumentCount()
{
return $this->hasAnArrayArgument ? \PHP_INT_MAX : \count($this->arguments);
}






public function getArgumentRequiredCount()
{
return $this->requiredCount;
}




public function getArgumentDefaults()
{
$values = [];
foreach ($this->arguments as $argument) {
$values[$argument->getName()] = $argument->getDefault();
}

return $values;
}






public function setOptions($options = [])
{
$this->options = [];
$this->shortcuts = [];
$this->addOptions($options);
}






public function addOptions($options = [])
{
foreach ($options as $option) {
$this->addOption($option);
}
}




public function addOption(InputOption $option)
{
if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) {
throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName()));
}

if ($option->getShortcut()) {
foreach (explode('|', $option->getShortcut()) as $shortcut) {
if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) {
throw new LogicException(sprintf('An option with shortcut "%s" already exists.', $shortcut));
}
}
}

$this->options[$option->getName()] = $option;
if ($option->getShortcut()) {
foreach (explode('|', $option->getShortcut()) as $shortcut) {
$this->shortcuts[$shortcut] = $option->getName();
}
}
}










public function getOption($name)
{
if (!$this->hasOption($name)) {
throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
}

return $this->options[$name];
}











public function hasOption($name)
{
return isset($this->options[$name]);
}






public function getOptions()
{
return $this->options;
}








public function hasShortcut($name)
{
return isset($this->shortcuts[$name]);
}








public function getOptionForShortcut($shortcut)
{
return $this->getOption($this->shortcutToName($shortcut));
}




public function getOptionDefaults()
{
$values = [];
foreach ($this->options as $option) {
$values[$option->getName()] = $option->getDefault();
}

return $values;
}








public function shortcutToName(string $shortcut): string
{
if (!isset($this->shortcuts[$shortcut])) {
throw new InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
}

return $this->shortcuts[$shortcut];
}








public function getSynopsis($short = false)
{
$elements = [];

if ($short && $this->getOptions()) {
$elements[] = '[options]';
} elseif (!$short) {
foreach ($this->getOptions() as $option) {
$value = '';
if ($option->acceptValue()) {
$value = sprintf(
' %s%s%s',
$option->isValueOptional() ? '[' : '',
strtoupper($option->getName()),
$option->isValueOptional() ? ']' : ''
);
}

$shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
$elements[] = sprintf('[%s--%s%s]', $shortcut, $option->getName(), $value);
}
}

if (\count($elements) && $this->getArguments()) {
$elements[] = '[--]';
}

$tail = '';
foreach ($this->getArguments() as $argument) {
$element = '<'.$argument->getName().'>';
if ($argument->isArray()) {
$element .= '...';
}

if (!$argument->isRequired()) {
$element = '['.$element;
$tail .= ']';
}

$elements[] = $element;
}

return implode(' ', $elements).$tail;
}
}
<?php










namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;






class InputOption
{



public const VALUE_NONE = 1;




public const VALUE_REQUIRED = 2;




public const VALUE_OPTIONAL = 4;




public const VALUE_IS_ARRAY = 8;

private $name;
private $shortcut;
private $mode;
private $default;
private $description;










public function __construct(string $name, $shortcut = null, int $mode = null, string $description = '', $default = null)
{
if (str_starts_with($name, '--')) {
$name = substr($name, 2);
}

if (empty($name)) {
throw new InvalidArgumentException('An option name cannot be empty.');
}

if (empty($shortcut)) {
$shortcut = null;
}

if (null !== $shortcut) {
if (\is_array($shortcut)) {
$shortcut = implode('|', $shortcut);
}
$shortcuts = preg_split('{(\|)-?}', ltrim($shortcut, '-'));
$shortcuts = array_filter($shortcuts);
$shortcut = implode('|', $shortcuts);

if (empty($shortcut)) {
throw new InvalidArgumentException('An option shortcut cannot be empty.');
}
}

if (null === $mode) {
$mode = self::VALUE_NONE;
} elseif ($mode > 15 || $mode < 1) {
throw new InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode));
}

$this->name = $name;
$this->shortcut = $shortcut;
$this->mode = $mode;
$this->description = $description;

if ($this->isArray() && !$this->acceptValue()) {
throw new InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');
}

$this->setDefault($default);
}






public function getShortcut()
{
return $this->shortcut;
}






public function getName()
{
return $this->name;
}






public function acceptValue()
{
return $this->isValueRequired() || $this->isValueOptional();
}






public function isValueRequired()
{
return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode);
}






public function isValueOptional()
{
return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode);
}






public function isArray()
{
return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);
}




public function setDefault($default = null)
{
if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) {
throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.');
}

if ($this->isArray()) {
if (null === $default) {
$default = [];
} elseif (!\is_array($default)) {
throw new LogicException('A default value for an array option must be an array.');
}
}

$this->default = $this->acceptValue() ? $default : false;
}






public function getDefault()
{
return $this->default;
}






public function getDescription()
{
return $this->description;
}






public function equals(self $option)
{
return $option->getName() === $this->getName()
&& $option->getShortcut() === $this->getShortcut()
&& $option->getDefault() === $this->getDefault()
&& $option->isArray() === $this->isArray()
&& $option->isValueRequired() === $this->isValueRequired()
&& $option->isValueOptional() === $this->isValueOptional()
;
}
}
<?php










namespace Symfony\Component\Console\Input;







interface InputAwareInterface
{



public function setInput(InputInterface $input);
}
<?php










namespace Symfony\Component\Yaml;

use Symfony\Component\Yaml\Exception\DumpException;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Tag\TaggedValue;








class Inline
{
public const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')';

public static $parsedLineNumber = -1;
public static $parsedFilename;

private static $exceptionOnInvalidType = false;
private static $objectSupport = false;
private static $objectForMap = false;
private static $constantSupport = false;

public static function initialize(int $flags, int $parsedLineNumber = null, string $parsedFilename = null)
{
self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags);
self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags);
self::$objectForMap = (bool) (Yaml::PARSE_OBJECT_FOR_MAP & $flags);
self::$constantSupport = (bool) (Yaml::PARSE_CONSTANT & $flags);
self::$parsedFilename = $parsedFilename;

if (null !== $parsedLineNumber) {
self::$parsedLineNumber = $parsedLineNumber;
}
}












public static function parse(string $value = null, int $flags = 0, array &$references = [])
{
self::initialize($flags);

$value = trim($value);

if ('' === $value) {
return '';
}

if (2  & (int) ini_get('mbstring.func_overload')) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('ASCII');
}

try {
$i = 0;
$tag = self::parseTag($value, $i, $flags);
switch ($value[$i]) {
case '[':
$result = self::parseSequence($value, $flags, $i, $references);
++$i;
break;
case '{':
$result = self::parseMapping($value, $flags, $i, $references);
++$i;
break;
default:
$result = self::parseScalar($value, $flags, null, $i, null === $tag, $references);
}


 if (preg_replace('/\s*#.*$/A', '', substr($value, $i))) {
throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
}

if (null !== $tag && '' !== $tag) {
return new TaggedValue($tag, $result);
}

return $result;
} finally {
if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}
}
}











public static function dump($value, int $flags = 0): string
{
switch (true) {
case \is_resource($value):
if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value)));
}

return self::dumpNull($flags);
case $value instanceof \DateTimeInterface:
return $value->format('c');
case $value instanceof \UnitEnum:
return sprintf('!php/const %s::%s', \get_class($value), $value->name);
case \is_object($value):
if ($value instanceof TaggedValue) {
return '!'.$value->getTag().' '.self::dump($value->getValue(), $flags);
}

if (Yaml::DUMP_OBJECT & $flags) {
return '!php/object '.self::dump(serialize($value));
}

if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \stdClass || $value instanceof \ArrayObject)) {
$output = [];

foreach ($value as $key => $val) {
$output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags));
}

return sprintf('{ %s }', implode(', ', $output));
}

if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
throw new DumpException('Object support when dumping a YAML file has been disabled.');
}

return self::dumpNull($flags);
case \is_array($value):
return self::dumpArray($value, $flags);
case null === $value:
return self::dumpNull($flags);
case true === $value:
return 'true';
case false === $value:
return 'false';
case \is_int($value):
return $value;
case is_numeric($value) && false === strpbrk($value, "\f\n\r\t\v"):
$locale = setlocale(\LC_NUMERIC, 0);
if (false !== $locale) {
setlocale(\LC_NUMERIC, 'C');
}
if (\is_float($value)) {
$repr = (string) $value;
if (is_infinite($value)) {
$repr = str_ireplace('INF', '.Inf', $repr);
} elseif (floor($value) == $value && $repr == $value) {

 $repr = '!!float '.$repr;
}
} else {
$repr = \is_string($value) ? "'$value'" : (string) $value;
}
if (false !== $locale) {
setlocale(\LC_NUMERIC, $locale);
}

return $repr;
case '' == $value:
return "''";
case self::isBinaryString($value):
return '!!binary '.base64_encode($value);
case Escaper::requiresDoubleQuoting($value):
return Escaper::escapeWithDoubleQuotes($value);
case Escaper::requiresSingleQuoting($value):
case Parser::preg_match('{^[0-9]+[_0-9]*$}', $value):
case Parser::preg_match(self::getHexRegex(), $value):
case Parser::preg_match(self::getTimestampRegex(), $value):
return Escaper::escapeWithSingleQuotes($value);
default:
return $value;
}
}








public static function isHash($value): bool
{
if ($value instanceof \stdClass || $value instanceof \ArrayObject) {
return true;
}

$expectedKey = 0;

foreach ($value as $key => $val) {
if ($key !== $expectedKey++) {
return true;
}
}

return false;
}









private static function dumpArray(array $value, int $flags): string
{

 if (($value || Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE & $flags) && !self::isHash($value)) {
$output = [];
foreach ($value as $val) {
$output[] = self::dump($val, $flags);
}

return sprintf('[%s]', implode(', ', $output));
}


 $output = [];
foreach ($value as $key => $val) {
$output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags));
}

return sprintf('{ %s }', implode(', ', $output));
}

private static function dumpNull(int $flags): string
{
if (Yaml::DUMP_NULL_AS_TILDE & $flags) {
return '~';
}

return 'null';
}








public static function parseScalar(string $scalar, int $flags = 0, array $delimiters = null, int &$i = 0, bool $evaluate = true, array &$references = [], bool &$isQuoted = null)
{
if (\in_array($scalar[$i], ['"', "'"])) {

 $isQuoted = true;
$output = self::parseQuotedScalar($scalar, $i);

if (null !== $delimiters) {
$tmp = ltrim(substr($scalar, $i), " \n");
if ('' === $tmp) {
throw new ParseException(sprintf('Unexpected end of line, expected one of "%s".', implode('', $delimiters)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}
if (!\in_array($tmp[0], $delimiters)) {
throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}
}
} else {

 $isQuoted = false;

if (!$delimiters) {
$output = substr($scalar, $i);
$i += \strlen($output);


 if (Parser::preg_match('/[ \t]+#/', $output, $match, \PREG_OFFSET_CAPTURE)) {
$output = substr($output, 0, $match[0][1]);
}
} elseif (Parser::preg_match('/^(.*?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) {
$output = $match[1];
$i += \strlen($output);
$output = trim($output);
} else {
throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $scalar), self::$parsedLineNumber + 1, null, self::$parsedFilename);
}


 if ($output && ('@' === $output[0] || '`' === $output[0] || '|' === $output[0] || '>' === $output[0] || '%' === $output[0])) {
throw new ParseException(sprintf('The reserved indicator "%s" cannot start a plain scalar; you need to quote the scalar.', $output[0]), self::$parsedLineNumber + 1, $output, self::$parsedFilename);
}

if ($evaluate) {
$output = self::evaluateScalar($output, $flags, $references, $isQuoted);
}
}

return $output;
}






private static function parseQuotedScalar(string $scalar, int &$i = 0): string
{
if (!Parser::preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
throw new ParseException(sprintf('Malformed inline YAML string: "%s".', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}

$output = substr($match[0], 1, \strlen($match[0]) - 2);

$unescaper = new Unescaper();
if ('"' == $scalar[$i]) {
$output = $unescaper->unescapeDoubleQuotedString($output);
} else {
$output = $unescaper->unescapeSingleQuotedString($output);
}

$i += \strlen($match[0]);

return $output;
}






private static function parseSequence(string $sequence, int $flags, int &$i = 0, array &$references = []): array
{
$output = [];
$len = \strlen($sequence);
++$i;


 while ($i < $len) {
if (']' === $sequence[$i]) {
return $output;
}
if (',' === $sequence[$i] || ' ' === $sequence[$i]) {
++$i;

continue;
}

$tag = self::parseTag($sequence, $i, $flags);
switch ($sequence[$i]) {
case '[':

 $value = self::parseSequence($sequence, $flags, $i, $references);
break;
case '{':

 $value = self::parseMapping($sequence, $flags, $i, $references);
break;
default:
$value = self::parseScalar($sequence, $flags, [',', ']'], $i, null === $tag, $references, $isQuoted);


 if (\is_string($value) && !$isQuoted && false !== strpos($value, ': ')) {

 try {
$pos = 0;
$value = self::parseMapping('{'.$value.'}', $flags, $pos, $references);
} catch (\InvalidArgumentException $e) {

 }
}

if (!$isQuoted && \is_string($value) && '' !== $value && '&' === $value[0] && Parser::preg_match(Parser::REFERENCE_PATTERN, $value, $matches)) {
$references[$matches['ref']] = $matches['value'];
$value = $matches['value'];
}

--$i;
}

if (null !== $tag && '' !== $tag) {
$value = new TaggedValue($tag, $value);
}

$output[] = $value;

++$i;
}

throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $sequence), self::$parsedLineNumber + 1, null, self::$parsedFilename);
}








private static function parseMapping(string $mapping, int $flags, int &$i = 0, array &$references = [])
{
$output = [];
$len = \strlen($mapping);
++$i;
$allowOverwrite = false;


 while ($i < $len) {
switch ($mapping[$i]) {
case ' ':
case ',':
case "\n":
++$i;
continue 2;
case '}':
if (self::$objectForMap) {
return (object) $output;
}

return $output;
}


 $offsetBeforeKeyParsing = $i;
$isKeyQuoted = \in_array($mapping[$i], ['"', "'"], true);
$key = self::parseScalar($mapping, $flags, [':', ' '], $i, false);

if ($offsetBeforeKeyParsing === $i) {
throw new ParseException('Missing mapping key.', self::$parsedLineNumber + 1, $mapping);
}

if ('!php/const' === $key) {
$key .= ' '.self::parseScalar($mapping, $flags, [':'], $i, false);
$key = self::evaluateScalar($key, $flags);
}

if (false === $i = strpos($mapping, ':', $i)) {
break;
}

if (!$isKeyQuoted) {
$evaluatedKey = self::evaluateScalar($key, $flags, $references);

if ('' !== $key && $evaluatedKey !== $key && !\is_string($evaluatedKey) && !\is_int($evaluatedKey)) {
throw new ParseException('Implicit casting of incompatible mapping keys to strings is not supported. Quote your evaluable mapping keys instead.', self::$parsedLineNumber + 1, $mapping);
}
}

if (!$isKeyQuoted && (!isset($mapping[$i + 1]) || !\in_array($mapping[$i + 1], [' ', ',', '[', ']', '{', '}', "\n"], true))) {
throw new ParseException('Colons must be followed by a space or an indication character (i.e. " ", ",", "[", "]", "{", "}").', self::$parsedLineNumber + 1, $mapping);
}

if ('<<' === $key) {
$allowOverwrite = true;
}

while ($i < $len) {
if (':' === $mapping[$i] || ' ' === $mapping[$i] || "\n" === $mapping[$i]) {
++$i;

continue;
}

$tag = self::parseTag($mapping, $i, $flags);
switch ($mapping[$i]) {
case '[':

 $value = self::parseSequence($mapping, $flags, $i, $references);

 
 
 
 if ('<<' === $key) {
foreach ($value as $parsedValue) {
$output += $parsedValue;
}
} elseif ($allowOverwrite || !isset($output[$key])) {
if (null !== $tag) {
$output[$key] = new TaggedValue($tag, $value);
} else {
$output[$key] = $value;
}
} elseif (isset($output[$key])) {
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
}
break;
case '{':

 $value = self::parseMapping($mapping, $flags, $i, $references);

 
 
 
 if ('<<' === $key) {
$output += $value;
} elseif ($allowOverwrite || !isset($output[$key])) {
if (null !== $tag) {
$output[$key] = new TaggedValue($tag, $value);
} else {
$output[$key] = $value;
}
} elseif (isset($output[$key])) {
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
}
break;
default:
$value = self::parseScalar($mapping, $flags, [',', '}', "\n"], $i, null === $tag, $references, $isValueQuoted);

 
 
 
 if ('<<' === $key) {
$output += $value;
} elseif ($allowOverwrite || !isset($output[$key])) {
if (!$isValueQuoted && \is_string($value) && '' !== $value && '&' === $value[0] && Parser::preg_match(Parser::REFERENCE_PATTERN, $value, $matches)) {
$references[$matches['ref']] = $matches['value'];
$value = $matches['value'];
}

if (null !== $tag) {
$output[$key] = new TaggedValue($tag, $value);
} else {
$output[$key] = $value;
}
} elseif (isset($output[$key])) {
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
}
--$i;
}
++$i;

continue 2;
}
}

throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $mapping), self::$parsedLineNumber + 1, null, self::$parsedFilename);
}








private static function evaluateScalar(string $scalar, int $flags, array &$references = [], bool &$isQuotedString = null)
{
$isQuotedString = false;
$scalar = trim($scalar);
$scalarLower = strtolower($scalar);

if (0 === strpos($scalar, '*')) {
if (false !== $pos = strpos($scalar, '#')) {
$value = substr($scalar, 1, $pos - 2);
} else {
$value = substr($scalar, 1);
}


 if (false === $value || '' === $value) {
throw new ParseException('A reference must contain at least one character.', self::$parsedLineNumber + 1, $value, self::$parsedFilename);
}

if (!\array_key_exists($value, $references)) {
throw new ParseException(sprintf('Reference "%s" does not exist.', $value), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
}

return $references[$value];
}

switch (true) {
case 'null' === $scalarLower:
case '' === $scalar:
case '~' === $scalar:
return null;
case 'true' === $scalarLower:
return true;
case 'false' === $scalarLower:
return false;
case '!' === $scalar[0]:
switch (true) {
case 0 === strpos($scalar, '!!str '):
$s = (string) substr($scalar, 6);

if (\in_array($s[0] ?? '', ['"', "'"], true)) {
$isQuotedString = true;
$s = self::parseQuotedScalar($s);
}

return $s;
case 0 === strpos($scalar, '! '):
return substr($scalar, 2);
case 0 === strpos($scalar, '!php/object'):
if (self::$objectSupport) {
if (!isset($scalar[12])) {
return false;
}

return unserialize(self::parseScalar(substr($scalar, 12)));
}

if (self::$exceptionOnInvalidType) {
throw new ParseException('Object support when parsing a YAML file has been disabled.', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}

return null;
case 0 === strpos($scalar, '!php/const'):
if (self::$constantSupport) {
if (!isset($scalar[11])) {
return '';
}

$i = 0;
if (\defined($const = self::parseScalar(substr($scalar, 11), 0, null, $i, false))) {
return \constant($const);
}

throw new ParseException(sprintf('The constant "%s" is not defined.', $const), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}
if (self::$exceptionOnInvalidType) {
throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Did you forget to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}

return null;
case 0 === strpos($scalar, '!!float '):
return (float) substr($scalar, 8);
case 0 === strpos($scalar, '!!binary '):
return self::evaluateBinaryScalar(substr($scalar, 9));
default:
throw new ParseException(sprintf('The string "%s" could not be parsed as it uses an unsupported built-in tag.', $scalar), self::$parsedLineNumber, $scalar, self::$parsedFilename);
}


 
 case '+' === $scalar[0] || '-' === $scalar[0] || '.' === $scalar[0] || is_numeric($scalar[0]):
if (Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar)) {
$scalar = str_replace('_', '', (string) $scalar);
}

switch (true) {
case ctype_digit($scalar):
if (preg_match('/^0[0-7]+$/', $scalar)) {
return octdec($scalar);
}

$cast = (int) $scalar;

return ($scalar === (string) $cast) ? $cast : $scalar;
case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)):
if (preg_match('/^-0[0-7]+$/', $scalar)) {
return -octdec(substr($scalar, 1));
}

$cast = (int) $scalar;

return ($scalar === (string) $cast) ? $cast : $scalar;
case is_numeric($scalar):
case Parser::preg_match(self::getHexRegex(), $scalar):
$scalar = str_replace('_', '', $scalar);

return '0x' === $scalar[0].$scalar[1] ? hexdec($scalar) : (float) $scalar;
case '.inf' === $scalarLower:
case '.nan' === $scalarLower:
return -log(0);
case '-.inf' === $scalarLower:
return log(0);
case Parser::preg_match('/^(-|\+)?[0-9][0-9_]*(\.[0-9_]+)?$/', $scalar):
return (float) str_replace('_', '', $scalar);
case Parser::preg_match(self::getTimestampRegex(), $scalar):

 $time = new \DateTime($scalar, new \DateTimeZone('UTC'));

if (Yaml::PARSE_DATETIME & $flags) {
return $time;
}

try {
if (false !== $scalar = $time->getTimestamp()) {
return $scalar;
}
} catch (\ValueError $e) {

 }

return $time->format('U');
}
}

return (string) $scalar;
}

private static function parseTag(string $value, int &$i, int $flags): ?string
{
if ('!' !== $value[$i]) {
return null;
}

$tagLength = strcspn($value, " \t\n[]{},", $i + 1);
$tag = substr($value, $i + 1, $tagLength);

$nextOffset = $i + $tagLength + 1;
$nextOffset += strspn($value, ' ', $nextOffset);

if ('' === $tag && (!isset($value[$nextOffset]) || \in_array($value[$nextOffset], [']', '}', ','], true))) {
throw new ParseException('Using the unquoted scalar value "!" is not supported. You must quote it.', self::$parsedLineNumber + 1, $value, self::$parsedFilename);
}


 if ('' !== $tag && (!isset($value[$nextOffset]) || !\in_array($value[$nextOffset], ['[', '{'], true)) && ('!' === $tag[0] || 'str' === $tag || 'php/const' === $tag || 'php/object' === $tag)) {

 return null;
}

$i = $nextOffset;


 if ('' !== $tag && '!' === $tag[0]) {
throw new ParseException(sprintf('The built-in tag "!%s" is not implemented.', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
}

if ('' !== $tag && !isset($value[$i])) {
throw new ParseException(sprintf('Missing value for tag "%s".', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
}

if ('' === $tag || Yaml::PARSE_CUSTOM_TAGS & $flags) {
return $tag;
}

throw new ParseException(sprintf('Tags support is not enabled. Enable the "Yaml::PARSE_CUSTOM_TAGS" flag to use "!%s".', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
}

public static function evaluateBinaryScalar(string $scalar): string
{
$parsedBinaryData = self::parseScalar(preg_replace('/\s/', '', $scalar));

if (0 !== (\strlen($parsedBinaryData) % 4)) {
throw new ParseException(sprintf('The normalized base64 encoded data (data without whitespace characters) length must be a multiple of four (%d bytes given).', \strlen($parsedBinaryData)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}

if (!Parser::preg_match('#^[A-Z0-9+/]+={0,2}$#i', $parsedBinaryData)) {
throw new ParseException(sprintf('The base64 encoded data (%s) contains invalid characters.', $parsedBinaryData), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}

return base64_decode($parsedBinaryData, true);
}

private static function isBinaryString(string $value)
{
return !preg_match('//u', $value) || preg_match('/[^\x00\x07-\x0d\x1B\x20-\xff]/', $value);
}








private static function getTimestampRegex(): string
{
return <<<EOF
        ~^
        (?P<year>[0-9][0-9][0-9][0-9])
        -(?P<month>[0-9][0-9]?)
        -(?P<day>[0-9][0-9]?)
        (?:(?:[Tt]|[ \t]+)
        (?P<hour>[0-9][0-9]?)
        :(?P<minute>[0-9][0-9])
        :(?P<second>[0-9][0-9])
        (?:\.(?P<fraction>[0-9]*))?
        (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
        (?::(?P<tz_minute>[0-9][0-9]))?))?)?
        $~x
EOF;
}




private static function getHexRegex(): string
{
return '~^0x[0-9a-f_]++$~i';
}
}
<?php










namespace Symfony\Component\Yaml\Tag;





final class TaggedValue
{
private $tag;
private $value;

public function __construct(string $tag, $value)
{
$this->tag = $tag;
$this->value = $value;
}

public function getTag(): string
{
return $this->tag;
}

public function getValue()
{
return $this->value;
}
}
<?php










namespace Symfony\Component\Yaml;

use Symfony\Component\Yaml\Tag\TaggedValue;








class Dumper
{





protected $indentation;

public function __construct(int $indentation = 4)
{
if ($indentation < 1) {
throw new \InvalidArgumentException('The indentation must be greater than zero.');
}

$this->indentation = $indentation;
}











public function dump($input, int $inline = 0, int $indent = 0, int $flags = 0): string
{
$output = '';
$prefix = $indent ? str_repeat(' ', $indent) : '';
$dumpObjectAsInlineMap = true;

if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($input instanceof \ArrayObject || $input instanceof \stdClass)) {
$dumpObjectAsInlineMap = empty((array) $input);
}

if ($inline <= 0 || (!\is_array($input) && !$input instanceof TaggedValue && $dumpObjectAsInlineMap) || empty($input)) {
$output .= $prefix.Inline::dump($input, $flags);
} else {
$dumpAsMap = Inline::isHash($input);

foreach ($input as $key => $value) {
if ('' !== $output && "\n" !== $output[-1]) {
$output .= "\n";
}

if (Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && \is_string($value) && false !== strpos($value, "\n") && false === strpos($value, "\r")) {

 
 $blockIndentationIndicator = (' ' === substr($value, 0, 1)) ? (string) $this->indentation : '';

if (isset($value[-2]) && "\n" === $value[-2] && "\n" === $value[-1]) {
$blockChompingIndicator = '+';
} elseif ("\n" === $value[-1]) {
$blockChompingIndicator = '';
} else {
$blockChompingIndicator = '-';
}

$output .= sprintf('%s%s%s |%s%s', $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', '', $blockIndentationIndicator, $blockChompingIndicator);

foreach (explode("\n", $value) as $row) {
if ('' === $row) {
$output .= "\n";
} else {
$output .= sprintf("\n%s%s%s", $prefix, str_repeat(' ', $this->indentation), $row);
}
}

continue;
}

if ($value instanceof TaggedValue) {
$output .= sprintf('%s%s !%s', $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', $value->getTag());

if (Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && \is_string($value->getValue()) && false !== strpos($value->getValue(), "\n") && false === strpos($value->getValue(), "\r\n")) {

 
 $blockIndentationIndicator = (' ' === substr($value->getValue(), 0, 1)) ? (string) $this->indentation : '';
$output .= sprintf(' |%s', $blockIndentationIndicator);

foreach (explode("\n", $value->getValue()) as $row) {
$output .= sprintf("\n%s%s%s", $prefix, str_repeat(' ', $this->indentation), $row);
}

continue;
}

if ($inline - 1 <= 0 || null === $value->getValue() || is_scalar($value->getValue())) {
$output .= ' '.$this->dump($value->getValue(), $inline - 1, 0, $flags)."\n";
} else {
$output .= "\n";
$output .= $this->dump($value->getValue(), $inline - 1, $dumpAsMap ? $indent + $this->indentation : $indent + 2, $flags);
}

continue;
}

$dumpObjectAsInlineMap = true;

if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \ArrayObject || $value instanceof \stdClass)) {
$dumpObjectAsInlineMap = empty((array) $value);
}

$willBeInlined = $inline - 1 <= 0 || !\is_array($value) && $dumpObjectAsInlineMap || empty($value);

$output .= sprintf('%s%s%s%s',
$prefix,
$dumpAsMap ? Inline::dump($key, $flags).':' : '-',
$willBeInlined ? ' ' : "\n",
$this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + $this->indentation, $flags)
).($willBeInlined ? "\n" : '');
}
}

return $output;
}
}
<?php










namespace Symfony\Component\Yaml;









class Escaper
{

 public const REGEX_CHARACTER_TO_ESCAPE = "[\\x00-\\x1f]|\x7f|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9";


 
 
 
 private const ESCAPEES = ['\\', '\\\\', '\\"', '"',
"\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07",
"\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f",
"\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17",
"\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f",
"\x7f",
"\xc2\x85", "\xc2\xa0", "\xe2\x80\xa8", "\xe2\x80\xa9",
];
private const ESCAPED = ['\\\\', '\\"', '\\\\', '\\"',
'\\0', '\\x01', '\\x02', '\\x03', '\\x04', '\\x05', '\\x06', '\\a',
'\\b', '\\t', '\\n', '\\v', '\\f', '\\r', '\\x0e', '\\x0f',
'\\x10', '\\x11', '\\x12', '\\x13', '\\x14', '\\x15', '\\x16', '\\x17',
'\\x18', '\\x19', '\\x1a', '\\e', '\\x1c', '\\x1d', '\\x1e', '\\x1f',
'\\x7f',
'\\N', '\\_', '\\L', '\\P',
];








public static function requiresDoubleQuoting(string $value): bool
{
return 0 < preg_match('/'.self::REGEX_CHARACTER_TO_ESCAPE.'/u', $value);
}








public static function escapeWithDoubleQuotes(string $value): string
{
return sprintf('"%s"', str_replace(self::ESCAPEES, self::ESCAPED, $value));
}








public static function requiresSingleQuoting(string $value): bool
{

 
 if (\in_array(strtolower($value), ['null', '~', 'true', 'false', 'y', 'n', 'yes', 'no', 'on', 'off'])) {
return true;
}


 
 return 0 < preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ \- ? | < > = ! % @ ` \p{Zs}]/xu', $value);
}








public static function escapeWithSingleQuotes(string $value): string
{
return sprintf("'%s'", str_replace('\'', '\'\'', $value));
}
}
<?php










namespace Symfony\Component\Yaml\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Parser;
use Symfony\Component\Yaml\Yaml;







class LintCommand extends Command
{
protected static $defaultName = 'lint:yaml';

private $parser;
private $format;
private $displayCorrectFiles;
private $directoryIteratorProvider;
private $isReadableProvider;

public function __construct(string $name = null, callable $directoryIteratorProvider = null, callable $isReadableProvider = null)
{
parent::__construct($name);

$this->directoryIteratorProvider = $directoryIteratorProvider;
$this->isReadableProvider = $isReadableProvider;
}




protected function configure()
{
$this
->setDescription('Lint a file and outputs encountered errors')
->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN')
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt')
->addOption('parse-tags', null, InputOption::VALUE_NONE, 'Parse custom tags')
->setHelp(<<<EOF
The <info>%command.name%</info> command lints a YAML file and outputs to STDOUT
the first encountered syntax error.

You can validates YAML contents passed from STDIN:

  <info>cat filename | php %command.full_name% -</info>

You can also validate the syntax of a file:

  <info>php %command.full_name% filename</info>

Or of a whole directory:

  <info>php %command.full_name% dirname</info>
  <info>php %command.full_name% dirname --format=json</info>

EOF
)
;
}

protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$filenames = (array) $input->getArgument('filename');
$this->format = $input->getOption('format');
$this->displayCorrectFiles = $output->isVerbose();
$flags = $input->getOption('parse-tags') ? Yaml::PARSE_CUSTOM_TAGS : 0;

if (['-'] === $filenames) {
return $this->display($io, [$this->validate(file_get_contents('php://stdin'), $flags)]);
}


 if (!$filenames) {
if (0 === ftell(\STDIN)) {
@trigger_error('Piping content from STDIN to the "lint:yaml" command without passing the dash symbol "-" as argument is deprecated since Symfony 4.4.', \E_USER_DEPRECATED);

return $this->display($io, [$this->validate(file_get_contents('php://stdin'), $flags)]);
}

throw new RuntimeException('Please provide a filename or pipe file content to STDIN.');
}

$filesInfo = [];
foreach ($filenames as $filename) {
if (!$this->isReadable($filename)) {
throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
}

foreach ($this->getFiles($filename) as $file) {
$filesInfo[] = $this->validate(file_get_contents($file), $flags, $file);
}
}

return $this->display($io, $filesInfo);
}

private function validate(string $content, int $flags, string $file = null)
{
$prevErrorHandler = set_error_handler(function ($level, $message, $file, $line) use (&$prevErrorHandler) {
if (\E_USER_DEPRECATED === $level) {
throw new ParseException($message, $this->getParser()->getRealCurrentLineNb() + 1);
}

return $prevErrorHandler ? $prevErrorHandler($level, $message, $file, $line) : false;
});

try {
$this->getParser()->parse($content, Yaml::PARSE_CONSTANT | $flags);
} catch (ParseException $e) {
return ['file' => $file, 'line' => $e->getParsedLine(), 'valid' => false, 'message' => $e->getMessage()];
} finally {
restore_error_handler();
}

return ['file' => $file, 'valid' => true];
}

private function display(SymfonyStyle $io, array $files): int
{
switch ($this->format) {
case 'txt':
return $this->displayTxt($io, $files);
case 'json':
return $this->displayJson($io, $files);
default:
throw new InvalidArgumentException(sprintf('The format "%s" is not supported.', $this->format));
}
}

private function displayTxt(SymfonyStyle $io, array $filesInfo): int
{
$countFiles = \count($filesInfo);
$erroredFiles = 0;
$suggestTagOption = false;

foreach ($filesInfo as $info) {
if ($info['valid'] && $this->displayCorrectFiles) {
$io->comment('<info>OK</info>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
} elseif (!$info['valid']) {
++$erroredFiles;
$io->text('<error> ERROR </error>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
$io->text(sprintf('<error> >> %s</error>', $info['message']));

if (false !== strpos($info['message'], 'PARSE_CUSTOM_TAGS')) {
$suggestTagOption = true;
}
}
}

if (0 === $erroredFiles) {
$io->success(sprintf('All %d YAML files contain valid syntax.', $countFiles));
} else {
$io->warning(sprintf('%d YAML files have valid syntax and %d contain errors.%s', $countFiles - $erroredFiles, $erroredFiles, $suggestTagOption ? ' Use the --parse-tags option if you want parse custom tags.' : ''));
}

return min($erroredFiles, 1);
}

private function displayJson(SymfonyStyle $io, array $filesInfo): int
{
$errors = 0;

array_walk($filesInfo, function (&$v) use (&$errors) {
$v['file'] = (string) $v['file'];
if (!$v['valid']) {
++$errors;
}

if (isset($v['message']) && false !== strpos($v['message'], 'PARSE_CUSTOM_TAGS')) {
$v['message'] .= ' Use the --parse-tags option if you want parse custom tags.';
}
});

$io->writeln(json_encode($filesInfo, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES));

return min($errors, 1);
}

private function getFiles(string $fileOrDirectory): iterable
{
if (is_file($fileOrDirectory)) {
yield new \SplFileInfo($fileOrDirectory);

return;
}

foreach ($this->getDirectoryIterator($fileOrDirectory) as $file) {
if (!\in_array($file->getExtension(), ['yml', 'yaml'])) {
continue;
}

yield $file;
}
}

private function getParser(): Parser
{
if (!$this->parser) {
$this->parser = new Parser();
}

return $this->parser;
}

private function getDirectoryIterator(string $directory): iterable
{
$default = function ($directory) {
return new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS),
\RecursiveIteratorIterator::LEAVES_ONLY
);
};

if (null !== $this->directoryIteratorProvider) {
return ($this->directoryIteratorProvider)($directory, $default);
}

return $default($directory);
}

private function isReadable(string $fileOrDirectory): bool
{
$default = function ($fileOrDirectory) {
return is_readable($fileOrDirectory);
};

if (null !== $this->isReadableProvider) {
return ($this->isReadableProvider)($fileOrDirectory, $default);
}

return $default($fileOrDirectory);
}
}
<?php










namespace Symfony\Component\Yaml;

use Symfony\Component\Yaml\Exception\ParseException;









class Unescaper
{



public const REGEX_ESCAPED_CHARACTER = '\\\\(x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}|.)';








public function unescapeSingleQuotedString(string $value): string
{
return str_replace('\'\'', '\'', $value);
}








public function unescapeDoubleQuotedString(string $value): string
{
$callback = function ($match) {
return $this->unescapeCharacter($match[0]);
};


 return preg_replace_callback('/'.self::REGEX_ESCAPED_CHARACTER.'/u', $callback, $value);
}








private function unescapeCharacter(string $value): string
{
switch ($value[1]) {
case '0':
return "\x0";
case 'a':
return "\x7";
case 'b':
return "\x8";
case 't':
return "\t";
case "\t":
return "\t";
case 'n':
return "\n";
case 'v':
return "\xB";
case 'f':
return "\xC";
case 'r':
return "\r";
case 'e':
return "\x1B";
case ' ':
return ' ';
case '"':
return '"';
case '/':
return '/';
case '\\':
return '\\';
case 'N':

 return "\xC2\x85";
case '_':

 return "\xC2\xA0";
case 'L':

 return "\xE2\x80\xA8";
case 'P':

 return "\xE2\x80\xA9";
case 'x':
return self::utf8chr(hexdec(substr($value, 2, 2)));
case 'u':
return self::utf8chr(hexdec(substr($value, 2, 4)));
case 'U':
return self::utf8chr(hexdec(substr($value, 2, 8)));
default:
throw new ParseException(sprintf('Found unknown escape character "%s".', $value));
}
}




private static function utf8chr(int $c): string
{
if (0x80 > $c %= 0x200000) {
return \chr($c);
}
if (0x800 > $c) {
return \chr(0xC0 | $c >> 6).\chr(0x80 | $c & 0x3F);
}
if (0x10000 > $c) {
return \chr(0xE0 | $c >> 12).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F);
}

return \chr(0xF0 | $c >> 18).\chr(0x80 | $c >> 12 & 0x3F).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F);
}
}
<?php










namespace Symfony\Component\Yaml\Exception;






class ParseException extends RuntimeException
{
private $parsedFile;
private $parsedLine;
private $snippet;
private $rawMessage;







public function __construct(string $message, int $parsedLine = -1, string $snippet = null, string $parsedFile = null, \Throwable $previous = null)
{
$this->parsedFile = $parsedFile;
$this->parsedLine = $parsedLine;
$this->snippet = $snippet;
$this->rawMessage = $message;

$this->updateRepr();

parent::__construct($this->message, 0, $previous);
}






public function getSnippet()
{
return $this->snippet;
}






public function setSnippet($snippet)
{
$this->snippet = $snippet;

$this->updateRepr();
}








public function getParsedFile()
{
return $this->parsedFile;
}






public function setParsedFile($parsedFile)
{
$this->parsedFile = $parsedFile;

$this->updateRepr();
}






public function getParsedLine()
{
return $this->parsedLine;
}






public function setParsedLine($parsedLine)
{
$this->parsedLine = $parsedLine;

$this->updateRepr();
}

private function updateRepr()
{
$this->message = $this->rawMessage;

$dot = false;
if ('.' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$dot = true;
}

if (null !== $this->parsedFile) {
$this->message .= sprintf(' in %s', json_encode($this->parsedFile, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE));
}

if ($this->parsedLine >= 0) {
$this->message .= sprintf(' at line %d', $this->parsedLine);
}

if ($this->snippet) {
$this->message .= sprintf(' (near "%s")', $this->snippet);
}

if ($dot) {
$this->message .= '.';
}
}
}
<?php










namespace Symfony\Component\Yaml\Exception;






class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
<?php










namespace Symfony\Component\Yaml\Exception;






class DumpException extends RuntimeException
{
}
<?php










namespace Symfony\Component\Yaml\Exception;






interface ExceptionInterface extends \Throwable
{
}
<?php










namespace Symfony\Component\Yaml;

use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Tag\TaggedValue;








class Parser
{
public const TAG_PATTERN = '(?P<tag>![\w!.\/:-]+)';
public const BLOCK_SCALAR_HEADER_PATTERN = '(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?';
public const REFERENCE_PATTERN = '#^&(?P<ref>[^ ]++) *+(?P<value>.*)#u';

private $filename;
private $offset = 0;
private $totalNumberOfLines;
private $lines = [];
private $currentLineNb = -1;
private $currentLine = '';
private $refs = [];
private $skippedLineNumbers = [];
private $locallySkippedLineNumbers = [];
private $refsBeingParsed = [];











public function parseFile(string $filename, int $flags = 0)
{
if (!is_file($filename)) {
throw new ParseException(sprintf('File "%s" does not exist.', $filename));
}

if (!is_readable($filename)) {
throw new ParseException(sprintf('File "%s" cannot be read.', $filename));
}

$this->filename = $filename;

try {
return $this->parse(file_get_contents($filename), $flags);
} finally {
$this->filename = null;
}
}











public function parse(string $value, int $flags = 0)
{
if (false === preg_match('//u', $value)) {
throw new ParseException('The YAML value does not appear to be valid UTF-8.', -1, null, $this->filename);
}

$this->refs = [];

$mbEncoding = null;

if (2  & (int) ini_get('mbstring.func_overload')) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('UTF-8');
}

try {
$data = $this->doParse($value, $flags);
} finally {
if (null !== $mbEncoding) {
mb_internal_encoding($mbEncoding);
}
$this->lines = [];
$this->currentLine = '';
$this->refs = [];
$this->skippedLineNumbers = [];
$this->locallySkippedLineNumbers = [];
$this->totalNumberOfLines = null;
}

return $data;
}

private function doParse(string $value, int $flags)
{
$this->currentLineNb = -1;
$this->currentLine = '';
$value = $this->cleanup($value);
$this->lines = explode("\n", $value);
$this->locallySkippedLineNumbers = [];

if (null === $this->totalNumberOfLines) {
$this->totalNumberOfLines = \count($this->lines);
}

if (!$this->moveToNextLine()) {
return null;
}

$data = [];
$context = null;
$allowOverwrite = false;

while ($this->isCurrentLineEmpty()) {
if (!$this->moveToNextLine()) {
return null;
}
}


 if (null !== ($tag = $this->getLineTag($this->currentLine, $flags, false)) && !$this->moveToNextLine()) {
return new TaggedValue($tag, '');
}

do {
if ($this->isCurrentLineEmpty()) {
continue;
}


 if ("\t" === $this->currentLine[0]) {
throw new ParseException('A YAML file cannot contain tabs as indentation.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}

Inline::initialize($flags, $this->getRealCurrentLineNb(), $this->filename);

$isRef = $mergeNode = false;
if ('-' === $this->currentLine[0] && self::preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+))?$#u', rtrim($this->currentLine), $values)) {
if ($context && 'mapping' == $context) {
throw new ParseException('You cannot define a sequence item when in a mapping.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
$context = 'sequence';

if (isset($values['value']) && '&' === $values['value'][0] && self::preg_match(self::REFERENCE_PATTERN, $values['value'], $matches)) {
$isRef = $matches['ref'];
$this->refsBeingParsed[] = $isRef;
$values['value'] = $matches['value'];
}

if (isset($values['value'][1]) && '?' === $values['value'][0] && ' ' === $values['value'][1]) {
throw new ParseException('Complex mappings are not supported.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}


 if (isset($values['value']) && 0 === strpos(ltrim($values['value'], ' '), '-')) {

 $currentLineNumber = $this->getRealCurrentLineNb();

$sequenceIndentation = \strlen($values['leadspaces']) + 1;
$sequenceYaml = substr($this->currentLine, $sequenceIndentation);
$sequenceYaml .= "\n".$this->getNextEmbedBlock($sequenceIndentation, true);

$data[] = $this->parseBlock($currentLineNumber, rtrim($sequenceYaml), $flags);
} elseif (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) {
$data[] = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(null, true) ?? '', $flags);
} elseif (null !== $subTag = $this->getLineTag(ltrim($values['value'], ' '), $flags)) {
$data[] = new TaggedValue(
$subTag,
$this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(null, true), $flags)
);
} else {
if (
isset($values['leadspaces'])
&& (
'!' === $values['value'][0]
|| self::preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->trimTag($values['value']), $matches)
)
) {

 $block = $values['value'];
if ($this->isNextLineIndented()) {
$block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + \strlen($values['leadspaces']) + 1);
}

$data[] = $this->parseBlock($this->getRealCurrentLineNb(), $block, $flags);
} else {
$data[] = $this->parseValue($values['value'], $flags, $context);
}
}
if ($isRef) {
$this->refs[$isRef] = end($data);
array_pop($this->refsBeingParsed);
}
} elseif (
self::preg_match('#^(?P<key>(?:![^\s]++\s++)?(?:'.Inline::REGEX_QUOTED_STRING.'|(?:!?!php/const:)?[^ \'"\[\{!].*?)) *\:(( |\t)++(?P<value>.+))?$#u', rtrim($this->currentLine), $values)
&& (false === strpos($values['key'], ' #') || \in_array($values['key'][0], ['"', "'"]))
) {
if ($context && 'sequence' == $context) {
throw new ParseException('You cannot define a mapping item when in a sequence.', $this->currentLineNb + 1, $this->currentLine, $this->filename);
}
$context = 'mapping';

try {
$key = Inline::parseScalar($values['key']);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);

throw $e;
}

if (!\is_string($key) && !\is_int($key)) {
throw new ParseException((is_numeric($key) ? 'Numeric' : 'Non-string').' keys are not supported. Quote your evaluable mapping keys instead.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}


 if (\is_float($key)) {
$key = (string) $key;
}

if ('<<' === $key && (!isset($values['value']) || '&' !== $values['value'][0] || !self::preg_match('#^&(?P<ref>[^ ]+)#u', $values['value'], $refMatches))) {
$mergeNode = true;
$allowOverwrite = true;
if (isset($values['value'][0]) && '*' === $values['value'][0]) {
$refName = substr(rtrim($values['value']), 1);
if (!\array_key_exists($refName, $this->refs)) {
if (false !== $pos = array_search($refName, $this->refsBeingParsed, true)) {
throw new ParseException(sprintf('Circular reference [%s] detected for reference "%s".', implode(', ', array_merge(\array_slice($this->refsBeingParsed, $pos), [$refName])), $refName), $this->currentLineNb + 1, $this->currentLine, $this->filename);
}

throw new ParseException(sprintf('Reference "%s" does not exist.', $refName), $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}

$refValue = $this->refs[$refName];

if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $refValue instanceof \stdClass) {
$refValue = (array) $refValue;
}

if (!\is_array($refValue)) {
throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}

$data += $refValue; 
 } else {
if (isset($values['value']) && '' !== $values['value']) {
$value = $values['value'];
} else {
$value = $this->getNextEmbedBlock();
}
$parsed = $this->parseBlock($this->getRealCurrentLineNb() + 1, $value, $flags);

if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $parsed instanceof \stdClass) {
$parsed = (array) $parsed;
}

if (!\is_array($parsed)) {
throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}

if (isset($parsed[0])) {

 
 
 foreach ($parsed as $parsedItem) {
if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $parsedItem instanceof \stdClass) {
$parsedItem = (array) $parsedItem;
}

if (!\is_array($parsedItem)) {
throw new ParseException('Merge items must be arrays.', $this->getRealCurrentLineNb() + 1, $parsedItem, $this->filename);
}

$data += $parsedItem; 
 }
} else {

 
 $data += $parsed; 
 }
}
} elseif ('<<' !== $key && isset($values['value']) && '&' === $values['value'][0] && self::preg_match(self::REFERENCE_PATTERN, $values['value'], $matches)) {
$isRef = $matches['ref'];
$this->refsBeingParsed[] = $isRef;
$values['value'] = $matches['value'];
}

$subTag = null;
if ($mergeNode) {

 } elseif (!isset($values['value']) || '' === $values['value'] || 0 === strpos($values['value'], '#') || (null !== $subTag = $this->getLineTag($values['value'], $flags)) || '<<' === $key) {

 
 if (!$this->isNextLineIndented() && !$this->isNextLineUnIndentedCollection()) {

 
 if ($allowOverwrite || !isset($data[$key])) {
if (null !== $subTag) {
$data[$key] = new TaggedValue($subTag, '');
} else {
$data[$key] = null;
}
} else {
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
} else {

 $realCurrentLineNbKey = $this->getRealCurrentLineNb();
$value = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(), $flags);
if ('<<' === $key) {
$this->refs[$refMatches['ref']] = $value;

if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $value instanceof \stdClass) {
$value = (array) $value;
}

$data += $value;
} elseif ($allowOverwrite || !isset($data[$key])) {

 
 if (null !== $subTag) {
$data[$key] = new TaggedValue($subTag, $value);
} else {
$data[$key] = $value;
}
} else {
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), $realCurrentLineNbKey + 1, $this->currentLine);
}
}
} else {
$value = $this->parseValue(rtrim($values['value']), $flags, $context);

 
 if ($allowOverwrite || !isset($data[$key])) {
$data[$key] = $value;
} else {
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
}
if ($isRef) {
$this->refs[$isRef] = $data[$key];
array_pop($this->refsBeingParsed);
}
} elseif ('"' === $this->currentLine[0] || "'" === $this->currentLine[0]) {
if (null !== $context) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}

try {
return Inline::parse($this->lexInlineQuotedString(), $flags, $this->refs);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);

throw $e;
}
} elseif ('{' === $this->currentLine[0]) {
if (null !== $context) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}

try {
$parsedMapping = Inline::parse($this->lexInlineMapping(), $flags, $this->refs);

while ($this->moveToNextLine()) {
if (!$this->isCurrentLineEmpty()) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
}

return $parsedMapping;
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);

throw $e;
}
} elseif ('[' === $this->currentLine[0]) {
if (null !== $context) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}

try {
$parsedSequence = Inline::parse($this->lexInlineSequence(), $flags, $this->refs);

while ($this->moveToNextLine()) {
if (!$this->isCurrentLineEmpty()) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
}

return $parsedSequence;
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);

throw $e;
}
} else {

 if ('---' === $this->currentLine) {
throw new ParseException('Multiple documents are not supported.', $this->currentLineNb + 1, $this->currentLine, $this->filename);
}

if ($deprecatedUsage = (isset($this->currentLine[1]) && '?' === $this->currentLine[0] && ' ' === $this->currentLine[1])) {
throw new ParseException('Complex mappings are not supported.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}


 if (\is_string($value) && $this->lines[0] === trim($value)) {
try {
$value = Inline::parse($this->lines[0], $flags, $this->refs);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);

throw $e;
}

return $value;
}


 if (0 === $this->currentLineNb) {
$previousLineWasNewline = false;
$previousLineWasTerminatedWithBackslash = false;
$value = '';

foreach ($this->lines as $line) {
if ('' !== ltrim($line) && '#' === ltrim($line)[0]) {
continue;
}

 if (0 === $this->offset && !$deprecatedUsage && isset($line[0]) && ' ' === $line[0]) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}

if (false !== strpos($line, ': ')) {
@trigger_error('Support for mapping keys in multi-line blocks is deprecated since Symfony 4.3 and will throw a ParseException in 5.0.', \E_USER_DEPRECATED);
}

if ('' === trim($line)) {
$value .= "\n";
} elseif (!$previousLineWasNewline && !$previousLineWasTerminatedWithBackslash) {
$value .= ' ';
}

if ('' !== trim($line) && '\\' === substr($line, -1)) {
$value .= ltrim(substr($line, 0, -1));
} elseif ('' !== trim($line)) {
$value .= trim($line);
}

if ('' === trim($line)) {
$previousLineWasNewline = true;
$previousLineWasTerminatedWithBackslash = false;
} elseif ('\\' === substr($line, -1)) {
$previousLineWasNewline = false;
$previousLineWasTerminatedWithBackslash = true;
} else {
$previousLineWasNewline = false;
$previousLineWasTerminatedWithBackslash = false;
}
}

try {
return Inline::parse(trim($value));
} catch (ParseException $e) {

 }
}

throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
} while ($this->moveToNextLine());

if (null !== $tag) {
$data = new TaggedValue($tag, $data);
}

if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && !\is_object($data) && 'mapping' === $context) {
$object = new \stdClass();

foreach ($data as $key => $value) {
$object->$key = $value;
}

$data = $object;
}

return empty($data) ? null : $data;
}

private function parseBlock(int $offset, string $yaml, int $flags)
{
$skippedLineNumbers = $this->skippedLineNumbers;

foreach ($this->locallySkippedLineNumbers as $lineNumber) {
if ($lineNumber < $offset) {
continue;
}

$skippedLineNumbers[] = $lineNumber;
}

$parser = new self();
$parser->offset = $offset;
$parser->totalNumberOfLines = $this->totalNumberOfLines;
$parser->skippedLineNumbers = $skippedLineNumbers;
$parser->refs = &$this->refs;
$parser->refsBeingParsed = $this->refsBeingParsed;

return $parser->doParse($yaml, $flags);
}








public function getRealCurrentLineNb(): int
{
$realCurrentLineNumber = $this->currentLineNb + $this->offset;

foreach ($this->skippedLineNumbers as $skippedLineNumber) {
if ($skippedLineNumber > $realCurrentLineNumber) {
break;
}

++$realCurrentLineNumber;
}

return $realCurrentLineNumber;
}






private function getCurrentLineIndentation(): int
{
return \strlen($this->currentLine) - \strlen(ltrim($this->currentLine, ' '));
}











private function getNextEmbedBlock(int $indentation = null, bool $inSequence = false): string
{
$oldLineIndentation = $this->getCurrentLineIndentation();

if (!$this->moveToNextLine()) {
return '';
}

if (null === $indentation) {
$newIndent = null;
$movements = 0;

do {
$EOF = false;


 if ($this->isCurrentLineEmpty() || $this->isCurrentLineComment()) {
$EOF = !$this->moveToNextLine();

if (!$EOF) {
++$movements;
}
} else {
$newIndent = $this->getCurrentLineIndentation();
}
} while (!$EOF && null === $newIndent);

for ($i = 0; $i < $movements; ++$i) {
$this->moveToPreviousLine();
}

$unindentedEmbedBlock = $this->isStringUnIndentedCollectionItem();

if (!$this->isCurrentLineEmpty() && 0 === $newIndent && !$unindentedEmbedBlock) {
throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
} else {
$newIndent = $indentation;
}

$data = [];

if ($this->getCurrentLineIndentation() >= $newIndent) {
$data[] = substr($this->currentLine, $newIndent ?? 0);
} elseif ($this->isCurrentLineEmpty() || $this->isCurrentLineComment()) {
$data[] = $this->currentLine;
} else {
$this->moveToPreviousLine();

return '';
}

if ($inSequence && $oldLineIndentation === $newIndent && isset($data[0][0]) && '-' === $data[0][0]) {

 
 $this->moveToPreviousLine();

return '';
}

$isItUnindentedCollection = $this->isStringUnIndentedCollectionItem();
$isItComment = $this->isCurrentLineComment();

while ($this->moveToNextLine()) {
if ($isItComment && !$isItUnindentedCollection) {
$isItUnindentedCollection = $this->isStringUnIndentedCollectionItem();
$isItComment = $this->isCurrentLineComment();
}

$indent = $this->getCurrentLineIndentation();

if ($isItUnindentedCollection && !$this->isCurrentLineEmpty() && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) {
$this->moveToPreviousLine();
break;
}

if ($this->isCurrentLineBlank()) {
$data[] = substr($this->currentLine, $newIndent);
continue;
}

if ($indent >= $newIndent) {
$data[] = substr($this->currentLine, $newIndent);
} elseif ($this->isCurrentLineComment()) {
$data[] = $this->currentLine;
} elseif (0 == $indent) {
$this->moveToPreviousLine();

break;
} else {
throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
}

return implode("\n", $data);
}

private function hasMoreLines(): bool
{
return (\count($this->lines) - 1) > $this->currentLineNb;
}




private function moveToNextLine(): bool
{
if ($this->currentLineNb >= \count($this->lines) - 1) {
return false;
}

$this->currentLine = $this->lines[++$this->currentLineNb];

return true;
}




private function moveToPreviousLine(): bool
{
if ($this->currentLineNb < 1) {
return false;
}

$this->currentLine = $this->lines[--$this->currentLineNb];

return true;
}












private function parseValue(string $value, int $flags, string $context)
{
if (0 === strpos($value, '*')) {
if (false !== $pos = strpos($value, '#')) {
$value = substr($value, 1, $pos - 2);
} else {
$value = substr($value, 1);
}

if (!\array_key_exists($value, $this->refs)) {
if (false !== $pos = array_search($value, $this->refsBeingParsed, true)) {
throw new ParseException(sprintf('Circular reference [%s] detected for reference "%s".', implode(', ', array_merge(\array_slice($this->refsBeingParsed, $pos), [$value])), $value), $this->currentLineNb + 1, $this->currentLine, $this->filename);
}

throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine, $this->filename);
}

return $this->refs[$value];
}

if (\in_array($value[0], ['!', '|', '>'], true) && self::preg_match('/^(?:'.self::TAG_PATTERN.' +)?'.self::BLOCK_SCALAR_HEADER_PATTERN.'$/', $value, $matches)) {
$modifiers = $matches['modifiers'] ?? '';

$data = $this->parseBlockScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), abs((int) $modifiers));

if ('' !== $matches['tag'] && '!' !== $matches['tag']) {
if ('!!binary' === $matches['tag']) {
return Inline::evaluateBinaryScalar($data);
}

return new TaggedValue(substr($matches['tag'], 1), $data);
}

return $data;
}

try {
if ('' !== $value && '{' === $value[0]) {
$cursor = \strlen(rtrim($this->currentLine)) - \strlen(rtrim($value));

return Inline::parse($this->lexInlineMapping($cursor), $flags, $this->refs);
} elseif ('' !== $value && '[' === $value[0]) {
$cursor = \strlen(rtrim($this->currentLine)) - \strlen(rtrim($value));

return Inline::parse($this->lexInlineSequence($cursor), $flags, $this->refs);
}

switch ($value[0] ?? '') {
case '"':
case "'":
$cursor = \strlen(rtrim($this->currentLine)) - \strlen(rtrim($value));
$parsedValue = Inline::parse($this->lexInlineQuotedString($cursor), $flags, $this->refs);

if (isset($this->currentLine[$cursor]) && preg_replace('/\s*(#.*)?$/A', '', substr($this->currentLine, $cursor))) {
throw new ParseException(sprintf('Unexpected characters near "%s".', substr($this->currentLine, $cursor)));
}

return $parsedValue;
default:
$lines = [];

while ($this->moveToNextLine()) {

 if (0 === $this->getCurrentLineIndentation()) {
$this->moveToPreviousLine();

break;
}

$lines[] = trim($this->currentLine);
}

for ($i = 0, $linesCount = \count($lines), $previousLineBlank = false; $i < $linesCount; ++$i) {
if ('' === $lines[$i]) {
$value .= "\n";
$previousLineBlank = true;
} elseif ($previousLineBlank) {
$value .= $lines[$i];
$previousLineBlank = false;
} else {
$value .= ' '.$lines[$i];
$previousLineBlank = false;
}
}

Inline::$parsedLineNumber = $this->getRealCurrentLineNb();

$parsedValue = Inline::parse($value, $flags, $this->refs);

if ('mapping' === $context && \is_string($parsedValue) && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) {
throw new ParseException('A colon cannot be used in an unquoted mapping value.', $this->getRealCurrentLineNb() + 1, $value, $this->filename);
}

return $parsedValue;
}
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);

throw $e;
}
}








private function parseBlockScalar(string $style, string $chomping = '', int $indentation = 0): string
{
$notEOF = $this->moveToNextLine();
if (!$notEOF) {
return '';
}

$isCurrentLineBlank = $this->isCurrentLineBlank();
$blockLines = [];


 while ($notEOF && $isCurrentLineBlank) {

 if ($notEOF = $this->moveToNextLine()) {
$blockLines[] = '';
$isCurrentLineBlank = $this->isCurrentLineBlank();
}
}


 if (0 === $indentation) {
$currentLineLength = \strlen($this->currentLine);

for ($i = 0; $i < $currentLineLength && ' ' === $this->currentLine[$i]; ++$i) {
++$indentation;
}
}

if ($indentation > 0) {
$pattern = sprintf('/^ {%d}(.*)$/', $indentation);

while (
$notEOF && (
$isCurrentLineBlank ||
self::preg_match($pattern, $this->currentLine, $matches)
)
) {
if ($isCurrentLineBlank && \strlen($this->currentLine) > $indentation) {
$blockLines[] = substr($this->currentLine, $indentation);
} elseif ($isCurrentLineBlank) {
$blockLines[] = '';
} else {
$blockLines[] = $matches[1];
}


 if ($notEOF = $this->moveToNextLine()) {
$isCurrentLineBlank = $this->isCurrentLineBlank();
}
}
} elseif ($notEOF) {
$blockLines[] = '';
}

if ($notEOF) {
$blockLines[] = '';
$this->moveToPreviousLine();
} elseif (!$notEOF && !$this->isCurrentLineLastLineInDocument()) {
$blockLines[] = '';
}


 if ('>' === $style) {
$text = '';
$previousLineIndented = false;
$previousLineBlank = false;

for ($i = 0, $blockLinesCount = \count($blockLines); $i < $blockLinesCount; ++$i) {
if ('' === $blockLines[$i]) {
$text .= "\n";
$previousLineIndented = false;
$previousLineBlank = true;
} elseif (' ' === $blockLines[$i][0]) {
$text .= "\n".$blockLines[$i];
$previousLineIndented = true;
$previousLineBlank = false;
} elseif ($previousLineIndented) {
$text .= "\n".$blockLines[$i];
$previousLineIndented = false;
$previousLineBlank = false;
} elseif ($previousLineBlank || 0 === $i) {
$text .= $blockLines[$i];
$previousLineIndented = false;
$previousLineBlank = false;
} else {
$text .= ' '.$blockLines[$i];
$previousLineIndented = false;
$previousLineBlank = false;
}
}
} else {
$text = implode("\n", $blockLines);
}


 if ('' === $chomping) {
$text = preg_replace('/\n+$/', "\n", $text);
} elseif ('-' === $chomping) {
$text = preg_replace('/\n+$/', '', $text);
}

return $text;
}






private function isNextLineIndented(): bool
{
$currentIndentation = $this->getCurrentLineIndentation();
$movements = 0;

do {
$EOF = !$this->moveToNextLine();

if (!$EOF) {
++$movements;
}
} while (!$EOF && ($this->isCurrentLineEmpty() || $this->isCurrentLineComment()));

if ($EOF) {
return false;
}

$ret = $this->getCurrentLineIndentation() > $currentIndentation;

for ($i = 0; $i < $movements; ++$i) {
$this->moveToPreviousLine();
}

return $ret;
}






private function isCurrentLineEmpty(): bool
{
return $this->isCurrentLineBlank() || $this->isCurrentLineComment();
}






private function isCurrentLineBlank(): bool
{
return '' == trim($this->currentLine, ' ');
}






private function isCurrentLineComment(): bool
{

 $ltrimmedLine = ltrim($this->currentLine, ' ');

return '' !== $ltrimmedLine && '#' === $ltrimmedLine[0];
}

private function isCurrentLineLastLineInDocument(): bool
{
return ($this->offset + $this->currentLineNb) >= ($this->totalNumberOfLines - 1);
}








private function cleanup(string $value): string
{
$value = str_replace(["\r\n", "\r"], "\n", $value);


 $count = 0;
$value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#u', '', $value, -1, $count);
$this->offset += $count;


 $trimmedValue = preg_replace('#^(\#.*?\n)+#s', '', $value, -1, $count);
if (1 === $count) {

 $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
$value = $trimmedValue;
}


 $trimmedValue = preg_replace('#^\-\-\-.*?\n#s', '', $value, -1, $count);
if (1 === $count) {

 $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
$value = $trimmedValue;


 $value = preg_replace('#\.\.\.\s*$#', '', $value);
}

return $value;
}






private function isNextLineUnIndentedCollection(): bool
{
$currentIndentation = $this->getCurrentLineIndentation();
$movements = 0;

do {
$EOF = !$this->moveToNextLine();

if (!$EOF) {
++$movements;
}
} while (!$EOF && ($this->isCurrentLineEmpty() || $this->isCurrentLineComment()));

if ($EOF) {
return false;
}

$ret = $this->getCurrentLineIndentation() === $currentIndentation && $this->isStringUnIndentedCollectionItem();

for ($i = 0; $i < $movements; ++$i) {
$this->moveToPreviousLine();
}

return $ret;
}






private function isStringUnIndentedCollectionItem(): bool
{
return '-' === rtrim($this->currentLine) || 0 === strpos($this->currentLine, '- ');
}














public static function preg_match(string $pattern, string $subject, array &$matches = null, int $flags = 0, int $offset = 0): int
{
if (false === $ret = preg_match($pattern, $subject, $matches, $flags, $offset)) {
switch (preg_last_error()) {
case \PREG_INTERNAL_ERROR:
$error = 'Internal PCRE error.';
break;
case \PREG_BACKTRACK_LIMIT_ERROR:
$error = 'pcre.backtrack_limit reached.';
break;
case \PREG_RECURSION_LIMIT_ERROR:
$error = 'pcre.recursion_limit reached.';
break;
case \PREG_BAD_UTF8_ERROR:
$error = 'Malformed UTF-8 data.';
break;
case \PREG_BAD_UTF8_OFFSET_ERROR:
$error = 'Offset doesn\'t correspond to the begin of a valid UTF-8 code point.';
break;
default:
$error = 'Error.';
}

throw new ParseException($error);
}

return $ret;
}







private function trimTag(string $value): string
{
if ('!' === $value[0]) {
return ltrim(substr($value, 1, strcspn($value, " \r\n", 1)), ' ');
}

return $value;
}

private function getLineTag(string $value, int $flags, bool $nextLineCheck = true): ?string
{
if ('' === $value || '!' !== $value[0] || 1 !== self::preg_match('/^'.self::TAG_PATTERN.' *( +#.*)?$/', $value, $matches)) {
return null;
}

if ($nextLineCheck && !$this->isNextLineIndented()) {
return null;
}

$tag = substr($matches['tag'], 1);


 if ($tag && '!' === $tag[0]) {
throw new ParseException(sprintf('The built-in tag "!%s" is not implemented.', $tag), $this->getRealCurrentLineNb() + 1, $value, $this->filename);
}

if (Yaml::PARSE_CUSTOM_TAGS & $flags) {
return $tag;
}

throw new ParseException(sprintf('Tags support is not enabled. You must use the flag "Yaml::PARSE_CUSTOM_TAGS" to use "%s".', $matches['tag']), $this->getRealCurrentLineNb() + 1, $value, $this->filename);
}

private function lexInlineQuotedString(int &$cursor = 0): string
{
$quotation = $this->currentLine[$cursor];
$value = $quotation;
++$cursor;

$previousLineWasNewline = true;
$previousLineWasTerminatedWithBackslash = false;
$lineNumber = 0;

do {
if (++$lineNumber > 1) {
$cursor += strspn($this->currentLine, ' ', $cursor);
}

if ($this->isCurrentLineBlank()) {
$value .= "\n";
} elseif (!$previousLineWasNewline && !$previousLineWasTerminatedWithBackslash) {
$value .= ' ';
}

for (; \strlen($this->currentLine) > $cursor; ++$cursor) {
switch ($this->currentLine[$cursor]) {
case '\\':
if ("'" === $quotation) {
$value .= '\\';
} elseif (isset($this->currentLine[++$cursor])) {
$value .= '\\'.$this->currentLine[$cursor];
}

break;
case $quotation:
++$cursor;

if ("'" === $quotation && isset($this->currentLine[$cursor]) && "'" === $this->currentLine[$cursor]) {
$value .= "''";
break;
}

return $value.$quotation;
default:
$value .= $this->currentLine[$cursor];
}
}

if ($this->isCurrentLineBlank()) {
$previousLineWasNewline = true;
$previousLineWasTerminatedWithBackslash = false;
} elseif ('\\' === $this->currentLine[-1]) {
$previousLineWasNewline = false;
$previousLineWasTerminatedWithBackslash = true;
} else {
$previousLineWasNewline = false;
$previousLineWasTerminatedWithBackslash = false;
}

if ($this->hasMoreLines()) {
$cursor = 0;
}
} while ($this->moveToNextLine());

throw new ParseException('Malformed inline YAML string.');
}

private function lexUnquotedString(int &$cursor): string
{
$offset = $cursor;
$cursor += strcspn($this->currentLine, '[]{},: ', $cursor);

if ($cursor === $offset) {
throw new ParseException('Malformed unquoted YAML string.');
}

return substr($this->currentLine, $offset, $cursor - $offset);
}

private function lexInlineMapping(int &$cursor = 0): string
{
return $this->lexInlineStructure($cursor, '}');
}

private function lexInlineSequence(int &$cursor = 0): string
{
return $this->lexInlineStructure($cursor, ']');
}

private function lexInlineStructure(int &$cursor, string $closingTag): string
{
$value = $this->currentLine[$cursor];
++$cursor;

do {
$this->consumeWhitespaces($cursor);

while (isset($this->currentLine[$cursor])) {
switch ($this->currentLine[$cursor]) {
case '"':
case "'":
$value .= $this->lexInlineQuotedString($cursor);
break;
case ':':
case ',':
$value .= $this->currentLine[$cursor];
++$cursor;
break;
case '{':
$value .= $this->lexInlineMapping($cursor);
break;
case '[':
$value .= $this->lexInlineSequence($cursor);
break;
case $closingTag:
$value .= $this->currentLine[$cursor];
++$cursor;

return $value;
case '#':
break 2;
default:
$value .= $this->lexUnquotedString($cursor);
}

if ($this->consumeWhitespaces($cursor)) {
$value .= ' ';
}
}

if ($this->hasMoreLines()) {
$cursor = 0;
}
} while ($this->moveToNextLine());

throw new ParseException('Malformed inline YAML string.');
}

private function consumeWhitespaces(int &$cursor): bool
{
$whitespacesConsumed = 0;

do {
$whitespaceOnlyTokenLength = strspn($this->currentLine, ' ', $cursor);
$whitespacesConsumed += $whitespaceOnlyTokenLength;
$cursor += $whitespaceOnlyTokenLength;

if (isset($this->currentLine[$cursor])) {
return 0 < $whitespacesConsumed;
}

if ($this->hasMoreLines()) {
$cursor = 0;
}
} while ($this->moveToNextLine());

return 0 < $whitespacesConsumed;
}
}
<?php










namespace Symfony\Component\Yaml;

use Symfony\Component\Yaml\Exception\ParseException;








class Yaml
{
public const DUMP_OBJECT = 1;
public const PARSE_EXCEPTION_ON_INVALID_TYPE = 2;
public const PARSE_OBJECT = 4;
public const PARSE_OBJECT_FOR_MAP = 8;
public const DUMP_EXCEPTION_ON_INVALID_TYPE = 16;
public const PARSE_DATETIME = 32;
public const DUMP_OBJECT_AS_MAP = 64;
public const DUMP_MULTI_LINE_LITERAL_BLOCK = 128;
public const PARSE_CONSTANT = 256;
public const PARSE_CUSTOM_TAGS = 512;
public const DUMP_EMPTY_ARRAY_AS_SEQUENCE = 1024;
public const DUMP_NULL_AS_TILDE = 2048;
















public static function parseFile(string $filename, int $flags = 0)
{
$yaml = new Parser();

return $yaml->parseFile($filename, $flags);
}

















public static function parse(string $input, int $flags = 0)
{
$yaml = new Parser();

return $yaml->parse($input, $flags);
}














public static function dump($input, int $inline = 2, int $indent = 4, int $flags = 0): string
{
$yaml = new Dumper($indent);

return $yaml->dump($input, $inline, 0, $flags);
}
}
<?php










use Symfony\Polyfill\Php72 as p;

if (\PHP_VERSION_ID >= 70200) {
return;
}

if (!defined('PHP_FLOAT_DIG')) {
define('PHP_FLOAT_DIG', 15);
}
if (!defined('PHP_FLOAT_EPSILON')) {
define('PHP_FLOAT_EPSILON', 2.2204460492503E-16);
}
if (!defined('PHP_FLOAT_MIN')) {
define('PHP_FLOAT_MIN', 2.2250738585072E-308);
}
if (!defined('PHP_FLOAT_MAX')) {
define('PHP_FLOAT_MAX', 1.7976931348623157E+308);
}
if (!defined('PHP_OS_FAMILY')) {
define('PHP_OS_FAMILY', p\Php72::php_os_family());
}

if ('\\' === \DIRECTORY_SEPARATOR && !function_exists('sapi_windows_vt100_support')) {
function sapi_windows_vt100_support($stream, $enable = null) { return p\Php72::sapi_windows_vt100_support($stream, $enable); }
}
if (!function_exists('stream_isatty')) {
function stream_isatty($stream) { return p\Php72::stream_isatty($stream); }
}
if (!function_exists('utf8_encode')) {
function utf8_encode($string) { return p\Php72::utf8_encode($string); }
}
if (!function_exists('utf8_decode')) {
function utf8_decode($string) { return p\Php72::utf8_decode($string); }
}
if (!function_exists('spl_object_id')) {
function spl_object_id($object) { return p\Php72::spl_object_id($object); }
}
if (!function_exists('mb_ord')) {
function mb_ord($string, $encoding = null) { return p\Php72::mb_ord($string, $encoding); }
}
if (!function_exists('mb_chr')) {
function mb_chr($codepoint, $encoding = null) { return p\Php72::mb_chr($codepoint, $encoding); }
}
if (!function_exists('mb_scrub')) {
function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); }
}
<?php










namespace Symfony\Polyfill\Php72;







final class Php72
{
private static $hashMask;

public static function utf8_encode($s)
{
$s .= $s;
$len = \strlen($s);

for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) {
switch (true) {
case $s[$i] < "\x80": $s[$j] = $s[$i]; break;
case $s[$i] < "\xC0": $s[$j] = "\xC2"; $s[++$j] = $s[$i]; break;
default: $s[$j] = "\xC3"; $s[++$j] = \chr(\ord($s[$i]) - 64); break;
}
}

return substr($s, 0, $j);
}

public static function utf8_decode($s)
{
$s = (string) $s;
$len = \strlen($s);

for ($i = 0, $j = 0; $i < $len; ++$i, ++$j) {
switch ($s[$i] & "\xF0") {
case "\xC0":
case "\xD0":
$c = (\ord($s[$i] & "\x1F") << 6) | \ord($s[++$i] & "\x3F");
$s[$j] = $c < 256 ? \chr($c) : '?';
break;

case "\xF0":
++$i;


case "\xE0":
$s[$j] = '?';
$i += 2;
break;

default:
$s[$j] = $s[$i];
}
}

return substr($s, 0, $j);
}

public static function php_os_family()
{
if ('\\' === \DIRECTORY_SEPARATOR) {
return 'Windows';
}

$map = [
'Darwin' => 'Darwin',
'DragonFly' => 'BSD',
'FreeBSD' => 'BSD',
'NetBSD' => 'BSD',
'OpenBSD' => 'BSD',
'Linux' => 'Linux',
'SunOS' => 'Solaris',
];

return isset($map[\PHP_OS]) ? $map[\PHP_OS] : 'Unknown';
}

public static function spl_object_id($object)
{
if (null === self::$hashMask) {
self::initHashMask();
}
if (null === $hash = spl_object_hash($object)) {
return;
}


 return self::$hashMask ^ hexdec(substr($hash, 16 - (\PHP_INT_SIZE * 2 - 1), (\PHP_INT_SIZE * 2 - 1)));
}

public static function sapi_windows_vt100_support($stream, $enable = null)
{
if (!\is_resource($stream)) {
trigger_error('sapi_windows_vt100_support() expects parameter 1 to be resource, '.\gettype($stream).' given', \E_USER_WARNING);

return false;
}

$meta = stream_get_meta_data($stream);

if ('STDIO' !== $meta['stream_type']) {
trigger_error('sapi_windows_vt100_support() was not able to analyze the specified stream', \E_USER_WARNING);

return false;
}


 if (false === $enable || !self::stream_isatty($stream)) {
return false;
}


 $meta = array_map('strtolower', $meta);
$stdin = 'php://stdin' === $meta['uri'] || 'php://fd/0' === $meta['uri'];

return !$stdin
&& (false !== getenv('ANSICON')
|| 'ON' === getenv('ConEmuANSI')
|| 'xterm' === getenv('TERM')
|| 'Hyper' === getenv('TERM_PROGRAM'));
}

public static function stream_isatty($stream)
{
if (!\is_resource($stream)) {
trigger_error('stream_isatty() expects parameter 1 to be resource, '.\gettype($stream).' given', \E_USER_WARNING);

return false;
}

if ('\\' === \DIRECTORY_SEPARATOR) {
$stat = @fstat($stream);

 return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
}

return \function_exists('posix_isatty') && @posix_isatty($stream);
}

private static function initHashMask()
{
$obj = (object) [];
self::$hashMask = -1;


 $obFuncs = ['ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush'];
foreach (debug_backtrace(\PHP_VERSION_ID >= 50400 ? \DEBUG_BACKTRACE_IGNORE_ARGS : false) as $frame) {
if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && \in_array($frame['function'], $obFuncs)) {
$frame['line'] = 0;
break;
}
}
if (!empty($frame['line'])) {
ob_start();
debug_zval_dump($obj);
self::$hashMask = (int) substr(ob_get_clean(), 17);
}

self::$hashMask ^= hexdec(substr(spl_object_hash($obj), 16 - (\PHP_INT_SIZE * 2 - 1), (\PHP_INT_SIZE * 2 - 1)));
}

public static function mb_chr($code, $encoding = null)
{
if (0x80 > $code %= 0x200000) {
$s = \chr($code);
} elseif (0x800 > $code) {
$s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
} elseif (0x10000 > $code) {
$s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
} else {
$s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
}

if ('UTF-8' !== $encoding = $encoding ?? mb_internal_encoding()) {
$s = mb_convert_encoding($s, $encoding, 'UTF-8');
}

return $s;
}

public static function mb_ord($s, $encoding = null)
{
if (null === $encoding) {
$s = mb_convert_encoding($s, 'UTF-8');
} elseif ('UTF-8' !== $encoding) {
$s = mb_convert_encoding($s, 'UTF-8', $encoding);
}

if (1 === \strlen($s)) {
return \ord($s);
}

$code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
if (0xF0 <= $code) {
return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
}
if (0xE0 <= $code) {
return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
}
if (0xC0 <= $code) {
return (($code - 0xC0) << 6) + $s[2] - 0x80;
}

return $code;
}
}
<?php










namespace Symfony\Contracts\EventDispatcher;

use Psr\EventDispatcher\EventDispatcherInterface as PsrEventDispatcherInterface;

if (interface_exists(PsrEventDispatcherInterface::class)) {



interface EventDispatcherInterface extends PsrEventDispatcherInterface
{













public function dispatch($event);
}
} else {



interface EventDispatcherInterface
{













public function dispatch($event);
}
}
<?php










namespace Symfony\Contracts\EventDispatcher;

use Psr\EventDispatcher\StoppableEventInterface;

if (interface_exists(StoppableEventInterface::class)) {















class Event implements StoppableEventInterface
{
private $propagationStopped = false;




public function isPropagationStopped(): bool
{
return $this->propagationStopped;
}








public function stopPropagation(): void
{
$this->propagationStopped = true;
}
}
} else {















class Event
{
private $propagationStopped = false;




public function isPropagationStopped(): bool
{
return $this->propagationStopped;
}








public function stopPropagation(): void
{
$this->propagationStopped = true;
}
}
}
<?php










namespace Symfony\Component\EventDispatcher\Debug;

use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Contracts\Service\ResetInterface;






interface TraceableEventDispatcherInterface extends EventDispatcherInterface, ResetInterface
{







public function getCalledListeners();








public function getNotCalledListeners();
}
<?php










namespace Symfony\Component\EventDispatcher\Debug;

use Psr\EventDispatcher\StoppableEventInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
use Symfony\Component\EventDispatcher\LegacyEventProxy;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;








class TraceableEventDispatcher implements TraceableEventDispatcherInterface
{
protected $logger;
protected $stopwatch;

private $callStack;
private $dispatcher;
private $wrappedListeners;
private $orphanedEvents;
private $requestStack;
private $currentRequestHash = '';

public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null, RequestStack $requestStack = null)
{
$this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
$this->stopwatch = $stopwatch;
$this->logger = $logger;
$this->wrappedListeners = [];
$this->orphanedEvents = [];
$this->requestStack = $requestStack;
}




public function addListener($eventName, $listener, $priority = 0)
{
$this->dispatcher->addListener($eventName, $listener, $priority);
}




public function addSubscriber(EventSubscriberInterface $subscriber)
{
$this->dispatcher->addSubscriber($subscriber);
}




public function removeListener($eventName, $listener)
{
if (isset($this->wrappedListeners[$eventName])) {
foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) {
if ($wrappedListener->getWrappedListener() === $listener) {
$listener = $wrappedListener;
unset($this->wrappedListeners[$eventName][$index]);
break;
}
}
}

return $this->dispatcher->removeListener($eventName, $listener);
}




public function removeSubscriber(EventSubscriberInterface $subscriber)
{
return $this->dispatcher->removeSubscriber($subscriber);
}




public function getListeners($eventName = null)
{
return $this->dispatcher->getListeners($eventName);
}




public function getListenerPriority($eventName, $listener)
{

 
 if (isset($this->wrappedListeners[$eventName])) {
foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) {
if ($wrappedListener->getWrappedListener() === $listener) {
return $this->dispatcher->getListenerPriority($eventName, $wrappedListener);
}
}
}

return $this->dispatcher->getListenerPriority($eventName, $listener);
}




public function hasListeners($eventName = null)
{
return $this->dispatcher->hasListeners($eventName);
}






public function dispatch($event)
{
if (null === $this->callStack) {
$this->callStack = new \SplObjectStorage();
}

$currentRequestHash = $this->currentRequestHash = $this->requestStack && ($request = $this->requestStack->getCurrentRequest()) ? spl_object_hash($request) : '';
$eventName = 1 < \func_num_args() ? func_get_arg(1) : null;

if (\is_object($event)) {
$eventName = $eventName ?? \get_class($event);
} else {
@trigger_error(sprintf('Calling the "%s::dispatch()" method with the event name as first argument is deprecated since Symfony 4.3, pass it second and provide the event object first instead.', EventDispatcherInterface::class), \E_USER_DEPRECATED);
$swap = $event;
$event = $eventName ?? new Event();
$eventName = $swap;

if (!$event instanceof Event) {
throw new \TypeError(sprintf('Argument 1 passed to "%s::dispatch()" must be an instance of "%s", "%s" given.', EventDispatcherInterface::class, Event::class, \is_object($event) ? \get_class($event) : \gettype($event)));
}
}

if (null !== $this->logger && ($event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface) && $event->isPropagationStopped()) {
$this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName));
}

$this->preProcess($eventName);
try {
$this->beforeDispatch($eventName, $event);
try {
$e = $this->stopwatch->start($eventName, 'section');
try {
$this->dispatcher->dispatch($event, $eventName);
} finally {
if ($e->isStarted()) {
$e->stop();
}
}
} finally {
$this->afterDispatch($eventName, $event);
}
} finally {
$this->currentRequestHash = $currentRequestHash;
$this->postProcess($eventName);
}

return $event;
}






public function getCalledListeners()
{
if (null === $this->callStack) {
return [];
}

$hash = 1 <= \func_num_args() && null !== ($request = func_get_arg(0)) ? spl_object_hash($request) : null;
$called = [];
foreach ($this->callStack as $listener) {
[$eventName, $requestHash] = $this->callStack->getInfo();
if (null === $hash || $hash === $requestHash) {
$called[] = $listener->getInfo($eventName);
}
}

return $called;
}






public function getNotCalledListeners()
{
try {
$allListeners = $this->getListeners();
} catch (\Exception $e) {
if (null !== $this->logger) {
$this->logger->info('An exception was thrown while getting the uncalled listeners.', ['exception' => $e]);
}


 return [];
}

$hash = 1 <= \func_num_args() && null !== ($request = func_get_arg(0)) ? spl_object_hash($request) : null;
$calledListeners = [];

if (null !== $this->callStack) {
foreach ($this->callStack as $calledListener) {
[, $requestHash] = $this->callStack->getInfo();

if (null === $hash || $hash === $requestHash) {
$calledListeners[] = $calledListener->getWrappedListener();
}
}
}

$notCalled = [];
foreach ($allListeners as $eventName => $listeners) {
foreach ($listeners as $listener) {
if (!\in_array($listener, $calledListeners, true)) {
if (!$listener instanceof WrappedListener) {
$listener = new WrappedListener($listener, null, $this->stopwatch, $this);
}
$notCalled[] = $listener->getInfo($eventName);
}
}
}

uasort($notCalled, [$this, 'sortNotCalledListeners']);

return $notCalled;
}




public function getOrphanedEvents(): array
{
if (1 <= \func_num_args() && null !== $request = func_get_arg(0)) {
return $this->orphanedEvents[spl_object_hash($request)] ?? [];
}

if (!$this->orphanedEvents) {
return [];
}

return array_merge(...array_values($this->orphanedEvents));
}

public function reset()
{
$this->callStack = null;
$this->orphanedEvents = [];
$this->currentRequestHash = '';
}









public function __call($method, $arguments)
{
return $this->dispatcher->{$method}(...$arguments);
}






protected function beforeDispatch(string $eventName, $event)
{
$this->preDispatch($eventName, $event instanceof Event ? $event : new LegacyEventProxy($event));
}






protected function afterDispatch(string $eventName, $event)
{
$this->postDispatch($eventName, $event instanceof Event ? $event : new LegacyEventProxy($event));
}




protected function preDispatch($eventName, Event $event)
{
}




protected function postDispatch($eventName, Event $event)
{
}

private function preProcess(string $eventName)
{
if (!$this->dispatcher->hasListeners($eventName)) {
$this->orphanedEvents[$this->currentRequestHash][] = $eventName;

return;
}

foreach ($this->dispatcher->getListeners($eventName) as $listener) {
$priority = $this->getListenerPriority($eventName, $listener);
$wrappedListener = new WrappedListener($listener instanceof WrappedListener ? $listener->getWrappedListener() : $listener, null, $this->stopwatch, $this);
$this->wrappedListeners[$eventName][] = $wrappedListener;
$this->dispatcher->removeListener($eventName, $listener);
$this->dispatcher->addListener($eventName, $wrappedListener, $priority);
$this->callStack->attach($wrappedListener, [$eventName, $this->currentRequestHash]);
}
}

private function postProcess(string $eventName)
{
unset($this->wrappedListeners[$eventName]);
$skipped = false;
foreach ($this->dispatcher->getListeners($eventName) as $listener) {
if (!$listener instanceof WrappedListener) { 
 continue;
}

 $priority = $this->getListenerPriority($eventName, $listener);
$this->dispatcher->removeListener($eventName, $listener);
$this->dispatcher->addListener($eventName, $listener->getWrappedListener(), $priority);

if (null !== $this->logger) {
$context = ['event' => $eventName, 'listener' => $listener->getPretty()];
}

if ($listener->wasCalled()) {
if (null !== $this->logger) {
$this->logger->debug('Notified event "{event}" to listener "{listener}".', $context);
}
} else {
$this->callStack->detach($listener);
}

if (null !== $this->logger && $skipped) {
$this->logger->debug('Listener "{listener}" was not called for event "{event}".', $context);
}

if ($listener->stoppedPropagation()) {
if (null !== $this->logger) {
$this->logger->debug('Listener "{listener}" stopped propagation of the event "{event}".', $context);
}

$skipped = true;
}
}
}

private function sortNotCalledListeners(array $a, array $b)
{
if (0 !== $cmp = strcmp($a['event'], $b['event'])) {
return $cmp;
}

if (\is_int($a['priority']) && !\is_int($b['priority'])) {
return 1;
}

if (!\is_int($a['priority']) && \is_int($b['priority'])) {
return -1;
}

if ($a['priority'] === $b['priority']) {
return 0;
}

if ($a['priority'] > $b['priority']) {
return -1;
}

return 1;
}
}
<?php










namespace Symfony\Component\EventDispatcher\Debug;

use Psr\EventDispatcher\StoppableEventInterface;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\LegacyEventProxy;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Component\VarDumper\Caster\ClassStub;
use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;






class WrappedListener
{
private $listener;
private $optimizedListener;
private $name;
private $called;
private $stoppedPropagation;
private $stopwatch;
private $dispatcher;
private $pretty;
private $stub;
private $priority;
private static $hasClassStub;

public function __construct($listener, ?string $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null)
{
$this->listener = $listener;
$this->optimizedListener = $listener instanceof \Closure ? $listener : (\is_callable($listener) ? \Closure::fromCallable($listener) : null);
$this->stopwatch = $stopwatch;
$this->dispatcher = $dispatcher;
$this->called = false;
$this->stoppedPropagation = false;

if (\is_array($listener)) {
$this->name = \is_object($listener[0]) ? \get_class($listener[0]) : $listener[0];
$this->pretty = $this->name.'::'.$listener[1];
} elseif ($listener instanceof \Closure) {
$r = new \ReflectionFunction($listener);
if (str_contains($r->name, '{closure}')) {
$this->pretty = $this->name = 'closure';
} elseif ($class = $r->getClosureScopeClass()) {
$this->name = $class->name;
$this->pretty = $this->name.'::'.$r->name;
} else {
$this->pretty = $this->name = $r->name;
}
} elseif (\is_string($listener)) {
$this->pretty = $this->name = $listener;
} else {
$this->name = \get_class($listener);
$this->pretty = $this->name.'::__invoke';
}

if (null !== $name) {
$this->name = $name;
}

if (null === self::$hasClassStub) {
self::$hasClassStub = class_exists(ClassStub::class);
}
}

public function getWrappedListener()
{
return $this->listener;
}

public function wasCalled()
{
return $this->called;
}

public function stoppedPropagation()
{
return $this->stoppedPropagation;
}

public function getPretty()
{
return $this->pretty;
}

public function getInfo($eventName)
{
if (null === $this->stub) {
$this->stub = self::$hasClassStub ? new ClassStub($this->pretty.'()', $this->listener) : $this->pretty.'()';
}

return [
'event' => $eventName,
'priority' => null !== $this->priority ? $this->priority : (null !== $this->dispatcher ? $this->dispatcher->getListenerPriority($eventName, $this->listener) : null),
'pretty' => $this->pretty,
'stub' => $this->stub,
];
}

public function __invoke(Event $event, $eventName, EventDispatcherInterface $dispatcher)
{
if ($event instanceof LegacyEventProxy) {
$event = $event->getEvent();
}

$dispatcher = $this->dispatcher ?: $dispatcher;

$this->called = true;
$this->priority = $dispatcher->getListenerPriority($eventName, $this->listener);

$e = $this->stopwatch->start($this->name, 'event_listener');

($this->optimizedListener ?? $this->listener)($event, $eventName, $dispatcher);

if ($e->isStarted()) {
$e->stop();
}

if (($event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface) && $event->isPropagationStopped()) {
$this->stoppedPropagation = true;
}
}
}
<?php










namespace Symfony\Component\EventDispatcher;






class ImmutableEventDispatcher implements EventDispatcherInterface
{
private $dispatcher;

public function __construct(EventDispatcherInterface $dispatcher)
{
$this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
}






public function dispatch($event)
{
$eventName = 1 < \func_num_args() ? func_get_arg(1) : null;

if (is_scalar($event)) {

 $swap = $event;
$event = $eventName ?? new Event();
$eventName = $swap;
}

return $this->dispatcher->dispatch($event, $eventName);
}




public function addListener($eventName, $listener, $priority = 0)
{
throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
}




public function addSubscriber(EventSubscriberInterface $subscriber)
{
throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
}




public function removeListener($eventName, $listener)
{
throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
}




public function removeSubscriber(EventSubscriberInterface $subscriber)
{
throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
}




public function getListeners($eventName = null)
{
return $this->dispatcher->getListeners($eventName);
}




public function getListenerPriority($eventName, $listener)
{
return $this->dispatcher->getListenerPriority($eventName, $listener);
}




public function hasListeners($eventName = null)
{
return $this->dispatcher->hasListeners($eventName);
}
}
<?php










namespace Symfony\Component\EventDispatcher;

use Psr\EventDispatcher\StoppableEventInterface;
use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;




final class LegacyEventProxy extends Event
{
private $event;




public function __construct($event)
{
$this->event = $event;
}




public function getEvent()
{
return $this->event;
}

public function isPropagationStopped(): bool
{
if (!$this->event instanceof ContractsEvent && !$this->event instanceof StoppableEventInterface) {
return false;
}

return $this->event->isPropagationStopped();
}

public function stopPropagation()
{
if (!$this->event instanceof ContractsEvent) {
return;
}

$this->event->stopPropagation();
}

public function __call($name, $args)
{
return $this->event->{$name}(...$args);
}
}
<?php










namespace Symfony\Component\EventDispatcher;

use Psr\EventDispatcher\StoppableEventInterface;
use Symfony\Component\EventDispatcher\Debug\WrappedListener;
use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
















class EventDispatcher implements EventDispatcherInterface
{
private $listeners = [];
private $sorted = [];
private $optimized;

public function __construct()
{
if (__CLASS__ === static::class) {
$this->optimized = [];
}
}






public function dispatch($event)
{
$eventName = 1 < \func_num_args() ? func_get_arg(1) : null;

if (\is_object($event)) {
$eventName = $eventName ?? \get_class($event);
} elseif (\is_string($event) && (null === $eventName || $eventName instanceof ContractsEvent || $eventName instanceof Event)) {
@trigger_error(sprintf('Calling the "%s::dispatch()" method with the event name as the first argument is deprecated since Symfony 4.3, pass it as the second argument and provide the event object as the first argument instead.', EventDispatcherInterface::class), \E_USER_DEPRECATED);
$swap = $event;
$event = $eventName ?? new Event();
$eventName = $swap;
} else {
throw new \TypeError(sprintf('Argument 1 passed to "%s::dispatch()" must be an object, "%s" given.', EventDispatcherInterface::class, \is_object($event) ? \get_class($event) : \gettype($event)));
}

if (null !== $this->optimized && null !== $eventName) {
$listeners = $this->optimized[$eventName] ?? (empty($this->listeners[$eventName]) ? [] : $this->optimizeListeners($eventName));
} else {
$listeners = $this->getListeners($eventName);
}

if ($listeners) {
$this->callListeners($listeners, $eventName, $event);
}

return $event;
}




public function getListeners($eventName = null)
{
if (null !== $eventName) {
if (empty($this->listeners[$eventName])) {
return [];
}

if (!isset($this->sorted[$eventName])) {
$this->sortListeners($eventName);
}

return $this->sorted[$eventName];
}

foreach ($this->listeners as $eventName => $eventListeners) {
if (!isset($this->sorted[$eventName])) {
$this->sortListeners($eventName);
}
}

return array_filter($this->sorted);
}




public function getListenerPriority($eventName, $listener)
{
if (empty($this->listeners[$eventName])) {
return null;
}

if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) {
$listener[0] = $listener[0]();
$listener[1] = $listener[1] ?? '__invoke';
}

foreach ($this->listeners[$eventName] as $priority => &$listeners) {
foreach ($listeners as &$v) {
if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) {
$v[0] = $v[0]();
$v[1] = $v[1] ?? '__invoke';
}
if ($v === $listener) {
return $priority;
}
}
}

return null;
}




public function hasListeners($eventName = null)
{
if (null !== $eventName) {
return !empty($this->listeners[$eventName]);
}

foreach ($this->listeners as $eventListeners) {
if ($eventListeners) {
return true;
}
}

return false;
}




public function addListener($eventName, $listener, $priority = 0)
{
$this->listeners[$eventName][$priority][] = $listener;
unset($this->sorted[$eventName], $this->optimized[$eventName]);
}




public function removeListener($eventName, $listener)
{
if (empty($this->listeners[$eventName])) {
return;
}

if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) {
$listener[0] = $listener[0]();
$listener[1] = $listener[1] ?? '__invoke';
}

foreach ($this->listeners[$eventName] as $priority => &$listeners) {
foreach ($listeners as $k => &$v) {
if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) {
$v[0] = $v[0]();
$v[1] = $v[1] ?? '__invoke';
}
if ($v === $listener) {
unset($listeners[$k], $this->sorted[$eventName], $this->optimized[$eventName]);
}
}

if (!$listeners) {
unset($this->listeners[$eventName][$priority]);
}
}
}




public function addSubscriber(EventSubscriberInterface $subscriber)
{
foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
if (\is_string($params)) {
$this->addListener($eventName, [$subscriber, $params]);
} elseif (\is_string($params[0])) {
$this->addListener($eventName, [$subscriber, $params[0]], $params[1] ?? 0);
} else {
foreach ($params as $listener) {
$this->addListener($eventName, [$subscriber, $listener[0]], $listener[1] ?? 0);
}
}
}
}




public function removeSubscriber(EventSubscriberInterface $subscriber)
{
foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
if (\is_array($params) && \is_array($params[0])) {
foreach ($params as $listener) {
$this->removeListener($eventName, [$subscriber, $listener[0]]);
}
} else {
$this->removeListener($eventName, [$subscriber, \is_string($params) ? $params : $params[0]]);
}
}
}











protected function callListeners(iterable $listeners, string $eventName, $event)
{
if ($event instanceof Event) {
$this->doDispatch($listeners, $eventName, $event);

return;
}

$stoppable = $event instanceof ContractsEvent || $event instanceof StoppableEventInterface;

foreach ($listeners as $listener) {
if ($stoppable && $event->isPropagationStopped()) {
break;
}

 $listener($listener instanceof WrappedListener ? new LegacyEventProxy($event) : $event, $eventName, $this);
}
}




protected function doDispatch($listeners, $eventName, Event $event)
{
foreach ($listeners as $listener) {
if ($event->isPropagationStopped()) {
break;
}
$listener($event, $eventName, $this);
}
}




private function sortListeners(string $eventName)
{
krsort($this->listeners[$eventName]);
$this->sorted[$eventName] = [];

foreach ($this->listeners[$eventName] as &$listeners) {
foreach ($listeners as $k => &$listener) {
if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) {
$listener[0] = $listener[0]();
$listener[1] = $listener[1] ?? '__invoke';
}
$this->sorted[$eventName][] = $listener;
}
}
}




private function optimizeListeners(string $eventName): array
{
krsort($this->listeners[$eventName]);
$this->optimized[$eventName] = [];

foreach ($this->listeners[$eventName] as &$listeners) {
foreach ($listeners as &$listener) {
$closure = &$this->optimized[$eventName][];
if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) {
$closure = static function (...$args) use (&$listener, &$closure) {
if ($listener[0] instanceof \Closure) {
$listener[0] = $listener[0]();
$listener[1] = $listener[1] ?? '__invoke';
}
($closure = \Closure::fromCallable($listener))(...$args);
};
} else {
$closure = $listener instanceof \Closure || $listener instanceof WrappedListener ? $listener : \Closure::fromCallable($listener);
}
}
}

return $this->optimized[$eventName];
}
}
<?php










namespace Symfony\Component\EventDispatcher;












interface EventSubscriberInterface
{





















public static function getSubscribedEvents();
}
<?php










namespace Symfony\Component\EventDispatcher\DependencyInjection;

use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\Event as LegacyEvent;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Contracts\EventDispatcher\Event;




class RegisterListenersPass implements CompilerPassInterface
{
protected $dispatcherService;
protected $listenerTag;
protected $subscriberTag;
protected $eventAliasesParameter;

private $hotPathEvents = [];
private $hotPathTagName;

public function __construct(string $dispatcherService = 'event_dispatcher', string $listenerTag = 'kernel.event_listener', string $subscriberTag = 'kernel.event_subscriber', string $eventAliasesParameter = 'event_dispatcher.event_aliases')
{
$this->dispatcherService = $dispatcherService;
$this->listenerTag = $listenerTag;
$this->subscriberTag = $subscriberTag;
$this->eventAliasesParameter = $eventAliasesParameter;
}

public function setHotPathEvents(array $hotPathEvents, $tagName = 'container.hot_path')
{
$this->hotPathEvents = array_flip($hotPathEvents);
$this->hotPathTagName = $tagName;

return $this;
}

public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition($this->dispatcherService) && !$container->hasAlias($this->dispatcherService)) {
return;
}

$aliases = [];

if ($container->hasParameter($this->eventAliasesParameter)) {
$aliases = $container->getParameter($this->eventAliasesParameter);
}

$definition = $container->findDefinition($this->dispatcherService);

foreach ($container->findTaggedServiceIds($this->listenerTag, true) as $id => $events) {
foreach ($events as $event) {
$priority = $event['priority'] ?? 0;

if (!isset($event['event'])) {
if ($container->getDefinition($id)->hasTag($this->subscriberTag)) {
continue;
}

$event['method'] = $event['method'] ?? '__invoke';
$event['event'] = $this->getEventFromTypeDeclaration($container, $id, $event['method']);
}

$event['event'] = $aliases[$event['event']] ?? $event['event'];

if (!isset($event['method'])) {
$event['method'] = 'on'.preg_replace_callback([
'/(?<=\b|_)[a-z]/i',
'/[^a-z0-9]/i',
], function ($matches) { return strtoupper($matches[0]); }, $event['event']);
$event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']);

if (null !== ($class = $container->getDefinition($id)->getClass()) && ($r = $container->getReflectionClass($class, false)) && !$r->hasMethod($event['method']) && $r->hasMethod('__invoke')) {
$event['method'] = '__invoke';
}
}

$definition->addMethodCall('addListener', [$event['event'], [new ServiceClosureArgument(new Reference($id)), $event['method']], $priority]);

if (isset($this->hotPathEvents[$event['event']])) {
$container->getDefinition($id)->addTag($this->hotPathTagName);
}
}
}

$extractingDispatcher = new ExtractingEventDispatcher();

foreach ($container->findTaggedServiceIds($this->subscriberTag, true) as $id => $attributes) {
$def = $container->getDefinition($id);


 $class = $def->getClass();

if (!$r = $container->getReflectionClass($class)) {
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
}
if (!$r->isSubclassOf(EventSubscriberInterface::class)) {
throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, EventSubscriberInterface::class));
}
$class = $r->name;

ExtractingEventDispatcher::$aliases = $aliases;
ExtractingEventDispatcher::$subscriber = $class;
$extractingDispatcher->addSubscriber($extractingDispatcher);
foreach ($extractingDispatcher->listeners as $args) {
$args[1] = [new ServiceClosureArgument(new Reference($id)), $args[1]];
$definition->addMethodCall('addListener', $args);

if (isset($this->hotPathEvents[$args[0]])) {
$container->getDefinition($id)->addTag($this->hotPathTagName);
}
}
$extractingDispatcher->listeners = [];
ExtractingEventDispatcher::$aliases = [];
}
}

private function getEventFromTypeDeclaration(ContainerBuilder $container, string $id, string $method): string
{
if (
null === ($class = $container->getDefinition($id)->getClass())
|| !($r = $container->getReflectionClass($class, false))
|| !$r->hasMethod($method)
|| 1 > ($m = $r->getMethod($method))->getNumberOfParameters()
|| !($type = $m->getParameters()[0]->getType()) instanceof \ReflectionNamedType
|| $type->isBuiltin()
|| Event::class === ($name = $type->getName())
|| LegacyEvent::class === $name
) {
throw new InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag));
}

return $name;
}
}




class ExtractingEventDispatcher extends EventDispatcher implements EventSubscriberInterface
{
public $listeners = [];

public static $aliases = [];
public static $subscriber;

public function addListener($eventName, $listener, $priority = 0)
{
$this->listeners[] = [$eventName, $listener[1], $priority];
}

public static function getSubscribedEvents(): array
{
$events = [];

foreach ([self::$subscriber, 'getSubscribedEvents']() as $eventName => $params) {
$events[self::$aliases[$eventName] ?? $eventName] = $params;
}

return $events;
}
}
<?php










namespace Symfony\Component\EventDispatcher\DependencyInjection;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;






class AddEventAliasesPass implements CompilerPassInterface
{
private $eventAliases;
private $eventAliasesParameter;

public function __construct(array $eventAliases, string $eventAliasesParameter = 'event_dispatcher.event_aliases')
{
$this->eventAliases = $eventAliases;
$this->eventAliasesParameter = $eventAliasesParameter;
}

public function process(ContainerBuilder $container): void
{
$eventAliases = $container->hasParameter($this->eventAliasesParameter) ? $container->getParameter($this->eventAliasesParameter) : [];

$container->setParameter(
$this->eventAliasesParameter,
array_merge($eventAliases, $this->eventAliases)
);
}
}
<?php










namespace Symfony\Component\EventDispatcher;

use Psr\EventDispatcher\StoppableEventInterface;
use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface;








final class LegacyEventDispatcherProxy implements EventDispatcherInterface
{
private $dispatcher;

public static function decorate(?ContractsEventDispatcherInterface $dispatcher): ?ContractsEventDispatcherInterface
{
if (null === $dispatcher) {
return null;
}
$r = new \ReflectionMethod($dispatcher, 'dispatch');
$param2 = $r->getParameters()[1] ?? null;

if (!$param2 || !$param2->hasType() || $param2->getType()->isBuiltin()) {
return $dispatcher;
}

@trigger_error(sprintf('The signature of the "%s::dispatch()" method should be updated to "dispatch($event, string $eventName = null)", not doing so is deprecated since Symfony 4.3.', $r->class), \E_USER_DEPRECATED);

$self = new self();
$self->dispatcher = $dispatcher;

return $self;
}








public function dispatch($event)
{
$eventName = 1 < \func_num_args() ? func_get_arg(1) : null;

if (\is_object($event)) {
$eventName = $eventName ?? \get_class($event);
} elseif (\is_string($event) && (null === $eventName || $eventName instanceof ContractsEvent || $eventName instanceof Event)) {
@trigger_error(sprintf('Calling the "%s::dispatch()" method with the event name as the first argument is deprecated since Symfony 4.3, pass it as the second argument and provide the event object as the first argument instead.', ContractsEventDispatcherInterface::class), \E_USER_DEPRECATED);
$swap = $event;
$event = $eventName ?? new Event();
$eventName = $swap;
} else {
throw new \TypeError(sprintf('Argument 1 passed to "%s::dispatch()" must be an object, "%s" given.', ContractsEventDispatcherInterface::class, \is_object($event) ? \get_class($event) : \gettype($event)));
}

$listeners = $this->getListeners($eventName);
$stoppable = $event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface;

foreach ($listeners as $listener) {
if ($stoppable && $event->isPropagationStopped()) {
break;
}
$listener($event, $eventName, $this);
}

return $event;
}




public function addListener($eventName, $listener, $priority = 0)
{
return $this->dispatcher->addListener($eventName, $listener, $priority);
}




public function addSubscriber(EventSubscriberInterface $subscriber)
{
return $this->dispatcher->addSubscriber($subscriber);
}




public function removeListener($eventName, $listener)
{
return $this->dispatcher->removeListener($eventName, $listener);
}




public function removeSubscriber(EventSubscriberInterface $subscriber)
{
return $this->dispatcher->removeSubscriber($subscriber);
}




public function getListeners($eventName = null): array
{
return $this->dispatcher->getListeners($eventName);
}




public function getListenerPriority($eventName, $listener): ?int
{
return $this->dispatcher->getListenerPriority($eventName, $listener);
}




public function hasListeners($eventName = null): bool
{
return $this->dispatcher->hasListeners($eventName);
}




public function __call($method, $arguments)
{
return $this->dispatcher->{$method}(...$arguments);
}
}
<?php










namespace Symfony\Component\EventDispatcher;








class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
{
protected $subject;
protected $arguments;







public function __construct($subject = null, array $arguments = [])
{
$this->subject = $subject;
$this->arguments = $arguments;
}






public function getSubject()
{
return $this->subject;
}










public function getArgument($key)
{
if ($this->hasArgument($key)) {
return $this->arguments[$key];
}

throw new \InvalidArgumentException(sprintf('Argument "%s" not found.', $key));
}









public function setArgument($key, $value)
{
$this->arguments[$key] = $value;

return $this;
}






public function getArguments()
{
return $this->arguments;
}








public function setArguments(array $args = [])
{
$this->arguments = $args;

return $this;
}








public function hasArgument($key)
{
return \array_key_exists($key, $this->arguments);
}











 public function offsetGet($key)
{
return $this->getArgument($key);
}










 public function offsetSet($key, $value)
{
$this->setArgument($key, $value);
}









 public function offsetUnset($key)
{
if ($this->hasArgument($key)) {
unset($this->arguments[$key]);
}
}









 public function offsetExists($key)
{
return $this->hasArgument($key);
}







 public function getIterator()
{
return new \ArrayIterator($this->arguments);
}
}
<?php










namespace Symfony\Component\EventDispatcher;

use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface;








interface EventDispatcherInterface extends ContractsEventDispatcherInterface
{








public function addListener($eventName, $listener, $priority = 0);







public function addSubscriber(EventSubscriberInterface $subscriber);







public function removeListener($eventName, $listener);

public function removeSubscriber(EventSubscriberInterface $subscriber);








public function getListeners($eventName = null);











public function getListenerPriority($eventName, $listener);








public function hasListeners($eventName = null);
}
<?php










namespace Symfony\Component\EventDispatcher;




class Event
{
private $propagationStopped = false;






public function isPropagationStopped()
{
return $this->propagationStopped;
}




public function stopPropagation()
{
$this->propagationStopped = true;
}
}
<?php










namespace Symfony\Contracts\Service;

use Psr\Container\ContainerInterface;







trait ServiceSubscriberTrait
{

protected $container;




public static function getSubscribedServices(): array
{
static $services;

if (null !== $services) {
return $services;
}

$services = \is_callable(['parent', __FUNCTION__]) ? parent::getSubscribedServices() : [];

foreach ((new \ReflectionClass(self::class))->getMethods() as $method) {
if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) {
continue;
}

if (self::class !== $method->getDeclaringClass()->name) {
continue;
}

if (!($returnType = $method->getReturnType()) instanceof \ReflectionNamedType) {
continue;
}

if ($returnType->isBuiltin()) {
continue;
}

$services[self::class.'::'.$method->name] = '?'.$returnType->getName();
}

return $services;
}






public function setContainer(ContainerInterface $container)
{
$this->container = $container;

if (\is_callable(['parent', __FUNCTION__])) {
return parent::setContainer($container);
}

return null;
}
}
<?php










namespace Symfony\Contracts\Service;














interface ResetInterface
{
public function reset();
}
<?php










namespace Symfony\Contracts\Service;

use Psr\Container\ContainerInterface;







interface ServiceProviderInterface extends ContainerInterface
{











public function getProvidedServices(): array;
}
<?php










namespace Symfony\Contracts\Service\Test;

use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
use Symfony\Contracts\Service\ServiceLocatorTrait;

abstract class ServiceLocatorTest extends TestCase
{



protected function getServiceLocator(array $factories)
{
return new class($factories) implements ContainerInterface {
use ServiceLocatorTrait;
};
}

public function testHas()
{
$locator = $this->getServiceLocator([
'foo' => function () { return 'bar'; },
'bar' => function () { return 'baz'; },
function () { return 'dummy'; },
]);

$this->assertTrue($locator->has('foo'));
$this->assertTrue($locator->has('bar'));
$this->assertFalse($locator->has('dummy'));
}

public function testGet()
{
$locator = $this->getServiceLocator([
'foo' => function () { return 'bar'; },
'bar' => function () { return 'baz'; },
]);

$this->assertSame('bar', $locator->get('foo'));
$this->assertSame('baz', $locator->get('bar'));
}

public function testGetDoesNotMemoize()
{
$i = 0;
$locator = $this->getServiceLocator([
'foo' => function () use (&$i) {
++$i;

return 'bar';
},
]);

$this->assertSame('bar', $locator->get('foo'));
$this->assertSame('bar', $locator->get('foo'));
$this->assertSame(2, $i);
}

public function testThrowsOnUndefinedInternalService()
{
if (!$this->getExpectedException()) {
$this->expectException(\Psr\Container\NotFoundExceptionInterface::class);
$this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.');
}
$locator = $this->getServiceLocator([
'foo' => function () use (&$locator) { return $locator->get('bar'); },
]);

$locator->get('foo');
}

public function testThrowsOnCircularReference()
{
$this->expectException(\Psr\Container\ContainerExceptionInterface::class);
$this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".');
$locator = $this->getServiceLocator([
'foo' => function () use (&$locator) { return $locator->get('bar'); },
'bar' => function () use (&$locator) { return $locator->get('baz'); },
'baz' => function () use (&$locator) { return $locator->get('bar'); },
]);

$locator->get('foo');
}
}
<?php










namespace Symfony\Contracts\Service;
















interface ServiceSubscriberInterface
{





















public static function getSubscribedServices();
}
<?php










namespace Symfony\Contracts\Service;

use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;


class_exists(ContainerExceptionInterface::class);
class_exists(NotFoundExceptionInterface::class);







trait ServiceLocatorTrait
{
private $factories;
private $loading = [];
private $providedTypes;




public function __construct(array $factories)
{
$this->factories = $factories;
}






public function has($id)
{
return isset($this->factories[$id]);
}






public function get($id)
{
if (!isset($this->factories[$id])) {
throw $this->createNotFoundException($id);
}

if (isset($this->loading[$id])) {
$ids = array_values($this->loading);
$ids = \array_slice($this->loading, array_search($id, $ids));
$ids[] = $id;

throw $this->createCircularReferenceException($id, $ids);
}

$this->loading[$id] = $id;
try {
return $this->factories[$id]($this);
} finally {
unset($this->loading[$id]);
}
}




public function getProvidedServices(): array
{
if (null === $this->providedTypes) {
$this->providedTypes = [];

foreach ($this->factories as $name => $factory) {
if (!\is_callable($factory)) {
$this->providedTypes[$name] = '?';
} else {
$type = (new \ReflectionFunction($factory))->getReturnType();

$this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?';
}
}
}

return $this->providedTypes;
}

private function createNotFoundException(string $id): NotFoundExceptionInterface
{
if (!$alternatives = array_keys($this->factories)) {
$message = 'is empty...';
} else {
$last = array_pop($alternatives);
if ($alternatives) {
$message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last);
} else {
$message = sprintf('only knows about the "%s" service.', $last);
}
}

if ($this->loading) {
$message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message);
} else {
$message = sprintf('Service "%s" not found: the current service locator %s', $id, $message);
}

return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface {
};
}

private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface
{
return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface {
};
}
}
<?php



require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInit8d2576a0103fe25d0268c6cba2a989ff::getLoader();
<?php

namespace Doctrine\Instantiator;

use Doctrine\Instantiator\Exception\ExceptionInterface;




interface InstantiatorInterface
{










public function instantiate($className);
}
<?php

namespace Doctrine\Instantiator;

use ArrayIterator;
use Doctrine\Instantiator\Exception\InvalidArgumentException;
use Doctrine\Instantiator\Exception\UnexpectedValueException;
use Exception;
use ReflectionClass;
use ReflectionException;
use Serializable;

use function class_exists;
use function is_subclass_of;
use function restore_error_handler;
use function set_error_handler;
use function sprintf;
use function strlen;
use function unserialize;

final class Instantiator implements InstantiatorInterface
{





public const SERIALIZATION_FORMAT_USE_UNSERIALIZER = 'C';
public const SERIALIZATION_FORMAT_AVOID_UNSERIALIZER = 'O';






private static $cachedInstantiators = [];






private static $cachedCloneables = [];




public function instantiate($className)
{
if (isset(self::$cachedCloneables[$className])) {
return clone self::$cachedCloneables[$className];
}

if (isset(self::$cachedInstantiators[$className])) {
$factory = self::$cachedInstantiators[$className];

return $factory();
}

return $this->buildAndCacheFromFactory($className);
}











private function buildAndCacheFromFactory(string $className)
{
$factory = self::$cachedInstantiators[$className] = $this->buildFactory($className);
$instance = $factory();

if ($this->isSafeToClone(new ReflectionClass($instance))) {
self::$cachedCloneables[$className] = clone $instance;
}

return $instance;
}














private function buildFactory(string $className): callable
{
$reflectionClass = $this->getReflectionClass($className);

if ($this->isInstantiableViaReflection($reflectionClass)) {
return [$reflectionClass, 'newInstanceWithoutConstructor'];
}

$serializedString = sprintf(
'%s:%d:"%s":0:{}',
is_subclass_of($className, Serializable::class) ? self::SERIALIZATION_FORMAT_USE_UNSERIALIZER : self::SERIALIZATION_FORMAT_AVOID_UNSERIALIZER,
strlen($className),
$className
);

$this->checkIfUnSerializationIsSupported($reflectionClass, $serializedString);

return static function () use ($serializedString) {
return unserialize($serializedString);
};
}










private function getReflectionClass(string $className): ReflectionClass
{
if (! class_exists($className)) {
throw InvalidArgumentException::fromNonExistingClass($className);
}

$reflection = new ReflectionClass($className);

if ($reflection->isAbstract()) {
throw InvalidArgumentException::fromAbstractClass($reflection);
}

return $reflection;
}







private function checkIfUnSerializationIsSupported(ReflectionClass $reflectionClass, string $serializedString): void
{
set_error_handler(static function (int $code, string $message, string $file, int $line) use ($reflectionClass, &$error): bool {
$error = UnexpectedValueException::fromUncleanUnSerialization(
$reflectionClass,
$message,
$code,
$file,
$line
);

return true;
});

try {
$this->attemptInstantiationViaUnSerialization($reflectionClass, $serializedString);
} finally {
restore_error_handler();
}

if ($error) {
throw $error;
}
}







private function attemptInstantiationViaUnSerialization(ReflectionClass $reflectionClass, string $serializedString): void
{
try {
unserialize($serializedString);
} catch (Exception $exception) {
throw UnexpectedValueException::fromSerializationTriggeredException($reflectionClass, $exception);
}
}





private function isInstantiableViaReflection(ReflectionClass $reflectionClass): bool
{
return ! ($this->hasInternalAncestors($reflectionClass) && $reflectionClass->isFinal());
}







private function hasInternalAncestors(ReflectionClass $reflectionClass): bool
{
do {
if ($reflectionClass->isInternal()) {
return true;
}

$reflectionClass = $reflectionClass->getParentClass();
} while ($reflectionClass);

return false;
}









private function isSafeToClone(ReflectionClass $reflectionClass): bool
{
return $reflectionClass->isCloneable()
&& ! $reflectionClass->hasMethod('__clone')
&& ! $reflectionClass->isSubclassOf(ArrayIterator::class);
}
}
<?php

namespace Doctrine\Instantiator\Exception;

use Exception;
use ReflectionClass;
use UnexpectedValueException as BaseUnexpectedValueException;

use function sprintf;




class UnexpectedValueException extends BaseUnexpectedValueException implements ExceptionInterface
{




public static function fromSerializationTriggeredException(
ReflectionClass $reflectionClass,
Exception $exception
): self {
return new self(
sprintf(
'An exception was raised while trying to instantiate an instance of "%s" via un-serialization',
$reflectionClass->getName()
),
0,
$exception
);
}





public static function fromUncleanUnSerialization(
ReflectionClass $reflectionClass,
string $errorString,
int $errorCode,
string $errorFile,
int $errorLine
): self {
return new self(
sprintf(
'Could not produce an instance of "%s" via un-serialization, since an error was triggered '
. 'in file "%s" at line "%d"',
$reflectionClass->getName(),
$errorFile,
$errorLine
),
0,
new Exception($errorString, $errorCode)
);
}
}
<?php

namespace Doctrine\Instantiator\Exception;

use InvalidArgumentException as BaseInvalidArgumentException;
use ReflectionClass;

use function interface_exists;
use function sprintf;
use function trait_exists;




class InvalidArgumentException extends BaseInvalidArgumentException implements ExceptionInterface
{
public static function fromNonExistingClass(string $className): self
{
if (interface_exists($className)) {
return new self(sprintf('The provided type "%s" is an interface, and can not be instantiated', $className));
}

if (trait_exists($className)) {
return new self(sprintf('The provided type "%s" is a trait, and can not be instantiated', $className));
}

return new self(sprintf('The provided class "%s" does not exist', $className));
}





public static function fromAbstractClass(ReflectionClass $reflectionClass): self
{
return new self(sprintf(
'The provided class "%s" is abstract, and can not be instantiated',
$reflectionClass->getName()
));
}
}
<?php

namespace Doctrine\Instantiator\Exception;

use Throwable;




interface ExceptionInterface extends Throwable
{
}
<?php

namespace JsonSchema;

use JsonSchema\Constraints\BaseConstraint;
use JsonSchema\Entity\JsonPointer;
use JsonSchema\Exception\UnresolvableJsonPointerException;
use JsonSchema\Uri\UriResolver;
use JsonSchema\Uri\UriRetriever;

class SchemaStorage implements SchemaStorageInterface
{
const INTERNAL_PROVIDED_SCHEMA_URI = 'internal://provided-schema/';

protected $uriRetriever;
protected $uriResolver;
protected $schemas = array();

public function __construct(
UriRetrieverInterface $uriRetriever = null,
UriResolverInterface $uriResolver = null
) {
$this->uriRetriever = $uriRetriever ?: new UriRetriever();
$this->uriResolver = $uriResolver ?: new UriResolver();
}




public function getUriRetriever()
{
return $this->uriRetriever;
}




public function getUriResolver()
{
return $this->uriResolver;
}




public function addSchema($id, $schema = null)
{
if (is_null($schema) && $id !== self::INTERNAL_PROVIDED_SCHEMA_URI) {

 
 
 $schema = $this->uriRetriever->retrieve($id);
}


 if (is_array($schema)) {
$schema = BaseConstraint::arrayToObjectRecursive($schema);
}


 
 if (is_object($schema) && property_exists($schema, 'id')) {
if ($schema->id == 'http://json-schema.org/draft-04/schema#') {
$schema->properties->id->format = 'uri-reference';
} elseif ($schema->id == 'http://json-schema.org/draft-03/schema#') {
$schema->properties->id->format = 'uri-reference';
$schema->properties->{'$ref'}->format = 'uri-reference';
}
}


 $this->expandRefs($schema, $id);

$this->schemas[$id] = $schema;
}







private function expandRefs(&$schema, $base = null)
{
if (!is_object($schema)) {
if (is_array($schema)) {
foreach ($schema as &$member) {
$this->expandRefs($member, $base);
}
}

return;
}

if (property_exists($schema, 'id') && is_string($schema->id) && $base != $schema->id) {
$base = $this->uriResolver->resolve($schema->id, $base);
}

if (property_exists($schema, '$ref') && is_string($schema->{'$ref'})) {
$refPointer = new JsonPointer($this->uriResolver->resolve($schema->{'$ref'}, $base));
$schema->{'$ref'} = (string) $refPointer;
}

foreach ($schema as &$member) {
$this->expandRefs($member, $base);
}
}




public function getSchema($id)
{
if (!array_key_exists($id, $this->schemas)) {
$this->addSchema($id);
}

return $this->schemas[$id];
}




public function resolveRef($ref)
{
$jsonPointer = new JsonPointer($ref);


 $fileName = $jsonPointer->getFilename();
if (!strlen($fileName)) {
throw new UnresolvableJsonPointerException(sprintf(
"Could not resolve fragment '%s': no file is defined",
$jsonPointer->getPropertyPathAsString()
));
}


 $refSchema = $this->getSchema($fileName);
foreach ($jsonPointer->getPropertyPaths() as $path) {
if (is_object($refSchema) && property_exists($refSchema, $path)) {
$refSchema = $this->resolveRefSchema($refSchema->{$path});
} elseif (is_array($refSchema) && array_key_exists($path, $refSchema)) {
$refSchema = $this->resolveRefSchema($refSchema[$path]);
} else {
throw new UnresolvableJsonPointerException(sprintf(
'File: %s is found, but could not resolve fragment: %s',
$jsonPointer->getFilename(),
$jsonPointer->getPropertyPathAsString()
));
}
}

return $refSchema;
}




public function resolveRefSchema($refSchema)
{
if (is_object($refSchema) && property_exists($refSchema, '$ref') && is_string($refSchema->{'$ref'})) {
$newSchema = $this->resolveRef($refSchema->{'$ref'});
$refSchema = (object) (get_object_vars($refSchema) + get_object_vars($newSchema));
unset($refSchema->{'$ref'});
}

return $refSchema;
}
}
<?php

namespace JsonSchema;

interface SchemaStorageInterface
{






public function addSchema($id, $schema = null);








public function getSchema($id);








public function resolveRef($ref);








public function resolveRefSchema($refSchema);
}
<?php








namespace JsonSchema;




interface UriResolverInterface
{








public function resolve($uri, $baseUri = null);
}
<?php








namespace JsonSchema;




interface UriRetrieverInterface
{








public function retrieve($uri, $baseUri = null);
}
<?php








namespace JsonSchema\Entity;

use JsonSchema\Exception\InvalidArgumentException;






class JsonPointer
{

private $filename;


private $propertyPaths = array();




private $fromDefault = false;






public function __construct($value)
{
if (!is_string($value)) {
throw new InvalidArgumentException('Ref value must be a string');
}

$splitRef = explode('#', $value, 2);
$this->filename = $splitRef[0];
if (array_key_exists(1, $splitRef)) {
$this->propertyPaths = $this->decodePropertyPaths($splitRef[1]);
}
}






private function decodePropertyPaths($propertyPathString)
{
$paths = array();
foreach (explode('/', trim($propertyPathString, '/')) as $path) {
$path = $this->decodePath($path);
if (is_string($path) && '' !== $path) {
$paths[] = $path;
}
}

return $paths;
}




private function encodePropertyPaths()
{
return array_map(
array($this, 'encodePath'),
$this->getPropertyPaths()
);
}






private function decodePath($path)
{
return strtr($path, array('~1' => '/', '~0' => '~', '%25' => '%'));
}






private function encodePath($path)
{
return strtr($path, array('/' => '~1', '~' => '~0', '%' => '%25'));
}




public function getFilename()
{
return $this->filename;
}




public function getPropertyPaths()
{
return $this->propertyPaths;
}






public function withPropertyPaths(array $propertyPaths)
{
$new = clone $this;
$new->propertyPaths = $propertyPaths;

return $new;
}




public function getPropertyPathAsString()
{
return rtrim('#/' . implode('/', $this->encodePropertyPaths()), '/');
}




public function __toString()
{
return $this->getFilename() . $this->getPropertyPathAsString();
}




public function setFromDefault()
{
$this->fromDefault = true;
}






public function fromDefault()
{
return $this->fromDefault;
}
}
<?php








namespace JsonSchema\Uri;

use JsonSchema\Exception\InvalidSchemaMediaTypeException;
use JsonSchema\Exception\JsonDecodingException;
use JsonSchema\Exception\ResourceNotFoundException;
use JsonSchema\Uri\Retrievers\FileGetContents;
use JsonSchema\Uri\Retrievers\UriRetrieverInterface;
use JsonSchema\UriRetrieverInterface as BaseUriRetrieverInterface;
use JsonSchema\Validator;






class UriRetriever implements BaseUriRetrieverInterface
{



protected $translationMap = array(

 '|^https?://json-schema.org/draft-(0[34])/schema#?|' => 'package://dist/schema/json-schema-draft-$1.json'
);




protected $allowedInvalidContentTypeEndpoints = array(
'http://json-schema.org/',
'https://json-schema.org/'
);




protected $uriRetriever = null;






private $schemaCache = array();






public function addInvalidContentTypeEndpoint($endpoint)
{
$this->allowedInvalidContentTypeEndpoints[] = $endpoint;
}









public function confirmMediaType($uriRetriever, $uri)
{
$contentType = $uriRetriever->getContentType();

if (is_null($contentType)) {

 return;
}

if (in_array($contentType, array(Validator::SCHEMA_MEDIA_TYPE, 'application/json'))) {
return;
}

foreach ($this->allowedInvalidContentTypeEndpoints as $endpoint) {
if (strpos($uri, $endpoint) === 0) {
return true;
}
}

throw new InvalidSchemaMediaTypeException(sprintf('Media type %s expected', Validator::SCHEMA_MEDIA_TYPE));
}









public function getUriRetriever()
{
if (is_null($this->uriRetriever)) {
$this->setUriRetriever(new FileGetContents());
}

return $this->uriRetriever;
}















public function resolvePointer($jsonSchema, $uri)
{
$resolver = new UriResolver();
$parsed = $resolver->parse($uri);
if (empty($parsed['fragment'])) {
return $jsonSchema;
}

$path = explode('/', $parsed['fragment']);
while ($path) {
$pathElement = array_shift($path);
if (!empty($pathElement)) {
$pathElement = str_replace('~1', '/', $pathElement);
$pathElement = str_replace('~0', '~', $pathElement);
if (!empty($jsonSchema->$pathElement)) {
$jsonSchema = $jsonSchema->$pathElement;
} else {
throw new ResourceNotFoundException(
'Fragment "' . $parsed['fragment'] . '" not found'
. ' in ' . $uri
);
}

if (!is_object($jsonSchema)) {
throw new ResourceNotFoundException(
'Fragment part "' . $pathElement . '" is no object '
. ' in ' . $uri
);
}
}
}

return $jsonSchema;
}




public function retrieve($uri, $baseUri = null, $translate = true)
{
$resolver = new UriResolver();
$resolvedUri = $fetchUri = $resolver->resolve($uri, $baseUri);


 $arParts = $resolver->parse($resolvedUri);
if (isset($arParts['fragment'])) {
unset($arParts['fragment']);
$fetchUri = $resolver->generate($arParts);
}


 if ($translate) {
$fetchUri = $this->translate($fetchUri);
}

$jsonSchema = $this->loadSchema($fetchUri);


 $jsonSchema = $this->resolvePointer($jsonSchema, $resolvedUri);

if ($jsonSchema instanceof \stdClass) {
$jsonSchema->id = $resolvedUri;
}

return $jsonSchema;
}









protected function loadSchema($fetchUri)
{
if (isset($this->schemaCache[$fetchUri])) {
return $this->schemaCache[$fetchUri];
}

$uriRetriever = $this->getUriRetriever();
$contents = $this->uriRetriever->retrieve($fetchUri);
$this->confirmMediaType($uriRetriever, $fetchUri);
$jsonSchema = json_decode($contents);

if (JSON_ERROR_NONE < $error = json_last_error()) {
throw new JsonDecodingException($error);
}

$this->schemaCache[$fetchUri] = $jsonSchema;

return $jsonSchema;
}








public function setUriRetriever(UriRetrieverInterface $uriRetriever)
{
$this->uriRetriever = $uriRetriever;

return $this;
}








public function parse($uri)
{
preg_match('|^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?|', $uri, $match);

$components = array();
if (5 < count($match)) {
$components = array(
'scheme' => $match[2],
'authority' => $match[4],
'path' => $match[5]
);
}

if (7 < count($match)) {
$components['query'] = $match[7];
}

if (9 < count($match)) {
$components['fragment'] = $match[9];
}

return $components;
}








public function generate(array $components)
{
$uri = $components['scheme'] . '://'
. $components['authority']
. $components['path'];

if (array_key_exists('query', $components)) {
$uri .= $components['query'];
}

if (array_key_exists('fragment', $components)) {
$uri .= $components['fragment'];
}

return $uri;
}









public function resolve($uri, $baseUri = null)
{
$components = $this->parse($uri);
$path = $components['path'];

if ((array_key_exists('scheme', $components)) && ('http' === $components['scheme'])) {
return $uri;
}

$baseComponents = $this->parse($baseUri);
$basePath = $baseComponents['path'];

$baseComponents['path'] = UriResolver::combineRelativePathWithBasePath($path, $basePath);

return $this->generate($baseComponents);
}






public function isValid($uri)
{
$components = $this->parse($uri);

return !empty($components);
}




public function setTranslation($from, $to)
{
$this->translationMap[$from] = $to;
}




public function translate($uri)
{
foreach ($this->translationMap as $from => $to) {
$uri = preg_replace($from, $to, $uri);
}


 $uri = preg_replace('|^package://|', sprintf('file://%s/', realpath(__DIR__ . '/../../..')), $uri);

return $uri;
}
}
<?php








namespace JsonSchema\Uri;

use JsonSchema\Exception\UriResolverException;
use JsonSchema\UriResolverInterface;






class UriResolver implements UriResolverInterface
{







public function parse($uri)
{
preg_match('|^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?|', $uri, $match);

$components = array();
if (5 < count($match)) {
$components = array(
'scheme' => $match[2],
'authority' => $match[4],
'path' => $match[5]
);
}
if (7 < count($match)) {
$components['query'] = $match[7];
}
if (9 < count($match)) {
$components['fragment'] = $match[9];
}

return $components;
}








public function generate(array $components)
{
$uri = $components['scheme'] . '://'
. $components['authority']
. $components['path'];

if (array_key_exists('query', $components) && strlen($components['query'])) {
$uri .= '?' . $components['query'];
}
if (array_key_exists('fragment', $components)) {
$uri .= '#' . $components['fragment'];
}

return $uri;
}




public function resolve($uri, $baseUri = null)
{

 if (
!is_null($baseUri) &&
!filter_var($baseUri, \FILTER_VALIDATE_URL) &&
!preg_match('|^[^/]+://|u', $baseUri)
) {
if (is_file($baseUri)) {
$baseUri = 'file://' . realpath($baseUri);
} elseif (is_dir($baseUri)) {
$baseUri = 'file://' . realpath($baseUri) . '/';
} else {
$baseUri = 'file://' . getcwd() . '/' . $baseUri;
}
}

if ($uri == '') {
return $baseUri;
}

$components = $this->parse($uri);
$path = $components['path'];

if (!empty($components['scheme'])) {
return $uri;
}
$baseComponents = $this->parse($baseUri);
$basePath = $baseComponents['path'];

$baseComponents['path'] = self::combineRelativePathWithBasePath($path, $basePath);
if (isset($components['fragment'])) {
$baseComponents['fragment'] = $components['fragment'];
}

return $this->generate($baseComponents);
}











public static function combineRelativePathWithBasePath($relativePath, $basePath)
{
$relativePath = self::normalizePath($relativePath);
if ($relativePath == '') {
return $basePath;
}
if ($relativePath[0] == '/') {
return $relativePath;
}

$basePathSegments = explode('/', $basePath);

preg_match('|^/?(\.\./(?:\./)*)*|', $relativePath, $match);
$numLevelUp = strlen($match[0]) /3 + 1;
if ($numLevelUp >= count($basePathSegments)) {
throw new UriResolverException(sprintf("Unable to resolve URI '%s' from base '%s'", $relativePath, $basePath));
}

$basePathSegments = array_slice($basePathSegments, 0, -$numLevelUp);
$path = preg_replace('|^/?(\.\./(\./)*)*|', '', $relativePath);

return implode('/', $basePathSegments) . '/' . $path;
}








private static function normalizePath($path)
{
$path = preg_replace('|((?<!\.)\./)*|', '', $path);
$path = preg_replace('|//|', '/', $path);

return $path;
}






public function isValid($uri)
{
$components = $this->parse($uri);

return !empty($components);
}
}
<?php






namespace JsonSchema\Uri\Retrievers;







abstract class AbstractRetriever implements UriRetrieverInterface
{





protected $contentType;






public function getContentType()
{
return $this->contentType;
}
}
<?php








namespace JsonSchema\Uri\Retrievers;

use JsonSchema\Exception\ResourceNotFoundException;






class FileGetContents extends AbstractRetriever
{
protected $messageBody;






public function retrieve($uri)
{
$errorMessage = null;
set_error_handler(function ($errno, $errstr) use (&$errorMessage) {
$errorMessage = $errstr;
});
$response = file_get_contents($uri);
restore_error_handler();

if ($errorMessage) {
throw new ResourceNotFoundException($errorMessage);
}

if (false === $response) {
throw new ResourceNotFoundException('JSON schema not found at ' . $uri);
}

if ($response == ''
&& substr($uri, 0, 7) == 'file://' && substr($uri, -1) == '/'
) {
throw new ResourceNotFoundException('JSON schema not found at ' . $uri);
}

$this->messageBody = $response;
if (!empty($http_response_header)) {

 
 $this->fetchContentType($http_response_header); 
 } else { 
 
 $this->contentType = null;
}

return $this->messageBody;
}






private function fetchContentType(array $headers)
{
foreach ($headers as $header) {
if ($this->contentType = self::getContentTypeMatchInHeader($header)) {
return true;
}
}

return false;
}






protected static function getContentTypeMatchInHeader($header)
{
if (0 < preg_match("/Content-Type:(\V*)/ims", $header, $match)) {
return trim($match[1]);
}

return null;
}
}
<?php








namespace JsonSchema\Uri\Retrievers;

use JsonSchema\Exception\RuntimeException;
use JsonSchema\Validator;






class Curl extends AbstractRetriever
{
protected $messageBody;

public function __construct()
{
if (!function_exists('curl_init')) {

 throw new RuntimeException('cURL not installed'); 
 }
}






public function retrieve($uri)
{
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $uri);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: ' . Validator::SCHEMA_MEDIA_TYPE));

$response = curl_exec($ch);
if (false === $response) {
throw new \JsonSchema\Exception\ResourceNotFoundException('JSON schema not found');
}

$this->fetchMessageBody($response);
$this->fetchContentType($response);

curl_close($ch);

return $this->messageBody;
}




private function fetchMessageBody($response)
{
preg_match("/(?:\r\n){2}(.*)$/ms", $response, $match);
$this->messageBody = $match[1];
}






protected function fetchContentType($response)
{
if (0 < preg_match("/Content-Type:(\V*)/ims", $response, $match)) {
$this->contentType = trim($match[1]);

return true;
}

return false;
}
}
<?php

namespace JsonSchema\Uri\Retrievers;

use JsonSchema\Validator;













class PredefinedArray extends AbstractRetriever
{





private $schemas;







public function __construct(array $schemas, $contentType = Validator::SCHEMA_MEDIA_TYPE)
{
$this->schemas = $schemas;
$this->contentType = $contentType;
}






public function retrieve($uri)
{
if (!array_key_exists($uri, $this->schemas)) {
throw new \JsonSchema\Exception\ResourceNotFoundException(sprintf(
'The JSON schema "%s" was not found.',
$uri
));
}

return $this->schemas[$uri];
}
}
<?php








namespace JsonSchema\Uri\Retrievers;






interface UriRetrieverInterface
{









public function retrieve($uri);






public function getContentType();
}
<?php

namespace JsonSchema;

class Rfc3339
{
const REGEX = '/^(\d{4}-\d{2}-\d{2}[T ]{1}\d{2}:\d{2}:\d{2})(\.\d+)?(Z|([+-]\d{2}):?(\d{2}))$/';








public static function createFromString($string)
{
if (!preg_match(self::REGEX, strtoupper($string), $matches)) {
return null;
}

$dateAndTime = $matches[1];
$microseconds = $matches[2] ?: '.000000';
$timeZone = 'Z' !== $matches[3] ? $matches[4] . ':' . $matches[5] : '+00:00';
$dateFormat = strpos($dateAndTime, 'T') === false ? 'Y-m-d H:i:s.uP' : 'Y-m-d\TH:i:s.uP';
$dateTime = \DateTime::createFromFormat($dateFormat, $dateAndTime . $microseconds . $timeZone, new \DateTimeZone('UTC'));

return $dateTime ?: null;
}
}
<?php








namespace JsonSchema\Iterator;






class ObjectIterator implements \Iterator, \Countable
{

private $object;


private $position = 0;


private $data = array();


private $initialized = false;




public function __construct($object)
{
$this->object = $object;
}




public function current()
{
$this->initialize();

return $this->data[$this->position];
}




public function next()
{
$this->initialize();
$this->position++;
}




public function key()
{
$this->initialize();

return $this->position;
}




public function valid()
{
$this->initialize();

return isset($this->data[$this->position]);
}




public function rewind()
{
$this->initialize();
$this->position = 0;
}




public function count()
{
$this->initialize();

return count($this->data);
}




private function initialize()
{
if (!$this->initialized) {
$this->data = $this->buildDataFromObject($this->object);
$this->initialized = true;
}
}






private function buildDataFromObject($object)
{
$result = array();

$stack = new \SplStack();
$stack->push($object);

while (!$stack->isEmpty()) {
$current = $stack->pop();
if (is_object($current)) {
array_push($result, $current);
}

foreach ($this->getDataFromItem($current) as $propertyName => $propertyValue) {
if (is_object($propertyValue) || is_array($propertyValue)) {
$stack->push($propertyValue);
}
}
}

return $result;
}






private function getDataFromItem($item)
{
if (!is_object($item) && !is_array($item)) {
return array();
}

return is_object($item) ? get_object_vars($item) : $item;
}
}
<?php

namespace JsonSchema\Constraints\TypeCheck;

class LooseTypeCheck implements TypeCheckInterface
{
public static function isObject($value)
{
return
is_object($value) ||
(is_array($value) && (count($value) == 0 || self::isAssociativeArray($value)));
}

public static function isArray($value)
{
return
is_array($value) &&
(count($value) == 0 || !self::isAssociativeArray($value));
}

public static function propertyGet($value, $property)
{
if (is_object($value)) {
return $value->{$property};
}

return $value[$property];
}

public static function propertySet(&$value, $property, $data)
{
if (is_object($value)) {
$value->{$property} = $data;
} else {
$value[$property] = $data;
}
}

public static function propertyExists($value, $property)
{
if (is_object($value)) {
return property_exists($value, $property);
}

return array_key_exists($property, $value);
}

public static function propertyCount($value)
{
if (is_object($value)) {
return count(get_object_vars($value));
}

return count($value);
}








private static function isAssociativeArray($arr)
{
return array_keys($arr) !== range(0, count($arr) - 1);
}
}
<?php

namespace JsonSchema\Constraints\TypeCheck;

class StrictTypeCheck implements TypeCheckInterface
{
public static function isObject($value)
{
return is_object($value);
}

public static function isArray($value)
{
return is_array($value);
}

public static function propertyGet($value, $property)
{
return $value->{$property};
}

public static function propertySet(&$value, $property, $data)
{
$value->{$property} = $data;
}

public static function propertyExists($value, $property)
{
return property_exists($value, $property);
}

public static function propertyCount($value)
{
if (!is_object($value)) {
return 0;
}

return count(get_object_vars($value));
}
}
<?php

namespace JsonSchema\Constraints\TypeCheck;

interface TypeCheckInterface
{
public static function isObject($value);

public static function isArray($value);

public static function propertyGet($value, $property);

public static function propertySet(&$value, $property, $data);

public static function propertyExists($value, $property);

public static function propertyCount($value);
}
<?php








namespace JsonSchema\Constraints;

use JsonSchema\Constraints\TypeCheck\LooseTypeCheck;
use JsonSchema\Entity\JsonPointer;
use JsonSchema\Exception\ValidationException;
use JsonSchema\Uri\UriResolver;







class UndefinedConstraint extends Constraint
{



protected $appliedDefaults = array();




public function check(&$value, $schema = null, JsonPointer $path = null, $i = null, $fromDefault = false)
{
if (is_null($schema) || !is_object($schema)) {
return;
}

$path = $this->incrementPath($path ?: new JsonPointer(''), $i);
if ($fromDefault) {
$path->setFromDefault();
}


 $this->validateCommonProperties($value, $schema, $path, $i);


 $this->validateOfProperties($value, $schema, $path, '');


 $this->validateTypes($value, $schema, $path, $i);
}









public function validateTypes(&$value, $schema, JsonPointer $path, $i = null)
{

 if ($this->getTypeCheck()->isArray($value)) {
$this->checkArray($value, $schema, $path, $i);
}


 if (LooseTypeCheck::isObject($value)) { 
 
 
 $this->checkObject(
$value,
$schema,
$path,
isset($schema->properties) ? $schema->properties : null,
isset($schema->additionalProperties) ? $schema->additionalProperties : null,
isset($schema->patternProperties) ? $schema->patternProperties : null,
$this->appliedDefaults
);
}


 if (is_string($value)) {
$this->checkString($value, $schema, $path, $i);
}


 if (is_numeric($value)) {
$this->checkNumber($value, $schema, $path, $i);
}


 if (isset($schema->enum)) {
$this->checkEnum($value, $schema, $path, $i);
}
}









protected function validateCommonProperties(&$value, $schema, JsonPointer $path, $i = '')
{

 if (isset($schema->extends)) {
if (is_string($schema->extends)) {
$schema->extends = $this->validateUri($schema, $schema->extends);
}
if (is_array($schema->extends)) {
foreach ($schema->extends as $extends) {
$this->checkUndefined($value, $extends, $path, $i);
}
} else {
$this->checkUndefined($value, $schema->extends, $path, $i);
}
}


 if (!$path->fromDefault()) {
$this->applyDefaultValues($value, $schema, $path);
}


 if ($this->getTypeCheck()->isObject($value)) {
if (!($value instanceof self) && isset($schema->required) && is_array($schema->required)) {

 foreach ($schema->required as $required) {
if (!$this->getTypeCheck()->propertyExists($value, $required)) {
$this->addError(
$this->incrementPath($path ?: new JsonPointer(''), $required),
'The property ' . $required . ' is required',
'required'
);
}
}
} elseif (isset($schema->required) && !is_array($schema->required)) {

 if ($schema->required && $value instanceof self) {
$propertyPaths = $path->getPropertyPaths();
$propertyName = end($propertyPaths);
$this->addError(
$path,
'The property ' . $propertyName . ' is required',
'required'
);
}
} else {

 
 if ($value instanceof self) {
return;
}
}
}


 if (!($value instanceof self)) {
$this->checkType($value, $schema, $path, $i);
}


 if (isset($schema->disallow)) {
$initErrors = $this->getErrors();

$typeSchema = new \stdClass();
$typeSchema->type = $schema->disallow;
$this->checkType($value, $typeSchema, $path);


 if (count($this->getErrors()) == count($initErrors)) {
$this->addError($path, 'Disallowed value was matched', 'disallow');
} else {
$this->errors = $initErrors;
}
}

if (isset($schema->not)) {
$initErrors = $this->getErrors();
$this->checkUndefined($value, $schema->not, $path, $i);


 if (count($this->getErrors()) == count($initErrors)) {
$this->addError($path, 'Matched a schema which it should not', 'not');
} else {
$this->errors = $initErrors;
}
}


 if (isset($schema->dependencies) && $this->getTypeCheck()->isObject($value)) {
$this->validateDependencies($value, $schema->dependencies, $path);
}
}










private function shouldApplyDefaultValue($requiredOnly, $schema, $name = null, $parentSchema = null)
{

 if (!$requiredOnly) {
return true;
}

 if (
$name !== null
&& isset($parentSchema->required)
&& is_array($parentSchema->required)
&& in_array($name, $parentSchema->required)
) {
return true;
}

 if (isset($schema->required) && !is_array($schema->required) && $schema->required) {
return true;
}

 return false;
}








protected function applyDefaultValues(&$value, $schema, $path)
{

 if (!$this->factory->getConfig(self::CHECK_MODE_APPLY_DEFAULTS)) {
return;
}


 $requiredOnly = $this->factory->getConfig(self::CHECK_MODE_ONLY_REQUIRED_DEFAULTS);
if (isset($schema->properties) && LooseTypeCheck::isObject($value)) {

 foreach ($schema->properties as $currentProperty => $propertyDefinition) {
$propertyDefinition = $this->factory->getSchemaStorage()->resolveRefSchema($propertyDefinition);
if (
!LooseTypeCheck::propertyExists($value, $currentProperty)
&& property_exists($propertyDefinition, 'default')
&& $this->shouldApplyDefaultValue($requiredOnly, $propertyDefinition, $currentProperty, $schema)
) {

 if (is_object($propertyDefinition->default)) {
LooseTypeCheck::propertySet($value, $currentProperty, clone $propertyDefinition->default);
} else {
LooseTypeCheck::propertySet($value, $currentProperty, $propertyDefinition->default);
}
$this->appliedDefaults[] = $currentProperty;
}
}
} elseif (isset($schema->items) && LooseTypeCheck::isArray($value)) {
$items = array();
if (LooseTypeCheck::isArray($schema->items)) {
$items = $schema->items;
} elseif (isset($schema->minItems) && count($value) < $schema->minItems) {
$items = array_fill(count($value), $schema->minItems - count($value), $schema->items);
}

 foreach ($items as $currentItem => $itemDefinition) {
$itemDefinition = $this->factory->getSchemaStorage()->resolveRefSchema($itemDefinition);
if (
!array_key_exists($currentItem, $value)
&& property_exists($itemDefinition, 'default')
&& $this->shouldApplyDefaultValue($requiredOnly, $itemDefinition)) {
if (is_object($itemDefinition->default)) {
$value[$currentItem] = clone $itemDefinition->default;
} else {
$value[$currentItem] = $itemDefinition->default;
}
}
$path->setFromDefault();
}
} elseif (
$value instanceof self
&& property_exists($schema, 'default')
&& $this->shouldApplyDefaultValue($requiredOnly, $schema)) {

 $value = is_object($schema->default) ? clone $schema->default : $schema->default;
$path->setFromDefault();
}
}









protected function validateOfProperties(&$value, $schema, JsonPointer $path, $i = '')
{

 if ($value instanceof self) {
return;
}

if (isset($schema->allOf)) {
$isValid = true;
foreach ($schema->allOf as $allOf) {
$initErrors = $this->getErrors();
$this->checkUndefined($value, $allOf, $path, $i);
$isValid = $isValid && (count($this->getErrors()) == count($initErrors));
}
if (!$isValid) {
$this->addError($path, 'Failed to match all schemas', 'allOf');
}
}

if (isset($schema->anyOf)) {
$isValid = false;
$startErrors = $this->getErrors();
$caughtException = null;
foreach ($schema->anyOf as $anyOf) {
$initErrors = $this->getErrors();
try {
$this->checkUndefined($value, $anyOf, $path, $i);
if ($isValid = (count($this->getErrors()) == count($initErrors))) {
break;
}
} catch (ValidationException $e) {
$isValid = false;
}
}
if (!$isValid) {
$this->addError($path, 'Failed to match at least one schema', 'anyOf');
} else {
$this->errors = $startErrors;
}
}

if (isset($schema->oneOf)) {
$allErrors = array();
$matchedSchemas = 0;
$startErrors = $this->getErrors();
foreach ($schema->oneOf as $oneOf) {
try {
$this->errors = array();
$this->checkUndefined($value, $oneOf, $path, $i);
if (count($this->getErrors()) == 0) {
$matchedSchemas++;
}
$allErrors = array_merge($allErrors, array_values($this->getErrors()));
} catch (ValidationException $e) {

 
 }
}
if ($matchedSchemas !== 1) {
$this->addErrors(array_merge($allErrors, $startErrors));
$this->addError($path, 'Failed to match exactly one schema', 'oneOf');
} else {
$this->errors = $startErrors;
}
}
}









protected function validateDependencies($value, $dependencies, JsonPointer $path, $i = '')
{
foreach ($dependencies as $key => $dependency) {
if ($this->getTypeCheck()->propertyExists($value, $key)) {
if (is_string($dependency)) {

 if (!$this->getTypeCheck()->propertyExists($value, $dependency)) {
$this->addError($path, "$key depends on $dependency and $dependency is missing", 'dependencies');
}
} elseif (is_array($dependency)) {

 foreach ($dependency as $d) {
if (!$this->getTypeCheck()->propertyExists($value, $d)) {
$this->addError($path, "$key depends on $d and $d is missing", 'dependencies');
}
}
} elseif (is_object($dependency)) {

 $this->checkUndefined($value, $dependency, $path, $i);
}
}
}
}

protected function validateUri($schema, $schemaUri = null)
{
$resolver = new UriResolver();
$retriever = $this->factory->getUriRetriever();

$jsonSchema = null;
if ($resolver->isValid($schemaUri)) {
$schemaId = property_exists($schema, 'id') ? $schema->id : null;
$jsonSchema = $retriever->retrieve($schemaId, $schemaUri);
}

return $jsonSchema;
}
}
<?php








namespace JsonSchema\Constraints;

use JsonSchema\Entity\JsonPointer;
use JsonSchema\Exception\InvalidArgumentException;
use JsonSchema\Exception\ValidationException;
use JsonSchema\Validator;





class BaseConstraint
{



protected $errors = array();




protected $errorMask = Validator::ERROR_NONE;




protected $factory;




public function __construct(Factory $factory = null)
{
$this->factory = $factory ?: new Factory();
}

public function addError(JsonPointer $path = null, $message, $constraint = '', array $more = null)
{
$error = array(
'property' => $this->convertJsonPointerIntoPropertyPath($path ?: new JsonPointer('')),
'pointer' => ltrim(strval($path ?: new JsonPointer('')), '#'),
'message' => $message,
'constraint' => $constraint,
'context' => $this->factory->getErrorContext(),
);

if ($this->factory->getConfig(Constraint::CHECK_MODE_EXCEPTIONS)) {
throw new ValidationException(sprintf('Error validating %s: %s', $error['pointer'], $error['message']));
}

if (is_array($more) && count($more) > 0) {
$error += $more;
}

$this->errors[] = $error;
$this->errorMask |= $error['context'];
}

public function addErrors(array $errors)
{
if ($errors) {
$this->errors = array_merge($this->errors, $errors);
$errorMask = &$this->errorMask;
array_walk($errors, function ($error) use (&$errorMask) {
if (isset($error['context'])) {
$errorMask |= $error['context'];
}
});
}
}

public function getErrors($errorContext = Validator::ERROR_ALL)
{
if ($errorContext === Validator::ERROR_ALL) {
return $this->errors;
}

return array_filter($this->errors, function ($error) use ($errorContext) {
if ($errorContext & $error['context']) {
return true;
}
});
}

public function numErrors($errorContext = Validator::ERROR_ALL)
{
if ($errorContext === Validator::ERROR_ALL) {
return count($this->errors);
}

return count($this->getErrors($errorContext));
}

public function isValid()
{
return !$this->getErrors();
}





public function reset()
{
$this->errors = array();
$this->errorMask = Validator::ERROR_NONE;
}






public function getErrorMask()
{
return $this->errorMask;
}








public static function arrayToObjectRecursive($array)
{
$json = json_encode($array);
if (json_last_error() !== \JSON_ERROR_NONE) {
$message = 'Unable to encode schema array as JSON';
if (function_exists('json_last_error_msg')) {
$message .= ': ' . json_last_error_msg();
}
throw new InvalidArgumentException($message);
}

return (object) json_decode($json);
}
}
<?php








namespace JsonSchema\Constraints;

use JsonSchema\Entity\JsonPointer;







class EnumConstraint extends Constraint
{



public function check(&$element, $schema = null, JsonPointer $path = null, $i = null)
{

 if ($element instanceof UndefinedConstraint && (!isset($schema->required) || !$schema->required)) {
return;
}
$type = gettype($element);

foreach ($schema->enum as $enum) {
$enumType = gettype($enum);
if ($this->factory->getConfig(self::CHECK_MODE_TYPE_CAST) && $type == 'array' && $enumType == 'object') {
if ((object) $element == $enum) {
return;
}
}

if ($type === gettype($enum)) {
if ($type == 'object') {
if ($element == $enum) {
return;
}
} elseif ($element === $enum) {
return;
}
}
}

$this->addError($path, 'Does not have a value in the enumeration ' . json_encode($schema->enum), 'enum', array('enum' => $schema->enum));
}
}
<?php








namespace JsonSchema\Constraints;

use JsonSchema\Entity\JsonPointer;







class ObjectConstraint extends Constraint
{



protected $appliedDefaults = array();




public function check(&$element, $schema = null, JsonPointer $path = null, $properties = null,
$additionalProp = null, $patternProperties = null, $appliedDefaults = array())
{
if ($element instanceof UndefinedConstraint) {
return;
}

$this->appliedDefaults = $appliedDefaults;

$matches = array();
if ($patternProperties) {

 $matches = $this->validatePatternProperties($element, $path, $patternProperties);
}

if ($properties) {

 $this->validateProperties($element, $properties, $path);
}


 $this->validateElement($element, $matches, $schema, $path, $properties, $additionalProp);
}

public function validatePatternProperties($element, JsonPointer $path = null, $patternProperties)
{
$try = array('/', '#', '+', '~', '%');
$matches = array();
foreach ($patternProperties as $pregex => $schema) {
$delimiter = '/';

 foreach ($try as $delimiter) {
if (strpos($pregex, $delimiter) === false) { 
 break;
}
}


 if (@preg_match($delimiter . $pregex . $delimiter . 'u', '') === false) {
$this->addError($path, 'The pattern "' . $pregex . '" is invalid', 'pregex', array('pregex' => $pregex));
continue;
}
foreach ($element as $i => $value) {
if (preg_match($delimiter . $pregex . $delimiter . 'u', $i)) {
$matches[] = $i;
$this->checkUndefined($value, $schema ?: new \stdClass(), $path, $i, in_array($i, $this->appliedDefaults));
}
}
}

return $matches;
}











public function validateElement($element, $matches, $schema = null, JsonPointer $path = null,
$properties = null, $additionalProp = null)
{
$this->validateMinMaxConstraint($element, $schema, $path);

foreach ($element as $i => $value) {
$definition = $this->getProperty($properties, $i);


 if (!in_array($i, $matches) && $additionalProp === false && $this->inlineSchemaProperty !== $i && !$definition) {
$this->addError($path, 'The property ' . $i . ' is not defined and the definition does not allow additional properties', 'additionalProp');
}


 if (!in_array($i, $matches) && $additionalProp && !$definition) {
if ($additionalProp === true) {
$this->checkUndefined($value, null, $path, $i, in_array($i, $this->appliedDefaults));
} else {
$this->checkUndefined($value, $additionalProp, $path, $i, in_array($i, $this->appliedDefaults));
}
}


 $require = $this->getProperty($definition, 'requires');
if ($require && !$this->getProperty($element, $require)) {
$this->addError($path, 'The presence of the property ' . $i . ' requires that ' . $require . ' also be present', 'requires');
}

$property = $this->getProperty($element, $i, $this->factory->createInstanceFor('undefined'));
if (is_object($property)) {
$this->validateMinMaxConstraint(!($property instanceof UndefinedConstraint) ? $property : $element, $definition, $path);
}
}
}








public function validateProperties(&$element, $properties = null, JsonPointer $path = null)
{
$undefinedConstraint = $this->factory->createInstanceFor('undefined');

foreach ($properties as $i => $value) {
$property = &$this->getProperty($element, $i, $undefinedConstraint);
$definition = $this->getProperty($properties, $i);

if (is_object($definition)) {

 $this->checkUndefined($property, $definition, $path, $i, in_array($i, $this->appliedDefaults));
}
}
}










protected function &getProperty(&$element, $property, $fallback = null)
{
if (is_array($element) && (isset($element[$property]) || array_key_exists($property, $element)) ) {
return $element[$property];
} elseif (is_object($element) && property_exists($element, $property)) {
return $element->$property;
}

return $fallback;
}








protected function validateMinMaxConstraint($element, $objectDefinition, JsonPointer $path = null)
{

 if (isset($objectDefinition->minProperties) && !is_object($objectDefinition->minProperties)) {
if ($this->getTypeCheck()->propertyCount($element) < $objectDefinition->minProperties) {
$this->addError($path, 'Must contain a minimum of ' . $objectDefinition->minProperties . ' properties', 'minProperties', array('minProperties' => $objectDefinition->minProperties));
}
}

 if (isset($objectDefinition->maxProperties) && !is_object($objectDefinition->maxProperties)) {
if ($this->getTypeCheck()->propertyCount($element) > $objectDefinition->maxProperties) {
$this->addError($path, 'Must contain no more than ' . $objectDefinition->maxProperties . ' properties', 'maxProperties', array('maxProperties' => $objectDefinition->maxProperties));
}
}
}
}
<?php








namespace JsonSchema\Constraints;

use JsonSchema\Exception\InvalidArgumentException;
use JsonSchema\SchemaStorage;
use JsonSchema\SchemaStorageInterface;
use JsonSchema\Uri\UriRetriever;
use JsonSchema\UriRetrieverInterface;
use JsonSchema\Validator;




class Factory
{



protected $schemaStorage;




protected $uriRetriever;




private $checkMode = Constraint::CHECK_MODE_NORMAL;




private $typeCheck = array();




protected $errorContext = Validator::ERROR_DOCUMENT_VALIDATION;




protected $constraintMap = array(
'array' => 'JsonSchema\Constraints\CollectionConstraint',
'collection' => 'JsonSchema\Constraints\CollectionConstraint',
'object' => 'JsonSchema\Constraints\ObjectConstraint',
'type' => 'JsonSchema\Constraints\TypeConstraint',
'undefined' => 'JsonSchema\Constraints\UndefinedConstraint',
'string' => 'JsonSchema\Constraints\StringConstraint',
'number' => 'JsonSchema\Constraints\NumberConstraint',
'enum' => 'JsonSchema\Constraints\EnumConstraint',
'format' => 'JsonSchema\Constraints\FormatConstraint',
'schema' => 'JsonSchema\Constraints\SchemaConstraint',
'validator' => 'JsonSchema\Validator'
);




private $instanceCache = array();






public function __construct(
SchemaStorageInterface $schemaStorage = null,
UriRetrieverInterface $uriRetriever = null,
$checkMode = Constraint::CHECK_MODE_NORMAL
) {

 $this->setConfig($checkMode);

$this->uriRetriever = $uriRetriever ?: new UriRetriever();
$this->schemaStorage = $schemaStorage ?: new SchemaStorage($this->uriRetriever);
}






public function setConfig($checkMode = Constraint::CHECK_MODE_NORMAL)
{
$this->checkMode = $checkMode;
}






public function addConfig($options)
{
$this->checkMode |= $options;
}






public function removeConfig($options)
{
$this->checkMode &= ~$options;
}








public function getConfig($options = null)
{
if ($options === null) {
return $this->checkMode;
}

return $this->checkMode & $options;
}




public function getUriRetriever()
{
return $this->uriRetriever;
}

public function getSchemaStorage()
{
return $this->schemaStorage;
}

public function getTypeCheck()
{
if (!isset($this->typeCheck[$this->checkMode])) {
$this->typeCheck[$this->checkMode] = ($this->checkMode & Constraint::CHECK_MODE_TYPE_CAST)
? new TypeCheck\LooseTypeCheck()
: new TypeCheck\StrictTypeCheck();
}

return $this->typeCheck[$this->checkMode];
}







public function setConstraintClass($name, $class)
{

 if (!class_exists($class)) {
throw new InvalidArgumentException('Unknown constraint ' . $name);
}

 if (!in_array('JsonSchema\Constraints\ConstraintInterface', class_implements($class))) {
throw new InvalidArgumentException('Invalid class ' . $name);
}
$this->constraintMap[$name] = $class;

return $this;
}










public function createInstanceFor($constraintName)
{
if (!isset($this->constraintMap[$constraintName])) {
throw new InvalidArgumentException('Unknown constraint ' . $constraintName);
}

if (!isset($this->instanceCache[$constraintName])) {
$this->instanceCache[$constraintName] = new $this->constraintMap[$constraintName]($this);
}

return clone $this->instanceCache[$constraintName];
}






public function getErrorContext()
{
return $this->errorContext;
}






public function setErrorContext($errorContext)
{
$this->errorContext = $errorContext;
}
}
<?php








namespace JsonSchema\Constraints;

use JsonSchema\Entity\JsonPointer;






interface ConstraintInterface
{





public function getErrors();






public function addErrors(array $errors);









public function addError(JsonPointer $path = null, $message, $constraint='', array $more = null);






public function isValid();













public function check(&$value, $schema = null, JsonPointer $path = null, $i = null);
}
<?php








namespace JsonSchema\Constraints;

use JsonSchema\Entity\JsonPointer;







class NumberConstraint extends Constraint
{



public function check(&$element, $schema = null, JsonPointer $path = null, $i = null)
{

 if (isset($schema->exclusiveMinimum)) {
if (isset($schema->minimum)) {
if ($schema->exclusiveMinimum && $element <= $schema->minimum) {
$this->addError($path, 'Must have a minimum value of ' . $schema->minimum, 'exclusiveMinimum', array('minimum' => $schema->minimum));
} elseif ($element < $schema->minimum) {
$this->addError($path, 'Must have a minimum value of ' . $schema->minimum, 'minimum', array('minimum' => $schema->minimum));
}
} else {
$this->addError($path, 'Use of exclusiveMinimum requires presence of minimum', 'missingMinimum');
}
} elseif (isset($schema->minimum) && $element < $schema->minimum) {
$this->addError($path, 'Must have a minimum value of ' . $schema->minimum, 'minimum', array('minimum' => $schema->minimum));
}


 if (isset($schema->exclusiveMaximum)) {
if (isset($schema->maximum)) {
if ($schema->exclusiveMaximum && $element >= $schema->maximum) {
$this->addError($path, 'Must have a maximum value of ' . $schema->maximum, 'exclusiveMaximum', array('maximum' => $schema->maximum));
} elseif ($element > $schema->maximum) {
$this->addError($path, 'Must have a maximum value of ' . $schema->maximum, 'maximum', array('maximum' => $schema->maximum));
}
} else {
$this->addError($path, 'Use of exclusiveMaximum requires presence of maximum', 'missingMaximum');
}
} elseif (isset($schema->maximum) && $element > $schema->maximum) {
$this->addError($path, 'Must have a maximum value of ' . $schema->maximum, 'maximum', array('maximum' => $schema->maximum));
}


 if (isset($schema->divisibleBy) && $this->fmod($element, $schema->divisibleBy) != 0) {
$this->addError($path, 'Is not divisible by ' . $schema->divisibleBy, 'divisibleBy', array('divisibleBy' => $schema->divisibleBy));
}


 if (isset($schema->multipleOf) && $this->fmod($element, $schema->multipleOf) != 0) {
$this->addError($path, 'Must be a multiple of ' . $schema->multipleOf, 'multipleOf', array('multipleOf' => $schema->multipleOf));
}

$this->checkFormat($element, $schema, $path, $i);
}

private function fmod($number1, $number2)
{
$modulus = ($number1 - round($number1 / $number2) * $number2);
$precision = 0.0000000001;

if (-$precision < $modulus && $modulus < $precision) {
return 0.0;
}

return $modulus;
}
}
<?php








namespace JsonSchema\Constraints;

use JsonSchema\Entity\JsonPointer;
use JsonSchema\Exception\InvalidArgumentException;
use JsonSchema\Exception\InvalidSchemaException;
use JsonSchema\Exception\RuntimeException;
use JsonSchema\Validator;







class SchemaConstraint extends Constraint
{
const DEFAULT_SCHEMA_SPEC = 'http://json-schema.org/draft-04/schema#';




public function check(&$element, $schema = null, JsonPointer $path = null, $i = null)
{
if ($schema !== null) {

 $validationSchema = $schema;
} elseif ($this->getTypeCheck()->propertyExists($element, $this->inlineSchemaProperty)) {

 $validationSchema = $this->getTypeCheck()->propertyGet($element, $this->inlineSchemaProperty);
} else {
throw new InvalidArgumentException('no schema found to verify against');
}


 if (is_array($validationSchema)) {
$validationSchema = BaseConstraint::arrayToObjectRecursive($validationSchema);
}


 
 if ($this->factory->getConfig(self::CHECK_MODE_VALIDATE_SCHEMA)) {
if (!$this->getTypeCheck()->isObject($validationSchema)) {
throw new RuntimeException('Cannot validate the schema of a non-object');
}
if ($this->getTypeCheck()->propertyExists($validationSchema, '$schema')) {
$schemaSpec = $this->getTypeCheck()->propertyGet($validationSchema, '$schema');
} else {
$schemaSpec = self::DEFAULT_SCHEMA_SPEC;
}


 $schemaStorage = $this->factory->getSchemaStorage();
if (!$this->getTypeCheck()->isObject($schemaSpec)) {
$schemaSpec = $schemaStorage->getSchema($schemaSpec);
}


 $initialErrorCount = $this->numErrors();
$initialConfig = $this->factory->getConfig();
$initialContext = $this->factory->getErrorContext();
$this->factory->removeConfig(self::CHECK_MODE_VALIDATE_SCHEMA | self::CHECK_MODE_APPLY_DEFAULTS);
$this->factory->addConfig(self::CHECK_MODE_TYPE_CAST);
$this->factory->setErrorContext(Validator::ERROR_SCHEMA_VALIDATION);


 try {
$this->check($validationSchema, $schemaSpec);
} catch (\Exception $e) {
if ($this->factory->getConfig(self::CHECK_MODE_EXCEPTIONS)) {
throw new InvalidSchemaException('Schema did not pass validation', 0, $e);
}
}
if ($this->numErrors() > $initialErrorCount) {
$this->addError($path, 'Schema is not valid', 'schema');
}


 $this->factory->setConfig($initialConfig);
$this->factory->setErrorContext($initialContext);
}


 $this->checkUndefined($element, $validationSchema, $path, $i);
}
}
<?php








namespace JsonSchema\Constraints;

use JsonSchema\Entity\JsonPointer;
use JsonSchema\Rfc3339;








class FormatConstraint extends Constraint
{



public function check(&$element, $schema = null, JsonPointer $path = null, $i = null)
{
if (!isset($schema->format) || $this->factory->getConfig(self::CHECK_MODE_DISABLE_FORMAT)) {
return;
}

switch ($schema->format) {
case 'date':
if (!$date = $this->validateDateTime($element, 'Y-m-d')) {
$this->addError($path, sprintf('Invalid date %s, expected format YYYY-MM-DD', json_encode($element)), 'format', array('format' => $schema->format));
}
break;

case 'time':
if (!$this->validateDateTime($element, 'H:i:s')) {
$this->addError($path, sprintf('Invalid time %s, expected format hh:mm:ss', json_encode($element)), 'format', array('format' => $schema->format));
}
break;

case 'date-time':
if (null === Rfc3339::createFromString($element)) {
$this->addError($path, sprintf('Invalid date-time %s, expected format YYYY-MM-DDThh:mm:ssZ or YYYY-MM-DDThh:mm:ss+hh:mm', json_encode($element)), 'format', array('format' => $schema->format));
}
break;

case 'utc-millisec':
if (!$this->validateDateTime($element, 'U')) {
$this->addError($path, sprintf('Invalid time %s, expected integer of milliseconds since Epoch', json_encode($element)), 'format', array('format' => $schema->format));
}
break;

case 'regex':
if (!$this->validateRegex($element)) {
$this->addError($path, 'Invalid regex format ' . $element, 'format', array('format' => $schema->format));
}
break;

case 'color':
if (!$this->validateColor($element)) {
$this->addError($path, 'Invalid color', 'format', array('format' => $schema->format));
}
break;

case 'style':
if (!$this->validateStyle($element)) {
$this->addError($path, 'Invalid style', 'format', array('format' => $schema->format));
}
break;

case 'phone':
if (!$this->validatePhone($element)) {
$this->addError($path, 'Invalid phone number', 'format', array('format' => $schema->format));
}
break;

case 'uri':
if (null === filter_var($element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)) {
$this->addError($path, 'Invalid URL format', 'format', array('format' => $schema->format));
}
break;

case 'uriref':
case 'uri-reference':
if (null === filter_var($element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)) {

 
 
 if (substr($element, 0, 2) === '//') { 
 $validURL = filter_var('scheme:' . $element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE);
} elseif (substr($element, 0, 1) === '/') { 
 $validURL = filter_var('scheme://host' . $element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE);
} elseif (strlen($element)) { 
 $pathParts = explode('/', $element, 2);
if (strpos($pathParts[0], ':') !== false) {
$validURL = null;
} else {
$validURL = filter_var('scheme://host/' . $element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE);
}
} else {
$validURL = null;
}
if ($validURL === null) {
$this->addError($path, 'Invalid URL format', 'format', array('format' => $schema->format));
}
}
break;

case 'email':
$filterFlags = FILTER_NULL_ON_FAILURE;
if (defined('FILTER_FLAG_EMAIL_UNICODE')) {

 $filterFlags |= constant('FILTER_FLAG_EMAIL_UNICODE'); 
 }
if (null === filter_var($element, FILTER_VALIDATE_EMAIL, $filterFlags)) {
$this->addError($path, 'Invalid email', 'format', array('format' => $schema->format));
}
break;

case 'ip-address':
case 'ipv4':
if (null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV4)) {
$this->addError($path, 'Invalid IP address', 'format', array('format' => $schema->format));
}
break;

case 'ipv6':
if (null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV6)) {
$this->addError($path, 'Invalid IP address', 'format', array('format' => $schema->format));
}
break;

case 'host-name':
case 'hostname':
if (!$this->validateHostname($element)) {
$this->addError($path, 'Invalid hostname', 'format', array('format' => $schema->format));
}
break;

default:

 
 
 
 
 
 break;
}
}

protected function validateDateTime($datetime, $format)
{
$dt = \DateTime::createFromFormat($format, $datetime);

if (!$dt) {
return false;
}

if ($datetime === $dt->format($format)) {
return true;
}


 
 
 
 if ((strpos('u', $format) !== -1) && (preg_match('/\.\d+Z$/', $datetime))) {
return true;
}

return false;
}

protected function validateRegex($regex)
{
return false !== @preg_match('/' . $regex . '/u', '');
}

protected function validateColor($color)
{
if (in_array(strtolower($color), array('aqua', 'black', 'blue', 'fuchsia',
'gray', 'green', 'lime', 'maroon', 'navy', 'olive', 'orange', 'purple',
'red', 'silver', 'teal', 'white', 'yellow'))) {
return true;
}

return preg_match('/^#([a-f0-9]{3}|[a-f0-9]{6})$/i', $color);
}

protected function validateStyle($style)
{
$properties = explode(';', rtrim($style, ';'));
$invalidEntries = preg_grep('/^\s*[-a-z]+\s*:\s*.+$/i', $properties, PREG_GREP_INVERT);

return empty($invalidEntries);
}

protected function validatePhone($phone)
{
return preg_match('/^\+?(\(\d{3}\)|\d{3}) \d{3} \d{4}$/', $phone);
}

protected function validateHostname($host)
{
$hostnameRegex = '/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/i';

return preg_match($hostnameRegex, $host);
}
}
<?php








namespace JsonSchema\Constraints;

use JsonSchema\Entity\JsonPointer;







class CollectionConstraint extends Constraint
{



public function check(&$value, $schema = null, JsonPointer $path = null, $i = null)
{

 if (isset($schema->minItems) && count($value) < $schema->minItems) {
$this->addError($path, 'There must be a minimum of ' . $schema->minItems . ' items in the array', 'minItems', array('minItems' => $schema->minItems));
}


 if (isset($schema->maxItems) && count($value) > $schema->maxItems) {
$this->addError($path, 'There must be a maximum of ' . $schema->maxItems . ' items in the array', 'maxItems', array('maxItems' => $schema->maxItems));
}


 if (isset($schema->uniqueItems) && $schema->uniqueItems) {
$unique = $value;
if (is_array($value) && count($value)) {
$unique = array_map(function ($e) {
return var_export($e, true);
}, $value);
}
if (count(array_unique($unique)) != count($value)) {
$this->addError($path, 'There are no duplicates allowed in the array', 'uniqueItems');
}
}


 if (isset($schema->items)) {
$this->validateItems($value, $schema, $path, $i);
}
}









protected function validateItems(&$value, $schema = null, JsonPointer $path = null, $i = null)
{
if (is_object($schema->items)) {

 foreach ($value as $k => &$v) {
$initErrors = $this->getErrors();


 $this->checkUndefined($v, $schema->items, $path, $k);


 if (count($initErrors) < count($this->getErrors()) && (isset($schema->additionalItems) && $schema->additionalItems !== false)) {
$secondErrors = $this->getErrors();
$this->checkUndefined($v, $schema->additionalItems, $path, $k);
}


 if (isset($secondErrors) && count($secondErrors) < count($this->getErrors())) {
$this->errors = $secondErrors;
} elseif (isset($secondErrors) && count($secondErrors) === count($this->getErrors())) {
$this->errors = $initErrors;
}
}
unset($v); 

} else {

 foreach ($value as $k => &$v) {
if (array_key_exists($k, $schema->items)) {
$this->checkUndefined($v, $schema->items[$k], $path, $k);
} else {

 if (property_exists($schema, 'additionalItems')) {
if ($schema->additionalItems !== false) {
$this->checkUndefined($v, $schema->additionalItems, $path, $k);
} else {
$this->addError(
$path, 'The item ' . $i . '[' . $k . '] is not defined and the definition does not allow additional items', 'additionalItems', array('additionalItems' => $schema->additionalItems));
}
} else {

 $this->checkUndefined($v, new \stdClass(), $path, $k);
}
}
}
unset($v); 



 if (count($value) > 0) {
for ($k = count($value); $k < count($schema->items); $k++) {
$undefinedInstance = $this->factory->createInstanceFor('undefined');
$this->checkUndefined($undefinedInstance, $schema->items[$k], $path, $k);
}
}
}
}
}
<?php








namespace JsonSchema\Constraints;

use JsonSchema\Entity\JsonPointer;
use JsonSchema\Exception\InvalidArgumentException;
use UnexpectedValueException as StandardUnexpectedValueException;







class TypeConstraint extends Constraint
{



public static $wording = array(
'integer' => 'an integer',
'number' => 'a number',
'boolean' => 'a boolean',
'object' => 'an object',
'array' => 'an array',
'string' => 'a string',
'null' => 'a null',
'any' => null, 
 0 => null, 
 );




public function check(&$value = null, $schema = null, JsonPointer $path = null, $i = null)
{
$type = isset($schema->type) ? $schema->type : null;
$isValid = false;
$wording = array();

if (is_array($type)) {
$this->validateTypesArray($value, $type, $wording, $isValid, $path);
} elseif (is_object($type)) {
$this->checkUndefined($value, $type, $path);

return;
} else {
$isValid = $this->validateType($value, $type);
}

if ($isValid === false) {
if (!is_array($type)) {
$this->validateTypeNameWording($type);
$wording[] = self::$wording[$type];
}
$this->addError($path, ucwords(gettype($value)) . ' value found, but ' .
$this->implodeWith($wording, ', ', 'or') . ' is required', 'type');
}
}












protected function validateTypesArray(&$value, array $type, &$validTypesWording, &$isValid, $path)
{
foreach ($type as $tp) {

 
 if (is_object($tp)) {
if (!$isValid) {
$validator = $this->factory->createInstanceFor('type');
$subSchema = new \stdClass();
$subSchema->type = $tp;
$validator->check($value, $subSchema, $path, null);
$error = $validator->getErrors();
$isValid = !(bool) $error;
$validTypesWording[] = self::$wording['object'];
}
} else {
$this->validateTypeNameWording($tp);
$validTypesWording[] = self::$wording[$tp];
if (!$isValid) {
$isValid = $this->validateType($value, $tp);
}
}
}
}












protected function implodeWith(array $elements, $delimiter = ', ', $listEnd = false)
{
if ($listEnd === false || !isset($elements[1])) {
return implode($delimiter, $elements);
}
$lastElement = array_slice($elements, -1);
$firsElements = join($delimiter, array_slice($elements, 0, -1));
$implodedElements = array_merge(array($firsElements), $lastElement);

return join(" $listEnd ", $implodedElements);
}









protected function validateTypeNameWording($type)
{
if (!isset(self::$wording[$type])) {
throw new StandardUnexpectedValueException(
sprintf(
'No wording for %s available, expected wordings are: [%s]',
var_export($type, true),
implode(', ', array_filter(self::$wording)))
);
}
}











protected function validateType(&$value, $type)
{

 if (!$type) {
return true;
}

if ('any' === $type) {
return true;
}

if ('object' === $type) {
return $this->getTypeCheck()->isObject($value);
}

if ('array' === $type) {
return $this->getTypeCheck()->isArray($value);
}

$coerce = $this->factory->getConfig(Constraint::CHECK_MODE_COERCE_TYPES);

if ('integer' === $type) {
if ($coerce) {
$value = $this->toInteger($value);
}

return is_int($value);
}

if ('number' === $type) {
if ($coerce) {
$value = $this->toNumber($value);
}

return is_numeric($value) && !is_string($value);
}

if ('boolean' === $type) {
if ($coerce) {
$value = $this->toBoolean($value);
}

return is_bool($value);
}

if ('string' === $type) {
return is_string($value);
}

if ('email' === $type) {
return is_string($value);
}

if ('null' === $type) {
return is_null($value);
}

throw new InvalidArgumentException((is_object($value) ? 'object' : $value) . ' is an invalid type for ' . $type);
}








protected function toBoolean($value)
{
if ($value === 'true') {
return true;
}

if ($value === 'false') {
return false;
}

return $value;
}








protected function toNumber($value)
{
if (is_numeric($value)) {
return $value + 0; 
 }

return $value;
}

protected function toInteger($value)
{
if (is_numeric($value) && (int) $value == $value) {
return (int) $value; 
 }

return $value;
}
}
<?php








namespace JsonSchema\Constraints;

use JsonSchema\Entity\JsonPointer;







abstract class Constraint extends BaseConstraint implements ConstraintInterface
{
protected $inlineSchemaProperty = '$schema';

const CHECK_MODE_NONE = 0x00000000;
const CHECK_MODE_NORMAL = 0x00000001;
const CHECK_MODE_TYPE_CAST = 0x00000002;
const CHECK_MODE_COERCE_TYPES = 0x00000004;
const CHECK_MODE_APPLY_DEFAULTS = 0x00000008;
const CHECK_MODE_EXCEPTIONS = 0x00000010;
const CHECK_MODE_DISABLE_FORMAT = 0x00000020;
const CHECK_MODE_ONLY_REQUIRED_DEFAULTS = 0x00000080;
const CHECK_MODE_VALIDATE_SCHEMA = 0x00000100;









protected function incrementPath(JsonPointer $path = null, $i)
{
$path = $path ?: new JsonPointer('');

if ($i === null || $i === '') {
return $path;
}

$path = $path->withPropertyPaths(
array_merge(
$path->getPropertyPaths(),
array($i)
)
);

return $path;
}









protected function checkArray(&$value, $schema = null, JsonPointer $path = null, $i = null)
{
$validator = $this->factory->createInstanceFor('collection');
$validator->check($value, $schema, $path, $i);

$this->addErrors($validator->getErrors());
}











protected function checkObject(&$value, $schema = null, JsonPointer $path = null, $properties = null,
$additionalProperties = null, $patternProperties = null, $appliedDefaults = array())
{
$validator = $this->factory->createInstanceFor('object');
$validator->check($value, $schema, $path, $properties, $additionalProperties, $patternProperties, $appliedDefaults);

$this->addErrors($validator->getErrors());
}









protected function checkType(&$value, $schema = null, JsonPointer $path = null, $i = null)
{
$validator = $this->factory->createInstanceFor('type');
$validator->check($value, $schema, $path, $i);

$this->addErrors($validator->getErrors());
}









protected function checkUndefined(&$value, $schema = null, JsonPointer $path = null, $i = null, $fromDefault = false)
{
$validator = $this->factory->createInstanceFor('undefined');

$validator->check($value, $this->factory->getSchemaStorage()->resolveRefSchema($schema), $path, $i, $fromDefault);

$this->addErrors($validator->getErrors());
}









protected function checkString($value, $schema = null, JsonPointer $path = null, $i = null)
{
$validator = $this->factory->createInstanceFor('string');
$validator->check($value, $schema, $path, $i);

$this->addErrors($validator->getErrors());
}









protected function checkNumber($value, $schema = null, JsonPointer $path = null, $i = null)
{
$validator = $this->factory->createInstanceFor('number');
$validator->check($value, $schema, $path, $i);

$this->addErrors($validator->getErrors());
}









protected function checkEnum($value, $schema = null, JsonPointer $path = null, $i = null)
{
$validator = $this->factory->createInstanceFor('enum');
$validator->check($value, $schema, $path, $i);

$this->addErrors($validator->getErrors());
}









protected function checkFormat($value, $schema = null, JsonPointer $path = null, $i = null)
{
$validator = $this->factory->createInstanceFor('format');
$validator->check($value, $schema, $path, $i);

$this->addErrors($validator->getErrors());
}






protected function getTypeCheck()
{
return $this->factory->getTypeCheck();
}






protected function convertJsonPointerIntoPropertyPath(JsonPointer $pointer)
{
$result = array_map(
function ($path) {
return sprintf(is_numeric($path) ? '[%d]' : '.%s', $path);
},
$pointer->getPropertyPaths()
);

return trim(implode('', $result), '.');
}
}
<?php








namespace JsonSchema\Constraints;

use JsonSchema\Entity\JsonPointer;







class StringConstraint extends Constraint
{



public function check(&$element, $schema = null, JsonPointer $path = null, $i = null)
{

 if (isset($schema->maxLength) && $this->strlen($element) > $schema->maxLength) {
$this->addError($path, 'Must be at most ' . $schema->maxLength . ' characters long', 'maxLength', array(
'maxLength' => $schema->maxLength,
));
}


 if (isset($schema->minLength) && $this->strlen($element) < $schema->minLength) {
$this->addError($path, 'Must be at least ' . $schema->minLength . ' characters long', 'minLength', array(
'minLength' => $schema->minLength,
));
}


 if (isset($schema->pattern) && !preg_match('#' . str_replace('#', '\\#', $schema->pattern) . '#u', $element)) {
$this->addError($path, 'Does not match the regex pattern ' . $schema->pattern, 'pattern', array(
'pattern' => $schema->pattern,
));
}

$this->checkFormat($element, $schema, $path, $i);
}

private function strlen($string)
{
if (extension_loaded('mbstring')) {
return mb_strlen($string, mb_detect_encoding($string));
}


 return strlen($string); 
 }
}
<?php








namespace JsonSchema\Exception;




class InvalidSchemaMediaTypeException extends RuntimeException
{
}
<?php








namespace JsonSchema\Exception;




class UriResolverException extends RuntimeException
{
}
<?php








namespace JsonSchema\Exception;




class InvalidSchemaException extends RuntimeException
{
}
<?php








namespace JsonSchema\Exception;

class ValidationException extends RuntimeException
{
}
<?php








namespace JsonSchema\Exception;




class InvalidConfigException extends RuntimeException
{
}
<?php








namespace JsonSchema\Exception;




class ResourceNotFoundException extends RuntimeException
{
}
<?php








namespace JsonSchema\Exception;






class UnresolvableJsonPointerException extends InvalidArgumentException
{
}
<?php








namespace JsonSchema\Exception;




class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
<?php








namespace JsonSchema\Exception;




class JsonDecodingException extends RuntimeException
{
public function __construct($code = JSON_ERROR_NONE, \Exception $previous = null)
{
switch ($code) {
case JSON_ERROR_DEPTH:
$message = 'The maximum stack depth has been exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
$message = 'Invalid or malformed JSON';
break;
case JSON_ERROR_CTRL_CHAR:
$message = 'Control character error, possibly incorrectly encoded';
break;
case JSON_ERROR_UTF8:
$message = 'Malformed UTF-8 characters, possibly incorrectly encoded';
break;
case JSON_ERROR_SYNTAX:
$message = 'JSON syntax is malformed';
break;
default:
$message = 'Syntax error';
}
parent::__construct($message, $code, $previous);
}
}
<?php








namespace JsonSchema\Exception;




class InvalidSourceUriException extends InvalidArgumentException
{
}
<?php








namespace JsonSchema\Exception;




class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?php

namespace JsonSchema\Exception;

interface ExceptionInterface
{
}
<?php








namespace JsonSchema;

use JsonSchema\Constraints\BaseConstraint;
use JsonSchema\Constraints\Constraint;









class Validator extends BaseConstraint
{
const SCHEMA_MEDIA_TYPE = 'application/schema+json';

const ERROR_NONE = 0x00000000;
const ERROR_ALL = 0xFFFFFFFF;
const ERROR_DOCUMENT_VALIDATION = 0x00000001;
const ERROR_SCHEMA_VALIDATION = 0x00000002;








public function validate(&$value, $schema = null, $checkMode = null)
{

 if (is_array($schema)) {
$schema = self::arrayToObjectRecursive($schema);
}


 $initialCheckMode = $this->factory->getConfig();
if ($checkMode !== null) {
$this->factory->setConfig($checkMode);
}


 if (is_object($schema) && property_exists($schema, 'id')) {
$schemaURI = $schema->id;
} else {
$schemaURI = SchemaStorage::INTERNAL_PROVIDED_SCHEMA_URI;
}
$this->factory->getSchemaStorage()->addSchema($schemaURI, $schema);

$validator = $this->factory->createInstanceFor('schema');
$validator->check(
$value,
$this->factory->getSchemaStorage()->getSchema($schemaURI)
);

$this->factory->setConfig($initialCheckMode);

$this->addErrors(array_unique($validator->getErrors(), SORT_REGULAR));

return $validator->getErrorMask();
}




public function check($value, $schema)
{
return $this->validate($value, $schema);
}




public function coerce(&$value, $schema)
{
return $this->validate($value, $schema, Constraint::CHECK_MODE_COERCE_TYPES);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class InvalidUrlException extends \InvalidArgumentException implements Exception {
}
<?php declare(strict_types = 1);
namespace PharIo\Manifest;

class ManifestDocumentException extends \RuntimeException implements Exception {
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

interface Exception extends \Throwable {
}
<?php declare(strict_types = 1);
namespace PharIo\Manifest;

class ManifestDocumentMapperException extends \RuntimeException implements Exception {
}
<?php declare(strict_types = 1);
namespace PharIo\Manifest;

class ManifestLoaderException extends \Exception implements Exception {
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class ElementCollectionException extends \InvalidArgumentException implements Exception {
}
<?php declare(strict_types = 1);
namespace PharIo\Manifest;

class ManifestElementException extends \RuntimeException implements Exception {
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

use LibXMLError;

class ManifestDocumentLoadingException extends \Exception implements Exception {

private $libxmlErrors;






public function __construct(array $libxmlErrors) {
$this->libxmlErrors = $libxmlErrors;
$first = $this->libxmlErrors[0];

parent::__construct(
\sprintf(
'%s (Line: %d / Column: %d / File: %s)',
$first->message,
$first->line,
$first->column,
$first->file
),
$first->code
);
}




public function getLibxmlErrors(): array {
return $this->libxmlErrors;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class InvalidApplicationNameException extends \InvalidArgumentException implements Exception {
public const InvalidFormat = 2;
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class InvalidEmailException extends \InvalidArgumentException implements Exception {
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

use PharIo\Version\Exception as VersionException;
use PharIo\Version\Version;
use PharIo\Version\VersionConstraintParser;

class ManifestDocumentMapper {
public function map(ManifestDocument $document): Manifest {
try {
$contains = $document->getContainsElement();
$type = $this->mapType($contains);
$copyright = $this->mapCopyright($document->getCopyrightElement());
$requirements = $this->mapRequirements($document->getRequiresElement());
$bundledComponents = $this->mapBundledComponents($document);

return new Manifest(
new ApplicationName($contains->getName()),
new Version($contains->getVersion()),
$type,
$copyright,
$requirements,
$bundledComponents
);
} catch (VersionException $e) {
throw new ManifestDocumentMapperException($e->getMessage(), (int)$e->getCode(), $e);
} catch (Exception $e) {
throw new ManifestDocumentMapperException($e->getMessage(), (int)$e->getCode(), $e);
}
}

private function mapType(ContainsElement $contains): Type {
switch ($contains->getType()) {
case 'application':
return Type::application();
case 'library':
return Type::library();
case 'extension':
return $this->mapExtension($contains->getExtensionElement());
}

throw new ManifestDocumentMapperException(
\sprintf('Unsupported type %s', $contains->getType())
);
}

private function mapCopyright(CopyrightElement $copyright): CopyrightInformation {
$authors = new AuthorCollection();

foreach ($copyright->getAuthorElements() as $authorElement) {
$authors->add(
new Author(
$authorElement->getName(),
new Email($authorElement->getEmail())
)
);
}

$licenseElement = $copyright->getLicenseElement();
$license = new License(
$licenseElement->getType(),
new Url($licenseElement->getUrl())
);

return new CopyrightInformation(
$authors,
$license
);
}

private function mapRequirements(RequiresElement $requires): RequirementCollection {
$collection = new RequirementCollection();
$phpElement = $requires->getPHPElement();
$parser = new VersionConstraintParser;

try {
$versionConstraint = $parser->parse($phpElement->getVersion());
} catch (VersionException $e) {
throw new ManifestDocumentMapperException(
\sprintf('Unsupported version constraint - %s', $e->getMessage()),
(int)$e->getCode(),
$e
);
}

$collection->add(
new PhpVersionRequirement(
$versionConstraint
)
);

if (!$phpElement->hasExtElements()) {
return $collection;
}

foreach ($phpElement->getExtElements() as $extElement) {
$collection->add(
new PhpExtensionRequirement($extElement->getName())
);
}

return $collection;
}

private function mapBundledComponents(ManifestDocument $document): BundledComponentCollection {
$collection = new BundledComponentCollection();

if (!$document->hasBundlesElement()) {
return $collection;
}

foreach ($document->getBundlesElement()->getComponentElements() as $componentElement) {
$collection->add(
new BundledComponent(
$componentElement->getName(),
new Version(
$componentElement->getVersion()
)
)
);
}

return $collection;
}

private function mapExtension(ExtensionElement $extension): Extension {
try {
$versionConstraint = (new VersionConstraintParser)->parse($extension->getCompatible());

return Type::extension(
new ApplicationName($extension->getFor()),
$versionConstraint
);
} catch (VersionException $e) {
throw new ManifestDocumentMapperException(
\sprintf('Unsupported version constraint - %s', $e->getMessage()),
(int)$e->getCode(),
$e
);
}
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class Author {

private $name;


private $email;

public function __construct(string $name, Email $email) {
$this->name = $name;
$this->email = $email;
}

public function asString(): string {
return \sprintf(
'%s <%s>',
$this->name,
$this->email->asString()
);
}

public function getName(): string {
return $this->name;
}

public function getEmail(): Email {
return $this->email;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class BundledComponentCollectionIterator implements \Iterator {

private $bundledComponents;


private $position = 0;

public function __construct(BundledComponentCollection $bundledComponents) {
$this->bundledComponents = $bundledComponents->getBundledComponents();
}

public function rewind(): void {
$this->position = 0;
}

public function valid(): bool {
return $this->position < \count($this->bundledComponents);
}

public function key(): int {
return $this->position;
}

public function current(): BundledComponent {
return $this->bundledComponents[$this->position];
}

public function next(): void {
$this->position++;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class CopyrightInformation {

private $authors;


private $license;

public function __construct(AuthorCollection $authors, License $license) {
$this->authors = $authors;
$this->license = $license;
}

public function getAuthors(): AuthorCollection {
return $this->authors;
}

public function getLicense(): License {
return $this->license;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class Library extends Type {
public function isLibrary(): bool {
return true;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class AuthorCollection implements \Countable, \IteratorAggregate {

private $authors = [];

public function add(Author $author): void {
$this->authors[] = $author;
}




public function getAuthors(): array {
return $this->authors;
}

public function count(): int {
return \count($this->authors);
}

public function getIterator(): AuthorCollectionIterator {
return new AuthorCollectionIterator($this);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

use PharIo\Version\VersionConstraint;

class PhpVersionRequirement implements Requirement {

private $versionConstraint;

public function __construct(VersionConstraint $versionConstraint) {
$this->versionConstraint = $versionConstraint;
}

public function getVersionConstraint(): VersionConstraint {
return $this->versionConstraint;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class BundledComponentCollection implements \Countable, \IteratorAggregate {

private $bundledComponents = [];

public function add(BundledComponent $bundledComponent): void {
$this->bundledComponents[] = $bundledComponent;
}




public function getBundledComponents(): array {
return $this->bundledComponents;
}

public function count(): int {
return \count($this->bundledComponents);
}

public function getIterator(): BundledComponentCollectionIterator {
return new BundledComponentCollectionIterator($this);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

interface Requirement {
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class AuthorCollectionIterator implements \Iterator {

private $authors;


private $position = 0;

public function __construct(AuthorCollection $authors) {
$this->authors = $authors->getAuthors();
}

public function rewind(): void {
$this->position = 0;
}

public function valid(): bool {
return $this->position < \count($this->authors);
}

public function key(): int {
return $this->position;
}

public function current(): Author {
return $this->authors[$this->position];
}

public function next(): void {
$this->position++;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class PhpExtensionRequirement implements Requirement {

private $extension;

public function __construct(string $extension) {
$this->extension = $extension;
}

public function asString(): string {
return $this->extension;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class Url {

private $url;

public function __construct(string $url) {
$this->ensureUrlIsValid($url);

$this->url = $url;
}

public function asString(): string {
return $this->url;
}






private function ensureUrlIsValid($url): void {
if (\filter_var($url, \FILTER_VALIDATE_URL) === false) {
throw new InvalidUrlException;
}
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class Email {

private $email;

public function __construct(string $email) {
$this->ensureEmailIsValid($email);

$this->email = $email;
}

public function asString(): string {
return $this->email;
}

private function ensureEmailIsValid(string $url): void {
if (\filter_var($url, \FILTER_VALIDATE_EMAIL) === false) {
throw new InvalidEmailException;
}
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class ApplicationName {

private $name;

public function __construct(string $name) {
$this->ensureValidFormat($name);
$this->name = $name;
}

public function asString(): string {
return $this->name;
}

public function isEqual(ApplicationName $name): bool {
return $this->name === $name->name;
}

private function ensureValidFormat(string $name): void {
if (!\preg_match('#\w/\w#', $name)) {
throw new InvalidApplicationNameException(
\sprintf('Format of name "%s" is not valid - expected: vendor/packagename', $name),
InvalidApplicationNameException::InvalidFormat
);
}
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class RequirementCollection implements \Countable, \IteratorAggregate {

private $requirements = [];

public function add(Requirement $requirement): void {
$this->requirements[] = $requirement;
}




public function getRequirements(): array {
return $this->requirements;
}

public function count(): int {
return \count($this->requirements);
}

public function getIterator(): RequirementCollectionIterator {
return new RequirementCollectionIterator($this);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class Application extends Type {
public function isApplication(): bool {
return true;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

use PharIo\Version\Version;
use PharIo\Version\VersionConstraint;

class Extension extends Type {

private $application;


private $versionConstraint;

public function __construct(ApplicationName $application, VersionConstraint $versionConstraint) {
$this->application = $application;
$this->versionConstraint = $versionConstraint;
}

public function getApplicationName(): ApplicationName {
return $this->application;
}

public function getVersionConstraint(): VersionConstraint {
return $this->versionConstraint;
}

public function isExtension(): bool {
return true;
}

public function isExtensionFor(ApplicationName $name): bool {
return $this->application->isEqual($name);
}

public function isCompatibleWith(ApplicationName $name, Version $version): bool {
return $this->isExtensionFor($name) && $this->versionConstraint->complies($version);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class RequirementCollectionIterator implements \Iterator {

private $requirements;


private $position = 0;

public function __construct(RequirementCollection $requirements) {
$this->requirements = $requirements->getRequirements();
}

public function rewind(): void {
$this->position = 0;
}

public function valid(): bool {
return $this->position < \count($this->requirements);
}

public function key(): int {
return $this->position;
}

public function current(): Requirement {
return $this->requirements[$this->position];
}

public function next(): void {
$this->position++;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

use PharIo\Version\Version;

class Manifest {

private $name;


private $version;


private $type;


private $copyrightInformation;


private $requirements;


private $bundledComponents;

public function __construct(ApplicationName $name, Version $version, Type $type, CopyrightInformation $copyrightInformation, RequirementCollection $requirements, BundledComponentCollection $bundledComponents) {
$this->name = $name;
$this->version = $version;
$this->type = $type;
$this->copyrightInformation = $copyrightInformation;
$this->requirements = $requirements;
$this->bundledComponents = $bundledComponents;
}

public function getName(): ApplicationName {
return $this->name;
}

public function getVersion(): Version {
return $this->version;
}

public function getType(): Type {
return $this->type;
}

public function getCopyrightInformation(): CopyrightInformation {
return $this->copyrightInformation;
}

public function getRequirements(): RequirementCollection {
return $this->requirements;
}

public function getBundledComponents(): BundledComponentCollection {
return $this->bundledComponents;
}

public function isApplication(): bool {
return $this->type->isApplication();
}

public function isLibrary(): bool {
return $this->type->isLibrary();
}

public function isExtension(): bool {
return $this->type->isExtension();
}

public function isExtensionFor(ApplicationName $application, Version $version = null): bool {
if (!$this->isExtension()) {
return false;
}


$type = $this->type;

if ($version !== null) {
return $type->isCompatibleWith($application, $version);
}

return $type->isExtensionFor($application);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

use PharIo\Version\VersionConstraint;

abstract class Type {
public static function application(): Application {
return new Application;
}

public static function library(): Library {
return new Library;
}

public static function extension(ApplicationName $application, VersionConstraint $versionConstraint): Extension {
return new Extension($application, $versionConstraint);
}


public function isApplication(): bool {
return false;
}


public function isLibrary(): bool {
return false;
}


public function isExtension(): bool {
return false;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class License {

private $name;


private $url;

public function __construct(string $name, Url $url) {
$this->name = $name;
$this->url = $url;
}

public function getName(): string {
return $this->name;
}

public function getUrl(): Url {
return $this->url;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

use PharIo\Version\Version;

class BundledComponent {

private $name;


private $version;

public function __construct(string $name, Version $version) {
$this->name = $name;
$this->version = $version;
}

public function getName(): string {
return $this->name;
}

public function getVersion(): Version {
return $this->version;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

use DOMElement;
use DOMNodeList;

class ManifestElement {
public const XMLNS = 'https://phar.io/xml/manifest/1.0';


private $element;

public function __construct(DOMElement $element) {
$this->element = $element;
}

protected function getAttributeValue(string $name): string {
if (!$this->element->hasAttribute($name)) {
throw new ManifestElementException(
\sprintf(
'Attribute %s not set on element %s',
$name,
$this->element->localName
)
);
}

return $this->element->getAttribute($name);
}

protected function getChildByName(string $elementName): DOMElement {
$element = $this->element->getElementsByTagNameNS(self::XMLNS, $elementName)->item(0);

if (!$element instanceof DOMElement) {
throw new ManifestElementException(
\sprintf('Element %s missing', $elementName)
);
}

return $element;
}

protected function getChildrenByName(string $elementName): DOMNodeList {
$elementList = $this->element->getElementsByTagNameNS(self::XMLNS, $elementName);

if ($elementList->length === 0) {
throw new ManifestElementException(
\sprintf('Element(s) %s missing', $elementName)
);
}

return $elementList;
}

protected function hasChild(string $elementName): bool {
return $this->element->getElementsByTagNameNS(self::XMLNS, $elementName)->length !== 0;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class PhpElement extends ManifestElement {
public function getVersion(): string {
return $this->getAttributeValue('version');
}

public function hasExtElements(): bool {
return $this->hasChild('ext');
}

public function getExtElements(): ExtElementCollection {
return new ExtElementCollection(
$this->getChildrenByName('ext')
);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class CopyrightElement extends ManifestElement {
public function getAuthorElements(): AuthorElementCollection {
return new AuthorElementCollection(
$this->getChildrenByName('author')
);
}

public function getLicenseElement(): LicenseElement {
return new LicenseElement(
$this->getChildByName('license')
);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class AuthorElementCollection extends ElementCollection {
public function current(): AuthorElement {
return new AuthorElement(
$this->getCurrentElement()
);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class LicenseElement extends ManifestElement {
public function getType(): string {
return $this->getAttributeValue('type');
}

public function getUrl(): string {
return $this->getAttributeValue('url');
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

use DOMDocument;
use DOMElement;

class ManifestDocument {
public const XMLNS = 'https://phar.io/xml/manifest/1.0';


private $dom;

public static function fromFile(string $filename): ManifestDocument {
if (!\file_exists($filename)) {
throw new ManifestDocumentException(
\sprintf('File "%s" not found', $filename)
);
}

return self::fromString(
\file_get_contents($filename)
);
}

public static function fromString(string $xmlString): ManifestDocument {
$prev = \libxml_use_internal_errors(true);
\libxml_clear_errors();

$dom = new DOMDocument();
$dom->loadXML($xmlString);

$errors = \libxml_get_errors();
\libxml_use_internal_errors($prev);

if (\count($errors) !== 0) {
throw new ManifestDocumentLoadingException($errors);
}

return new self($dom);
}

private function __construct(DOMDocument $dom) {
$this->ensureCorrectDocumentType($dom);

$this->dom = $dom;
}

public function getContainsElement(): ContainsElement {
return new ContainsElement(
$this->fetchElementByName('contains')
);
}

public function getCopyrightElement(): CopyrightElement {
return new CopyrightElement(
$this->fetchElementByName('copyright')
);
}

public function getRequiresElement(): RequiresElement {
return new RequiresElement(
$this->fetchElementByName('requires')
);
}

public function hasBundlesElement(): bool {
return $this->dom->getElementsByTagNameNS(self::XMLNS, 'bundles')->length === 1;
}

public function getBundlesElement(): BundlesElement {
return new BundlesElement(
$this->fetchElementByName('bundles')
);
}

private function ensureCorrectDocumentType(DOMDocument $dom): void {
$root = $dom->documentElement;

if ($root->localName !== 'phar' || $root->namespaceURI !== self::XMLNS) {
throw new ManifestDocumentException('Not a phar.io manifest document');
}
}

private function fetchElementByName(string $elementName): DOMElement {
$element = $this->dom->getElementsByTagNameNS(self::XMLNS, $elementName)->item(0);

if (!$element instanceof DOMElement) {
throw new ManifestDocumentException(
\sprintf('Element %s missing', $elementName)
);
}

return $element;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class ExtensionElement extends ManifestElement {
public function getFor(): string {
return $this->getAttributeValue('for');
}

public function getCompatible(): string {
return $this->getAttributeValue('compatible');
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class ExtElement extends ManifestElement {
public function getName(): string {
return $this->getAttributeValue('name');
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class ComponentElement extends ManifestElement {
public function getName(): string {
return $this->getAttributeValue('name');
}

public function getVersion(): string {
return $this->getAttributeValue('version');
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class ContainsElement extends ManifestElement {
public function getName(): string {
return $this->getAttributeValue('name');
}

public function getVersion(): string {
return $this->getAttributeValue('version');
}

public function getType(): string {
return $this->getAttributeValue('type');
}

public function getExtensionElement(): ExtensionElement {
return new ExtensionElement(
$this->getChildByName('extension')
);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class AuthorElement extends ManifestElement {
public function getName(): string {
return $this->getAttributeValue('name');
}

public function getEmail(): string {
return $this->getAttributeValue('email');
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class RequiresElement extends ManifestElement {
public function getPHPElement(): PhpElement {
return new PhpElement(
$this->getChildByName('php')
);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class ComponentElementCollection extends ElementCollection {
public function current(): ComponentElement {
return new ComponentElement(
$this->getCurrentElement()
);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class BundlesElement extends ManifestElement {
public function getComponentElements(): ComponentElementCollection {
return new ComponentElementCollection(
$this->getChildrenByName('component')
);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class ExtElementCollection extends ElementCollection {
public function current(): ExtElement {
return new ExtElement(
$this->getCurrentElement()
);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

use DOMElement;
use DOMNodeList;

abstract class ElementCollection implements \Iterator {

private $nodes = [];


private $position;

public function __construct(DOMNodeList $nodeList) {
$this->position = 0;
$this->importNodes($nodeList);
}


 abstract public function current();

public function next(): void {
$this->position++;
}

public function key(): int {
return $this->position;
}

public function valid(): bool {
return $this->position < \count($this->nodes);
}

public function rewind(): void {
$this->position = 0;
}

protected function getCurrentElement(): DOMElement {
return $this->nodes[$this->position];
}

private function importNodes(DOMNodeList $nodeList): void {
foreach ($nodeList as $node) {
if (!$node instanceof DOMElement) {
throw new ElementCollectionException(
\sprintf('\DOMElement expected, got \%s', \get_class($node))
);
}

$this->nodes[] = $node;
}
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

use PharIo\Version\AnyVersionConstraint;
use PharIo\Version\Version;
use PharIo\Version\VersionConstraint;
use XMLWriter;


class ManifestSerializer {

private $xmlWriter;

public function serializeToFile(Manifest $manifest, string $filename): void {
\file_put_contents(
$filename,
$this->serializeToString($manifest)
);
}

public function serializeToString(Manifest $manifest): string {
$this->startDocument();

$this->addContains($manifest->getName(), $manifest->getVersion(), $manifest->getType());
$this->addCopyright($manifest->getCopyrightInformation());
$this->addRequirements($manifest->getRequirements());
$this->addBundles($manifest->getBundledComponents());

return $this->finishDocument();
}

private function startDocument(): void {
$xmlWriter = new XMLWriter();
$xmlWriter->openMemory();
$xmlWriter->setIndent(true);
$xmlWriter->setIndentString(\str_repeat(' ', 4));
$xmlWriter->startDocument('1.0', 'UTF-8');
$xmlWriter->startElement('phar');
$xmlWriter->writeAttribute('xmlns', 'https://phar.io/xml/manifest/1.0');

$this->xmlWriter = $xmlWriter;
}

private function finishDocument(): string {
$this->xmlWriter->endElement();
$this->xmlWriter->endDocument();

return $this->xmlWriter->outputMemory();
}

private function addContains(ApplicationName $name, Version $version, Type $type): void {
$this->xmlWriter->startElement('contains');
$this->xmlWriter->writeAttribute('name', $name->asString());
$this->xmlWriter->writeAttribute('version', $version->getVersionString());

switch (true) {
case $type->isApplication(): {
$this->xmlWriter->writeAttribute('type', 'application');

break;
}

case $type->isLibrary(): {
$this->xmlWriter->writeAttribute('type', 'library');

break;
}

case $type->isExtension(): {
$this->xmlWriter->writeAttribute('type', 'extension');

$this->addExtension(
$type->getApplicationName(),
$type->getVersionConstraint()
);

break;
}

default: {
$this->xmlWriter->writeAttribute('type', 'custom');
}
}

$this->xmlWriter->endElement();
}

private function addCopyright(CopyrightInformation $copyrightInformation): void {
$this->xmlWriter->startElement('copyright');

foreach ($copyrightInformation->getAuthors() as $author) {
$this->xmlWriter->startElement('author');
$this->xmlWriter->writeAttribute('name', $author->getName());
$this->xmlWriter->writeAttribute('email', $author->getEmail()->asString());
$this->xmlWriter->endElement();
}

$license = $copyrightInformation->getLicense();

$this->xmlWriter->startElement('license');
$this->xmlWriter->writeAttribute('type', $license->getName());
$this->xmlWriter->writeAttribute('url', $license->getUrl()->asString());
$this->xmlWriter->endElement();

$this->xmlWriter->endElement();
}

private function addRequirements(RequirementCollection $requirementCollection): void {
$phpRequirement = new AnyVersionConstraint();
$extensions = [];

foreach ($requirementCollection as $requirement) {
if ($requirement instanceof PhpVersionRequirement) {
$phpRequirement = $requirement->getVersionConstraint();

continue;
}

if ($requirement instanceof PhpExtensionRequirement) {
$extensions[] = $requirement->asString();
}
}

$this->xmlWriter->startElement('requires');
$this->xmlWriter->startElement('php');
$this->xmlWriter->writeAttribute('version', $phpRequirement->asString());

foreach ($extensions as $extension) {
$this->xmlWriter->startElement('ext');
$this->xmlWriter->writeAttribute('name', $extension);
$this->xmlWriter->endElement();
}

$this->xmlWriter->endElement();
$this->xmlWriter->endElement();
}

private function addBundles(BundledComponentCollection $bundledComponentCollection): void {
if (\count($bundledComponentCollection) === 0) {
return;
}
$this->xmlWriter->startElement('bundles');

foreach ($bundledComponentCollection as $bundledComponent) {
$this->xmlWriter->startElement('component');
$this->xmlWriter->writeAttribute('name', $bundledComponent->getName());
$this->xmlWriter->writeAttribute('version', $bundledComponent->getVersion()->getVersionString());
$this->xmlWriter->endElement();
}

$this->xmlWriter->endElement();
}

private function addExtension(ApplicationName $applicationName, VersionConstraint $versionConstraint): void {
$this->xmlWriter->startElement('extension');
$this->xmlWriter->writeAttribute('for', $applicationName->asString());
$this->xmlWriter->writeAttribute('compatible', $versionConstraint->asString());
$this->xmlWriter->endElement();
}
}
<?php declare(strict_types = 1);








namespace PharIo\Manifest;

class ManifestLoader {
public static function fromFile(string $filename): Manifest {
try {
return (new ManifestDocumentMapper())->map(
ManifestDocument::fromFile($filename)
);
} catch (Exception $e) {
throw new ManifestLoaderException(
\sprintf('Loading %s failed.', $filename),
(int)$e->getCode(),
$e
);
}
}

public static function fromPhar(string $filename): Manifest {
return self::fromFile('phar://' . $filename . '/manifest.xml');
}

public static function fromString(string $manifest): Manifest {
try {
return (new ManifestDocumentMapper())->map(
ManifestDocument::fromString($manifest)
);
} catch (Exception $e) {
throw new ManifestLoaderException(
'Processing string failed',
(int)$e->getCode(),
$e
);
}
}
}
<?php declare(strict_types = 1);
namespace PharIo\Version;

class NoPreReleaseSuffixException extends \Exception implements Exception {
}
<?php declare(strict_types = 1);








namespace PharIo\Version;

use Throwable;

interface Exception extends Throwable {
}
<?php declare(strict_types = 1);
namespace PharIo\Version;

class InvalidPreReleaseSuffixException extends \Exception implements Exception {
}
<?php declare(strict_types = 1);
namespace PharIo\Version;

class InvalidVersionException extends \InvalidArgumentException implements Exception {
}
<?php declare(strict_types = 1);








namespace PharIo\Version;

final class UnsupportedVersionConstraintException extends \RuntimeException implements Exception {
}
<?php declare(strict_types = 1);








namespace PharIo\Version;

class Version {

private $originalVersionString;


private $major;


private $minor;


private $patch;


private $preReleaseSuffix;

public function __construct(string $versionString) {
$this->ensureVersionStringIsValid($versionString);
$this->originalVersionString = $versionString;
}

public function getPreReleaseSuffix(): PreReleaseSuffix {
if ($this->preReleaseSuffix === null) {
throw new NoPreReleaseSuffixException('No pre-release suffix set');
}

return $this->preReleaseSuffix;
}

public function getOriginalString(): string {
return $this->originalVersionString;
}

public function getVersionString(): string {
$str = \sprintf(
'%d.%d.%d',
$this->getMajor()->getValue() ?? 0,
$this->getMinor()->getValue() ?? 0,
$this->getPatch()->getValue() ?? 0
);

if (!$this->hasPreReleaseSuffix()) {
return $str;
}

return $str . '-' . $this->getPreReleaseSuffix()->asString();
}

public function hasPreReleaseSuffix(): bool {
return $this->preReleaseSuffix !== null;
}

public function equals(Version $other): bool {
return $this->getVersionString() === $other->getVersionString();
}

public function isGreaterThan(Version $version): bool {
if ($version->getMajor()->getValue() > $this->getMajor()->getValue()) {
return false;
}

if ($version->getMajor()->getValue() < $this->getMajor()->getValue()) {
return true;
}

if ($version->getMinor()->getValue() > $this->getMinor()->getValue()) {
return false;
}

if ($version->getMinor()->getValue() < $this->getMinor()->getValue()) {
return true;
}

if ($version->getPatch()->getValue() > $this->getPatch()->getValue()) {
return false;
}

if ($version->getPatch()->getValue() < $this->getPatch()->getValue()) {
return true;
}

if (!$version->hasPreReleaseSuffix() && !$this->hasPreReleaseSuffix()) {
return false;
}

if ($version->hasPreReleaseSuffix() && !$this->hasPreReleaseSuffix()) {
return true;
}

if (!$version->hasPreReleaseSuffix() && $this->hasPreReleaseSuffix()) {
return false;
}

return $this->getPreReleaseSuffix()->isGreaterThan($version->getPreReleaseSuffix());
}

public function getMajor(): VersionNumber {
return $this->major;
}

public function getMinor(): VersionNumber {
return $this->minor;
}

public function getPatch(): VersionNumber {
return $this->patch;
}






private function parseVersion(array $matches): void {
$this->major = new VersionNumber((int)$matches['Major']);
$this->minor = new VersionNumber((int)$matches['Minor']);
$this->patch = isset($matches['Patch']) ? new VersionNumber((int)$matches['Patch']) : new VersionNumber(0);

if (isset($matches['PreReleaseSuffix'])) {
$this->preReleaseSuffix = new PreReleaseSuffix($matches['PreReleaseSuffix']);
}
}






private function ensureVersionStringIsValid($version): void {
$regex = '/^v?
            (?<Major>(0|(?:[1-9]\d*)))
            \\.
            (?<Minor>(0|(?:[1-9]\d*)))
            (\\.
                (?<Patch>(0|(?:[1-9]\d*)))
            )?
            (?:
                -
                (?<PreReleaseSuffix>(?:(dev|beta|b|rc|alpha|a|patch|p)\.?\d*))
            )?       
        $/xi';

if (\preg_match($regex, $version, $matches) !== 1) {
throw new InvalidVersionException(
\sprintf("Version string '%s' does not follow SemVer semantics", $version)
);
}

$this->parseVersion($matches);
}
}
<?php declare(strict_types = 1);
namespace PharIo\Version;

class VersionConstraintValue {

private $major;


private $minor;


private $patch;


private $label = '';


private $buildMetaData = '';


private $versionString = '';

public function __construct(string $versionString) {
$this->versionString = $versionString;

$this->parseVersion($versionString);
}

public function getLabel(): string {
return $this->label;
}

public function getBuildMetaData(): string {
return $this->buildMetaData;
}

public function getVersionString(): string {
return $this->versionString;
}

public function getMajor(): VersionNumber {
return $this->major;
}

public function getMinor(): VersionNumber {
return $this->minor;
}

public function getPatch(): VersionNumber {
return $this->patch;
}

private function parseVersion(string $versionString): void {
$this->extractBuildMetaData($versionString);
$this->extractLabel($versionString);
$this->stripPotentialVPrefix($versionString);

$versionSegments = \explode('.', $versionString);
$this->major = new VersionNumber(\is_numeric($versionSegments[0]) ? (int)$versionSegments[0] : null);

$minorValue = isset($versionSegments[1]) && \is_numeric($versionSegments[1]) ? (int)$versionSegments[1] : null;
$patchValue = isset($versionSegments[2]) && \is_numeric($versionSegments[2]) ? (int)$versionSegments[2] : null;

$this->minor = new VersionNumber($minorValue);
$this->patch = new VersionNumber($patchValue);
}

private function extractBuildMetaData(string &$versionString): void {
if (\preg_match('/\+(.*)/', $versionString, $matches) === 1) {
$this->buildMetaData = $matches[1];
$versionString = \str_replace($matches[0], '', $versionString);
}
}

private function extractLabel(string &$versionString): void {
if (\preg_match('/-(.*)/', $versionString, $matches) === 1) {
$this->label = $matches[1];
$versionString = \str_replace($matches[0], '', $versionString);
}
}

private function stripPotentialVPrefix(string &$versionString): void {
if ($versionString[0] !== 'v') {
return;
}
$versionString = \substr($versionString, 1);
}
}
<?php declare(strict_types = 1);
namespace PharIo\Version;

class PreReleaseSuffix {
private const valueScoreMap = [
'dev' => 0,
'a' => 1,
'alpha' => 1,
'b' => 2,
'beta' => 2,
'rc' => 3,
'p' => 4,
'patch' => 4,
];


private $value;


private $valueScore;


private $number = 0;


private $full;




public function __construct(string $value) {
$this->parseValue($value);
}

public function asString(): string {
return $this->full;
}

public function getValue(): string {
return $this->value;
}

public function getNumber(): ?int {
return $this->number;
}

public function isGreaterThan(PreReleaseSuffix $suffix): bool {
if ($this->valueScore > $suffix->valueScore) {
return true;
}

if ($this->valueScore < $suffix->valueScore) {
return false;
}

return $this->getNumber() > $suffix->getNumber();
}

private function mapValueToScore(string $value): int {
$value = \strtolower($value);

if (\array_key_exists($value, self::valueScoreMap)) {
return self::valueScoreMap[$value];
}

return 0;
}

private function parseValue(string $value): void {
$regex = '/-?((dev|beta|b|rc|alpha|a|patch|p)\.?(\d*)).*$/i';

if (\preg_match($regex, $value, $matches) !== 1) {
throw new InvalidPreReleaseSuffixException(\sprintf('Invalid label %s', $value));
}

$this->full = $matches[1];
$this->value = $matches[2];

if ($matches[3] !== '') {
$this->number = (int)$matches[3];
}

$this->valueScore = $this->mapValueToScore($matches[2]);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Version;

class VersionNumber {


private $value;

public function __construct(?int $value) {
$this->value = $value;
}

public function isAny(): bool {
return $this->value === null;
}

public function getValue(): ?int {
return $this->value;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Version;

class VersionConstraintParser {



public function parse(string $value): VersionConstraint {
if (\strpos($value, '||') !== false) {
return $this->handleOrGroup($value);
}

if (!\preg_match('/^[\^~*]?v?[\d.*]+(?:-.*)?$/i', $value)) {
throw new UnsupportedVersionConstraintException(
\sprintf('Version constraint %s is not supported.', $value)
);
}

switch ($value[0]) {
case '~':
return $this->handleTildeOperator($value);
case '^':
return $this->handleCaretOperator($value);
}

$constraint = new VersionConstraintValue($value);

if ($constraint->getMajor()->isAny()) {
return new AnyVersionConstraint();
}

if ($constraint->getMinor()->isAny()) {
return new SpecificMajorVersionConstraint(
$constraint->getVersionString(),
$constraint->getMajor()->getValue() ?? 0
);
}

if ($constraint->getPatch()->isAny()) {
return new SpecificMajorAndMinorVersionConstraint(
$constraint->getVersionString(),
$constraint->getMajor()->getValue() ?? 0,
$constraint->getMinor()->getValue() ?? 0
);
}

return new ExactVersionConstraint($constraint->getVersionString());
}

private function handleOrGroup(string $value): OrVersionConstraintGroup {
$constraints = [];

foreach (\explode('||', $value) as $groupSegment) {
$constraints[] = $this->parse(\trim($groupSegment));
}

return new OrVersionConstraintGroup($value, $constraints);
}

private function handleTildeOperator(string $value): AndVersionConstraintGroup {
$constraintValue = new VersionConstraintValue(\substr($value, 1));

if ($constraintValue->getPatch()->isAny()) {
return $this->handleCaretOperator($value);
}

$constraints = [
new GreaterThanOrEqualToVersionConstraint(
$value,
new Version(\substr($value, 1))
),
new SpecificMajorAndMinorVersionConstraint(
$value,
$constraintValue->getMajor()->getValue() ?? 0,
$constraintValue->getMinor()->getValue() ?? 0
)
];

return new AndVersionConstraintGroup($value, $constraints);
}

private function handleCaretOperator(string $value): AndVersionConstraintGroup {
$constraintValue = new VersionConstraintValue(\substr($value, 1));

$constraints = [
new GreaterThanOrEqualToVersionConstraint($value, new Version(\substr($value, 1)))
];

if ($constraintValue->getMajor()->getValue() === 0) {
$constraints[] = new SpecificMajorAndMinorVersionConstraint(
$value,
$constraintValue->getMajor()->getValue() ?? 0,
$constraintValue->getMinor()->getValue() ?? 0
);
} else {
$constraints[] = new SpecificMajorVersionConstraint(
$value,
$constraintValue->getMajor()->getValue() ?? 0
);
}

return new AndVersionConstraintGroup(
$value,
$constraints
);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Version;

class SpecificMajorAndMinorVersionConstraint extends AbstractVersionConstraint {

private $major;


private $minor;

public function __construct(string $originalValue, int $major, int $minor) {
parent::__construct($originalValue);

$this->major = $major;
$this->minor = $minor;
}

public function complies(Version $version): bool {
if ($version->getMajor()->getValue() !== $this->major) {
return false;
}

return $version->getMinor()->getValue() === $this->minor;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Version;

class OrVersionConstraintGroup extends AbstractVersionConstraint {

private $constraints = [];





public function __construct($originalValue, array $constraints) {
parent::__construct($originalValue);

$this->constraints = $constraints;
}

public function complies(Version $version): bool {
foreach ($this->constraints as $constraint) {
if ($constraint->complies($version)) {
return true;
}
}

return false;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Version;

interface VersionConstraint {
public function complies(Version $version): bool;

public function asString(): string;
}
<?php declare(strict_types = 1);








namespace PharIo\Version;

class AndVersionConstraintGroup extends AbstractVersionConstraint {

private $constraints = [];




public function __construct(string $originalValue, array $constraints) {
parent::__construct($originalValue);

$this->constraints = $constraints;
}

public function complies(Version $version): bool {
foreach ($this->constraints as $constraint) {
if (!$constraint->complies($version)) {
return false;
}
}

return true;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Version;

class SpecificMajorVersionConstraint extends AbstractVersionConstraint {

private $major;

public function __construct(string $originalValue, int $major) {
parent::__construct($originalValue);

$this->major = $major;
}

public function complies(Version $version): bool {
return $version->getMajor()->getValue() === $this->major;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Version;

class GreaterThanOrEqualToVersionConstraint extends AbstractVersionConstraint {

private $minimalVersion;

public function __construct(string $originalValue, Version $minimalVersion) {
parent::__construct($originalValue);

$this->minimalVersion = $minimalVersion;
}

public function complies(Version $version): bool {
return $version->getVersionString() === $this->minimalVersion->getVersionString()
|| $version->isGreaterThan($this->minimalVersion);
}
}
<?php declare(strict_types = 1);








namespace PharIo\Version;

abstract class AbstractVersionConstraint implements VersionConstraint {

private $originalValue;

public function __construct(string $originalValue) {
$this->originalValue = $originalValue;
}

public function asString(): string {
return $this->originalValue;
}
}
<?php declare(strict_types = 1);








namespace PharIo\Version;

class AnyVersionConstraint implements VersionConstraint {
public function complies(Version $version): bool {
return true;
}

public function asString(): string {
return '*';
}
}
<?php declare(strict_types = 1);








namespace PharIo\Version;

class ExactVersionConstraint extends AbstractVersionConstraint {
public function complies(Version $version): bool {
return $this->asString() === $version->getVersionString();
}
}
<?php










namespace Prophecy\Prediction;

use Prophecy\Call\Call;
use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Argument\ArgumentsWildcard;
use Prophecy\Argument\Token\AnyValuesToken;
use Prophecy\Util\StringUtil;
use Prophecy\Exception\Prediction\UnexpectedCallsCountException;







class CallTimesPrediction implements PredictionInterface
{
private $times;
private $util;







public function __construct($times, StringUtil $util = null)
{
$this->times = intval($times);
$this->util = $util ?: new StringUtil;
}










public function check(array $calls, ObjectProphecy $object, MethodProphecy $method)
{
if ($this->times == count($calls)) {
return;
}

$methodCalls = $object->findProphecyMethodCalls(
$method->getMethodName(),
new ArgumentsWildcard(array(new AnyValuesToken))
);

if (count($calls)) {
$message = sprintf(
"Expected exactly %d calls that match:\n".
"  %s->%s(%s)\n".
"but %d were made:\n%s",

$this->times,
get_class($object->reveal()),
$method->getMethodName(),
$method->getArgumentsWildcard(),
count($calls),
$this->util->stringifyCalls($calls)
);
} elseif (count($methodCalls)) {
$message = sprintf(
"Expected exactly %d calls that match:\n".
"  %s->%s(%s)\n".
"but none were made.\n".
"Recorded `%s(...)` calls:\n%s",

$this->times,
get_class($object->reveal()),
$method->getMethodName(),
$method->getArgumentsWildcard(),
$method->getMethodName(),
$this->util->stringifyCalls($methodCalls)
);
} else {
$message = sprintf(
"Expected exactly %d calls that match:\n".
"  %s->%s(%s)\n".
"but none were made.",

$this->times,
get_class($object->reveal()),
$method->getMethodName(),
$method->getArgumentsWildcard()
);
}

throw new UnexpectedCallsCountException($message, $method, $this->times, $calls);
}
}
<?php










namespace Prophecy\Prediction;

use Prophecy\Call\Call;
use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Argument\ArgumentsWildcard;
use Prophecy\Argument\Token\AnyValuesToken;
use Prophecy\Util\StringUtil;
use Prophecy\Exception\Prediction\NoCallsException;






class CallPrediction implements PredictionInterface
{
private $util;






public function __construct(StringUtil $util = null)
{
$this->util = $util ?: new StringUtil;
}










public function check(array $calls, ObjectProphecy $object, MethodProphecy $method)
{
if (count($calls)) {
return;
}

$methodCalls = $object->findProphecyMethodCalls(
$method->getMethodName(),
new ArgumentsWildcard(array(new AnyValuesToken))
);

if (count($methodCalls)) {
throw new NoCallsException(sprintf(
"No calls have been made that match:\n".
"  %s->%s(%s)\n".
"but expected at least one.\n".
"Recorded `%s(...)` calls:\n%s",

get_class($object->reveal()),
$method->getMethodName(),
$method->getArgumentsWildcard(),
$method->getMethodName(),
$this->util->stringifyCalls($methodCalls)
), $method);
}

throw new NoCallsException(sprintf(
"No calls have been made that match:\n".
"  %s->%s(%s)\n".
"but expected at least one.",

get_class($object->reveal()),
$method->getMethodName(),
$method->getArgumentsWildcard()
), $method);
}
}
<?php










namespace Prophecy\Prediction;

use Prophecy\Call\Call;
use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Exception\InvalidArgumentException;
use Closure;
use ReflectionFunction;






class CallbackPrediction implements PredictionInterface
{
private $callback;








public function __construct($callback)
{
if (!is_callable($callback)) {
throw new InvalidArgumentException(sprintf(
'Callable expected as an argument to CallbackPrediction, but got %s.',
gettype($callback)
));
}

$this->callback = $callback;
}








public function check(array $calls, ObjectProphecy $object, MethodProphecy $method)
{
$callback = $this->callback;

if ($callback instanceof Closure && method_exists('Closure', 'bind') && (new ReflectionFunction($callback))->getClosureThis() !== null) {
$callback = Closure::bind($callback, $object);
}

call_user_func($callback, $calls, $object, $method);
}
}
<?php










namespace Prophecy\Prediction;

use Prophecy\Call\Call;
use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Util\StringUtil;
use Prophecy\Exception\Prediction\UnexpectedCallsException;






class NoCallsPrediction implements PredictionInterface
{
private $util;






public function __construct(StringUtil $util = null)
{
$this->util = $util ?: new StringUtil;
}










public function check(array $calls, ObjectProphecy $object, MethodProphecy $method)
{
if (!count($calls)) {
return;
}

$verb = count($calls) === 1 ? 'was' : 'were';

throw new UnexpectedCallsException(sprintf(
"No calls expected that match:\n".
"  %s->%s(%s)\n".
"but %d %s made:\n%s",
get_class($object->reveal()),
$method->getMethodName(),
$method->getArgumentsWildcard(),
count($calls),
$verb,
$this->util->stringifyCalls($calls)
), $method, $calls);
}
}
<?php










namespace Prophecy\Prediction;

use Prophecy\Call\Call;
use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Prophecy\MethodProphecy;







interface PredictionInterface
{










public function check(array $calls, ObjectProphecy $object, MethodProphecy $method);
}
<?php










namespace Prophecy\Comparator;

use SebastianBergmann\Comparator\Comparator;
use SebastianBergmann\Comparator\ComparisonFailure;






final class ClosureComparator extends Comparator
{
public function accepts($expected, $actual): bool
{
return is_object($expected) && $expected instanceof \Closure
&& is_object($actual) && $actual instanceof \Closure;
}

public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false, array &$processed = array()): void
{
if ($expected !== $actual) {
throw new ComparisonFailure(
$expected,
$actual,

 '',
'',
false,
'all closures are different if not identical'
);
}
}
}
<?php










namespace Prophecy\Comparator;

use SebastianBergmann\Comparator\Factory as BaseFactory;






final class Factory extends BaseFactory
{



private static $instance;

public function __construct()
{
parent::__construct();

$this->register(new ClosureComparator());
$this->register(new ProphecyComparator());
}




public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new Factory;
}

return self::$instance;
}
}
<?php










namespace Prophecy\Comparator;

use Prophecy\Prophecy\ProphecyInterface;
use SebastianBergmann\Comparator\ObjectComparator;




class ProphecyComparator extends ObjectComparator
{
public function accepts($expected, $actual): bool
{
return is_object($expected) && is_object($actual) && $actual instanceof ProphecyInterface;
}

public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false, array &$processed = array()): void
{
parent::assertEquals($expected, $actual->reveal(), $delta, $canonicalize, $ignoreCase, $processed);
}
}
<?php










namespace Prophecy\Util;

use Prophecy\Call\Call;






class StringUtil
{
private $verbose;




public function __construct($verbose = true)
{
$this->verbose = $verbose;
}









public function stringify($value, $exportObject = true)
{
if (is_array($value)) {
if (range(0, count($value) - 1) === array_keys($value)) {
return '['.implode(', ', array_map(array($this, __FUNCTION__), $value)).']';
}

$stringify = array($this, __FUNCTION__);

return '['.implode(', ', array_map(function ($item, $key) use ($stringify) {
return (is_integer($key) ? $key : '"'.$key.'"').
' => '.call_user_func($stringify, $item);
}, $value, array_keys($value))).']';
}
if (is_resource($value)) {
return get_resource_type($value).':'.$value;
}
if (is_object($value)) {
return $exportObject ? ExportUtil::export($value) : sprintf('%s:%s', get_class($value), spl_object_hash($value));
}
if (true === $value || false === $value) {
return $value ? 'true' : 'false';
}
if (is_string($value)) {
$str = sprintf('"%s"', str_replace("\n", '\\n', $value));

if (!$this->verbose && 50 <= strlen($str)) {
return substr($str, 0, 50).'"...';
}

return $str;
}
if (null === $value) {
return 'null';
}

return (string) $value;
}








public function stringifyCalls(array $calls)
{
$self = $this;

return implode(PHP_EOL, array_map(function (Call $call) use ($self) {
return sprintf('  - %s(%s) @ %s',
$call->getMethodName(),
implode(', ', array_map(array($self, 'stringify'), $call->getArguments())),
str_replace(GETCWD().DIRECTORY_SEPARATOR, '', $call->getCallPlace())
);
}, $calls));
}
}
<?php

namespace Prophecy\Util;

use Prophecy\Prophecy\ProphecyInterface;
use SebastianBergmann\RecursionContext\Context;














class ExportUtil
{

















public static function export($value, $indentation = 0)
{
return self::recursiveExport($value, $indentation);
}








public static function toArray($value)
{
if (!is_object($value)) {
return (array) $value;
}

$array = array();

foreach ((array) $value as $key => $val) {

 
 
 
 if (preg_match('/^\0.+\0(.+)$/', $key, $matches)) {
$key = $matches[1];
}


 if ($key === "\0gcdata") {
continue;
}

$array[$key] = $val;
}


 
 
 if ($value instanceof \SplObjectStorage) {

 
 if (property_exists('\SplObjectStorage', '__storage')) {
unset($array['__storage']);
} elseif (property_exists('\SplObjectStorage', 'storage')) {
unset($array['storage']);
}

if (property_exists('\SplObjectStorage', '__key')) {
unset($array['__key']);
}

foreach ($value as $key => $val) {
$array[spl_object_hash($val)] = array(
'obj' => $val,
'inf' => $value->getInfo(),
);
}
}

return $array;
}










protected static function recursiveExport(&$value, $indentation, $processed = null)
{
if ($value === null) {
return 'null';
}

if ($value === true) {
return 'true';
}

if ($value === false) {
return 'false';
}

if (is_float($value) && floatval(intval($value)) === $value) {
return "$value.0";
}

if (is_resource($value)) {
return sprintf(
'resource(%d) of type (%s)',
$value,
get_resource_type($value)
);
}

if (is_string($value)) {

 if (preg_match('/[^\x09-\x0d\x20-\xff]/', $value)) {
return 'Binary String: 0x' . bin2hex($value);
}

return "'" .
str_replace(array("\r\n", "\n\r", "\r"), array("\n", "\n", "\n"), $value) .
"'";
}

$whitespace = str_repeat(' ', 4 * $indentation);

if (!$processed) {
$processed = new Context;
}

if (is_array($value)) {
if (($key = $processed->contains($value)) !== false) {
return 'Array &' . $key;
}

$array = $value;
$key = $processed->add($value);
$values = '';

if (count($array) > 0) {
foreach ($array as $k => $v) {
$values .= sprintf(
'%s    %s => %s' . "\n",
$whitespace,
self::recursiveExport($k, $indentation),
self::recursiveExport($value[$k], $indentation + 1, $processed)
);
}

$values = "\n" . $values . $whitespace;
}

return sprintf('Array &%s (%s)', $key, $values);
}

if (is_object($value)) {
$class = get_class($value);

if ($hash = $processed->contains($value)) {
return sprintf('%s:%s Object', $class, $hash);
}

$hash = $processed->add($value);
$values = '';
$array = self::toArray($value);

if (count($array) > 0) {
foreach ($array as $k => $v) {
$values .= sprintf(
'%s    %s => %s' . "\n",
$whitespace,
self::recursiveExport($k, $indentation),
self::recursiveExport($v, $indentation + 1, $processed)
);
}

$values = "\n" . $values . $whitespace;
}

return sprintf('%s:%s Object (%s)', $class, $hash, $values);
}

return var_export($value, true);
}
}
<?php










namespace Prophecy\Promise;

use Prophecy\Exception\InvalidArgumentException;
use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Prophecy\MethodProphecy;






class ReturnArgumentPromise implements PromiseInterface
{



private $index;








public function __construct($index = 0)
{
if (!is_int($index) || $index < 0) {
throw new InvalidArgumentException(sprintf(
'Zero-based index expected as argument to ReturnArgumentPromise, but got %s.',
$index
));
}
$this->index = $index;
}










public function execute(array $args, ObjectProphecy $object, MethodProphecy $method)
{
return count($args) > $this->index ? $args[$this->index] : null;
}
}
<?php










namespace Prophecy\Promise;

use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Exception\InvalidArgumentException;
use Closure;
use ReflectionFunction;






class CallbackPromise implements PromiseInterface
{
private $callback;








public function __construct($callback)
{
if (!is_callable($callback)) {
throw new InvalidArgumentException(sprintf(
'Callable expected as an argument to CallbackPromise, but got %s.',
gettype($callback)
));
}

$this->callback = $callback;
}










public function execute(array $args, ObjectProphecy $object, MethodProphecy $method)
{
$callback = $this->callback;

if ($callback instanceof Closure && method_exists('Closure', 'bind') && (new ReflectionFunction($callback))->getClosureThis() !== null) {
$callback = Closure::bind($callback, $object);
}

return call_user_func($callback, $args, $object, $method);
}
}
<?php










namespace Prophecy\Promise;

use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Prophecy\MethodProphecy;







interface PromiseInterface
{









public function execute(array $args, ObjectProphecy $object, MethodProphecy $method);
}
<?php










namespace Prophecy\Promise;

use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Prophecy\MethodProphecy;






class ReturnPromise implements PromiseInterface
{
private $returnValues = array();






public function __construct(array $returnValues)
{
$this->returnValues = $returnValues;
}










public function execute(array $args, ObjectProphecy $object, MethodProphecy $method)
{
$value = array_shift($this->returnValues);

if (!count($this->returnValues)) {
$this->returnValues[] = $value;
}

return $value;
}
}
<?php










namespace Prophecy\Promise;

use Doctrine\Instantiator\Instantiator;
use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Exception\InvalidArgumentException;
use ReflectionClass;






class ThrowPromise implements PromiseInterface
{
private $exception;




private $instantiator;








public function __construct($exception)
{
if (is_string($exception)) {
if ((!class_exists($exception) && !interface_exists($exception)) || !$this->isAValidThrowable($exception)) {
throw new InvalidArgumentException(sprintf(
'Exception / Throwable class or instance expected as argument to ThrowPromise, but got %s.',
$exception
));
}
} elseif (!$exception instanceof \Exception && !$exception instanceof \Throwable) {
throw new InvalidArgumentException(sprintf(
'Exception / Throwable class or instance expected as argument to ThrowPromise, but got %s.',
is_object($exception) ? get_class($exception) : gettype($exception)
));
}

$this->exception = $exception;
}










public function execute(array $args, ObjectProphecy $object, MethodProphecy $method)
{
if (is_string($this->exception)) {
$classname = $this->exception;
$reflection = new ReflectionClass($classname);
$constructor = $reflection->getConstructor();

if ($constructor->isPublic() && 0 == $constructor->getNumberOfRequiredParameters()) {
throw $reflection->newInstance();
}

if (!$this->instantiator) {
$this->instantiator = new Instantiator();
}

throw $this->instantiator->instantiate($classname);
}

throw $this->exception;
}






private function isAValidThrowable($exception)
{
return is_a($exception, 'Exception', true)
|| is_a($exception, 'Throwable', true);
}
}
<?php










namespace Prophecy;

use Prophecy\Doubler\CachedDoubler;
use Prophecy\Doubler\Doubler;
use Prophecy\Doubler\LazyDouble;
use Prophecy\Doubler\ClassPatch;
use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Prophecy\RevealerInterface;
use Prophecy\Prophecy\Revealer;
use Prophecy\Call\CallCenter;
use Prophecy\Util\StringUtil;
use Prophecy\Exception\Prediction\PredictionException;
use Prophecy\Exception\Prediction\AggregateException;






class Prophet
{
private $doubler;
private $revealer;
private $util;




private $prophecies = array();








public function __construct(
Doubler $doubler = null,
RevealerInterface $revealer = null,
StringUtil $util = null
) {
if (null === $doubler) {
$doubler = new CachedDoubler();
$doubler->registerClassPatch(new ClassPatch\SplFileInfoPatch);
$doubler->registerClassPatch(new ClassPatch\TraversablePatch);
$doubler->registerClassPatch(new ClassPatch\ThrowablePatch);
$doubler->registerClassPatch(new ClassPatch\DisableConstructorPatch);
$doubler->registerClassPatch(new ClassPatch\ProphecySubjectPatch);
$doubler->registerClassPatch(new ClassPatch\ReflectionClassNewInstancePatch);
$doubler->registerClassPatch(new ClassPatch\HhvmExceptionPatch());
$doubler->registerClassPatch(new ClassPatch\MagicCallPatch);
$doubler->registerClassPatch(new ClassPatch\KeywordPatch);
}

$this->doubler = $doubler;
$this->revealer = $revealer ?: new Revealer;
$this->util = $util ?: new StringUtil;
}








public function prophesize($classOrInterface = null)
{
$this->prophecies[] = $prophecy = new ObjectProphecy(
new LazyDouble($this->doubler),
new CallCenter($this->util),
$this->revealer
);

if ($classOrInterface && class_exists($classOrInterface)) {
return $prophecy->willExtend($classOrInterface);
}

if ($classOrInterface && interface_exists($classOrInterface)) {
return $prophecy->willImplement($classOrInterface);
}

return $prophecy;
}






public function getProphecies()
{
return $this->prophecies;
}






public function getDoubler()
{
return $this->doubler;
}






public function checkPredictions()
{
$exception = new AggregateException("Some predictions failed:\n");
foreach ($this->prophecies as $prophecy) {
try {
$prophecy->checkProphecyMethodsPredictions();
} catch (PredictionException $e) {
$exception->append($e);
}
}

if (count($exception->getExceptions())) {
throw $exception;
}
}
}
<?php










namespace Prophecy\Argument\Token;

use SebastianBergmann\Comparator\ComparisonFailure;
use Prophecy\Comparator\Factory as ComparatorFactory;
use Prophecy\Util\StringUtil;






class ObjectStateToken implements TokenInterface
{
private $name;
private $value;
private $util;
private $comparatorFactory;









public function __construct(
$methodName,
$value,
StringUtil $util = null,
ComparatorFactory $comparatorFactory = null
) {
$this->name = $methodName;
$this->value = $value;
$this->util = $util ?: new StringUtil;

$this->comparatorFactory = $comparatorFactory ?: ComparatorFactory::getInstance();
}








public function scoreArgument($argument)
{
if (is_object($argument) && method_exists($argument, $this->name)) {
$actual = call_user_func(array($argument, $this->name));

$comparator = $this->comparatorFactory->getComparatorFor(
$this->value, $actual
);

try {
$comparator->assertEquals($this->value, $actual);
return 8;
} catch (ComparisonFailure $failure) {
return false;
}
}

if (is_object($argument) && property_exists($argument, $this->name)) {
return $argument->{$this->name} === $this->value ? 8 : false;
}

return false;
}






public function isLast()
{
return false;
}






public function __toString()
{
return sprintf('state(%s(), %s)',
$this->name,
$this->util->stringify($this->value)
);
}
}
<?php










namespace Prophecy\Argument\Token;






class ArrayEveryEntryToken implements TokenInterface
{



private $value;




public function __construct($value)
{
if (!$value instanceof TokenInterface) {
$value = new ExactValueToken($value);
}

$this->value = $value;
}




public function scoreArgument($argument)
{
if (!$argument instanceof \Traversable && !is_array($argument)) {
return false;
}

$scores = array();
foreach ($argument as $key => $argumentEntry) {
$scores[] = $this->value->scoreArgument($argumentEntry);
}

if (empty($scores) || in_array(false, $scores, true)) {
return false;
}

return array_sum($scores) / count($scores);
}




public function isLast()
{
return false;
}




public function __toString()
{
return sprintf('[%s, ..., %s]', $this->value, $this->value);
}




public function getValue()
{
return $this->value;
}
}
<?php










namespace Prophecy\Argument\Token;

use Prophecy\Exception\InvalidArgumentException;






class TypeToken implements TokenInterface
{
private $type;




public function __construct($type)
{
$checker = "is_{$type}";
if (!function_exists($checker) && !interface_exists($type) && !class_exists($type)) {
throw new InvalidArgumentException(sprintf(
'Type or class name expected as an argument to TypeToken, but got %s.', $type
));
}

$this->type = $type;
}








public function scoreArgument($argument)
{
$checker = "is_{$this->type}";
if (function_exists($checker)) {
return call_user_func($checker, $argument) ? 5 : false;
}

return $argument instanceof $this->type ? 5 : false;
}






public function isLast()
{
return false;
}






public function __toString()
{
return sprintf('type(%s)', $this->type);
}
}
<?php










namespace Prophecy\Argument\Token;






class AnyValuesToken implements TokenInterface
{







public function scoreArgument($argument)
{
return 2;
}






public function isLast()
{
return true;
}






public function __toString()
{
return '* [, ...]';
}
}
<?php










namespace Prophecy\Argument\Token;






class ApproximateValueToken implements TokenInterface
{
private $value;
private $precision;

public function __construct($value, $precision = 0)
{
$this->value = $value;
$this->precision = $precision;
}




public function scoreArgument($argument)
{
return round((float)$argument, $this->precision) === round($this->value, $this->precision) ? 10 : false;
}




public function isLast()
{
return false;
}






public function __toString()
{
return sprintf('≅%s', round($this->value, $this->precision));
}
}
<?php










namespace Prophecy\Argument\Token;

use Prophecy\Exception\InvalidArgumentException;






class CallbackToken implements TokenInterface
{
private $callback;








public function __construct($callback)
{
if (!is_callable($callback)) {
throw new InvalidArgumentException(sprintf(
'Callable expected as an argument to CallbackToken, but got %s.',
gettype($callback)
));
}

$this->callback = $callback;
}








public function scoreArgument($argument)
{
return call_user_func($this->callback, $argument) ? 7 : false;
}






public function isLast()
{
return false;
}






public function __toString()
{
return 'callback()';
}
}
<?php










namespace Prophecy\Argument\Token;

use Prophecy\Util\StringUtil;






class IdenticalValueToken implements TokenInterface
{
private $value;
private $string;
private $util;







public function __construct($value, StringUtil $util = null)
{
$this->value = $value;
$this->util = $util ?: new StringUtil();
}








public function scoreArgument($argument)
{
return $argument === $this->value ? 11 : false;
}






public function isLast()
{
return false;
}






public function __toString()
{
if (null === $this->string) {
$this->string = sprintf('identical(%s)', $this->util->stringify($this->value));
}

return $this->string;
}
}
<?php










namespace Prophecy\Argument\Token;






class LogicalNotToken implements TokenInterface
{

private $token;




public function __construct($value)
{
$this->token = $value instanceof TokenInterface? $value : new ExactValueToken($value);
}








public function scoreArgument($argument)
{
return false === $this->token->scoreArgument($argument) ? 4 : false;
}






public function isLast()
{
return $this->token->isLast();
}






public function getOriginatingToken()
{
return $this->token;
}






public function __toString()
{
return sprintf('not(%s)', $this->token);
}
}
<?php










namespace Prophecy\Argument\Token;






class LogicalAndToken implements TokenInterface
{
private $tokens = array();




public function __construct(array $arguments)
{
foreach ($arguments as $argument) {
if (!$argument instanceof TokenInterface) {
$argument = new ExactValueToken($argument);
}
$this->tokens[] = $argument;
}
}








public function scoreArgument($argument)
{
if (0 === count($this->tokens)) {
return false;
}

$maxScore = 0;
foreach ($this->tokens as $token) {
$score = $token->scoreArgument($argument);
if (false === $score) {
return false;
}
$maxScore = max($score, $maxScore);
}

return $maxScore;
}






public function isLast()
{
return false;
}






public function __toString()
{
return sprintf('bool(%s)', implode(' AND ', $this->tokens));
}
}
<?php










namespace Prophecy\Argument\Token;







class ArrayCountToken implements TokenInterface
{
private $count;




public function __construct($value)
{
$this->count = $value;
}








public function scoreArgument($argument)
{
return $this->isCountable($argument) && $this->hasProperCount($argument) ? 6 : false;
}






public function isLast()
{
return false;
}






public function __toString()
{
return sprintf('count(%s)', $this->count);
}







private function isCountable($argument)
{
return (is_array($argument) || $argument instanceof \Countable);
}








private function hasProperCount($argument)
{
return $this->count === count($argument);
}
}
<?php










namespace Prophecy\Argument\Token;






class StringContainsToken implements TokenInterface
{
private $value;






public function __construct($value)
{
$this->value = $value;
}

public function scoreArgument($argument)
{
return is_string($argument) && strpos($argument, $this->value) !== false ? 6 : false;
}






public function getValue()
{
return $this->value;
}






public function isLast()
{
return false;
}






public function __toString()
{
return sprintf('contains("%s")', $this->value);
}
}
<?php










namespace Prophecy\Argument\Token;

use Prophecy\Exception\InvalidArgumentException;






class ArrayEntryToken implements TokenInterface
{

private $key;

private $value;





public function __construct($key, $value)
{
$this->key = $this->wrapIntoExactValueToken($key);
$this->value = $this->wrapIntoExactValueToken($value);
}










public function scoreArgument($argument)
{
if ($argument instanceof \Traversable) {
$argument = iterator_to_array($argument);
}

if ($argument instanceof \ArrayAccess) {
$argument = $this->convertArrayAccessToEntry($argument);
}

if (!is_array($argument) || empty($argument)) {
return false;
}

$keyScores = array_map(array($this->key,'scoreArgument'), array_keys($argument));
$valueScores = array_map(array($this->value,'scoreArgument'), $argument);
$scoreEntry = function ($value, $key) {
return $value && $key ? min(8, ($key + $value) / 2) : false;
};

return max(array_map($scoreEntry, $valueScores, $keyScores));
}






public function isLast()
{
return false;
}






public function __toString()
{
return sprintf('[..., %s => %s, ...]', $this->key, $this->value);
}






public function getKey()
{
return $this->key;
}






public function getValue()
{
return $this->value;
}







private function wrapIntoExactValueToken($value)
{
return $value instanceof TokenInterface ? $value : new ExactValueToken($value);
}









private function convertArrayAccessToEntry(\ArrayAccess $object)
{
if (!$this->key instanceof ExactValueToken) {
throw new InvalidArgumentException(sprintf(
'You can only use exact value tokens to match key of ArrayAccess object'.PHP_EOL.
'But you used `%s`.',
$this->key
));
}

$key = $this->key->getValue();

return $object->offsetExists($key) ? array($key => $object[$key]) : array();
}
}
<?php










namespace Prophecy\Argument\Token;

use SebastianBergmann\Comparator\ComparisonFailure;
use Prophecy\Comparator\Factory as ComparatorFactory;
use Prophecy\Util\StringUtil;






class ExactValueToken implements TokenInterface
{
private $value;
private $string;
private $util;
private $comparatorFactory;








public function __construct($value, StringUtil $util = null, ComparatorFactory $comparatorFactory = null)
{
$this->value = $value;
$this->util = $util ?: new StringUtil();

$this->comparatorFactory = $comparatorFactory ?: ComparatorFactory::getInstance();
}








public function scoreArgument($argument)
{
if (is_object($argument) && is_object($this->value)) {
$comparator = $this->comparatorFactory->getComparatorFor(
$argument, $this->value
);

try {
$comparator->assertEquals($argument, $this->value);
return 10;
} catch (ComparisonFailure $failure) {
return false;
}
}


 if (is_object($argument) xor is_object($this->value)) {
if (is_object($argument) && !method_exists($argument, '__toString')) {
return false;
}

if (is_object($this->value) && !method_exists($this->value, '__toString')) {
return false;
}
} elseif (is_numeric($argument) && is_numeric($this->value)) {

 } elseif (gettype($argument) !== gettype($this->value)) {
return false;
}

return $argument == $this->value ? 10 : false;
}






public function getValue()
{
return $this->value;
}






public function isLast()
{
return false;
}






public function __toString()
{
if (null === $this->string) {
$this->string = sprintf('exact(%s)', $this->util->stringify($this->value));
}

return $this->string;
}
}
<?php










namespace Prophecy\Argument\Token;






class InArrayToken implements TokenInterface
{
private $token = array();
private $strict;





public function __construct(array $arguments, $strict = true)
{
$this->token = $arguments;
$this->strict = $strict;
}








public function scoreArgument($argument)
{
if (count($this->token) === 0) {
return false;
}

if (\in_array($argument, $this->token, $this->strict)) {
return 8;
}

return false;
}






public function isLast()
{
return false;
}






public function __toString()
{
$arrayAsString = implode(', ', $this->token);
return "[{$arrayAsString}]";
}
}
<?php










namespace Prophecy\Argument\Token;






class AnyValueToken implements TokenInterface
{







public function scoreArgument($argument)
{
return 3;
}






public function isLast()
{
return false;
}






public function __toString()
{
return '*';
}
}
<?php










namespace Prophecy\Argument\Token;






class NotInArrayToken implements TokenInterface
{
private $token = array();
private $strict;





public function __construct(array $arguments, $strict = true)
{
$this->token = $arguments;
$this->strict = $strict;
}








public function scoreArgument($argument)
{
if (count($this->token) === 0) {
return false;
}

if (!\in_array($argument, $this->token, $this->strict)) {
return 8;
}

return false;
}






public function isLast()
{
return false;
}






public function __toString()
{
$arrayAsString = implode(', ', $this->token);
return "[{$arrayAsString}]";
}
}

<?php










namespace Prophecy\Argument\Token;






interface TokenInterface
{







public function scoreArgument($argument);






public function isLast();






public function __toString();
}
<?php










namespace Prophecy\Argument;






class ArgumentsWildcard
{



private $tokens = array();
private $string;






public function __construct(array $arguments)
{
foreach ($arguments as $argument) {
if (!$argument instanceof Token\TokenInterface) {
$argument = new Token\ExactValueToken($argument);
}

$this->tokens[] = $argument;
}
}








public function scoreArguments(array $arguments)
{
if (0 == count($arguments) && 0 == count($this->tokens)) {
return 1;
}

$arguments = array_values($arguments);
$totalScore = 0;
foreach ($this->tokens as $i => $token) {
$argument = isset($arguments[$i]) ? $arguments[$i] : null;
if (1 >= $score = $token->scoreArgument($argument)) {
return false;
}

$totalScore += $score;

if (true === $token->isLast()) {
return $totalScore;
}
}

if (count($arguments) > count($this->tokens)) {
return false;
}

return $totalScore;
}






public function __toString()
{
if (null === $this->string) {
$this->string = implode(', ', array_map(function ($token) {
return (string) $token;
}, $this->tokens));
}

return $this->string;
}




public function getTokens()
{
return $this->tokens;
}
}
<?php










namespace Prophecy\Prophecy;






interface ProphecySubjectInterface
{





public function setProphecy(ProphecyInterface $prophecy);






public function getProphecy();
}
<?php










namespace Prophecy\Prophecy;

use Prophecy\Argument;
use Prophecy\Prophet;
use Prophecy\Promise;
use Prophecy\Prediction;
use Prophecy\Exception\Doubler\MethodNotFoundException;
use Prophecy\Exception\InvalidArgumentException;
use Prophecy\Exception\Prophecy\MethodProphecyException;
use ReflectionNamedType;
use ReflectionType;
use ReflectionUnionType;






class MethodProphecy
{
private $objectProphecy;
private $methodName;
private $argumentsWildcard;
private $promise;
private $prediction;
private $checkedPredictions = array();
private $bound = false;
private $voidReturnType = false;










public function __construct(ObjectProphecy $objectProphecy, $methodName, $arguments = null)
{
$double = $objectProphecy->reveal();
if (!method_exists($double, $methodName)) {
throw new MethodNotFoundException(sprintf(
'Method `%s::%s()` is not defined.', get_class($double), $methodName
), get_class($double), $methodName, $arguments);
}

$this->objectProphecy = $objectProphecy;
$this->methodName = $methodName;

$reflectedMethod = new \ReflectionMethod($double, $methodName);
if ($reflectedMethod->isFinal()) {
throw new MethodProphecyException(sprintf(
"Can not add prophecy for a method `%s::%s()`\n".
"as it is a final method.",
get_class($double),
$methodName
), $this);
}

if (null !== $arguments) {
$this->withArguments($arguments);
}

$hasTentativeReturnType = method_exists($reflectedMethod, 'hasTentativeReturnType')
&& $reflectedMethod->hasTentativeReturnType();

if (true === $reflectedMethod->hasReturnType() || $hasTentativeReturnType) {
if ($hasTentativeReturnType) {
$reflectionType = $reflectedMethod->getTentativeReturnType();
}
else {
$reflectionType = $reflectedMethod->getReturnType();
}

if ($reflectionType instanceof ReflectionNamedType) {
$types = [$reflectionType];
}
elseif ($reflectionType instanceof ReflectionUnionType) {
$types = $reflectionType->getTypes();
}

$types = array_map(
function(ReflectionType $type) { return $type->getName(); },
$types
);

usort(
$types,
static function(string $type1, string $type2) {


 if ($type2 == 'null') {
return -1;
}
elseif ($type1 == 'null') {
return 1;
}


 $isObject = static function($type) {
return class_exists($type) || interface_exists($type);
};

if($isObject($type1) && !$isObject($type2)) {
return -1;
}
elseif(!$isObject($type1) && $isObject($type2))
{
return 1;
}


 return 0;
}
);

$defaultType = $types[0];

if ('void' === $defaultType) {
$this->voidReturnType = true;
}

$this->will(function () use ($defaultType) {
switch ($defaultType) {
case 'void': return;
case 'string': return '';
case 'float': return 0.0;
case 'int': return 0;
case 'bool': return false;
case 'array': return array();

case 'callable':
case 'Closure':
return function () {};

case 'Traversable':
case 'Generator':
return (function () { yield; })();

default:
$prophet = new Prophet;
return $prophet->prophesize($defaultType)->reveal();
}
});
}
}










public function withArguments($arguments)
{
if (is_array($arguments)) {
$arguments = new Argument\ArgumentsWildcard($arguments);
}

if (!$arguments instanceof Argument\ArgumentsWildcard) {
throw new InvalidArgumentException(sprintf(
"Either an array or an instance of ArgumentsWildcard expected as\n".
'a `MethodProphecy::withArguments()` argument, but got %s.',
gettype($arguments)
));
}

$this->argumentsWildcard = $arguments;

return $this;
}










public function will($promise)
{
if (is_callable($promise)) {
$promise = new Promise\CallbackPromise($promise);
}

if (!$promise instanceof Promise\PromiseInterface) {
throw new InvalidArgumentException(sprintf(
'Expected callable or instance of PromiseInterface, but got %s.',
gettype($promise)
));
}

$this->bindToObjectProphecy();
$this->promise = $promise;

return $this;
}








public function willReturn()
{
if ($this->voidReturnType) {
throw new MethodProphecyException(
"The method \"$this->methodName\" has a void return type, and so cannot return anything",
$this
);
}

return $this->will(new Promise\ReturnPromise(func_get_args()));
}









public function willYield($items, $return = null)
{
if ($this->voidReturnType) {
throw new MethodProphecyException(
"The method \"$this->methodName\" has a void return type, and so cannot yield anything",
$this
);
}

if (!is_array($items)) {
throw new InvalidArgumentException(sprintf(
'Expected array, but got %s.',
gettype($items)
));
}

$generator = function() use ($items, $return) {
yield from $items;

return $return;
};

return $this->will($generator);
}










public function willReturnArgument($index = 0)
{
if ($this->voidReturnType) {
throw new MethodProphecyException("The method \"$this->methodName\" has a void return type", $this);
}

return $this->will(new Promise\ReturnArgumentPromise($index));
}










public function willThrow($exception)
{
return $this->will(new Promise\ThrowPromise($exception));
}










public function should($prediction)
{
if (is_callable($prediction)) {
$prediction = new Prediction\CallbackPrediction($prediction);
}

if (!$prediction instanceof Prediction\PredictionInterface) {
throw new InvalidArgumentException(sprintf(
'Expected callable or instance of PredictionInterface, but got %s.',
gettype($prediction)
));
}

$this->bindToObjectProphecy();
$this->prediction = $prediction;

return $this;
}








public function shouldBeCalled()
{
return $this->should(new Prediction\CallPrediction);
}








public function shouldNotBeCalled()
{
return $this->should(new Prediction\NoCallsPrediction);
}










public function shouldBeCalledTimes($count)
{
return $this->should(new Prediction\CallTimesPrediction($count));
}








public function shouldBeCalledOnce()
{
return $this->shouldBeCalledTimes(1);
}










public function shouldHave($prediction)
{
if (is_callable($prediction)) {
$prediction = new Prediction\CallbackPrediction($prediction);
}

if (!$prediction instanceof Prediction\PredictionInterface) {
throw new InvalidArgumentException(sprintf(
'Expected callable or instance of PredictionInterface, but got %s.',
gettype($prediction)
));
}

if (null === $this->promise && !$this->voidReturnType) {
$this->willReturn();
}

$calls = $this->getObjectProphecy()->findProphecyMethodCalls(
$this->getMethodName(),
$this->getArgumentsWildcard()
);

try {
$prediction->check($calls, $this->getObjectProphecy(), $this);
$this->checkedPredictions[] = $prediction;
} catch (\Exception $e) {
$this->checkedPredictions[] = $prediction;

throw $e;
}

return $this;
}








public function shouldHaveBeenCalled()
{
return $this->shouldHave(new Prediction\CallPrediction);
}








public function shouldNotHaveBeenCalled()
{
return $this->shouldHave(new Prediction\NoCallsPrediction);
}









public function shouldNotBeenCalled()
{
return $this->shouldNotHaveBeenCalled();
}










public function shouldHaveBeenCalledTimes($count)
{
return $this->shouldHave(new Prediction\CallTimesPrediction($count));
}








public function shouldHaveBeenCalledOnce()
{
return $this->shouldHaveBeenCalledTimes(1);
}




public function checkPrediction()
{
if (null === $this->prediction) {
return;
}

$this->shouldHave($this->prediction);
}






public function getPromise()
{
return $this->promise;
}






public function getPrediction()
{
return $this->prediction;
}






public function getCheckedPredictions()
{
return $this->checkedPredictions;
}






public function getObjectProphecy()
{
return $this->objectProphecy;
}






public function getMethodName()
{
return $this->methodName;
}






public function getArgumentsWildcard()
{
return $this->argumentsWildcard;
}




public function hasReturnVoid()
{
return $this->voidReturnType;
}

private function bindToObjectProphecy()
{
if ($this->bound) {
return;
}

$this->getObjectProphecy()->addMethodProphecy($this);
$this->bound = true;
}
}
<?php










namespace Prophecy\Prophecy;

use SebastianBergmann\Comparator\ComparisonFailure;
use Prophecy\Comparator\Factory as ComparatorFactory;
use Prophecy\Call\Call;
use Prophecy\Doubler\LazyDouble;
use Prophecy\Argument\ArgumentsWildcard;
use Prophecy\Call\CallCenter;
use Prophecy\Exception\Prophecy\ObjectProphecyException;
use Prophecy\Exception\Prophecy\MethodProphecyException;
use Prophecy\Exception\Prediction\AggregateException;
use Prophecy\Exception\Prediction\PredictionException;






class ObjectProphecy implements ProphecyInterface
{
private $lazyDouble;
private $callCenter;
private $revealer;
private $comparatorFactory;




private $methodProphecies = array();









public function __construct(
LazyDouble $lazyDouble,
CallCenter $callCenter = null,
RevealerInterface $revealer = null,
ComparatorFactory $comparatorFactory = null
) {
$this->lazyDouble = $lazyDouble;
$this->callCenter = $callCenter ?: new CallCenter;
$this->revealer = $revealer ?: new Revealer;

$this->comparatorFactory = $comparatorFactory ?: ComparatorFactory::getInstance();
}








public function willExtend($class)
{
$this->lazyDouble->setParentClass($class);

return $this;
}








public function willImplement($interface)
{
$this->lazyDouble->addInterface($interface);

return $this;
}








public function willBeConstructedWith(array $arguments = null)
{
$this->lazyDouble->setArguments($arguments);

return $this;
}








public function reveal()
{
$double = $this->lazyDouble->getInstance();

if (null === $double || !$double instanceof ProphecySubjectInterface) {
throw new ObjectProphecyException(
"Generated double must implement ProphecySubjectInterface, but it does not.\n".
'It seems you have wrongly configured doubler without required ClassPatch.',
$this
);
}

$double->setProphecy($this);

return $double;
}









public function addMethodProphecy(MethodProphecy $methodProphecy)
{
$argumentsWildcard = $methodProphecy->getArgumentsWildcard();
if (null === $argumentsWildcard) {
throw new MethodProphecyException(sprintf(
"Can not add prophecy for a method `%s::%s()`\n".
"as you did not specify arguments wildcard for it.",
get_class($this->reveal()),
$methodProphecy->getMethodName()
), $methodProphecy);
}

$methodName = strtolower($methodProphecy->getMethodName());

if (!isset($this->methodProphecies[$methodName])) {
$this->methodProphecies[$methodName] = array();
}

$this->methodProphecies[$methodName][] = $methodProphecy;
}








public function getMethodProphecies($methodName = null)
{
if (null === $methodName) {
return $this->methodProphecies;
}

$methodName = strtolower($methodName);

if (!isset($this->methodProphecies[$methodName])) {
return array();
}

return $this->methodProphecies[$methodName];
}









public function makeProphecyMethodCall($methodName, array $arguments)
{
$arguments = $this->revealer->reveal($arguments);
$return = $this->callCenter->makeCall($this, $methodName, $arguments);

return $this->revealer->reveal($return);
}









public function findProphecyMethodCalls($methodName, ArgumentsWildcard $wildcard)
{
return $this->callCenter->findCalls($methodName, $wildcard);
}







public function checkProphecyMethodsPredictions()
{
$exception = new AggregateException(sprintf("%s:\n", get_class($this->reveal())));
$exception->setObjectProphecy($this);

$this->callCenter->checkUnexpectedCalls();

foreach ($this->methodProphecies as $prophecies) {
foreach ($prophecies as $prophecy) {
try {
$prophecy->checkPrediction();
} catch (PredictionException $e) {
$exception->append($e);
}
}
}

if (count($exception->getExceptions())) {
throw $exception;
}
}









public function __call($methodName, array $arguments)
{
$arguments = new ArgumentsWildcard($this->revealer->reveal($arguments));

foreach ($this->getMethodProphecies($methodName) as $prophecy) {
$argumentsWildcard = $prophecy->getArgumentsWildcard();
$comparator = $this->comparatorFactory->getComparatorFor(
$argumentsWildcard, $arguments
);

try {
$comparator->assertEquals($argumentsWildcard, $arguments);
return $prophecy;
} catch (ComparisonFailure $failure) {}
}

return new MethodProphecy($this, $methodName, $arguments);
}








public function __get($name)
{
return $this->reveal()->$name;
}







public function __set($name, $value)
{
$this->reveal()->$name = $this->revealer->reveal($value);
}
}
<?php










namespace Prophecy\Prophecy;






interface RevealerInterface
{







public function reveal($value);
}
<?php










namespace Prophecy\Prophecy;






class Revealer implements RevealerInterface
{







public function reveal($value)
{
if (is_array($value)) {
return array_map(array($this, __FUNCTION__), $value);
}

if (!is_object($value)) {
return $value;
}

if ($value instanceof ProphecyInterface) {
$value = $value->reveal();
}

return $value;
}
}
<?php










namespace Prophecy\Prophecy;






interface ProphecyInterface
{





public function reveal();
}
<?php










namespace Prophecy\PhpDocumentor;

use phpDocumentor\Reflection\DocBlock\Tag\MethodTag as LegacyMethodTag;
use phpDocumentor\Reflection\DocBlock\Tags\Method;






interface MethodTagRetrieverInterface
{





public function getTagList(\ReflectionClass $reflectionClass);
}
<?php










namespace Prophecy\PhpDocumentor;

use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tag\MethodTag as LegacyMethodTag;






final class LegacyClassTagRetriever implements MethodTagRetrieverInterface
{





public function getTagList(\ReflectionClass $reflectionClass)
{
$phpdoc = new DocBlock($reflectionClass->getDocComment());

return $phpdoc->getTagsByName('method');
}
}
<?php










namespace Prophecy\PhpDocumentor;

use phpDocumentor\Reflection\DocBlock\Tags\Method;
use phpDocumentor\Reflection\DocBlockFactory;
use phpDocumentor\Reflection\Types\ContextFactory;






final class ClassTagRetriever implements MethodTagRetrieverInterface
{
private $docBlockFactory;
private $contextFactory;

public function __construct()
{
$this->docBlockFactory = DocBlockFactory::createInstance();
$this->contextFactory = new ContextFactory();
}






public function getTagList(\ReflectionClass $reflectionClass)
{
try {
$phpdoc = $this->docBlockFactory->create(
$reflectionClass,
$this->contextFactory->createFromReflector($reflectionClass)
);

$methods = array();

foreach ($phpdoc->getTagsByName('method') as $tag) {
if ($tag instanceof Method) {
$methods[] = $tag;
}
}

return $methods;
} catch (\InvalidArgumentException $e) {
return array();
}
}
}
<?php










namespace Prophecy\PhpDocumentor;

use phpDocumentor\Reflection\DocBlock\Tag\MethodTag as LegacyMethodTag;
use phpDocumentor\Reflection\DocBlock\Tags\Method;






final class ClassAndInterfaceTagRetriever implements MethodTagRetrieverInterface
{
private $classRetriever;

public function __construct(MethodTagRetrieverInterface $classRetriever = null)
{
if (null !== $classRetriever) {
$this->classRetriever = $classRetriever;

return;
}

$this->classRetriever = class_exists('phpDocumentor\Reflection\DocBlockFactory') && class_exists('phpDocumentor\Reflection\Types\ContextFactory')
? new ClassTagRetriever()
: new LegacyClassTagRetriever()
;
}






public function getTagList(\ReflectionClass $reflectionClass)
{
return array_merge(
$this->classRetriever->getTagList($reflectionClass),
$this->getInterfacesTagList($reflectionClass)
);
}






private function getInterfacesTagList(\ReflectionClass $reflectionClass)
{
$interfaces = $reflectionClass->getInterfaces();
$tagList = array();

foreach($interfaces as $interface) {
$tagList = array_merge($tagList, $this->classRetriever->getTagList($interface));
}

return $tagList;
}
}
<?php










namespace Prophecy;

use Prophecy\Argument\Token;






class Argument
{







public static function exact($value)
{
return new Token\ExactValueToken($value);
}








public static function type($type)
{
return new Token\TypeToken($type);
}









public static function which($methodName, $value)
{
return new Token\ObjectStateToken($methodName, $value);
}








public static function that($callback)
{
return new Token\CallbackToken($callback);
}






public static function any()
{
return new Token\AnyValueToken;
}






public static function cetera()
{
return new Token\AnyValuesToken;
}








public static function allOf()
{
return new Token\LogicalAndToken(func_get_args());
}








public static function size($value)
{
return new Token\ArrayCountToken($value);
}









public static function withEntry($key, $value)
{
return new Token\ArrayEntryToken($key, $value);
}








public static function withEveryEntry($value)
{
return new Token\ArrayEveryEntryToken($value);
}








public static function containing($value)
{
return new Token\ArrayEntryToken(self::any(), $value);
}








public static function withKey($key)
{
return new Token\ArrayEntryToken($key, self::any());
}








public static function not($value)
{
return new Token\LogicalNotToken($value);
}






public static function containingString($value)
{
return new Token\StringContainsToken($value);
}








public static function is($value)
{
return new Token\IdenticalValueToken($value);
}










public static function approximate($value, $precision = 0)
{
return new Token\ApproximateValueToken($value, $precision);
}









public static function in($value)
{
return new Token\InArrayToken($value);
}









public static function notIn($value)
{
return new Token\NotInArrayToken($value);
}

}
<?php










namespace Prophecy\Call;

use Prophecy\Exception\Prophecy\MethodProphecyException;
use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Argument\ArgumentsWildcard;
use Prophecy\Util\StringUtil;
use Prophecy\Exception\Call\UnexpectedCallException;
use SplObjectStorage;






class CallCenter
{
private $util;




private $recordedCalls = array();




private $unexpectedCalls;






public function __construct(StringUtil $util = null)
{
$this->util = $util ?: new StringUtil;
$this->unexpectedCalls = new SplObjectStorage();
}












public function makeCall(ObjectProphecy $prophecy, $methodName, array $arguments)
{

 
 $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);

$file = $line = null;
if (isset($backtrace[2]) && isset($backtrace[2]['file'])) {
$file = $backtrace[2]['file'];
$line = $backtrace[2]['line'];
}


 if ('__destruct' === strtolower($methodName) || 0 == count($prophecy->getMethodProphecies())) {
$this->recordedCalls[] = new Call($methodName, $arguments, null, null, $file, $line);

return null;
}


 $matches = $this->findMethodProphecies($prophecy, $methodName, $arguments);


 if (!count($matches)) {
$this->unexpectedCalls->attach(new Call($methodName, $arguments, null, null, $file, $line), $prophecy);
$this->recordedCalls[] = new Call($methodName, $arguments, null, null, $file, $line);

return null;
}


 @usort($matches, function ($match1, $match2) { return $match2[0] - $match1[0]; });

$score = $matches[0][0];

 $methodProphecy = $matches[0][1];
$returnValue = null;
$exception = null;
if ($promise = $methodProphecy->getPromise()) {
try {
$returnValue = $promise->execute($arguments, $prophecy, $methodProphecy);
} catch (\Exception $e) {
$exception = $e;
}
}

if ($methodProphecy->hasReturnVoid() && $returnValue !== null) {
throw new MethodProphecyException(
"The method \"$methodName\" has a void return type, but the promise returned a value",
$methodProphecy
);
}

$this->recordedCalls[] = $call = new Call(
$methodName, $arguments, $returnValue, $exception, $file, $line
);
$call->addScore($methodProphecy->getArgumentsWildcard(), $score);

if (null !== $exception) {
throw $exception;
}

return $returnValue;
}









public function findCalls($methodName, ArgumentsWildcard $wildcard)
{
$methodName = strtolower($methodName);

return array_values(
array_filter($this->recordedCalls, function (Call $call) use ($methodName, $wildcard) {
return $methodName === strtolower($call->getMethodName())
&& 0 < $call->getScore($wildcard)
;
})
);
}




public function checkUnexpectedCalls()
{

foreach ($this->unexpectedCalls as $call) {
$prophecy = $this->unexpectedCalls[$call];


 if (!count($this->findMethodProphecies($prophecy, $call->getMethodName(), $call->getArguments()))) {
throw $this->createUnexpectedCallException($prophecy, $call->getMethodName(), $call->getArguments());
}
}
}

private function createUnexpectedCallException(ObjectProphecy $prophecy, $methodName,
array $arguments)
{
$classname = get_class($prophecy->reveal());
$indentationLength = 8; 
 $argstring = implode(
",\n",
$this->indentArguments(
array_map(array($this->util, 'stringify'), $arguments),
$indentationLength
)
);

$expected = array();

foreach (array_merge(...array_values($prophecy->getMethodProphecies())) as $methodProphecy) {
$expected[] = sprintf(
"  - %s(\n" .
"%s\n" .
"    )",
$methodProphecy->getMethodName(),
implode(
",\n",
$this->indentArguments(
array_map('strval', $methodProphecy->getArgumentsWildcard()->getTokens()),
$indentationLength
)
)
);
}

return new UnexpectedCallException(
sprintf(
"Unexpected method call on %s:\n".
"  - %s(\n".
"%s\n".
"    )\n".
"expected calls were:\n".
"%s",

$classname, $methodName, $argstring, implode("\n", $expected)
),
$prophecy, $methodName, $arguments

);
}

private function indentArguments(array $arguments, $indentationLength)
{
return preg_replace_callback(
'/^/m',
function () use ($indentationLength) {
return str_repeat(' ', $indentationLength);
},
$arguments
);
}








private function findMethodProphecies(ObjectProphecy $prophecy, $methodName, array $arguments)
{
$matches = array();
foreach ($prophecy->getMethodProphecies($methodName) as $methodProphecy) {
if (0 < $score = $methodProphecy->getArgumentsWildcard()->scoreArguments($arguments)) {
$matches[] = array($score, $methodProphecy);
}
}

return $matches;
}
}
<?php










namespace Prophecy\Call;

use Exception;
use Prophecy\Argument\ArgumentsWildcard;






class Call
{
private $methodName;
private $arguments;
private $returnValue;
private $exception;
private $file;
private $line;
private $scores;











public function __construct($methodName, array $arguments, $returnValue,
Exception $exception = null, $file, $line)
{
$this->methodName = $methodName;
$this->arguments = $arguments;
$this->returnValue = $returnValue;
$this->exception = $exception;
$this->scores = new \SplObjectStorage();

if ($file) {
$this->file = $file;
$this->line = intval($line);
}
}






public function getMethodName()
{
return $this->methodName;
}






public function getArguments()
{
return $this->arguments;
}






public function getReturnValue()
{
return $this->returnValue;
}






public function getException()
{
return $this->exception;
}






public function getFile()
{
return $this->file;
}






public function getLine()
{
return $this->line;
}






public function getCallPlace()
{
if (null === $this->file) {
return 'unknown';
}

return sprintf('%s:%d', $this->file, $this->line);
}









public function addScore(ArgumentsWildcard $wildcard, $score)
{
$this->scores[$wildcard] = $score;

return $this;
}









public function getScore(ArgumentsWildcard $wildcard)
{
if (isset($this->scores[$wildcard])) {
return $this->scores[$wildcard];
}

return $this->scores[$wildcard] = $wildcard->scoreArguments($this->getArguments());
}
}
<?php










namespace Prophecy\Doubler;

use ReflectionClass;







class NameGenerator
{
private static $counter = 1;









public function name(ReflectionClass $class = null, array $interfaces)
{
$parts = array();

if (null !== $class) {
$parts[] = $class->getName();
} else {
foreach ($interfaces as $interface) {
$parts[] = $interface->getShortName();
}
}

if (!count($parts)) {
$parts[] = 'stdClass';
}

return sprintf('Double\%s\P%d', implode('\\', $parts), self::$counter++);
}
}
<?php










namespace Prophecy\Doubler\Generator;







interface ReflectionInterface
{
}
<?php










namespace Prophecy\Doubler\Generator;

use Prophecy\Exception\Doubler\ClassCreatorException;







class ClassCreator
{
private $generator;






public function __construct(ClassCodeGenerator $generator = null)
{
$this->generator = $generator ?: new ClassCodeGenerator;
}











public function create($classname, Node\ClassNode $class)
{
$code = $this->generator->generate($classname, $class);
$return = eval($code);

if (!class_exists($classname, false)) {
if (count($class->getInterfaces())) {
throw new ClassCreatorException(sprintf(
'Could not double `%s` and implement interfaces: [%s].',
$class->getParentClass(), implode(', ', $class->getInterfaces())
), $class);
}

throw new ClassCreatorException(
sprintf('Could not double `%s`.', $class->getParentClass()),
$class
);
}

return $return;
}
}
<?php










namespace Prophecy\Doubler\Generator\Node;

use Prophecy\Exception\Doubler\MethodNotExtendableException;
use Prophecy\Exception\InvalidArgumentException;






class ClassNode
{
private $parentClass = 'stdClass';
private $interfaces = array();
private $properties = array();
private $unextendableMethods = array();




private $methods = array();

public function getParentClass()
{
return $this->parentClass;
}




public function setParentClass($class)
{
$this->parentClass = $class ?: 'stdClass';
}




public function getInterfaces()
{
return $this->interfaces;
}




public function addInterface($interface)
{
if ($this->hasInterface($interface)) {
return;
}

array_unshift($this->interfaces, $interface);
}






public function hasInterface($interface)
{
return in_array($interface, $this->interfaces);
}

public function getProperties()
{
return $this->properties;
}

public function addProperty($name, $visibility = 'public')
{
$visibility = strtolower($visibility);

if (!in_array($visibility, array('public', 'private', 'protected'))) {
throw new InvalidArgumentException(sprintf(
'`%s` property visibility is not supported.', $visibility
));
}

$this->properties[$name] = $visibility;
}




public function getMethods()
{
return $this->methods;
}

public function addMethod(MethodNode $method, $force = false)
{
if (!$this->isExtendable($method->getName())){
$message = sprintf(
'Method `%s` is not extendable, so can not be added.', $method->getName()
);
throw new MethodNotExtendableException($message, $this->getParentClass(), $method->getName());
}

if ($force || !isset($this->methods[$method->getName()])) {
$this->methods[$method->getName()] = $method;
}
}

public function removeMethod($name)
{
unset($this->methods[$name]);
}






public function getMethod($name)
{
return $this->hasMethod($name) ? $this->methods[$name] : null;
}






public function hasMethod($name)
{
return isset($this->methods[$name]);
}




public function getUnextendableMethods()
{
return $this->unextendableMethods;
}




public function addUnextendableMethod($unextendableMethod)
{
if (!$this->isExtendable($unextendableMethod)){
return;
}
$this->unextendableMethods[] = $unextendableMethod;
}





public function isExtendable($method)
{
return !in_array($method, $this->unextendableMethods);
}
}
<?php










namespace Prophecy\Doubler\Generator\Node;

use Prophecy\Doubler\Generator\TypeHintReference;
use Prophecy\Exception\InvalidArgumentException;






class MethodNode
{
private $name;
private $code;
private $visibility = 'public';
private $static = false;
private $returnsReference = false;


private $returnTypeNode;




private $arguments = array();





public function __construct($name, $code = null, TypeHintReference $typeHintReference = null)
{
$this->name = $name;
$this->code = $code;
$this->returnTypeNode = new ReturnTypeNode();
}

public function getVisibility()
{
return $this->visibility;
}




public function setVisibility($visibility)
{
$visibility = strtolower($visibility);

if (!in_array($visibility, array('public', 'private', 'protected'))) {
throw new InvalidArgumentException(sprintf(
'`%s` method visibility is not supported.', $visibility
));
}

$this->visibility = $visibility;
}

public function isStatic()
{
return $this->static;
}

public function setStatic($static = true)
{
$this->static = (bool) $static;
}

public function returnsReference()
{
return $this->returnsReference;
}

public function setReturnsReference()
{
$this->returnsReference = true;
}

public function getName()
{
return $this->name;
}

public function addArgument(ArgumentNode $argument)
{
$this->arguments[] = $argument;
}




public function getArguments()
{
return $this->arguments;
}





public function hasReturnType()
{
return (bool) $this->returnTypeNode->getNonNullTypes();
}

public function setReturnTypeNode(ReturnTypeNode $returnTypeNode): void
{
$this->returnTypeNode = $returnTypeNode;
}





public function setReturnType($type = null)
{
$this->returnTypeNode = ($type === '' || $type === null) ? new ReturnTypeNode() : new ReturnTypeNode($type);
}





public function setNullableReturnType($bool = true)
{
if ($bool) {
$this->returnTypeNode = new ReturnTypeNode('null', ...$this->returnTypeNode->getTypes());
}
else {
$this->returnTypeNode = new ReturnTypeNode(...$this->returnTypeNode->getNonNullTypes());
}
}





public function getReturnType()
{
if ($types = $this->returnTypeNode->getNonNullTypes())
{
return $types[0];
}

return null;
}

public function getReturnTypeNode() : ReturnTypeNode
{
return $this->returnTypeNode;
}





public function hasNullableReturnType()
{
return $this->returnTypeNode->canUseNullShorthand();
}




public function setCode($code)
{
$this->code = $code;
}

public function getCode()
{
if ($this->returnsReference)
{
return "throw new \Prophecy\Exception\Doubler\ReturnByReferenceException('Returning by reference not supported', get_class(\$this), '{$this->name}');";
}

return (string) $this->code;
}

public function useParentCode()
{
$this->code = sprintf(
'return parent::%s(%s);', $this->getName(), implode(', ',
array_map(array($this, 'generateArgument'), $this->arguments)
)
);
}

private function generateArgument(ArgumentNode $arg)
{
$argument = '$'.$arg->getName();

if ($arg->isVariadic()) {
$argument = '...'.$argument;
}

return $argument;
}
}
<?php

namespace Prophecy\Doubler\Generator\Node;

use Prophecy\Exception\Doubler\DoubleException;

class ArgumentTypeNode extends TypeNodeAbstract
{

}
<?php

namespace Prophecy\Doubler\Generator\Node;

use Prophecy\Exception\Doubler\DoubleException;

final class ReturnTypeNode extends TypeNodeAbstract
{
protected function getRealType(string $type): string
{
switch ($type) {
case 'void':
case 'never':
return $type;
default:
return parent::getRealType($type);
}
}

protected function guardIsValidType()
{
if (isset($this->types['void']) && count($this->types) !== 1) {
throw new DoubleException('void cannot be part of a union');
}
if (isset($this->types['never']) && count($this->types) !== 1) {
throw new DoubleException('never cannot be part of a union');
}

parent::guardIsValidType();
}




public function isVoid()
{
return $this->types == ['void' => 'void'];
}

public function hasReturnStatement(): bool
{
return $this->types !== ['void' => 'void']
&& $this->types !== ['never' => 'never'];
}
}
<?php

namespace Prophecy\Doubler\Generator\Node;

use Prophecy\Exception\Doubler\DoubleException;

abstract class TypeNodeAbstract
{

protected $types = [];

public function __construct(string ...$types)
{
foreach ($types as $type) {
$type = $this->getRealType($type);
$this->types[$type] = $type;
}

$this->guardIsValidType();
}

public function canUseNullShorthand(): bool
{
return isset($this->types['null']) && count($this->types) <= 2;
}

public function getTypes(): array
{
return array_values($this->types);
}

public function getNonNullTypes(): array
{
$nonNullTypes = $this->types;
unset($nonNullTypes['null']);

return array_values($nonNullTypes);
}

protected function prefixWithNsSeparator(string $type): string
{
return '\\' . ltrim($type, '\\');
}

protected function getRealType(string $type): string
{
switch ($type) {

 case 'double':
case 'real':
return 'float';
case 'boolean':
return 'bool';
case 'integer':
return 'int';


 case 'self':
case 'static':
case 'array':
case 'callable':
case 'bool':
case 'false':
case 'float':
case 'int':
case 'string':
case 'iterable':
case 'object':
case 'null':
return $type;
case 'mixed':
return \PHP_VERSION_ID < 80000 ? $this->prefixWithNsSeparator($type) : $type;

default:
return $this->prefixWithNsSeparator($type);
}
}

protected function guardIsValidType()
{
if ($this->types == ['null' => 'null']) {
throw new DoubleException('Type cannot be standalone null');
}

if ($this->types == ['false' => 'false']) {
throw new DoubleException('Type cannot be standalone false');
}

if ($this->types == ['false' => 'false', 'null' => 'null']) {
throw new DoubleException('Type cannot be nullable false');
}

if (\PHP_VERSION_ID >= 80000 && isset($this->types['mixed']) && count($this->types) !== 1) {
throw new DoubleException('mixed cannot be part of a union');
}
}
}
<?php










namespace Prophecy\Doubler\Generator\Node;






class ArgumentNode
{
private $name;
private $default;
private $optional = false;
private $byReference = false;
private $isVariadic = false;


private $typeNode;




public function __construct($name)
{
$this->name = $name;
$this->typeNode = new ArgumentTypeNode();
}

public function getName()
{
return $this->name;
}

public function setTypeNode(ArgumentTypeNode $typeNode)
{
$this->typeNode = $typeNode;
}

public function getTypeNode() : ArgumentTypeNode
{
return $this->typeNode;
}

public function hasDefault()
{
return $this->isOptional() && !$this->isVariadic();
}

public function getDefault()
{
return $this->default;
}

public function setDefault($default = null)
{
$this->optional = true;
$this->default = $default;
}

public function isOptional()
{
return $this->optional;
}

public function setAsPassedByReference($byReference = true)
{
$this->byReference = $byReference;
}

public function isPassedByReference()
{
return $this->byReference;
}

public function setAsVariadic($isVariadic = true)
{
$this->isVariadic = $isVariadic;
}

public function isVariadic()
{
return $this->isVariadic;
}





public function getTypeHint()
{
$type = $this->typeNode->getNonNullTypes() ? $this->typeNode->getNonNullTypes()[0] : null;

return $type ? ltrim($type, '\\') : null;
}





public function setTypeHint($typeHint = null)
{
$this->typeNode = ($typeHint === null) ? new ArgumentTypeNode() : new ArgumentTypeNode($typeHint);
}





public function isNullable()
{
return $this->typeNode->canUseNullShorthand();
}





public function setAsNullable($isNullable = true)
{
$nonNullTypes = $this->typeNode->getNonNullTypes();
$this->typeNode = $isNullable ? new ArgumentTypeNode('null', ...$nonNullTypes) : new ArgumentTypeNode(...$nonNullTypes);
}
}
<?php

namespace Prophecy\Doubler\Generator;







final class TypeHintReference
{
public function isBuiltInParamTypeHint($type)
{
switch ($type) {
case 'self':
case 'array':
case 'callable':
case 'bool':
case 'float':
case 'int':
case 'string':
case 'iterable':
case 'object':
return true;

case 'mixed':
return PHP_VERSION_ID >= 80000;

default:
return false;
}
}

public function isBuiltInReturnTypeHint($type)
{
if ($type === 'void') {
return true;
}

return $this->isBuiltInParamTypeHint($type);
}
}
<?php










namespace Prophecy\Doubler\Generator;

use Prophecy\Doubler\Generator\Node\ReturnTypeNode;
use Prophecy\Doubler\Generator\Node\TypeNodeAbstract;







class ClassCodeGenerator
{
public function __construct(TypeHintReference $typeHintReference = null)
{
}









public function generate($classname, Node\ClassNode $class)
{
$parts = explode('\\', $classname);
$classname = array_pop($parts);
$namespace = implode('\\', $parts);

$code = sprintf("class %s extends \%s implements %s {\n",
$classname, $class->getParentClass(), implode(', ',
array_map(function ($interface) {return '\\'.$interface;}, $class->getInterfaces())
)
);

foreach ($class->getProperties() as $name => $visibility) {
$code .= sprintf("%s \$%s;\n", $visibility, $name);
}
$code .= "\n";

foreach ($class->getMethods() as $method) {
$code .= $this->generateMethod($method)."\n";
}
$code .= "\n}";

return sprintf("namespace %s {\n%s\n}", $namespace, $code);
}

private function generateMethod(Node\MethodNode $method)
{
$php = sprintf("%s %s function %s%s(%s)%s {\n",
$method->getVisibility(),
$method->isStatic() ? 'static' : '',
$method->returnsReference() ? '&':'',
$method->getName(),
implode(', ', $this->generateArguments($method->getArguments())),
($ret = $this->generateTypes($method->getReturnTypeNode())) ? ': '.$ret : ''
);
$php .= $method->getCode()."\n";

return $php.'}';
}

private function generateTypes(TypeNodeAbstract $typeNode): string
{
if (!$typeNode->getTypes()) {
return '';
}


 if ($typeNode->canUseNullShorthand()) {
return sprintf( '?%s', $typeNode->getNonNullTypes()[0]);
} else {
return join('|', $typeNode->getTypes());
}
}

private function generateArguments(array $arguments)
{
return array_map(function (Node\ArgumentNode $argument){

$php = $this->generateTypes($argument->getTypeNode());

$php .= ' '.($argument->isPassedByReference() ? '&' : '');

$php .= $argument->isVariadic() ? '...' : '';

$php .= '$'.$argument->getName();

if ($argument->isOptional() && !$argument->isVariadic()) {
$php .= ' = '.var_export($argument->getDefault(), true);
}

return $php;
}, $arguments);
}
}
<?php










namespace Prophecy\Doubler\Generator;

use Prophecy\Doubler\Generator\Node\ArgumentTypeNode;
use Prophecy\Doubler\Generator\Node\ReturnTypeNode;
use Prophecy\Exception\InvalidArgumentException;
use Prophecy\Exception\Doubler\ClassMirrorException;
use ReflectionClass;
use ReflectionIntersectionType;
use ReflectionMethod;
use ReflectionNamedType;
use ReflectionParameter;
use ReflectionType;
use ReflectionUnionType;







class ClassMirror
{
private static $reflectableMethods = array(
'__construct',
'__destruct',
'__sleep',
'__wakeup',
'__toString',
'__call',
'__invoke'
);










public function reflect(?ReflectionClass $class, array $interfaces)
{
$node = new Node\ClassNode;

if (null !== $class) {
if (true === $class->isInterface()) {
throw new InvalidArgumentException(sprintf(
"Could not reflect %s as a class, because it\n".
"is interface - use the second argument instead.",
$class->getName()
));
}

$this->reflectClassToNode($class, $node);
}

foreach ($interfaces as $interface) {
if (!$interface instanceof ReflectionClass) {
throw new InvalidArgumentException(sprintf(
"[ReflectionClass \$interface1 [, ReflectionClass \$interface2]] array expected as\n".
"a second argument to `ClassMirror::reflect(...)`, but got %s.",
is_object($interface) ? get_class($interface).' class' : gettype($interface)
));
}
if (false === $interface->isInterface()) {
throw new InvalidArgumentException(sprintf(
"Could not reflect %s as an interface, because it\n".
"is class - use the first argument instead.",
$interface->getName()
));
}

$this->reflectInterfaceToNode($interface, $node);
}

$node->addInterface('Prophecy\Doubler\Generator\ReflectionInterface');

return $node;
}

private function reflectClassToNode(ReflectionClass $class, Node\ClassNode $node)
{
if (true === $class->isFinal()) {
throw new ClassMirrorException(sprintf(
'Could not reflect class %s as it is marked final.', $class->getName()
), $class);
}

$node->setParentClass($class->getName());

foreach ($class->getMethods(ReflectionMethod::IS_ABSTRACT) as $method) {
if (false === $method->isProtected()) {
continue;
}

$this->reflectMethodToNode($method, $node);
}

foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
if (0 === strpos($method->getName(), '_')
&& !in_array($method->getName(), self::$reflectableMethods)) {
continue;
}

if (true === $method->isFinal()) {
$node->addUnextendableMethod($method->getName());
continue;
}

$this->reflectMethodToNode($method, $node);
}
}

private function reflectInterfaceToNode(ReflectionClass $interface, Node\ClassNode $node)
{
$node->addInterface($interface->getName());

foreach ($interface->getMethods() as $method) {
$this->reflectMethodToNode($method, $node);
}
}

private function reflectMethodToNode(ReflectionMethod $method, Node\ClassNode $classNode)
{
$node = new Node\MethodNode($method->getName());

if (true === $method->isProtected()) {
$node->setVisibility('protected');
}

if (true === $method->isStatic()) {
$node->setStatic();
}

if (true === $method->returnsReference()) {
$node->setReturnsReference();
}

if ($method->hasReturnType()) {
$returnTypes = $this->getTypeHints($method->getReturnType(), $method->getDeclaringClass(), $method->getReturnType()->allowsNull());
$node->setReturnTypeNode(new ReturnTypeNode(...$returnTypes));
}
elseif (method_exists($method, 'hasTentativeReturnType') && $method->hasTentativeReturnType()) {
$returnTypes = $this->getTypeHints($method->getTentativeReturnType(), $method->getDeclaringClass(), $method->getTentativeReturnType()->allowsNull());
$node->setReturnTypeNode(new ReturnTypeNode(...$returnTypes));
}

if (is_array($params = $method->getParameters()) && count($params)) {
foreach ($params as $param) {
$this->reflectArgumentToNode($param, $node);
}
}

$classNode->addMethod($node);
}

private function reflectArgumentToNode(ReflectionParameter $parameter, Node\MethodNode $methodNode)
{
$name = $parameter->getName() == '...' ? '__dot_dot_dot__' : $parameter->getName();
$node = new Node\ArgumentNode($name);

$typeHints = $this->getTypeHints($parameter->getType(), $parameter->getDeclaringClass(), $parameter->allowsNull());

$node->setTypeNode(new ArgumentTypeNode(...$typeHints));

if ($parameter->isVariadic()) {
$node->setAsVariadic();
}

if ($this->hasDefaultValue($parameter)) {
$node->setDefault($this->getDefaultValue($parameter));
}

if ($parameter->isPassedByReference()) {
$node->setAsPassedByReference();
}


$methodNode->addArgument($node);
}

private function hasDefaultValue(ReflectionParameter $parameter)
{
if ($parameter->isVariadic()) {
return false;
}

if ($parameter->isDefaultValueAvailable()) {
return true;
}

return $parameter->isOptional() || ($parameter->allowsNull() && $parameter->getType() && \PHP_VERSION_ID < 80100);
}

private function getDefaultValue(ReflectionParameter $parameter)
{
if (!$parameter->isDefaultValueAvailable()) {
return null;
}

return $parameter->getDefaultValue();
}

private function getTypeHints(?ReflectionType $type, ?ReflectionClass $class, bool $allowsNull) : array
{
$types = [];

if ($type instanceof ReflectionNamedType) {
$types = [$type->getName()];

}
elseif ($type instanceof ReflectionUnionType) {
$types = $type->getTypes();
}
elseif ($type instanceof ReflectionIntersectionType) {
throw new ClassMirrorException('Doubling intersection types is not supported', $class);
}
elseif(is_object($type)) {
throw new ClassMirrorException('Unknown reflection type ' . get_class($type), $class);
}

$types = array_map(
function(string $type) use ($class) {
if ($type === 'self') {
return $class->getName();
}
if ($type === 'parent') {
return $class->getParentClass()->getName();
}

return $type;
},
$types
);

if ($types && $types != ['mixed'] && $allowsNull) {
$types[] = 'null';
}

return $types;
}
}
<?php










namespace Prophecy\Doubler;

use ReflectionClass;







class CachedDoubler extends Doubler
{
private static $classes = array();




protected function createDoubleClass(ReflectionClass $class = null, array $interfaces)
{
$classId = $this->generateClassId($class, $interfaces);
if (isset(self::$classes[$classId])) {
return self::$classes[$classId];
}

return self::$classes[$classId] = parent::createDoubleClass($class, $interfaces);
}







private function generateClassId(ReflectionClass $class = null, array $interfaces)
{
$parts = array();
if (null !== $class) {
$parts[] = $class->getName();
}
foreach ($interfaces as $interface) {
$parts[] = $interface->getName();
}
foreach ($this->getClassPatches() as $patch) {
$parts[] = get_class($patch);
}
sort($parts);

return md5(implode('', $parts));
}

public function resetCache()
{
self::$classes = array();
}
}
<?php










namespace Prophecy\Doubler;

use Prophecy\Exception\Doubler\DoubleException;
use Prophecy\Exception\Doubler\ClassNotFoundException;
use Prophecy\Exception\Doubler\InterfaceNotFoundException;
use ReflectionClass;







class LazyDouble
{
private $doubler;
private $class;
private $interfaces = array();
private $arguments = null;
private $double;






public function __construct(Doubler $doubler)
{
$this->doubler = $doubler;
}









public function setParentClass($class)
{
if (null !== $this->double) {
throw new DoubleException('Can not extend class with already instantiated double.');
}

if (!$class instanceof ReflectionClass) {
if (!class_exists($class)) {
throw new ClassNotFoundException(sprintf('Class %s not found.', $class), $class);
}

$class = new ReflectionClass($class);
}

$this->class = $class;
}









public function addInterface($interface)
{
if (null !== $this->double) {
throw new DoubleException(
'Can not implement interface with already instantiated double.'
);
}

if (!$interface instanceof ReflectionClass) {
if (!interface_exists($interface)) {
throw new InterfaceNotFoundException(
sprintf('Interface %s not found.', $interface),
$interface
);
}

$interface = new ReflectionClass($interface);
}

$this->interfaces[] = $interface;
}






public function setArguments(array $arguments = null)
{
$this->arguments = $arguments;
}






public function getInstance()
{
if (null === $this->double) {
if (null !== $this->arguments) {
return $this->double = $this->doubler->double(
$this->class, $this->interfaces, $this->arguments
);
}

$this->double = $this->doubler->double($this->class, $this->interfaces);
}

return $this->double;
}
}
<?php










namespace Prophecy\Doubler;

use Doctrine\Instantiator\Instantiator;
use Prophecy\Doubler\ClassPatch\ClassPatchInterface;
use Prophecy\Doubler\Generator\ClassMirror;
use Prophecy\Doubler\Generator\ClassCreator;
use Prophecy\Exception\InvalidArgumentException;
use ReflectionClass;







class Doubler
{
private $mirror;
private $creator;
private $namer;




private $patches = array();




private $instantiator;








public function __construct(ClassMirror $mirror = null, ClassCreator $creator = null,
NameGenerator $namer = null)
{
$this->mirror = $mirror ?: new ClassMirror;
$this->creator = $creator ?: new ClassCreator;
$this->namer = $namer ?: new NameGenerator;
}






public function getClassPatches()
{
return $this->patches;
}






public function registerClassPatch(ClassPatchInterface $patch)
{
$this->patches[] = $patch;

@usort($this->patches, function (ClassPatchInterface $patch1, ClassPatchInterface $patch2) {
return $patch2->getPriority() - $patch1->getPriority();
});
}












public function double(ReflectionClass $class = null, array $interfaces, array $args = null)
{
foreach ($interfaces as $interface) {
if (!$interface instanceof ReflectionClass) {
throw new InvalidArgumentException(sprintf(
"[ReflectionClass \$interface1 [, ReflectionClass \$interface2]] array expected as\n".
"a second argument to `Doubler::double(...)`, but got %s.",
is_object($interface) ? get_class($interface).' class' : gettype($interface)
));
}
}

$classname = $this->createDoubleClass($class, $interfaces);
$reflection = new ReflectionClass($classname);

if (null !== $args) {
return $reflection->newInstanceArgs($args);
}
if ((null === $constructor = $reflection->getConstructor())
|| ($constructor->isPublic() && !$constructor->isFinal())) {
return $reflection->newInstance();
}

if (!$this->instantiator) {
$this->instantiator = new Instantiator();
}

return $this->instantiator->instantiate($classname);
}









protected function createDoubleClass(ReflectionClass $class = null, array $interfaces)
{
$name = $this->namer->name($class, $interfaces);
$node = $this->mirror->reflect($class, $interfaces);

foreach ($this->patches as $patch) {
if ($patch->supports($node)) {
$patch->apply($node);
}
}

$this->creator->create($name, $node);

return $name;
}
}
<?php










namespace Prophecy\Doubler;







interface DoubleInterface
{
}
<?php










namespace Prophecy\Doubler\ClassPatch;

use Prophecy\Doubler\Generator\Node\ClassNode;






class KeywordPatch implements ClassPatchInterface
{







public function supports(ClassNode $node)
{
return true;
}






public function apply(ClassNode $node)
{
$methodNames = array_keys($node->getMethods());
$methodsToRemove = array_intersect($methodNames, $this->getKeywords());
foreach ($methodsToRemove as $methodName) {
$node->removeMethod($methodName);
}
}






public function getPriority()
{
return 49;
}






private function getKeywords()
{
return ['__halt_compiler'];
}
}
<?php










namespace Prophecy\Doubler\ClassPatch;

use Prophecy\Doubler\Generator\Node\ClassNode;







class ReflectionClassNewInstancePatch implements ClassPatchInterface
{







public function supports(ClassNode $node)
{
return 'ReflectionClass' === $node->getParentClass();
}






public function apply(ClassNode $node)
{
foreach ($node->getMethod('newInstance')->getArguments() as $argument) {
$argument->setDefault(null);
}
}






public function getPriority()
{
return 50;
}
}
<?php










namespace Prophecy\Doubler\ClassPatch;

use Prophecy\Doubler\Generator\Node\ClassNode;
use Prophecy\Doubler\Generator\Node\MethodNode;







class DisableConstructorPatch implements ClassPatchInterface
{







public function supports(ClassNode $node)
{
return true;
}






public function apply(ClassNode $node)
{
if (!$node->isExtendable('__construct')) {
return;
}

if (!$node->hasMethod('__construct')) {
$node->addMethod(new MethodNode('__construct', ''));

return;
}

$constructor = $node->getMethod('__construct');
foreach ($constructor->getArguments() as $argument) {
$argument->setDefault(null);
}

$constructor->setCode(<<<PHP
if (0 < func_num_args()) {
    call_user_func_array(array('parent', '__construct'), func_get_args());
}
PHP
);
}






public function getPriority()
{
return 100;
}
}
<?php










namespace Prophecy\Doubler\ClassPatch;

use Prophecy\Doubler\Generator\Node\ClassNode;






class HhvmExceptionPatch implements ClassPatchInterface
{







public function supports(ClassNode $node)
{
if (!defined('HHVM_VERSION')) {
return false;
}

return 'Exception' === $node->getParentClass() || is_subclass_of($node->getParentClass(), 'Exception');
}








public function apply(ClassNode $node)
{
if ($node->hasMethod('setTraceOptions')) {
$node->getMethod('setTraceOptions')->useParentCode();
}
if ($node->hasMethod('getTraceOptions')) {
$node->getMethod('getTraceOptions')->useParentCode();
}
}




public function getPriority()
{
return -50;
}
}
<?php










namespace Prophecy\Doubler\ClassPatch;

use Prophecy\Doubler\Generator\Node\ArgumentNode;
use Prophecy\Doubler\Generator\Node\ClassNode;
use Prophecy\Doubler\Generator\Node\MethodNode;
use Prophecy\PhpDocumentor\ClassAndInterfaceTagRetriever;
use Prophecy\PhpDocumentor\MethodTagRetrieverInterface;








class MagicCallPatch implements ClassPatchInterface
{
const MAGIC_METHODS_WITH_ARGUMENTS = ['__call', '__callStatic', '__get', '__isset', '__set', '__set_state', '__unserialize', '__unset'];

private $tagRetriever;

public function __construct(MethodTagRetrieverInterface $tagRetriever = null)
{
$this->tagRetriever = null === $tagRetriever ? new ClassAndInterfaceTagRetriever() : $tagRetriever;
}








public function supports(ClassNode $node)
{
return true;
}






public function apply(ClassNode $node)
{
$types = array_filter($node->getInterfaces(), function ($interface) {
return 0 !== strpos($interface, 'Prophecy\\');
});
$types[] = $node->getParentClass();

foreach ($types as $type) {
$reflectionClass = new \ReflectionClass($type);

while ($reflectionClass) {
$tagList = $this->tagRetriever->getTagList($reflectionClass);

foreach ($tagList as $tag) {
$methodName = $tag->getMethodName();

if (empty($methodName)) {
continue;
}

if (!$reflectionClass->hasMethod($methodName)) {
$methodNode = new MethodNode($methodName);


 if (in_array($methodName, self::MAGIC_METHODS_WITH_ARGUMENTS)) {
foreach($tag->getArguments() as $argument) {
$argumentNode = new ArgumentNode($argument['name']);
$methodNode->addArgument($argumentNode);
}
}

$methodNode->setStatic($tag->isStatic());
$node->addMethod($methodNode);
}
}

$reflectionClass = $reflectionClass->getParentClass();
}
}
}






public function getPriority()
{
return 50;
}
}
<?php










namespace Prophecy\Doubler\ClassPatch;

use Prophecy\Doubler\Generator\Node\ClassNode;








interface ClassPatchInterface
{







public function supports(ClassNode $node);







public function apply(ClassNode $node);






public function getPriority();
}
<?php










namespace Prophecy\Doubler\ClassPatch;

use Prophecy\Doubler\Generator\Node\ArgumentTypeNode;
use Prophecy\Doubler\Generator\Node\ClassNode;
use Prophecy\Doubler\Generator\Node\MethodNode;
use Prophecy\Doubler\Generator\Node\ArgumentNode;
use Prophecy\Doubler\Generator\Node\ReturnTypeNode;







class ProphecySubjectPatch implements ClassPatchInterface
{







public function supports(ClassNode $node)
{
return true;
}






public function apply(ClassNode $node)
{
$node->addInterface('Prophecy\Prophecy\ProphecySubjectInterface');
$node->addProperty('objectProphecyClosure', 'private');

foreach ($node->getMethods() as $name => $method) {
if ('__construct' === strtolower($name)) {
continue;
}

if (!$method->getReturnTypeNode()->hasReturnStatement()) {
$method->setCode(
'$this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());'
);
} else {
$method->setCode(
'return $this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());'
);
}
}

$prophecySetter = new MethodNode('setProphecy');
$prophecyArgument = new ArgumentNode('prophecy');
$prophecyArgument->setTypeNode(new ArgumentTypeNode('Prophecy\Prophecy\ProphecyInterface'));
$prophecySetter->addArgument($prophecyArgument);
$prophecySetter->setCode(<<<PHP
if (null === \$this->objectProphecyClosure) {
    \$this->objectProphecyClosure = static function () use (\$prophecy) {
        return \$prophecy;
    };
}
PHP
);

$prophecyGetter = new MethodNode('getProphecy');
$prophecyGetter->setCode('return \call_user_func($this->objectProphecyClosure);');

if ($node->hasMethod('__call')) {
$__call = $node->getMethod('__call');
} else {
$__call = new MethodNode('__call');
$__call->addArgument(new ArgumentNode('name'));
$__call->addArgument(new ArgumentNode('arguments'));

$node->addMethod($__call, true);
}

$__call->setCode(<<<PHP
throw new \Prophecy\Exception\Doubler\MethodNotFoundException(
    sprintf('Method `%s::%s()` not found.', get_class(\$this), func_get_arg(0)),
    get_class(\$this), func_get_arg(0)
);
PHP
);

$node->addMethod($prophecySetter, true);
$node->addMethod($prophecyGetter, true);
}






public function getPriority()
{
return 0;
}
}
<?php










namespace Prophecy\Doubler\ClassPatch;

use Prophecy\Doubler\Generator\Node\ClassNode;
use Prophecy\Doubler\Generator\Node\MethodNode;
use Prophecy\Doubler\Generator\Node\ReturnTypeNode;







class TraversablePatch implements ClassPatchInterface
{







public function supports(ClassNode $node)
{
if (in_array('Iterator', $node->getInterfaces())) {
return false;
}
if (in_array('IteratorAggregate', $node->getInterfaces())) {
return false;
}

foreach ($node->getInterfaces() as $interface) {
if ('Traversable' !== $interface && !is_subclass_of($interface, 'Traversable')) {
continue;
}
if ('Iterator' === $interface || is_subclass_of($interface, 'Iterator')) {
continue;
}
if ('IteratorAggregate' === $interface || is_subclass_of($interface, 'IteratorAggregate')) {
continue;
}

return true;
}

return false;
}






public function apply(ClassNode $node)
{
$node->addInterface('Iterator');

$currentMethod = new MethodNode('current');
(\PHP_VERSION_ID >= 80100) && $currentMethod->setReturnTypeNode(new ReturnTypeNode('mixed'));
$node->addMethod($currentMethod);

$keyMethod = new MethodNode('key');
(\PHP_VERSION_ID >= 80100) && $keyMethod->setReturnTypeNode(new ReturnTypeNode('mixed'));
$node->addMethod($keyMethod);

$nextMethod = new MethodNode('next');
(\PHP_VERSION_ID >= 80100) && $nextMethod->setReturnTypeNode(new ReturnTypeNode('void'));
$node->addMethod($nextMethod);

$rewindMethod = new MethodNode('rewind');
(\PHP_VERSION_ID >= 80100) && $rewindMethod->setReturnTypeNode(new ReturnTypeNode('void'));
$node->addMethod($rewindMethod);

$validMethod = new MethodNode('valid');
(\PHP_VERSION_ID >= 80100) && $validMethod->setReturnTypeNode(new ReturnTypeNode('bool'));
$node->addMethod($validMethod);
}






public function getPriority()
{
return 100;
}
}
<?php

namespace Prophecy\Doubler\ClassPatch;

use Prophecy\Doubler\Generator\Node\ClassNode;
use Prophecy\Exception\Doubler\ClassCreatorException;

class ThrowablePatch implements ClassPatchInterface
{






public function supports(ClassNode $node)
{
return $this->implementsAThrowableInterface($node) && $this->doesNotExtendAThrowableClass($node);
}





private function implementsAThrowableInterface(ClassNode $node)
{
foreach ($node->getInterfaces() as $type) {
if (is_a($type, 'Throwable', true)) {
return true;
}
}

return false;
}





private function doesNotExtendAThrowableClass(ClassNode $node)
{
return !is_a($node->getParentClass(), 'Throwable', true);
}








public function apply(ClassNode $node)
{
$this->checkItCanBeDoubled($node);
$this->setParentClassToException($node);
}

private function checkItCanBeDoubled(ClassNode $node)
{
$className = $node->getParentClass();
if ($className !== 'stdClass') {
throw new ClassCreatorException(
sprintf(
'Cannot double concrete class %s as well as implement Traversable',
$className
),
$node
);
}
}

private function setParentClassToException(ClassNode $node)
{
$node->setParentClass('Exception');

$node->removeMethod('getMessage');
$node->removeMethod('getCode');
$node->removeMethod('getFile');
$node->removeMethod('getLine');
$node->removeMethod('getTrace');
$node->removeMethod('getPrevious');
$node->removeMethod('getNext');
$node->removeMethod('getTraceAsString');
}






public function getPriority()
{
return 100;
}
}
<?php










namespace Prophecy\Doubler\ClassPatch;

use Prophecy\Doubler\Generator\Node\ClassNode;
use Prophecy\Doubler\Generator\Node\MethodNode;







class SplFileInfoPatch implements ClassPatchInterface
{







public function supports(ClassNode $node)
{
if (null === $node->getParentClass()) {
return false;
}
return 'SplFileInfo' === $node->getParentClass()
|| is_subclass_of($node->getParentClass(), 'SplFileInfo')
;
}






public function apply(ClassNode $node)
{
if ($node->hasMethod('__construct')) {
$constructor = $node->getMethod('__construct');
} else {
$constructor = new MethodNode('__construct');
$node->addMethod($constructor);
}

if ($this->nodeIsDirectoryIterator($node)) {
$constructor->setCode('return parent::__construct("' . __DIR__ . '");');

return;
}

if ($this->nodeIsSplFileObject($node)) {
$filePath = str_replace('\\','\\\\',__FILE__);
$constructor->setCode('return parent::__construct("' . $filePath .'");');

return;
}

if ($this->nodeIsSymfonySplFileInfo($node)) {
$filePath = str_replace('\\','\\\\',__FILE__);
$constructor->setCode('return parent::__construct("' . $filePath .'", "", "");');

return;
}

$constructor->useParentCode();
}






public function getPriority()
{
return 50;
}





private function nodeIsDirectoryIterator(ClassNode $node)
{
$parent = $node->getParentClass();

return 'DirectoryIterator' === $parent
|| is_subclass_of($parent, 'DirectoryIterator');
}





private function nodeIsSplFileObject(ClassNode $node)
{
$parent = $node->getParentClass();

return 'SplFileObject' === $parent
|| is_subclass_of($parent, 'SplFileObject');
}





private function nodeIsSymfonySplFileInfo(ClassNode $node)
{
$parent = $node->getParentClass();

return 'Symfony\\Component\\Finder\\SplFileInfo' === $parent;
}
}
<?php










namespace Prophecy\Exception\Prediction;

use RuntimeException;







class FailedPredictionException extends RuntimeException implements PredictionException
{
}
<?php










namespace Prophecy\Exception\Prediction;

use Prophecy\Exception\Exception;

interface PredictionException extends Exception
{
}
<?php










namespace Prophecy\Exception\Prediction;

use Prophecy\Prophecy\MethodProphecy;

class UnexpectedCallsCountException extends UnexpectedCallsException
{
private $expectedCount;

public function __construct($message, MethodProphecy $methodProphecy, $count, array $calls)
{
parent::__construct($message, $methodProphecy, $calls);

$this->expectedCount = intval($count);
}

public function getExpectedCount()
{
return $this->expectedCount;
}
}
<?php










namespace Prophecy\Exception\Prediction;

use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Exception\Prophecy\MethodProphecyException;

class UnexpectedCallsException extends MethodProphecyException implements PredictionException
{
private $calls = array();

public function __construct($message, MethodProphecy $methodProphecy, array $calls)
{
parent::__construct($message, $methodProphecy);

$this->calls = $calls;
}

public function getCalls()
{
return $this->calls;
}
}
<?php










namespace Prophecy\Exception\Prediction;

use Prophecy\Exception\Prophecy\MethodProphecyException;

class NoCallsException extends MethodProphecyException implements PredictionException
{
}
<?php










namespace Prophecy\Exception\Prediction;

use Prophecy\Prophecy\ObjectProphecy;

class AggregateException extends \RuntimeException implements PredictionException
{
private $exceptions = array();
private $objectProphecy;

public function append(PredictionException $exception)
{
$message = $exception->getMessage();
$message = strtr($message, array("\n" => "\n  "))."\n";
$message = empty($this->exceptions) ? $message : "\n" . $message;

$this->message = rtrim($this->message.$message);
$this->exceptions[] = $exception;
}




public function getExceptions()
{
return $this->exceptions;
}

public function setObjectProphecy(ObjectProphecy $objectProphecy)
{
$this->objectProphecy = $objectProphecy;
}




public function getObjectProphecy()
{
return $this->objectProphecy;
}
}
<?php










namespace Prophecy\Exception;







interface Exception extends \Throwable
{
}
<?php










namespace Prophecy\Exception\Prophecy;

use Prophecy\Prophecy\MethodProphecy;

class MethodProphecyException extends ObjectProphecyException
{
private $methodProphecy;

public function __construct($message, MethodProphecy $methodProphecy)
{
parent::__construct($message, $methodProphecy->getObjectProphecy());

$this->methodProphecy = $methodProphecy;
}




public function getMethodProphecy()
{
return $this->methodProphecy;
}
}
<?php










namespace Prophecy\Exception\Prophecy;

use Prophecy\Exception\Exception;

interface ProphecyException extends Exception
{
}
<?php










namespace Prophecy\Exception\Prophecy;

use Prophecy\Prophecy\ObjectProphecy;

class ObjectProphecyException extends \RuntimeException implements ProphecyException
{
private $objectProphecy;

public function __construct($message, ObjectProphecy $objectProphecy)
{
parent::__construct($message);

$this->objectProphecy = $objectProphecy;
}




public function getObjectProphecy()
{
return $this->objectProphecy;
}
}
<?php










namespace Prophecy\Exception\Call;

use Prophecy\Exception\Prophecy\ObjectProphecyException;
use Prophecy\Prophecy\ObjectProphecy;

class UnexpectedCallException extends ObjectProphecyException
{
private $methodName;
private $arguments;

public function __construct($message, ObjectProphecy $objectProphecy,
$methodName, array $arguments)
{
parent::__construct($message, $objectProphecy);

$this->methodName = $methodName;
$this->arguments = $arguments;
}

public function getMethodName()
{
return $this->methodName;
}

public function getArguments()
{
return $this->arguments;
}
}
<?php

namespace Prophecy\Exception\Doubler;

class MethodNotExtendableException extends DoubleException
{
private $methodName;

private $className;






public function __construct($message, $className, $methodName)
{
parent::__construct($message);

$this->methodName = $methodName;
$this->className = $className;
}





public function getMethodName()
{
return $this->methodName;
}




public function getClassName()
{
return $this->className;
}

}
<?php










namespace Prophecy\Exception\Doubler;

use Prophecy\Doubler\Generator\Node\ClassNode;

class ClassCreatorException extends \RuntimeException implements DoublerException
{
private $node;

public function __construct($message, ClassNode $node)
{
parent::__construct($message);

$this->node = $node;
}

public function getClassNode()
{
return $this->node;
}
}
<?php










namespace Prophecy\Exception\Doubler;

use Prophecy\Exception\Exception;

interface DoublerException extends Exception
{
}
<?php










namespace Prophecy\Exception\Doubler;

use ReflectionClass;

class ClassMirrorException extends \RuntimeException implements DoublerException
{
private $class;

public function __construct($message, ReflectionClass $class)
{
parent::__construct($message);

$this->class = $class;
}

public function getReflectedClass()
{
return $this->class;
}
}
<?php










namespace Prophecy\Exception\Doubler;

class ReturnByReferenceException extends DoubleException
{
private $classname;
private $methodName;






public function __construct($message, $classname, $methodName)
{
parent::__construct($message);

$this->classname = $classname;
$this->methodName = $methodName;
}

public function getClassname()
{
return $this->classname;
}

public function getMethodName()
{
return $this->methodName;
}
}
<?php










namespace Prophecy\Exception\Doubler;

class InterfaceNotFoundException extends ClassNotFoundException
{
public function getInterfaceName()
{
return $this->getClassname();
}
}
<?php










namespace Prophecy\Exception\Doubler;

use RuntimeException;

class DoubleException extends RuntimeException implements DoublerException
{
}
<?php










namespace Prophecy\Exception\Doubler;

class MethodNotFoundException extends DoubleException
{



private $classname;




private $methodName;




private $arguments;







public function __construct($message, $classname, $methodName, $arguments = null)
{
parent::__construct($message);

$this->classname = $classname;
$this->methodName = $methodName;
$this->arguments = $arguments;
}

public function getClassname()
{
return $this->classname;
}

public function getMethodName()
{
return $this->methodName;
}

public function getArguments()
{
return $this->arguments;
}
}
<?php










namespace Prophecy\Exception\Doubler;

class ClassNotFoundException extends DoubleException
{
private $classname;





public function __construct($message, $classname)
{
parent::__construct($message);

$this->classname = $classname;
}

public function getClassname()
{
return $this->classname;
}
}
<?php










namespace Prophecy\Exception;

class InvalidArgumentException extends \InvalidArgumentException implements Exception
{
}
<?php return array(
'root' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => 'd56c57e2e78441a6d2db7189df9aa37cf7493928',
'name' => 'codeception/phar-file',
'dev' => true,
),
'versions' => array(
'behat/gherkin' => array(
'pretty_version' => 'v4.9.0',
'version' => '4.9.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../behat/gherkin',
'aliases' => array(),
'reference' => '0bc8d1e30e96183e4f36db9dc79caead300beff4',
'dev_requirement' => false,
),
'codeception/codeception' => array(
'pretty_version' => '4.1.24',
'version' => '4.1.24.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/codeception',
'aliases' => array(),
'reference' => '1fc3a8f4d6cf7350e1b69afd136708cfffc89e9e',
'dev_requirement' => false,
),
'codeception/lib-asserts' => array(
'pretty_version' => '1.13.2',
'version' => '1.13.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/lib-asserts',
'aliases' => array(),
'reference' => '184231d5eab66bc69afd6b9429344d80c67a33b6',
'dev_requirement' => false,
),
'codeception/lib-innerbrowser' => array(
'pretty_version' => '1.5.1',
'version' => '1.5.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/lib-innerbrowser',
'aliases' => array(),
'reference' => '31b4b56ad53c3464fcb2c0a14d55a51a201bd3c2',
'dev_requirement' => false,
),
'codeception/module-amqp' => array(
'pretty_version' => '1.1.1',
'version' => '1.1.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/module-amqp',
'aliases' => array(),
'reference' => 'be399360429aff06d6291c389e9c64aff567b041',
'dev_requirement' => false,
),
'codeception/module-apc' => array(
'pretty_version' => '1.0.2',
'version' => '1.0.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/module-apc',
'aliases' => array(),
'reference' => '07fbd6dd12b9d3f4b738bcac8266eecefb470365',
'dev_requirement' => false,
),
'codeception/module-asserts' => array(
'pretty_version' => '1.3.1',
'version' => '1.3.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/module-asserts',
'aliases' => array(),
'reference' => '59374f2fef0cabb9e8ddb53277e85cdca74328de',
'dev_requirement' => false,
),
'codeception/module-cli' => array(
'pretty_version' => '1.1.1',
'version' => '1.1.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/module-cli',
'aliases' => array(),
'reference' => '1f841ad4a1d43e5d9e60a43c4cc9e5af8008024f',
'dev_requirement' => false,
),
'codeception/module-db' => array(
'pretty_version' => '1.1.0',
'version' => '1.1.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/module-db',
'aliases' => array(),
'reference' => '8c8076cd05d4db95798acd7dba2a56578210982c',
'dev_requirement' => false,
),
'codeception/module-filesystem' => array(
'pretty_version' => '1.0.3',
'version' => '1.0.3.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/module-filesystem',
'aliases' => array(),
'reference' => '781be167fb1557bfc9b61e0a4eac60a32c534ec1',
'dev_requirement' => false,
),
'codeception/module-ftp' => array(
'pretty_version' => '1.0.2',
'version' => '1.0.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/module-ftp',
'aliases' => array(),
'reference' => 'eed215edf32998c212da6f375a6d1c5e7c3a01c0',
'dev_requirement' => false,
),
'codeception/module-memcache' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/module-memcache',
'aliases' => array(),
'reference' => '96d65b6cf80bf19a858d7fa21257b8af1fe806ee',
'dev_requirement' => false,
),
'codeception/module-mongodb' => array(
'pretty_version' => '1.1.1',
'version' => '1.1.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/module-mongodb',
'aliases' => array(),
'reference' => '7bafcc9e7755b762436d742aa88c53726b5ddca5',
'dev_requirement' => false,
),
'codeception/module-phpbrowser' => array(
'pretty_version' => '1.0.2',
'version' => '1.0.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/module-phpbrowser',
'aliases' => array(),
'reference' => '770a6be4160a5c0c08d100dd51bff35f6056bbf1',
'dev_requirement' => false,
),
'codeception/module-queue' => array(
'pretty_version' => '1.1.1',
'version' => '1.1.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/module-queue',
'aliases' => array(),
'reference' => 'cf4116ed143758c8f36ac24c787f6647787e40f8',
'dev_requirement' => false,
),
'codeception/module-redis' => array(
'pretty_version' => '1.2.0',
'version' => '1.2.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/module-redis',
'aliases' => array(),
'reference' => 'eb68a805ee7a84af6548697bf6e21f1125e99b92',
'dev_requirement' => false,
),
'codeception/module-rest' => array(
'pretty_version' => '1.4.2',
'version' => '1.4.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/module-rest',
'aliases' => array(),
'reference' => '9cd7a87fd9343494e7782f7bdb51687c25046917',
'dev_requirement' => false,
),
'codeception/module-sequence' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/module-sequence',
'aliases' => array(),
'reference' => 'b75be26681ae90824cde8f8df785981f293667e1',
'dev_requirement' => false,
),
'codeception/module-soap' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/module-soap',
'aliases' => array(),
'reference' => '49d081cb0c455f405344a497fdbfda20168dcb9d',
'dev_requirement' => false,
),
'codeception/module-webdriver' => array(
'pretty_version' => '1.4.0',
'version' => '1.4.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/module-webdriver',
'aliases' => array(),
'reference' => 'baa18b7bf70aa024012f967b5ce5021e1faa9151',
'dev_requirement' => false,
),
'codeception/phar-file' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => 'd56c57e2e78441a6d2db7189df9aa37cf7493928',
'dev_requirement' => false,
),
'codeception/phpunit-wrapper' => array(
'pretty_version' => '8.1.4',
'version' => '8.1.4.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/phpunit-wrapper',
'aliases' => array(),
'reference' => 'f41335f0b4dd17cf7bbc63e87943b3ae72a8bbc3',
'dev_requirement' => false,
),
'codeception/stub' => array(
'pretty_version' => '3.7.0',
'version' => '3.7.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../codeception/stub',
'aliases' => array(),
'reference' => '468dd5fe659f131fc997f5196aad87512f9b1304',
'dev_requirement' => false,
),
'composer/ca-bundle' => array(
'pretty_version' => '1.3.1',
'version' => '1.3.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/./ca-bundle',
'aliases' => array(),
'reference' => '4c679186f2aca4ab6a0f1b0b9cf9252decb44d0b',
'dev_requirement' => false,
),
'doctrine/instantiator' => array(
'pretty_version' => '1.4.0',
'version' => '1.4.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../doctrine/instantiator',
'aliases' => array(),
'reference' => 'd56bf6102915de5702778fe20f2de3b2fe570b5b',
'dev_requirement' => false,
),
'facebook/webdriver' => array(
'dev_requirement' => false,
'replaced' => array(
0 => '*',
),
),
'flow/jsonpath' => array(
'dev_requirement' => false,
'replaced' => array(
0 => '*',
),
),
'guzzlehttp/guzzle' => array(
'pretty_version' => '6.5.5',
'version' => '6.5.5.0',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
'aliases' => array(),
'reference' => '9d4290de1cfd701f38099ef7e183b64b4b7b0c5e',
'dev_requirement' => false,
),
'guzzlehttp/promises' => array(
'pretty_version' => '1.5.1',
'version' => '1.5.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/promises',
'aliases' => array(),
'reference' => 'fe752aedc9fd8fcca3fe7ad05d419d32998a06da',
'dev_requirement' => false,
),
'guzzlehttp/psr7' => array(
'pretty_version' => '1.8.3',
'version' => '1.8.3.0',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/psr7',
'aliases' => array(),
'reference' => '1afdd860a2566ed3c2b0b4a3de6e23434a79ec85',
'dev_requirement' => false,
),
'hoa/consistency' => array(
'pretty_version' => '1.17.05.02',
'version' => '1.17.05.02',
'type' => 'library',
'install_path' => __DIR__ . '/../hoa/consistency',
'aliases' => array(),
'reference' => 'fd7d0adc82410507f332516faf655b6ed22e4c2f',
'dev_requirement' => false,
),
'hoa/console' => array(
'pretty_version' => '3.17.05.02',
'version' => '3.17.05.02',
'type' => 'library',
'install_path' => __DIR__ . '/../hoa/console',
'aliases' => array(),
'reference' => 'e231fd3ea70e6d773576ae78de0bdc1daf331a66',
'dev_requirement' => false,
),
'hoa/event' => array(
'pretty_version' => '1.17.01.13',
'version' => '1.17.01.13',
'type' => 'library',
'install_path' => __DIR__ . '/../hoa/event',
'aliases' => array(),
'reference' => '6c0060dced212ffa3af0e34bb46624f990b29c54',
'dev_requirement' => false,
),
'hoa/exception' => array(
'pretty_version' => '1.17.01.16',
'version' => '1.17.01.16',
'type' => 'library',
'install_path' => __DIR__ . '/../hoa/exception',
'aliases' => array(),
'reference' => '091727d46420a3d7468ef0595651488bfc3a458f',
'dev_requirement' => false,
),
'hoa/file' => array(
'pretty_version' => '1.17.07.11',
'version' => '1.17.07.11',
'type' => 'library',
'install_path' => __DIR__ . '/../hoa/file',
'aliases' => array(),
'reference' => '35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca',
'dev_requirement' => false,
),
'hoa/iterator' => array(
'pretty_version' => '2.17.01.10',
'version' => '2.17.01.10',
'type' => 'library',
'install_path' => __DIR__ . '/../hoa/iterator',
'aliases' => array(),
'reference' => 'd1120ba09cb4ccd049c86d10058ab94af245f0cc',
'dev_requirement' => false,
),
'hoa/protocol' => array(
'pretty_version' => '1.17.01.14',
'version' => '1.17.01.14',
'type' => 'library',
'install_path' => __DIR__ . '/../hoa/protocol',
'aliases' => array(),
'reference' => '5c2cf972151c45f373230da170ea015deecf19e2',
'dev_requirement' => false,
),
'hoa/stream' => array(
'pretty_version' => '1.17.02.21',
'version' => '1.17.02.21',
'type' => 'library',
'install_path' => __DIR__ . '/../hoa/stream',
'aliases' => array(),
'reference' => '3293cfffca2de10525df51436adf88a559151d82',
'dev_requirement' => false,
),
'hoa/ustring' => array(
'pretty_version' => '4.17.01.16',
'version' => '4.17.01.16',
'type' => 'library',
'install_path' => __DIR__ . '/../hoa/ustring',
'aliases' => array(),
'reference' => 'e6326e2739178799b1fe3fdd92029f9517fa17a0',
'dev_requirement' => false,
),
'justinrainbow/json-schema' => array(
'pretty_version' => '5.2.11',
'version' => '5.2.11.0',
'type' => 'library',
'install_path' => __DIR__ . '/../justinrainbow/json-schema',
'aliases' => array(),
'reference' => '2ab6744b7296ded80f8cc4f9509abbff393399aa',
'dev_requirement' => false,
),
'myclabs/deep-copy' => array(
'pretty_version' => '1.10.2',
'version' => '1.10.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../myclabs/deep-copy',
'aliases' => array(),
'reference' => '776f831124e9c62e1a2c601ecc52e776d8bb7220',
'dev_requirement' => false,
'replaced' => array(
0 => '1.10.2',
),
),
'padraic/humbug_get_contents' => array(
'pretty_version' => '1.1.2',
'version' => '1.1.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../padraic/humbug_get_contents',
'aliases' => array(),
'reference' => 'dcb086060c9dd6b2f51d8f7a895500307110b7a7',
'dev_requirement' => false,
),
'padraic/phar-updater' => array(
'pretty_version' => 'v1.0.6',
'version' => '1.0.6.0',
'type' => 'library',
'install_path' => __DIR__ . '/../padraic/phar-updater',
'aliases' => array(),
'reference' => 'd01d3b8f26e541ac9b9eeba1e18d005d852f7ff1',
'dev_requirement' => false,
),
'phar-io/manifest' => array(
'pretty_version' => '2.0.3',
'version' => '2.0.3.0',
'type' => 'library',
'install_path' => __DIR__ . '/../phar-io/manifest',
'aliases' => array(),
'reference' => '97803eca37d319dfa7826cc2437fc020857acb53',
'dev_requirement' => false,
),
'phar-io/version' => array(
'pretty_version' => '3.1.0',
'version' => '3.1.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../phar-io/version',
'aliases' => array(),
'reference' => 'bae7c545bef187884426f042434e561ab1ddb182',
'dev_requirement' => false,
),
'php-amqplib/php-amqplib' => array(
'pretty_version' => 'v3.1.1',
'version' => '3.1.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../php-amqplib/php-amqplib',
'aliases' => array(),
'reference' => '1d8e724c1de8ac5a4322f26ba735695880514874',
'dev_requirement' => false,
),
'php-webdriver/webdriver' => array(
'pretty_version' => '1.12.0',
'version' => '1.12.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../php-webdriver/webdriver',
'aliases' => array(),
'reference' => '99d4856ed7dffcdf6a52eccd6551e83d8d557ceb',
'dev_requirement' => false,
),
'phpdocumentor/reflection-common' => array(
'pretty_version' => '2.2.0',
'version' => '2.2.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../phpdocumentor/reflection-common',
'aliases' => array(),
'reference' => '1d01c49d4ed62f25aa84a747ad35d5a16924662b',
'dev_requirement' => false,
),
'phpdocumentor/reflection-docblock' => array(
'pretty_version' => '5.3.0',
'version' => '5.3.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../phpdocumentor/reflection-docblock',
'aliases' => array(),
'reference' => '622548b623e81ca6d78b721c5e029f4ce664f170',
'dev_requirement' => false,
),
'phpdocumentor/type-resolver' => array(
'pretty_version' => '1.5.1',
'version' => '1.5.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../phpdocumentor/type-resolver',
'aliases' => array(),
'reference' => 'a12f7e301eb7258bb68acd89d4aefa05c2906cae',
'dev_requirement' => false,
),
'phpseclib/phpseclib' => array(
'pretty_version' => '2.0.35',
'version' => '2.0.35.0',
'type' => 'library',
'install_path' => __DIR__ . '/../phpseclib/phpseclib',
'aliases' => array(),
'reference' => '4e16cf3f5f927a7d3f5317820af795c0366c0420',
'dev_requirement' => false,
),
'phpspec/prophecy' => array(
'pretty_version' => 'v1.15.0',
'version' => '1.15.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../phpspec/prophecy',
'aliases' => array(),
'reference' => 'bbcd7380b0ebf3961ee21409db7b38bc31d69a13',
'dev_requirement' => false,
),
'phpunit/php-code-coverage' => array(
'pretty_version' => '7.0.15',
'version' => '7.0.15.0',
'type' => 'library',
'install_path' => __DIR__ . '/../phpunit/php-code-coverage',
'aliases' => array(),
'reference' => '819f92bba8b001d4363065928088de22f25a3a48',
'dev_requirement' => false,
),
'phpunit/php-file-iterator' => array(
'pretty_version' => '2.0.5',
'version' => '2.0.5.0',
'type' => 'library',
'install_path' => __DIR__ . '/../phpunit/php-file-iterator',
'aliases' => array(),
'reference' => '42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5',
'dev_requirement' => false,
),
'phpunit/php-text-template' => array(
'pretty_version' => '1.2.1',
'version' => '1.2.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../phpunit/php-text-template',
'aliases' => array(),
'reference' => '31f8b717e51d9a2afca6c9f046f5d69fc27c8686',
'dev_requirement' => false,
),
'phpunit/php-timer' => array(
'pretty_version' => '2.1.3',
'version' => '2.1.3.0',
'type' => 'library',
'install_path' => __DIR__ . '/../phpunit/php-timer',
'aliases' => array(),
'reference' => '2454ae1765516d20c4ffe103d85a58a9a3bd5662',
'dev_requirement' => false,
),
'phpunit/php-token-stream' => array(
'pretty_version' => '3.1.3',
'version' => '3.1.3.0',
'type' => 'library',
'install_path' => __DIR__ . '/../phpunit/php-token-stream',
'aliases' => array(),
'reference' => '9c1da83261628cb24b6a6df371b6e312b3954768',
'dev_requirement' => false,
),
'phpunit/phpunit' => array(
'pretty_version' => '8.5.21',
'version' => '8.5.21.0',
'type' => 'library',
'install_path' => __DIR__ . '/../phpunit/phpunit',
'aliases' => array(),
'reference' => '50a58a60b85947b0bee4c8ecfe0f4bbdcf20e984',
'dev_requirement' => false,
),
'predis/predis' => array(
'pretty_version' => 'v1.1.9',
'version' => '1.1.9.0',
'type' => 'library',
'install_path' => __DIR__ . '/../predis/predis',
'aliases' => array(),
'reference' => 'c50c3393bb9f47fa012d0cdfb727a266b0818259',
'dev_requirement' => false,
),
'psr/container' => array(
'pretty_version' => '1.1.1',
'version' => '1.1.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/container',
'aliases' => array(),
'reference' => '8622567409010282b7aeebe4bb841fe98b58dcaf',
'dev_requirement' => false,
),
'psr/event-dispatcher-implementation' => array(
'dev_requirement' => false,
'provided' => array(
0 => '1.0',
),
),
'psr/http-message' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-message',
'aliases' => array(),
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
'dev_requirement' => false,
),
'psr/http-message-implementation' => array(
'dev_requirement' => false,
'provided' => array(
0 => '1.0',
),
),
'psr/log-implementation' => array(
'dev_requirement' => false,
'provided' => array(
0 => '1.0|2.0',
),
),
'ralouphie/getallheaders' => array(
'pretty_version' => '3.0.3',
'version' => '3.0.3.0',
'type' => 'library',
'install_path' => __DIR__ . '/../ralouphie/getallheaders',
'aliases' => array(),
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
'dev_requirement' => false,
),
'sebastian/code-unit-reverse-lookup' => array(
'pretty_version' => '1.0.2',
'version' => '1.0.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sebastian/code-unit-reverse-lookup',
'aliases' => array(),
'reference' => '1de8cd5c010cb153fcd68b8d0f64606f523f7619',
'dev_requirement' => false,
),
'sebastian/comparator' => array(
'pretty_version' => '3.0.3',
'version' => '3.0.3.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sebastian/comparator',
'aliases' => array(),
'reference' => '1071dfcef776a57013124ff35e1fc41ccd294758',
'dev_requirement' => false,
),
'sebastian/diff' => array(
'pretty_version' => '3.0.3',
'version' => '3.0.3.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sebastian/diff',
'aliases' => array(),
'reference' => '14f72dd46eaf2f2293cbe79c93cc0bc43161a211',
'dev_requirement' => false,
),
'sebastian/environment' => array(
'pretty_version' => '4.2.4',
'version' => '4.2.4.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sebastian/environment',
'aliases' => array(),
'reference' => 'd47bbbad83711771f167c72d4e3f25f7fcc1f8b0',
'dev_requirement' => false,
),
'sebastian/exporter' => array(
'pretty_version' => '3.1.4',
'version' => '3.1.4.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sebastian/exporter',
'aliases' => array(),
'reference' => '0c32ea2e40dbf59de29f3b49bf375176ce7dd8db',
'dev_requirement' => false,
),
'sebastian/global-state' => array(
'pretty_version' => '3.0.1',
'version' => '3.0.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sebastian/global-state',
'aliases' => array(),
'reference' => '474fb9edb7ab891665d3bfc6317f42a0a150454b',
'dev_requirement' => false,
),
'sebastian/object-enumerator' => array(
'pretty_version' => '3.0.4',
'version' => '3.0.4.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sebastian/object-enumerator',
'aliases' => array(),
'reference' => 'e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2',
'dev_requirement' => false,
),
'sebastian/object-reflector' => array(
'pretty_version' => '1.1.2',
'version' => '1.1.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sebastian/object-reflector',
'aliases' => array(),
'reference' => '9b8772b9cbd456ab45d4a598d2dd1a1bced6363d',
'dev_requirement' => false,
),
'sebastian/recursion-context' => array(
'pretty_version' => '3.0.1',
'version' => '3.0.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sebastian/recursion-context',
'aliases' => array(),
'reference' => '367dcba38d6e1977be014dc4b22f47a484dac7fb',
'dev_requirement' => false,
),
'sebastian/resource-operations' => array(
'pretty_version' => '2.0.2',
'version' => '2.0.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sebastian/resource-operations',
'aliases' => array(),
'reference' => '31d35ca87926450c44eae7e2611d45a7a65ea8b3',
'dev_requirement' => false,
),
'sebastian/type' => array(
'pretty_version' => '1.1.4',
'version' => '1.1.4.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sebastian/type',
'aliases' => array(),
'reference' => '0150cfbc4495ed2df3872fb31b26781e4e077eb4',
'dev_requirement' => false,
),
'sebastian/version' => array(
'pretty_version' => '2.0.1',
'version' => '2.0.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sebastian/version',
'aliases' => array(),
'reference' => '99732be0ddb3361e16ad77b68ba41efc8e979019',
'dev_requirement' => false,
),
'softcreatr/jsonpath' => array(
'pretty_version' => '0.7.5',
'version' => '0.7.5.0',
'type' => 'library',
'install_path' => __DIR__ . '/../softcreatr/jsonpath',
'aliases' => array(),
'reference' => '008569bf80aa3584834f7890781576bc7b65afa7',
'dev_requirement' => false,
),
'symfony/browser-kit' => array(
'pretty_version' => 'v4.4.27',
'version' => '4.4.27.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/browser-kit',
'aliases' => array(),
'reference' => '9629d1524d8ced5a4ec3e94abdbd638b4ec8319b',
'dev_requirement' => false,
),
'symfony/console' => array(
'pretty_version' => 'v4.4.34',
'version' => '4.4.34.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/console',
'aliases' => array(),
'reference' => '329b3a75cc6b16d435ba1b1a41df54a53382a3f0',
'dev_requirement' => false,
),
'symfony/css-selector' => array(
'pretty_version' => 'v4.4.27',
'version' => '4.4.27.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/css-selector',
'aliases' => array(),
'reference' => '5194f18bd80d106f11efa8f7cd0fbdcc3af96ce6',
'dev_requirement' => false,
),
'symfony/dom-crawler' => array(
'pretty_version' => 'v4.4.30',
'version' => '4.4.30.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/dom-crawler',
'aliases' => array(),
'reference' => '4632ae3567746c7e915c33c67a2fb6ab746090c4',
'dev_requirement' => false,
),
'symfony/event-dispatcher' => array(
'pretty_version' => 'v4.4.34',
'version' => '4.4.34.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/event-dispatcher',
'aliases' => array(),
'reference' => '1a024b45369c9d55d76b6b8a241bd20c9ea1cbd8',
'dev_requirement' => false,
),
'symfony/event-dispatcher-contracts' => array(
'pretty_version' => 'v1.1.11',
'version' => '1.1.11.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/event-dispatcher-contracts',
'aliases' => array(),
'reference' => '01e9a4efac0ee33a05dfdf93b346f62e7d0e998c',
'dev_requirement' => false,
),
'symfony/event-dispatcher-implementation' => array(
'dev_requirement' => false,
'provided' => array(
0 => '1.1',
),
),
'symfony/finder' => array(
'pretty_version' => 'v4.4.30',
'version' => '4.4.30.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/finder',
'aliases' => array(),
'reference' => '70362f1e112280d75b30087c7598b837c1b468b6',
'dev_requirement' => false,
),
'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(),
'reference' => '46cd95797e9df938fdd2b03693b5fca5e64b01ce',
'dev_requirement' => false,
),
'symfony/polyfill-intl-idn' => array(
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn',
'aliases' => array(),
'reference' => '65bd267525e82759e7d8c4e8ceea44f398838e65',
'dev_requirement' => false,
),
'symfony/polyfill-intl-normalizer' => array(
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',
'aliases' => array(),
'reference' => '8590a5f561694770bdcd3f9b5c69dde6945028e8',
'dev_requirement' => false,
),
'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.23.1',
'version' => '1.23.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(),
'reference' => '9174a3d80210dca8daa7f31fec659150bbeabfc6',
'dev_requirement' => false,
),
'symfony/polyfill-php72' => array(
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php72',
'aliases' => array(),
'reference' => '9a142215a36a3888e30d0a9eeea9766764e96976',
'dev_requirement' => false,
),
'symfony/polyfill-php73' => array(
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php73',
'aliases' => array(),
'reference' => 'fba8933c384d6476ab14fb7b8526e5287ca7e010',
'dev_requirement' => false,
),
'symfony/polyfill-php80' => array(
'pretty_version' => 'v1.23.1',
'version' => '1.23.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
'aliases' => array(),
'reference' => '1100343ed1a92e3a38f9ae122fc0eb21602547be',
'dev_requirement' => false,
),
'symfony/process' => array(
'pretty_version' => 'v4.4.35',
'version' => '4.4.35.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/process',
'aliases' => array(),
'reference' => 'c2098705326addae6e6742151dfade47ac71da1b',
'dev_requirement' => false,
),
'symfony/service-contracts' => array(
'pretty_version' => 'v1.1.11',
'version' => '1.1.11.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/service-contracts',
'aliases' => array(),
'reference' => '633df678bec3452e04a7b0337c9bcfe7354124b3',
'dev_requirement' => false,
),
'symfony/yaml' => array(
'pretty_version' => 'v4.4.34',
'version' => '4.4.34.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/yaml',
'aliases' => array(),
'reference' => '2c309e258adeb9970229042be39b360d34986fad',
'dev_requirement' => false,
),
'theseer/tokenizer' => array(
'pretty_version' => '1.2.1',
'version' => '1.2.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../theseer/tokenizer',
'aliases' => array(),
'reference' => '34a41e998c2183e22995f158c581e7b5e755ab9e',
'dev_requirement' => false,
),
'videlalvaro/php-amqplib' => array(
'dev_requirement' => false,
'replaced' => array(
0 => 'v3.1.1',
),
),
'webmozart/assert' => array(
'pretty_version' => '1.10.0',
'version' => '1.10.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../webmozart/assert',
'aliases' => array(),
'reference' => '6964c76c7804814a842473e0c8fd15bab0f18e25',
'dev_requirement' => false,
),
),
);
<?php



$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'e88992873b7765f9b5710cab95ba5dd7' => $vendorDir . '/hoa/consistency/Prelude.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
'e3b2795a8a512b6083af088fb53afe6c' => $vendorDir . '/codeception/codeception/functions.php',
'3e76f7f02b41af8cea96018933f6b7e3' => $vendorDir . '/hoa/protocol/Wrapper.php',
'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',
'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'6124b4c8570aa390c21fafd04a26c69f' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/deep_copy.php',
'd9d39f82a605ebe5918f683dd402334c' => $vendorDir . '/padraic/humbug_get_contents/src/function.php',
'3a50d90d85c7fe889a94ae1114b921ce' => $vendorDir . '/padraic/humbug_get_contents/src/functions.php',
'2a3c2110e8e0295330dc3d11a4cbc4cb' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/TimeoutException.php',
);
<?php



class ComposerAutoloaderInit8d2576a0103fe25d0268c6cba2a989ff
{
private static $loader;

public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}




public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}

require __DIR__ . '/platform_check.php';

spl_autoload_register(array('ComposerAutoloaderInit8d2576a0103fe25d0268c6cba2a989ff', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInit8d2576a0103fe25d0268c6cba2a989ff', 'loadClassLoader'));

$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';

call_user_func(\Composer\Autoload\ComposerStaticInit8d2576a0103fe25d0268c6cba2a989ff::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}

$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}

$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}

$loader->register(true);

if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit8d2576a0103fe25d0268c6cba2a989ff::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire8d2576a0103fe25d0268c6cba2a989ff($fileIdentifier, $file);
}

return $loader;
}
}

function composerRequire8d2576a0103fe25d0268c6cba2a989ff($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;

$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}
<?php



$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Behat\\Gherkin\\Cache\\CacheInterface' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Cache/CacheInterface.php',
'Behat\\Gherkin\\Cache\\FileCache' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Cache/FileCache.php',
'Behat\\Gherkin\\Cache\\MemoryCache' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Cache/MemoryCache.php',
'Behat\\Gherkin\\Exception\\CacheException' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Exception/CacheException.php',
'Behat\\Gherkin\\Exception\\Exception' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Exception/Exception.php',
'Behat\\Gherkin\\Exception\\LexerException' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Exception/LexerException.php',
'Behat\\Gherkin\\Exception\\NodeException' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Exception/NodeException.php',
'Behat\\Gherkin\\Exception\\ParserException' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Exception/ParserException.php',
'Behat\\Gherkin\\Filter\\ComplexFilter' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Filter/ComplexFilter.php',
'Behat\\Gherkin\\Filter\\ComplexFilterInterface' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Filter/ComplexFilterInterface.php',
'Behat\\Gherkin\\Filter\\FeatureFilterInterface' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Filter/FeatureFilterInterface.php',
'Behat\\Gherkin\\Filter\\FilterInterface' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Filter/FilterInterface.php',
'Behat\\Gherkin\\Filter\\LineFilter' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Filter/LineFilter.php',
'Behat\\Gherkin\\Filter\\LineRangeFilter' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Filter/LineRangeFilter.php',
'Behat\\Gherkin\\Filter\\NameFilter' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Filter/NameFilter.php',
'Behat\\Gherkin\\Filter\\NarrativeFilter' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Filter/NarrativeFilter.php',
'Behat\\Gherkin\\Filter\\PathsFilter' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Filter/PathsFilter.php',
'Behat\\Gherkin\\Filter\\RoleFilter' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Filter/RoleFilter.php',
'Behat\\Gherkin\\Filter\\SimpleFilter' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Filter/SimpleFilter.php',
'Behat\\Gherkin\\Filter\\TagFilter' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Filter/TagFilter.php',
'Behat\\Gherkin\\Gherkin' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Gherkin.php',
'Behat\\Gherkin\\Keywords\\ArrayKeywords' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Keywords/ArrayKeywords.php',
'Behat\\Gherkin\\Keywords\\CachedArrayKeywords' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Keywords/CachedArrayKeywords.php',
'Behat\\Gherkin\\Keywords\\CucumberKeywords' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Keywords/CucumberKeywords.php',
'Behat\\Gherkin\\Keywords\\KeywordsDumper' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Keywords/KeywordsDumper.php',
'Behat\\Gherkin\\Keywords\\KeywordsInterface' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Keywords/KeywordsInterface.php',
'Behat\\Gherkin\\Lexer' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Lexer.php',
'Behat\\Gherkin\\Loader\\AbstractFileLoader' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Loader/AbstractFileLoader.php',
'Behat\\Gherkin\\Loader\\ArrayLoader' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Loader/ArrayLoader.php',
'Behat\\Gherkin\\Loader\\CucumberNDJsonAstLoader' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Loader/CucumberNDJsonAstLoader.php',
'Behat\\Gherkin\\Loader\\DirectoryLoader' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Loader/DirectoryLoader.php',
'Behat\\Gherkin\\Loader\\FileLoaderInterface' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Loader/FileLoaderInterface.php',
'Behat\\Gherkin\\Loader\\GherkinFileLoader' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Loader/GherkinFileLoader.php',
'Behat\\Gherkin\\Loader\\LoaderInterface' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Loader/LoaderInterface.php',
'Behat\\Gherkin\\Loader\\YamlFileLoader' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Loader/YamlFileLoader.php',
'Behat\\Gherkin\\Node\\ArgumentInterface' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Node/ArgumentInterface.php',
'Behat\\Gherkin\\Node\\BackgroundNode' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Node/BackgroundNode.php',
'Behat\\Gherkin\\Node\\ExampleNode' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Node/ExampleNode.php',
'Behat\\Gherkin\\Node\\ExampleTableNode' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Node/ExampleTableNode.php',
'Behat\\Gherkin\\Node\\FeatureNode' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Node/FeatureNode.php',
'Behat\\Gherkin\\Node\\KeywordNodeInterface' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Node/KeywordNodeInterface.php',
'Behat\\Gherkin\\Node\\NodeInterface' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Node/NodeInterface.php',
'Behat\\Gherkin\\Node\\OutlineNode' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Node/OutlineNode.php',
'Behat\\Gherkin\\Node\\PyStringNode' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Node/PyStringNode.php',
'Behat\\Gherkin\\Node\\ScenarioInterface' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Node/ScenarioInterface.php',
'Behat\\Gherkin\\Node\\ScenarioLikeInterface' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Node/ScenarioLikeInterface.php',
'Behat\\Gherkin\\Node\\ScenarioNode' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Node/ScenarioNode.php',
'Behat\\Gherkin\\Node\\StepContainerInterface' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Node/StepContainerInterface.php',
'Behat\\Gherkin\\Node\\StepNode' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Node/StepNode.php',
'Behat\\Gherkin\\Node\\TableNode' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Node/TableNode.php',
'Behat\\Gherkin\\Node\\TaggedNodeInterface' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Node/TaggedNodeInterface.php',
'Behat\\Gherkin\\Parser' => $vendorDir . '/behat/gherkin/src/Behat/Gherkin/Parser.php',
'Codeception\\Actor' => $vendorDir . '/codeception/codeception/src/Codeception/Actor.php',
'Codeception\\Application' => $vendorDir . '/codeception/codeception/src/Codeception/Application.php',
'Codeception\\Codecept' => $vendorDir . '/codeception/codeception/src/Codeception/Codecept.php',
'Codeception\\Command\\Bootstrap' => $vendorDir . '/codeception/codeception/src/Codeception/Command/Bootstrap.php',
'Codeception\\Command\\Build' => $vendorDir . '/codeception/codeception/src/Codeception/Command/Build.php',
'Codeception\\Command\\Clean' => $vendorDir . '/codeception/codeception/src/Codeception/Command/Clean.php',
'Codeception\\Command\\Completion' => $vendorDir . '/codeception/codeception/src/Codeception/Command/Completion.php',
'Codeception\\Command\\CompletionFallback' => $vendorDir . '/codeception/codeception/src/Codeception/Command/CompletionFallback.php',
'Codeception\\Command\\ConfigValidate' => $vendorDir . '/codeception/codeception/src/Codeception/Command/ConfigValidate.php',
'Codeception\\Command\\Console' => $vendorDir . '/codeception/codeception/src/Codeception/Command/Console.php',
'Codeception\\Command\\DryRun' => $vendorDir . '/codeception/codeception/src/Codeception/Command/DryRun.php',
'Codeception\\Command\\GenerateCept' => $vendorDir . '/codeception/codeception/src/Codeception/Command/GenerateCept.php',
'Codeception\\Command\\GenerateCest' => $vendorDir . '/codeception/codeception/src/Codeception/Command/GenerateCest.php',
'Codeception\\Command\\GenerateEnvironment' => $vendorDir . '/codeception/codeception/src/Codeception/Command/GenerateEnvironment.php',
'Codeception\\Command\\GenerateFeature' => $vendorDir . '/codeception/codeception/src/Codeception/Command/GenerateFeature.php',
'Codeception\\Command\\GenerateGroup' => $vendorDir . '/codeception/codeception/src/Codeception/Command/GenerateGroup.php',
'Codeception\\Command\\GenerateHelper' => $vendorDir . '/codeception/codeception/src/Codeception/Command/GenerateHelper.php',
'Codeception\\Command\\GeneratePageObject' => $vendorDir . '/codeception/codeception/src/Codeception/Command/GeneratePageObject.php',
'Codeception\\Command\\GenerateScenarios' => $vendorDir . '/codeception/codeception/src/Codeception/Command/GenerateScenarios.php',
'Codeception\\Command\\GenerateSnapshot' => $vendorDir . '/codeception/codeception/src/Codeception/Command/GenerateSnapshot.php',
'Codeception\\Command\\GenerateStepObject' => $vendorDir . '/codeception/codeception/src/Codeception/Command/GenerateStepObject.php',
'Codeception\\Command\\GenerateSuite' => $vendorDir . '/codeception/codeception/src/Codeception/Command/GenerateSuite.php',
'Codeception\\Command\\GenerateTest' => $vendorDir . '/codeception/codeception/src/Codeception/Command/GenerateTest.php',
'Codeception\\Command\\GherkinSnippets' => $vendorDir . '/codeception/codeception/src/Codeception/Command/GherkinSnippets.php',
'Codeception\\Command\\GherkinSteps' => $vendorDir . '/codeception/codeception/src/Codeception/Command/GherkinSteps.php',
'Codeception\\Command\\Init' => $vendorDir . '/codeception/codeception/src/Codeception/Command/Init.php',
'Codeception\\Command\\Run' => $vendorDir . '/codeception/codeception/src/Codeception/Command/Run.php',
'Codeception\\Command\\SelfUpdate' => $vendorDir . '/codeception/codeception/src/Codeception/Command/SelfUpdate.php',
'Codeception\\Command\\Shared\\Config' => $vendorDir . '/codeception/codeception/src/Codeception/Command/Shared/Config.php',
'Codeception\\Command\\Shared\\FileSystem' => $vendorDir . '/codeception/codeception/src/Codeception/Command/Shared/FileSystem.php',
'Codeception\\Command\\Shared\\Style' => $vendorDir . '/codeception/codeception/src/Codeception/Command/Shared/Style.php',
'Codeception\\Configuration' => $vendorDir . '/codeception/codeception/src/Codeception/Configuration.php',
'Codeception\\Coverage\\Filter' => $vendorDir . '/codeception/codeception/src/Codeception/Coverage/Filter.php',
'Codeception\\Coverage\\PhpCodeCoverageFactory' => $vendorDir . '/codeception/codeception/src/Codeception/Coverage/PhpCodeCoverageFactory.php',
'Codeception\\Coverage\\Subscriber\\Local' => $vendorDir . '/codeception/codeception/src/Codeception/Coverage/Subscriber/Local.php',
'Codeception\\Coverage\\Subscriber\\LocalServer' => $vendorDir . '/codeception/codeception/src/Codeception/Coverage/Subscriber/LocalServer.php',
'Codeception\\Coverage\\Subscriber\\Printer' => $vendorDir . '/codeception/codeception/src/Codeception/Coverage/Subscriber/Printer.php',
'Codeception\\Coverage\\Subscriber\\RemoteServer' => $vendorDir . '/codeception/codeception/src/Codeception/Coverage/Subscriber/RemoteServer.php',
'Codeception\\Coverage\\SuiteSubscriber' => $vendorDir . '/codeception/codeception/src/Codeception/Coverage/SuiteSubscriber.php',
'Codeception\\CustomCommandInterface' => $vendorDir . '/codeception/codeception/src/Codeception/CustomCommandInterface.php',
'Codeception\\Event\\DispatcherWrapper' => $vendorDir . '/codeception/codeception/src/Codeception/Event/DispatcherWrapper.php',
'Codeception\\Event\\FailEvent' => $vendorDir . '/codeception/codeception/src/Codeception/Event/FailEvent.php',
'Codeception\\Event\\PrintResultEvent' => $vendorDir . '/codeception/codeception/src/Codeception/Event/PrintResultEvent.php',
'Codeception\\Event\\StepEvent' => $vendorDir . '/codeception/codeception/src/Codeception/Event/StepEvent.php',
'Codeception\\Event\\SuiteEvent' => $vendorDir . '/codeception/codeception/src/Codeception/Event/SuiteEvent.php',
'Codeception\\Event\\TestEvent' => $vendorDir . '/codeception/codeception/src/Codeception/Event/TestEvent.php',
'Codeception\\Events' => $vendorDir . '/codeception/codeception/src/Codeception/Events.php',
'Codeception\\Example' => $vendorDir . '/codeception/codeception/src/Codeception/Example.php',
'Codeception\\Exception\\ConditionalAssertionFailed' => $vendorDir . '/codeception/codeception/src/Codeception/Exception/ConditionalAssertionFailed.php',
'Codeception\\Exception\\ConfigurationException' => $vendorDir . '/codeception/codeception/src/Codeception/Exception/ConfigurationException.php',
'Codeception\\Exception\\ConnectionException' => $vendorDir . '/codeception/module-webdriver/src/Codeception/Exception/ConnectionException.php',
'Codeception\\Exception\\ContentNotFound' => $vendorDir . '/codeception/codeception/src/Codeception/Exception/ContentNotFound.php',
'Codeception\\Exception\\ElementNotFound' => $vendorDir . '/codeception/codeception/src/Codeception/Exception/ElementNotFound.php',
'Codeception\\Exception\\ExtensionException' => $vendorDir . '/codeception/codeception/src/Codeception/Exception/ExtensionException.php',
'Codeception\\Exception\\ExternalUrlException' => $vendorDir . '/codeception/lib-innerbrowser/src/Codeception/Exception/ExternalUrlException.php',
'Codeception\\Exception\\InjectionException' => $vendorDir . '/codeception/codeception/src/Codeception/Exception/InjectionException.php',
'Codeception\\Exception\\MalformedLocatorException' => $vendorDir . '/codeception/codeception/src/Codeception/Exception/MalformedLocatorException.php',
'Codeception\\Exception\\ModuleConfigException' => $vendorDir . '/codeception/codeception/src/Codeception/Exception/ModuleConfigException.php',
'Codeception\\Exception\\ModuleConflictException' => $vendorDir . '/codeception/codeception/src/Codeception/Exception/ModuleConflictException.php',
'Codeception\\Exception\\ModuleException' => $vendorDir . '/codeception/codeception/src/Codeception/Exception/ModuleException.php',
'Codeception\\Exception\\ModuleRequireException' => $vendorDir . '/codeception/codeception/src/Codeception/Exception/ModuleRequireException.php',
'Codeception\\Exception\\ParseException' => $vendorDir . '/codeception/codeception/src/Codeception/Exception/ParseException.php',
'Codeception\\Exception\\RemoteException' => $vendorDir . '/codeception/codeception/src/Codeception/Exception/RemoteException.php',
'Codeception\\Exception\\TestParseException' => $vendorDir . '/codeception/codeception/src/Codeception/Exception/TestParseException.php',
'Codeception\\Exception\\TestRuntimeException' => $vendorDir . '/codeception/codeception/src/Codeception/Exception/TestRuntimeException.php',
'Codeception\\Extension' => $vendorDir . '/codeception/codeception/src/Codeception/Extension.php',
'Codeception\\Extension\\DotReporter' => $vendorDir . '/codeception/codeception/ext/DotReporter.php',
'Codeception\\Extension\\Logger' => $vendorDir . '/codeception/codeception/ext/Logger.php',
'Codeception\\Extension\\Recorder' => $vendorDir . '/codeception/codeception/ext/Recorder.php',
'Codeception\\Extension\\RunBefore' => $vendorDir . '/codeception/codeception/ext/RunBefore.php',
'Codeception\\Extension\\RunFailed' => $vendorDir . '/codeception/codeception/ext/RunFailed.php',
'Codeception\\Extension\\RunProcess' => $vendorDir . '/codeception/codeception/ext/RunProcess.php',
'Codeception\\Extension\\SimpleReporter' => $vendorDir . '/codeception/codeception/ext/SimpleReporter.php',
'Codeception\\GroupObject' => $vendorDir . '/codeception/codeception/src/Codeception/GroupObject.php',
'Codeception\\InitTemplate' => $vendorDir . '/codeception/codeception/src/Codeception/InitTemplate.php',
'Codeception\\Lib\\Actor\\Shared\\Comment' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Actor/Shared/Comment.php',
'Codeception\\Lib\\Actor\\Shared\\Friend' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Actor/Shared/Friend.php',
'Codeception\\Lib\\Actor\\Shared\\Pause' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Actor/Shared/Pause.php',
'Codeception\\Lib\\Actor\\Shared\\Retry' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Actor/Shared/Retry.php',
'Codeception\\Lib\\Connector\\Guzzle' => $vendorDir . '/codeception/module-phpbrowser/src/Codeception/Lib/Connector/Guzzle.php',
'Codeception\\Lib\\Connector\\Shared\\PhpSuperGlobalsConverter' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Connector/Shared/PhpSuperGlobalsConverter.php',
'Codeception\\Lib\\Console\\Colorizer' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Console/Colorizer.php',
'Codeception\\Lib\\Console\\DiffFactory' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Console/DiffFactory.php',
'Codeception\\Lib\\Console\\Message' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Console/Message.php',
'Codeception\\Lib\\Console\\MessageFactory' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Console/MessageFactory.php',
'Codeception\\Lib\\Console\\Output' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Console/Output.php',
'Codeception\\Lib\\Console\\ReplHistory' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Console/ReplHistory.php',
'Codeception\\Lib\\DbPopulator' => $vendorDir . '/codeception/module-db/src/Codeception/Lib/DbPopulator.php',
'Codeception\\Lib\\Di' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Di.php',
'Codeception\\Lib\\Driver\\AmazonSQS' => $vendorDir . '/codeception/module-queue/src/Codeception/Lib/Driver/AmazonSQS.php',
'Codeception\\Lib\\Driver\\Beanstalk' => $vendorDir . '/codeception/module-queue/src/Codeception/Lib/Driver/Beanstalk.php',
'Codeception\\Lib\\Driver\\Db' => $vendorDir . '/codeception/module-db/src/Codeception/Lib/Driver/Db.php',
'Codeception\\Lib\\Driver\\Iron' => $vendorDir . '/codeception/module-queue/src/Codeception/Lib/Driver/Iron.php',
'Codeception\\Lib\\Driver\\MongoDb' => $vendorDir . '/codeception/module-mongodb/src/Codeception/Lib/Driver/MongoDb.php',
'Codeception\\Lib\\Driver\\MySql' => $vendorDir . '/codeception/module-db/src/Codeception/Lib/Driver/MySql.php',
'Codeception\\Lib\\Driver\\Oci' => $vendorDir . '/codeception/module-db/src/Codeception/Lib/Driver/Oci.php',
'Codeception\\Lib\\Driver\\Pheanstalk4' => $vendorDir . '/codeception/module-queue/src/Codeception/Lib/Driver/Pheanstalk4.php',
'Codeception\\Lib\\Driver\\PostgreSql' => $vendorDir . '/codeception/module-db/src/Codeception/Lib/Driver/PostgreSql.php',
'Codeception\\Lib\\Driver\\SqlSrv' => $vendorDir . '/codeception/module-db/src/Codeception/Lib/Driver/SqlSrv.php',
'Codeception\\Lib\\Driver\\Sqlite' => $vendorDir . '/codeception/module-db/src/Codeception/Lib/Driver/Sqlite.php',
'Codeception\\Lib\\Framework' => $vendorDir . '/codeception/lib-innerbrowser/src/Codeception/Lib/Framework.php',
'Codeception\\Lib\\Friend' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Friend.php',
'Codeception\\Lib\\Generator\\Actions' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Generator/Actions.php',
'Codeception\\Lib\\Generator\\Actor' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Generator/Actor.php',
'Codeception\\Lib\\Generator\\Cept' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Generator/Cept.php',
'Codeception\\Lib\\Generator\\Cest' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Generator/Cest.php',
'Codeception\\Lib\\Generator\\Feature' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Generator/Feature.php',
'Codeception\\Lib\\Generator\\GherkinSnippets' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Generator/GherkinSnippets.php',
'Codeception\\Lib\\Generator\\Group' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Generator/Group.php',
'Codeception\\Lib\\Generator\\Helper' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Generator/Helper.php',
'Codeception\\Lib\\Generator\\PageObject' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Generator/PageObject.php',
'Codeception\\Lib\\Generator\\Shared\\Classname' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Generator/Shared/Classname.php',
'Codeception\\Lib\\Generator\\Snapshot' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Generator/Snapshot.php',
'Codeception\\Lib\\Generator\\StepObject' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Generator/StepObject.php',
'Codeception\\Lib\\Generator\\Test' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Generator/Test.php',
'Codeception\\Lib\\GroupManager' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/GroupManager.php',
'Codeception\\Lib\\InnerBrowser' => $vendorDir . '/codeception/lib-innerbrowser/src/Codeception/Lib/InnerBrowser.php',
'Codeception\\Lib\\Interfaces\\API' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Interfaces/API.php',
'Codeception\\Lib\\Interfaces\\ActiveRecord' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Interfaces/ActiveRecord.php',
'Codeception\\Lib\\Interfaces\\ConflictsWithModule' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Interfaces/ConflictsWithModule.php',
'Codeception\\Lib\\Interfaces\\DataMapper' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Interfaces/DataMapper.php',
'Codeception\\Lib\\Interfaces\\Db' => $vendorDir . '/codeception/module-db/src/Codeception/Lib/Interfaces/Db.php',
'Codeception\\Lib\\Interfaces\\DependsOnModule' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Interfaces/DependsOnModule.php',
'Codeception\\Lib\\Interfaces\\DoctrineProvider' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Interfaces/DoctrineProvider.php',
'Codeception\\Lib\\Interfaces\\ElementLocator' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Interfaces/ElementLocator.php',
'Codeception\\Lib\\Interfaces\\MultiSession' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Interfaces/MultiSession.php',
'Codeception\\Lib\\Interfaces\\ORM' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Interfaces/ORM.php',
'Codeception\\Lib\\Interfaces\\PageSourceSaver' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Interfaces/PageSourceSaver.php',
'Codeception\\Lib\\Interfaces\\PartedModule' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Interfaces/PartedModule.php',
'Codeception\\Lib\\Interfaces\\Queue' => $vendorDir . '/codeception/module-queue/src/Codeception/Lib/Interfaces/Queue.php',
'Codeception\\Lib\\Interfaces\\Remote' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Interfaces/Remote.php',
'Codeception\\Lib\\Interfaces\\RequiresPackage' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Interfaces/RequiresPackage.php',
'Codeception\\Lib\\Interfaces\\ScreenshotSaver' => $vendorDir . '/codeception/module-webdriver/src/Codeception/Lib/Interfaces/ScreenshotSaver.php',
'Codeception\\Lib\\Interfaces\\SessionSnapshot' => $vendorDir . '/codeception/module-webdriver/src/Codeception/Lib/Interfaces/SessionSnapshot.php',
'Codeception\\Lib\\Interfaces\\Web' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Interfaces/Web.php',
'Codeception\\Lib\\ModuleContainer' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/ModuleContainer.php',
'Codeception\\Lib\\Notification' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Notification.php',
'Codeception\\Lib\\ParamsLoader' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/ParamsLoader.php',
'Codeception\\Lib\\Parser' => $vendorDir . '/codeception/codeception/src/Codeception/Lib/Parser.php',
'Codeception\\Module' => $vendorDir . '/codeception/codeception/src/Codeception/Module.php',
'Codeception\\Module\\AMQP' => $vendorDir . '/codeception/module-amqp/src/Codeception/Module/AMQP.php',
'Codeception\\Module\\AbstractAsserts' => $vendorDir . '/codeception/module-asserts/src/Codeception/Module/AbstractAsserts.php',
'Codeception\\Module\\Apc' => $vendorDir . '/codeception/module-apc/src/Codeception/Module/Apc.php',
'Codeception\\Module\\Asserts' => $vendorDir . '/codeception/module-asserts/src/Codeception/Module/Asserts.php',
'Codeception\\Module\\Cli' => $vendorDir . '/codeception/module-cli/src/Codeception/Module/Cli.php',
'Codeception\\Module\\Db' => $vendorDir . '/codeception/module-db/src/Codeception/Module/Db.php',
'Codeception\\Module\\FTP' => $vendorDir . '/codeception/module-ftp/src/Codeception/Module/FTP.php',
'Codeception\\Module\\Filesystem' => $vendorDir . '/codeception/module-filesystem/src/Codeception/Module/Filesystem.php',
'Codeception\\Module\\Memcache' => $vendorDir . '/codeception/module-memcache/src/Codeception/Module/Memcache.php',
'Codeception\\Module\\MongoDb' => $vendorDir . '/codeception/module-mongodb/src/Codeception/Module/MongoDb.php',
'Codeception\\Module\\PhpBrowser' => $vendorDir . '/codeception/module-phpbrowser/src/Codeception/Module/PhpBrowser.php',
'Codeception\\Module\\Queue' => $vendorDir . '/codeception/module-queue/src/Codeception/Module/Queue.php',
'Codeception\\Module\\REST' => $vendorDir . '/codeception/module-rest/src/Codeception/Module/REST.php',
'Codeception\\Module\\Redis' => $vendorDir . '/codeception/module-redis/src/Codeception/Module/Redis.php',
'Codeception\\Module\\SOAP' => $vendorDir . '/codeception/module-soap/src/Codeception/Module/SOAP.php',
'Codeception\\Module\\Sequence' => $vendorDir . '/codeception/module-sequence/src/Codeception/Module/Sequence.php',
'Codeception\\Module\\WebDriver' => $vendorDir . '/codeception/module-webdriver/src/Codeception/Module/WebDriver.php',
'Codeception\\PHPUnit\\ConsolePrinter' => $vendorDir . '/codeception/phpunit-wrapper/src/ConsolePrinter.php',
'Codeception\\PHPUnit\\Constraint\\Crawler' => $vendorDir . '/codeception/phpunit-wrapper/src/Constraint/Crawler.php',
'Codeception\\PHPUnit\\Constraint\\CrawlerNot' => $vendorDir . '/codeception/phpunit-wrapper/src/Constraint/CrawlerNot.php',
'Codeception\\PHPUnit\\Constraint\\JsonContains' => $vendorDir . '/codeception/phpunit-wrapper/src/Constraint/JsonContains.php',
'Codeception\\PHPUnit\\Constraint\\JsonType' => $vendorDir . '/codeception/phpunit-wrapper/src/Constraint/JsonType.php',
'Codeception\\PHPUnit\\Constraint\\Page' => $vendorDir . '/codeception/phpunit-wrapper/src/Constraint/Page.php',
'Codeception\\PHPUnit\\Constraint\\WebDriver' => $vendorDir . '/codeception/phpunit-wrapper/src/Constraint/WebDriver.php',
'Codeception\\PHPUnit\\Constraint\\WebDriverNot' => $vendorDir . '/codeception/phpunit-wrapper/src/Constraint/WebDriverNot.php',
'Codeception\\PHPUnit\\DispatcherWrapper' => $vendorDir . '/codeception/phpunit-wrapper/src/DispatcherWrapper.php',
'Codeception\\PHPUnit\\FilterTest' => $vendorDir . '/codeception/phpunit-wrapper/src/FilterTest.php',
'Codeception\\PHPUnit\\Init' => $vendorDir . '/codeception/phpunit-wrapper/src/Init.php',
'Codeception\\PHPUnit\\Listener' => $vendorDir . '/codeception/phpunit-wrapper/src/Listener.php',
'Codeception\\PHPUnit\\Log\\JUnit' => $vendorDir . '/codeception/phpunit-wrapper/src/Log/JUnit.php',
'Codeception\\PHPUnit\\Log\\PhpUnit' => $vendorDir . '/codeception/phpunit-wrapper/src/Log/PhpUnit.php',
'Codeception\\PHPUnit\\NonFinal\\JUnit' => $vendorDir . '/codeception/phpunit-wrapper/src/NonFinal/JUnit.php',
'Codeception\\PHPUnit\\NonFinal\\NameFilterIterator' => $vendorDir . '/codeception/phpunit-wrapper/src/NonFinal/NameFilterIterator.php',
'Codeception\\PHPUnit\\NonFinal\\TestRunner' => $vendorDir . '/codeception/phpunit-wrapper/src/NonFinal/TestRunner.php',
'Codeception\\PHPUnit\\ResultPrinter' => $vendorDir . '/codeception/phpunit-wrapper/src/ResultPrinter.php',
'Codeception\\PHPUnit\\ResultPrinter\\HTML' => $vendorDir . '/codeception/phpunit-wrapper/src/ResultPrinter/HTML.php',
'Codeception\\PHPUnit\\ResultPrinter\\Report' => $vendorDir . '/codeception/phpunit-wrapper/src/ResultPrinter/Report.php',
'Codeception\\PHPUnit\\ResultPrinter\\UI' => $vendorDir . '/codeception/phpunit-wrapper/src/ResultPrinter/UI.php',
'Codeception\\PHPUnit\\Runner' => $vendorDir . '/codeception/phpunit-wrapper/src/Runner.php',
'Codeception\\PHPUnit\\TestCase' => $vendorDir . '/codeception/phpunit-wrapper/src/TestCase.php',
'Codeception\\Scenario' => $vendorDir . '/codeception/codeception/src/Codeception/Scenario.php',
'Codeception\\Snapshot' => $vendorDir . '/codeception/codeception/src/Codeception/Snapshot.php',
'Codeception\\Step' => $vendorDir . '/codeception/codeception/src/Codeception/Step.php',
'Codeception\\Step\\Action' => $vendorDir . '/codeception/codeception/src/Codeception/Step/Action.php',
'Codeception\\Step\\Argument\\FormattedOutput' => $vendorDir . '/codeception/codeception/src/Codeception/Step/Argument/FormattedOutput.php',
'Codeception\\Step\\Argument\\PasswordArgument' => $vendorDir . '/codeception/codeception/src/Codeception/Step/Argument/PasswordArgument.php',
'Codeception\\Step\\AsJson' => $vendorDir . '/codeception/module-rest/src/Codeception/Step/AsJson.php',
'Codeception\\Step\\Assertion' => $vendorDir . '/codeception/codeception/src/Codeception/Step/Assertion.php',
'Codeception\\Step\\Comment' => $vendorDir . '/codeception/codeception/src/Codeception/Step/Comment.php',
'Codeception\\Step\\Condition' => $vendorDir . '/codeception/codeception/src/Codeception/Step/Condition.php',
'Codeception\\Step\\ConditionalAssertion' => $vendorDir . '/codeception/codeception/src/Codeception/Step/ConditionalAssertion.php',
'Codeception\\Step\\Executor' => $vendorDir . '/codeception/codeception/src/Codeception/Step/Executor.php',
'Codeception\\Step\\GeneratedStep' => $vendorDir . '/codeception/codeception/src/Codeception/Step/GeneratedStep.php',
'Codeception\\Step\\Incomplete' => $vendorDir . '/codeception/codeception/src/Codeception/Step/Incomplete.php',
'Codeception\\Step\\Meta' => $vendorDir . '/codeception/codeception/src/Codeception/Step/Meta.php',
'Codeception\\Step\\Retry' => $vendorDir . '/codeception/codeception/src/Codeception/Step/Retry.php',
'Codeception\\Step\\Skip' => $vendorDir . '/codeception/codeception/src/Codeception/Step/Skip.php',
'Codeception\\Step\\TryTo' => $vendorDir . '/codeception/codeception/src/Codeception/Step/TryTo.php',
'Codeception\\Stub' => $vendorDir . '/codeception/stub/src/Stub.php',
'Codeception\\Stub\\ConsecutiveMap' => $vendorDir . '/codeception/stub/src/Stub/ConsecutiveMap.php',
'Codeception\\Stub\\Expected' => $vendorDir . '/codeception/stub/src/Stub/Expected.php',
'Codeception\\Stub\\StubMarshaler' => $vendorDir . '/codeception/stub/src/Stub/StubMarshaler.php',
'Codeception\\Subscriber\\AutoRebuild' => $vendorDir . '/codeception/codeception/src/Codeception/Subscriber/AutoRebuild.php',
'Codeception\\Subscriber\\BeforeAfterTest' => $vendorDir . '/codeception/codeception/src/Codeception/Subscriber/BeforeAfterTest.php',
'Codeception\\Subscriber\\Bootstrap' => $vendorDir . '/codeception/codeception/src/Codeception/Subscriber/Bootstrap.php',
'Codeception\\Subscriber\\Console' => $vendorDir . '/codeception/codeception/src/Codeception/Subscriber/Console.php',
'Codeception\\Subscriber\\Dependencies' => $vendorDir . '/codeception/codeception/src/Codeception/Subscriber/Dependencies.php',
'Codeception\\Subscriber\\ErrorHandler' => $vendorDir . '/codeception/codeception/src/Codeception/Subscriber/ErrorHandler.php',
'Codeception\\Subscriber\\ExtensionLoader' => $vendorDir . '/codeception/codeception/src/Codeception/Subscriber/ExtensionLoader.php',
'Codeception\\Subscriber\\FailFast' => $vendorDir . '/codeception/codeception/src/Codeception/Subscriber/FailFast.php',
'Codeception\\Subscriber\\GracefulTermination' => $vendorDir . '/codeception/codeception/src/Codeception/Subscriber/GracefulTermination.php',
'Codeception\\Subscriber\\Module' => $vendorDir . '/codeception/codeception/src/Codeception/Subscriber/Module.php',
'Codeception\\Subscriber\\PrepareTest' => $vendorDir . '/codeception/codeception/src/Codeception/Subscriber/PrepareTest.php',
'Codeception\\Subscriber\\Shared\\StaticEvents' => $vendorDir . '/codeception/codeception/src/Codeception/Subscriber/Shared/StaticEvents.php',
'Codeception\\Suite' => $vendorDir . '/codeception/codeception/src/Codeception/Suite.php',
'Codeception\\SuiteManager' => $vendorDir . '/codeception/codeception/src/Codeception/SuiteManager.php',
'Codeception\\Template\\Acceptance' => $vendorDir . '/codeception/codeception/src/Codeception/Template/Acceptance.php',
'Codeception\\Template\\Api' => $vendorDir . '/codeception/codeception/src/Codeception/Template/Api.php',
'Codeception\\Template\\Bootstrap' => $vendorDir . '/codeception/codeception/src/Codeception/Template/Bootstrap.php',
'Codeception\\Template\\Unit' => $vendorDir . '/codeception/codeception/src/Codeception/Template/Unit.php',
'Codeception\\Template\\Upgrade4' => $vendorDir . '/codeception/codeception/src/Codeception/Template/Upgrade4.php',
'Codeception\\TestInterface' => $vendorDir . '/codeception/codeception/src/Codeception/TestInterface.php',
'Codeception\\Test\\Cept' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Cept.php',
'Codeception\\Test\\Cest' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Cest.php',
'Codeception\\Test\\Descriptor' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Descriptor.php',
'Codeception\\Test\\Feature\\AssertionCounter' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Feature/AssertionCounter.php',
'Codeception\\Test\\Feature\\CodeCoverage' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Feature/CodeCoverage.php',
'Codeception\\Test\\Feature\\ErrorLogger' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Feature/ErrorLogger.php',
'Codeception\\Test\\Feature\\IgnoreIfMetadataBlocked' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Feature/IgnoreIfMetadataBlocked.php',
'Codeception\\Test\\Feature\\MetadataCollector' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Feature/MetadataCollector.php',
'Codeception\\Test\\Feature\\ScenarioLoader' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Feature/ScenarioLoader.php',
'Codeception\\Test\\Feature\\Stub' => $vendorDir . '/codeception/stub/src/Test/Feature/Stub.php',
'Codeception\\Test\\Gherkin' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Gherkin.php',
'Codeception\\Test\\Interfaces\\Dependent' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Interfaces/Dependent.php',
'Codeception\\Test\\Interfaces\\Descriptive' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Interfaces/Descriptive.php',
'Codeception\\Test\\Interfaces\\Plain' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Interfaces/Plain.php',
'Codeception\\Test\\Interfaces\\Reported' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Interfaces/Reported.php',
'Codeception\\Test\\Interfaces\\ScenarioDriven' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Interfaces/ScenarioDriven.php',
'Codeception\\Test\\Interfaces\\StrictCoverage' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Interfaces/StrictCoverage.php',
'Codeception\\Test\\Loader' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Loader.php',
'Codeception\\Test\\Loader\\Cept' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Loader/Cept.php',
'Codeception\\Test\\Loader\\Cest' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Loader/Cest.php',
'Codeception\\Test\\Loader\\Gherkin' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Loader/Gherkin.php',
'Codeception\\Test\\Loader\\LoaderInterface' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Loader/LoaderInterface.php',
'Codeception\\Test\\Loader\\Unit' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Loader/Unit.php',
'Codeception\\Test\\Metadata' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Metadata.php',
'Codeception\\Test\\Test' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Test.php',
'Codeception\\Test\\Unit' => $vendorDir . '/codeception/codeception/src/Codeception/Test/Unit.php',
'Codeception\\Util\\ActionSequence' => $vendorDir . '/codeception/codeception/src/Codeception/Util/ActionSequence.php',
'Codeception\\Util\\Annotation' => $vendorDir . '/codeception/codeception/src/Codeception/Util/Annotation.php',
'Codeception\\Util\\ArrayContainsComparator' => $vendorDir . '/codeception/codeception/src/Codeception/Util/ArrayContainsComparator.php',
'Codeception\\Util\\Autoload' => $vendorDir . '/codeception/codeception/src/Codeception/Util/Autoload.php',
'Codeception\\Util\\Debug' => $vendorDir . '/codeception/codeception/src/Codeception/Util/Debug.php',
'Codeception\\Util\\FileSystem' => $vendorDir . '/codeception/codeception/src/Codeception/Util/FileSystem.php',
'Codeception\\Util\\Fixtures' => $vendorDir . '/codeception/codeception/src/Codeception/Util/Fixtures.php',
'Codeception\\Util\\HttpCode' => $vendorDir . '/codeception/lib-innerbrowser/src/Codeception/Util/HttpCode.php',
'Codeception\\Util\\JsonArray' => $vendorDir . '/codeception/module-rest/src/Codeception/Util/JsonArray.php',
'Codeception\\Util\\JsonType' => $vendorDir . '/codeception/module-rest/src/Codeception/Util/JsonType.php',
'Codeception\\Util\\Locator' => $vendorDir . '/codeception/codeception/src/Codeception/Util/Locator.php',
'Codeception\\Util\\Maybe' => $vendorDir . '/codeception/codeception/src/Codeception/Util/Maybe.php',
'Codeception\\Util\\PathResolver' => $vendorDir . '/codeception/codeception/src/Codeception/Util/PathResolver.php',
'Codeception\\Util\\ReflectionHelper' => $vendorDir . '/codeception/codeception/src/Codeception/Util/ReflectionHelper.php',
'Codeception\\Util\\ReflectionPropertyAccessor' => $vendorDir . '/codeception/codeception/src/Codeception/Util/ReflectionPropertyAccessor.php',
'Codeception\\Util\\Shared\\Asserts' => $vendorDir . '/codeception/lib-asserts/src/Codeception/Util/Shared/Asserts.php',
'Codeception\\Util\\Shared\\InheritedAsserts' => $vendorDir . '/codeception/lib-asserts/src/Codeception/Util/Shared/InheritedAsserts.php',
'Codeception\\Util\\Shared\\Namespaces' => $vendorDir . '/codeception/codeception/src/Codeception/Util/Shared/Namespaces.php',
'Codeception\\Util\\Soap' => $vendorDir . '/codeception/codeception/src/Codeception/Util/Soap.php',
'Codeception\\Util\\Stub' => $vendorDir . '/codeception/codeception/src/Codeception/Util/Stub.php',
'Codeception\\Util\\Template' => $vendorDir . '/codeception/codeception/src/Codeception/Util/Template.php',
'Codeception\\Util\\Uri' => $vendorDir . '/codeception/codeception/src/Codeception/Util/Uri.php',
'Codeception\\Util\\Xml' => $vendorDir . '/codeception/codeception/src/Codeception/Util/Xml.php',
'Codeception\\Util\\XmlBuilder' => $vendorDir . '/codeception/codeception/src/Codeception/Util/XmlBuilder.php',
'Codeception\\Util\\XmlStructure' => $vendorDir . '/codeception/codeception/src/Codeception/Util/XmlStructure.php',
'Composer\\CaBundle\\CaBundle' => $vendorDir . '/composer/ca-bundle/src/CaBundle.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'DeepCopy\\DeepCopy' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/DeepCopy.php',
'DeepCopy\\Exception\\CloneException' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Exception/CloneException.php',
'DeepCopy\\Exception\\PropertyException' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Exception/PropertyException.php',
'DeepCopy\\Filter\\Doctrine\\DoctrineCollectionFilter' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php',
'DeepCopy\\Filter\\Doctrine\\DoctrineEmptyCollectionFilter' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php',
'DeepCopy\\Filter\\Doctrine\\DoctrineProxyFilter' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineProxyFilter.php',
'DeepCopy\\Filter\\Filter' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Filter/Filter.php',
'DeepCopy\\Filter\\KeepFilter' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Filter/KeepFilter.php',
'DeepCopy\\Filter\\ReplaceFilter' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Filter/ReplaceFilter.php',
'DeepCopy\\Filter\\SetNullFilter' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Filter/SetNullFilter.php',
'DeepCopy\\Matcher\\Doctrine\\DoctrineProxyMatcher' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php',
'DeepCopy\\Matcher\\Matcher' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Matcher/Matcher.php',
'DeepCopy\\Matcher\\PropertyMatcher' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyMatcher.php',
'DeepCopy\\Matcher\\PropertyNameMatcher' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyNameMatcher.php',
'DeepCopy\\Matcher\\PropertyTypeMatcher' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyTypeMatcher.php',
'DeepCopy\\Reflection\\ReflectionHelper' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Reflection/ReflectionHelper.php',
'DeepCopy\\TypeFilter\\Date\\DateIntervalFilter' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/TypeFilter/Date/DateIntervalFilter.php',
'DeepCopy\\TypeFilter\\ReplaceFilter' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/TypeFilter/ReplaceFilter.php',
'DeepCopy\\TypeFilter\\ShallowCopyFilter' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/TypeFilter/ShallowCopyFilter.php',
'DeepCopy\\TypeFilter\\Spl\\ArrayObjectFilter' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/ArrayObjectFilter.php',
'DeepCopy\\TypeFilter\\Spl\\SplDoublyLinkedList' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedList.php',
'DeepCopy\\TypeFilter\\Spl\\SplDoublyLinkedListFilter' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedListFilter.php',
'DeepCopy\\TypeFilter\\TypeFilter' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/TypeFilter/TypeFilter.php',
'DeepCopy\\TypeMatcher\\TypeMatcher' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/TypeMatcher/TypeMatcher.php',
'Doctrine\\Instantiator\\Exception\\ExceptionInterface' => $vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator/Exception/ExceptionInterface.php',
'Doctrine\\Instantiator\\Exception\\InvalidArgumentException' => $vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator/Exception/InvalidArgumentException.php',
'Doctrine\\Instantiator\\Exception\\UnexpectedValueException' => $vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator/Exception/UnexpectedValueException.php',
'Doctrine\\Instantiator\\Instantiator' => $vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator/Instantiator.php',
'Doctrine\\Instantiator\\InstantiatorInterface' => $vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator/InstantiatorInterface.php',
'Facebook\\WebDriver\\AbstractWebDriverCheckboxOrRadio' => $vendorDir . '/php-webdriver/webdriver/lib/AbstractWebDriverCheckboxOrRadio.php',
'Facebook\\WebDriver\\Chrome\\ChromeDevToolsDriver' => $vendorDir . '/php-webdriver/webdriver/lib/Chrome/ChromeDevToolsDriver.php',
'Facebook\\WebDriver\\Chrome\\ChromeDriver' => $vendorDir . '/php-webdriver/webdriver/lib/Chrome/ChromeDriver.php',
'Facebook\\WebDriver\\Chrome\\ChromeDriverService' => $vendorDir . '/php-webdriver/webdriver/lib/Chrome/ChromeDriverService.php',
'Facebook\\WebDriver\\Chrome\\ChromeOptions' => $vendorDir . '/php-webdriver/webdriver/lib/Chrome/ChromeOptions.php',
'Facebook\\WebDriver\\Cookie' => $vendorDir . '/php-webdriver/webdriver/lib/Cookie.php',
'Facebook\\WebDriver\\Exception\\DriverServerDiedException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/DriverServerDiedException.php',
'Facebook\\WebDriver\\Exception\\ElementClickInterceptedException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/ElementClickInterceptedException.php',
'Facebook\\WebDriver\\Exception\\ElementNotInteractableException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/ElementNotInteractableException.php',
'Facebook\\WebDriver\\Exception\\ElementNotSelectableException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/ElementNotSelectableException.php',
'Facebook\\WebDriver\\Exception\\ElementNotVisibleException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/ElementNotVisibleException.php',
'Facebook\\WebDriver\\Exception\\ExpectedException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/ExpectedException.php',
'Facebook\\WebDriver\\Exception\\IMEEngineActivationFailedException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/IMEEngineActivationFailedException.php',
'Facebook\\WebDriver\\Exception\\IMENotAvailableException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/IMENotAvailableException.php',
'Facebook\\WebDriver\\Exception\\IndexOutOfBoundsException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/IndexOutOfBoundsException.php',
'Facebook\\WebDriver\\Exception\\InsecureCertificateException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/InsecureCertificateException.php',
'Facebook\\WebDriver\\Exception\\InvalidArgumentException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/InvalidArgumentException.php',
'Facebook\\WebDriver\\Exception\\InvalidCookieDomainException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/InvalidCookieDomainException.php',
'Facebook\\WebDriver\\Exception\\InvalidCoordinatesException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/InvalidCoordinatesException.php',
'Facebook\\WebDriver\\Exception\\InvalidElementStateException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/InvalidElementStateException.php',
'Facebook\\WebDriver\\Exception\\InvalidSelectorException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/InvalidSelectorException.php',
'Facebook\\WebDriver\\Exception\\InvalidSessionIdException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/InvalidSessionIdException.php',
'Facebook\\WebDriver\\Exception\\JavascriptErrorException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/JavascriptErrorException.php',
'Facebook\\WebDriver\\Exception\\MoveTargetOutOfBoundsException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/MoveTargetOutOfBoundsException.php',
'Facebook\\WebDriver\\Exception\\NoAlertOpenException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/NoAlertOpenException.php',
'Facebook\\WebDriver\\Exception\\NoCollectionException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/NoCollectionException.php',
'Facebook\\WebDriver\\Exception\\NoScriptResultException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/NoScriptResultException.php',
'Facebook\\WebDriver\\Exception\\NoStringException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/NoStringException.php',
'Facebook\\WebDriver\\Exception\\NoStringLengthException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/NoStringLengthException.php',
'Facebook\\WebDriver\\Exception\\NoStringWrapperException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/NoStringWrapperException.php',
'Facebook\\WebDriver\\Exception\\NoSuchAlertException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/NoSuchAlertException.php',
'Facebook\\WebDriver\\Exception\\NoSuchCollectionException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/NoSuchCollectionException.php',
'Facebook\\WebDriver\\Exception\\NoSuchCookieException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/NoSuchCookieException.php',
'Facebook\\WebDriver\\Exception\\NoSuchDocumentException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/NoSuchDocumentException.php',
'Facebook\\WebDriver\\Exception\\NoSuchDriverException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/NoSuchDriverException.php',
'Facebook\\WebDriver\\Exception\\NoSuchElementException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/NoSuchElementException.php',
'Facebook\\WebDriver\\Exception\\NoSuchFrameException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/NoSuchFrameException.php',
'Facebook\\WebDriver\\Exception\\NoSuchWindowException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/NoSuchWindowException.php',
'Facebook\\WebDriver\\Exception\\NullPointerException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/NullPointerException.php',
'Facebook\\WebDriver\\Exception\\ScriptTimeoutException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/ScriptTimeoutException.php',
'Facebook\\WebDriver\\Exception\\SessionNotCreatedException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/SessionNotCreatedException.php',
'Facebook\\WebDriver\\Exception\\StaleElementReferenceException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/StaleElementReferenceException.php',
'Facebook\\WebDriver\\Exception\\TimeoutException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/TimeoutException.php',
'Facebook\\WebDriver\\Exception\\UnableToCaptureScreenException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/UnableToCaptureScreenException.php',
'Facebook\\WebDriver\\Exception\\UnableToSetCookieException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/UnableToSetCookieException.php',
'Facebook\\WebDriver\\Exception\\UnexpectedAlertOpenException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/UnexpectedAlertOpenException.php',
'Facebook\\WebDriver\\Exception\\UnexpectedJavascriptException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/UnexpectedJavascriptException.php',
'Facebook\\WebDriver\\Exception\\UnexpectedTagNameException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/UnexpectedTagNameException.php',
'Facebook\\WebDriver\\Exception\\UnknownCommandException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/UnknownCommandException.php',
'Facebook\\WebDriver\\Exception\\UnknownErrorException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/UnknownErrorException.php',
'Facebook\\WebDriver\\Exception\\UnknownMethodException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/UnknownMethodException.php',
'Facebook\\WebDriver\\Exception\\UnknownServerException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/UnknownServerException.php',
'Facebook\\WebDriver\\Exception\\UnrecognizedExceptionException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/UnrecognizedExceptionException.php',
'Facebook\\WebDriver\\Exception\\UnsupportedOperationException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/UnsupportedOperationException.php',
'Facebook\\WebDriver\\Exception\\WebDriverCurlException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/WebDriverCurlException.php',
'Facebook\\WebDriver\\Exception\\WebDriverException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/WebDriverException.php',
'Facebook\\WebDriver\\Exception\\XPathLookupException' => $vendorDir . '/php-webdriver/webdriver/lib/Exception/XPathLookupException.php',
'Facebook\\WebDriver\\Firefox\\FirefoxDriver' => $vendorDir . '/php-webdriver/webdriver/lib/Firefox/FirefoxDriver.php',
'Facebook\\WebDriver\\Firefox\\FirefoxDriverService' => $vendorDir . '/php-webdriver/webdriver/lib/Firefox/FirefoxDriverService.php',
'Facebook\\WebDriver\\Firefox\\FirefoxOptions' => $vendorDir . '/php-webdriver/webdriver/lib/Firefox/FirefoxOptions.php',
'Facebook\\WebDriver\\Firefox\\FirefoxPreferences' => $vendorDir . '/php-webdriver/webdriver/lib/Firefox/FirefoxPreferences.php',
'Facebook\\WebDriver\\Firefox\\FirefoxProfile' => $vendorDir . '/php-webdriver/webdriver/lib/Firefox/FirefoxProfile.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverButtonReleaseAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverButtonReleaseAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverClickAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverClickAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverClickAndHoldAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverClickAndHoldAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverContextClickAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverContextClickAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverCoordinates' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverCoordinates.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverDoubleClickAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverDoubleClickAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverKeyDownAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverKeyDownAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverKeyUpAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverKeyUpAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverKeysRelatedAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverKeysRelatedAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverMouseAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverMouseAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverMouseMoveAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverMouseMoveAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverMoveToOffsetAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverMoveToOffsetAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverSendKeysAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverSendKeysAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverSingleKeyAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverSingleKeyAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverDoubleTapAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverDoubleTapAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverDownAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverDownAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverFlickAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverFlickAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverFlickFromElementAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverFlickFromElementAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverLongPressAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverLongPressAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverMoveAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverMoveAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverScrollAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverScrollAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverScrollFromElementAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverScrollFromElementAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverTapAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverTapAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverTouchAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverTouchAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverTouchScreen' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverTouchScreen.php',
'Facebook\\WebDriver\\Interactions\\WebDriverActions' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/WebDriverActions.php',
'Facebook\\WebDriver\\Interactions\\WebDriverCompositeAction' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/WebDriverCompositeAction.php',
'Facebook\\WebDriver\\Interactions\\WebDriverTouchActions' => $vendorDir . '/php-webdriver/webdriver/lib/Interactions/WebDriverTouchActions.php',
'Facebook\\WebDriver\\Internal\\WebDriverLocatable' => $vendorDir . '/php-webdriver/webdriver/lib/Internal/WebDriverLocatable.php',
'Facebook\\WebDriver\\JavaScriptExecutor' => $vendorDir . '/php-webdriver/webdriver/lib/JavaScriptExecutor.php',
'Facebook\\WebDriver\\Local\\LocalWebDriver' => $vendorDir . '/php-webdriver/webdriver/lib/Local/LocalWebDriver.php',
'Facebook\\WebDriver\\Net\\URLChecker' => $vendorDir . '/php-webdriver/webdriver/lib/Net/URLChecker.php',
'Facebook\\WebDriver\\Remote\\CustomWebDriverCommand' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/CustomWebDriverCommand.php',
'Facebook\\WebDriver\\Remote\\DesiredCapabilities' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/DesiredCapabilities.php',
'Facebook\\WebDriver\\Remote\\DriverCommand' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/DriverCommand.php',
'Facebook\\WebDriver\\Remote\\ExecuteMethod' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/ExecuteMethod.php',
'Facebook\\WebDriver\\Remote\\FileDetector' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/FileDetector.php',
'Facebook\\WebDriver\\Remote\\HttpCommandExecutor' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/HttpCommandExecutor.php',
'Facebook\\WebDriver\\Remote\\JsonWireCompat' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/JsonWireCompat.php',
'Facebook\\WebDriver\\Remote\\LocalFileDetector' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/LocalFileDetector.php',
'Facebook\\WebDriver\\Remote\\RemoteExecuteMethod' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/RemoteExecuteMethod.php',
'Facebook\\WebDriver\\Remote\\RemoteKeyboard' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/RemoteKeyboard.php',
'Facebook\\WebDriver\\Remote\\RemoteMouse' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/RemoteMouse.php',
'Facebook\\WebDriver\\Remote\\RemoteStatus' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/RemoteStatus.php',
'Facebook\\WebDriver\\Remote\\RemoteTargetLocator' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/RemoteTargetLocator.php',
'Facebook\\WebDriver\\Remote\\RemoteTouchScreen' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/RemoteTouchScreen.php',
'Facebook\\WebDriver\\Remote\\RemoteWebDriver' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/RemoteWebDriver.php',
'Facebook\\WebDriver\\Remote\\RemoteWebElement' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/RemoteWebElement.php',
'Facebook\\WebDriver\\Remote\\Service\\DriverCommandExecutor' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/Service/DriverCommandExecutor.php',
'Facebook\\WebDriver\\Remote\\Service\\DriverService' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/Service/DriverService.php',
'Facebook\\WebDriver\\Remote\\UselessFileDetector' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/UselessFileDetector.php',
'Facebook\\WebDriver\\Remote\\WebDriverBrowserType' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/WebDriverBrowserType.php',
'Facebook\\WebDriver\\Remote\\WebDriverCapabilityType' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/WebDriverCapabilityType.php',
'Facebook\\WebDriver\\Remote\\WebDriverCommand' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/WebDriverCommand.php',
'Facebook\\WebDriver\\Remote\\WebDriverResponse' => $vendorDir . '/php-webdriver/webdriver/lib/Remote/WebDriverResponse.php',
'Facebook\\WebDriver\\Support\\Events\\EventFiringWebDriver' => $vendorDir . '/php-webdriver/webdriver/lib/Support/Events/EventFiringWebDriver.php',
'Facebook\\WebDriver\\Support\\Events\\EventFiringWebDriverNavigation' => $vendorDir . '/php-webdriver/webdriver/lib/Support/Events/EventFiringWebDriverNavigation.php',
'Facebook\\WebDriver\\Support\\Events\\EventFiringWebElement' => $vendorDir . '/php-webdriver/webdriver/lib/Support/Events/EventFiringWebElement.php',
'Facebook\\WebDriver\\Support\\XPathEscaper' => $vendorDir . '/php-webdriver/webdriver/lib/Support/XPathEscaper.php',
'Facebook\\WebDriver\\WebDriver' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriver.php',
'Facebook\\WebDriver\\WebDriverAction' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverAction.php',
'Facebook\\WebDriver\\WebDriverAlert' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverAlert.php',
'Facebook\\WebDriver\\WebDriverBy' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverBy.php',
'Facebook\\WebDriver\\WebDriverCapabilities' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverCapabilities.php',
'Facebook\\WebDriver\\WebDriverCheckboxes' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverCheckboxes.php',
'Facebook\\WebDriver\\WebDriverCommandExecutor' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverCommandExecutor.php',
'Facebook\\WebDriver\\WebDriverDimension' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverDimension.php',
'Facebook\\WebDriver\\WebDriverDispatcher' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverDispatcher.php',
'Facebook\\WebDriver\\WebDriverElement' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverElement.php',
'Facebook\\WebDriver\\WebDriverEventListener' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverEventListener.php',
'Facebook\\WebDriver\\WebDriverExpectedCondition' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverExpectedCondition.php',
'Facebook\\WebDriver\\WebDriverHasInputDevices' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverHasInputDevices.php',
'Facebook\\WebDriver\\WebDriverKeyboard' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverKeyboard.php',
'Facebook\\WebDriver\\WebDriverKeys' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverKeys.php',
'Facebook\\WebDriver\\WebDriverMouse' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverMouse.php',
'Facebook\\WebDriver\\WebDriverNavigation' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverNavigation.php',
'Facebook\\WebDriver\\WebDriverNavigationInterface' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverNavigationInterface.php',
'Facebook\\WebDriver\\WebDriverOptions' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverOptions.php',
'Facebook\\WebDriver\\WebDriverPlatform' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverPlatform.php',
'Facebook\\WebDriver\\WebDriverPoint' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverPoint.php',
'Facebook\\WebDriver\\WebDriverRadios' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverRadios.php',
'Facebook\\WebDriver\\WebDriverSearchContext' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverSearchContext.php',
'Facebook\\WebDriver\\WebDriverSelect' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverSelect.php',
'Facebook\\WebDriver\\WebDriverSelectInterface' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverSelectInterface.php',
'Facebook\\WebDriver\\WebDriverTargetLocator' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverTargetLocator.php',
'Facebook\\WebDriver\\WebDriverTimeouts' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverTimeouts.php',
'Facebook\\WebDriver\\WebDriverUpAction' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverUpAction.php',
'Facebook\\WebDriver\\WebDriverWait' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverWait.php',
'Facebook\\WebDriver\\WebDriverWindow' => $vendorDir . '/php-webdriver/webdriver/lib/WebDriverWindow.php',
'Flow\\JSONPath\\AccessHelper' => $vendorDir . '/softcreatr/jsonpath/src/AccessHelper.php',
'Flow\\JSONPath\\Filters\\AbstractFilter' => $vendorDir . '/softcreatr/jsonpath/src/Filters/AbstractFilter.php',
'Flow\\JSONPath\\Filters\\IndexFilter' => $vendorDir . '/softcreatr/jsonpath/src/Filters/IndexFilter.php',
'Flow\\JSONPath\\Filters\\IndexesFilter' => $vendorDir . '/softcreatr/jsonpath/src/Filters/IndexesFilter.php',
'Flow\\JSONPath\\Filters\\QueryMatchFilter' => $vendorDir . '/softcreatr/jsonpath/src/Filters/QueryMatchFilter.php',
'Flow\\JSONPath\\Filters\\QueryResultFilter' => $vendorDir . '/softcreatr/jsonpath/src/Filters/QueryResultFilter.php',
'Flow\\JSONPath\\Filters\\RecursiveFilter' => $vendorDir . '/softcreatr/jsonpath/src/Filters/RecursiveFilter.php',
'Flow\\JSONPath\\Filters\\SliceFilter' => $vendorDir . '/softcreatr/jsonpath/src/Filters/SliceFilter.php',
'Flow\\JSONPath\\JSONPath' => $vendorDir . '/softcreatr/jsonpath/src/JSONPath.php',
'Flow\\JSONPath\\JSONPathException' => $vendorDir . '/softcreatr/jsonpath/src/JSONPathException.php',
'Flow\\JSONPath\\JSONPathLexer' => $vendorDir . '/softcreatr/jsonpath/src/JSONPathLexer.php',
'Flow\\JSONPath\\JSONPathToken' => $vendorDir . '/softcreatr/jsonpath/src/JSONPathToken.php',
'GuzzleHttp\\Client' => $vendorDir . '/guzzlehttp/guzzle/src/Client.php',
'GuzzleHttp\\ClientInterface' => $vendorDir . '/guzzlehttp/guzzle/src/ClientInterface.php',
'GuzzleHttp\\Cookie\\CookieJar' => $vendorDir . '/guzzlehttp/guzzle/src/Cookie/CookieJar.php',
'GuzzleHttp\\Cookie\\CookieJarInterface' => $vendorDir . '/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php',
'GuzzleHttp\\Cookie\\FileCookieJar' => $vendorDir . '/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php',
'GuzzleHttp\\Cookie\\SessionCookieJar' => $vendorDir . '/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php',
'GuzzleHttp\\Cookie\\SetCookie' => $vendorDir . '/guzzlehttp/guzzle/src/Cookie/SetCookie.php',
'GuzzleHttp\\Exception\\BadResponseException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/BadResponseException.php',
'GuzzleHttp\\Exception\\ClientException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/ClientException.php',
'GuzzleHttp\\Exception\\ConnectException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/ConnectException.php',
'GuzzleHttp\\Exception\\GuzzleException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/GuzzleException.php',
'GuzzleHttp\\Exception\\InvalidArgumentException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/InvalidArgumentException.php',
'GuzzleHttp\\Exception\\RequestException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/RequestException.php',
'GuzzleHttp\\Exception\\SeekException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/SeekException.php',
'GuzzleHttp\\Exception\\ServerException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/ServerException.php',
'GuzzleHttp\\Exception\\TooManyRedirectsException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php',
'GuzzleHttp\\Exception\\TransferException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/TransferException.php',
'GuzzleHttp\\HandlerStack' => $vendorDir . '/guzzlehttp/guzzle/src/HandlerStack.php',
'GuzzleHttp\\Handler\\CurlFactory' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/CurlFactory.php',
'GuzzleHttp\\Handler\\CurlFactoryInterface' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php',
'GuzzleHttp\\Handler\\CurlHandler' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/CurlHandler.php',
'GuzzleHttp\\Handler\\CurlMultiHandler' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php',
'GuzzleHttp\\Handler\\EasyHandle' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/EasyHandle.php',
'GuzzleHttp\\Handler\\MockHandler' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/MockHandler.php',
'GuzzleHttp\\Handler\\Proxy' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/Proxy.php',
'GuzzleHttp\\Handler\\StreamHandler' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/StreamHandler.php',
'GuzzleHttp\\MessageFormatter' => $vendorDir . '/guzzlehttp/guzzle/src/MessageFormatter.php',
'GuzzleHttp\\Middleware' => $vendorDir . '/guzzlehttp/guzzle/src/Middleware.php',
'GuzzleHttp\\Pool' => $vendorDir . '/guzzlehttp/guzzle/src/Pool.php',
'GuzzleHttp\\PrepareBodyMiddleware' => $vendorDir . '/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php',
'GuzzleHttp\\Promise\\AggregateException' => $vendorDir . '/guzzlehttp/promises/src/AggregateException.php',
'GuzzleHttp\\Promise\\CancellationException' => $vendorDir . '/guzzlehttp/promises/src/CancellationException.php',
'GuzzleHttp\\Promise\\Coroutine' => $vendorDir . '/guzzlehttp/promises/src/Coroutine.php',
'GuzzleHttp\\Promise\\Create' => $vendorDir . '/guzzlehttp/promises/src/Create.php',
'GuzzleHttp\\Promise\\Each' => $vendorDir . '/guzzlehttp/promises/src/Each.php',
'GuzzleHttp\\Promise\\EachPromise' => $vendorDir . '/guzzlehttp/promises/src/EachPromise.php',
'GuzzleHttp\\Promise\\FulfilledPromise' => $vendorDir . '/guzzlehttp/promises/src/FulfilledPromise.php',
'GuzzleHttp\\Promise\\Is' => $vendorDir . '/guzzlehttp/promises/src/Is.php',
'GuzzleHttp\\Promise\\Promise' => $vendorDir . '/guzzlehttp/promises/src/Promise.php',
'GuzzleHttp\\Promise\\PromiseInterface' => $vendorDir . '/guzzlehttp/promises/src/PromiseInterface.php',
'GuzzleHttp\\Promise\\PromisorInterface' => $vendorDir . '/guzzlehttp/promises/src/PromisorInterface.php',
'GuzzleHttp\\Promise\\RejectedPromise' => $vendorDir . '/guzzlehttp/promises/src/RejectedPromise.php',
'GuzzleHttp\\Promise\\RejectionException' => $vendorDir . '/guzzlehttp/promises/src/RejectionException.php',
'GuzzleHttp\\Promise\\TaskQueue' => $vendorDir . '/guzzlehttp/promises/src/TaskQueue.php',
'GuzzleHttp\\Promise\\TaskQueueInterface' => $vendorDir . '/guzzlehttp/promises/src/TaskQueueInterface.php',
'GuzzleHttp\\Promise\\Utils' => $vendorDir . '/guzzlehttp/promises/src/Utils.php',
'GuzzleHttp\\Psr7\\AppendStream' => $vendorDir . '/guzzlehttp/psr7/src/AppendStream.php',
'GuzzleHttp\\Psr7\\BufferStream' => $vendorDir . '/guzzlehttp/psr7/src/BufferStream.php',
'GuzzleHttp\\Psr7\\CachingStream' => $vendorDir . '/guzzlehttp/psr7/src/CachingStream.php',
'GuzzleHttp\\Psr7\\DroppingStream' => $vendorDir . '/guzzlehttp/psr7/src/DroppingStream.php',
'GuzzleHttp\\Psr7\\FnStream' => $vendorDir . '/guzzlehttp/psr7/src/FnStream.php',
'GuzzleHttp\\Psr7\\Header' => $vendorDir . '/guzzlehttp/psr7/src/Header.php',
'GuzzleHttp\\Psr7\\InflateStream' => $vendorDir . '/guzzlehttp/psr7/src/InflateStream.php',
'GuzzleHttp\\Psr7\\LazyOpenStream' => $vendorDir . '/guzzlehttp/psr7/src/LazyOpenStream.php',
'GuzzleHttp\\Psr7\\LimitStream' => $vendorDir . '/guzzlehttp/psr7/src/LimitStream.php',
'GuzzleHttp\\Psr7\\Message' => $vendorDir . '/guzzlehttp/psr7/src/Message.php',
'GuzzleHttp\\Psr7\\MessageTrait' => $vendorDir . '/guzzlehttp/psr7/src/MessageTrait.php',
'GuzzleHttp\\Psr7\\MimeType' => $vendorDir . '/guzzlehttp/psr7/src/MimeType.php',
'GuzzleHttp\\Psr7\\MultipartStream' => $vendorDir . '/guzzlehttp/psr7/src/MultipartStream.php',
'GuzzleHttp\\Psr7\\NoSeekStream' => $vendorDir . '/guzzlehttp/psr7/src/NoSeekStream.php',
'GuzzleHttp\\Psr7\\PumpStream' => $vendorDir . '/guzzlehttp/psr7/src/PumpStream.php',
'GuzzleHttp\\Psr7\\Query' => $vendorDir . '/guzzlehttp/psr7/src/Query.php',
'GuzzleHttp\\Psr7\\Request' => $vendorDir . '/guzzlehttp/psr7/src/Request.php',
'GuzzleHttp\\Psr7\\Response' => $vendorDir . '/guzzlehttp/psr7/src/Response.php',
'GuzzleHttp\\Psr7\\Rfc7230' => $vendorDir . '/guzzlehttp/psr7/src/Rfc7230.php',
'GuzzleHttp\\Psr7\\ServerRequest' => $vendorDir . '/guzzlehttp/psr7/src/ServerRequest.php',
'GuzzleHttp\\Psr7\\Stream' => $vendorDir . '/guzzlehttp/psr7/src/Stream.php',
'GuzzleHttp\\Psr7\\StreamDecoratorTrait' => $vendorDir . '/guzzlehttp/psr7/src/StreamDecoratorTrait.php',
'GuzzleHttp\\Psr7\\StreamWrapper' => $vendorDir . '/guzzlehttp/psr7/src/StreamWrapper.php',
'GuzzleHttp\\Psr7\\UploadedFile' => $vendorDir . '/guzzlehttp/psr7/src/UploadedFile.php',
'GuzzleHttp\\Psr7\\Uri' => $vendorDir . '/guzzlehttp/psr7/src/Uri.php',
'GuzzleHttp\\Psr7\\UriNormalizer' => $vendorDir . '/guzzlehttp/psr7/src/UriNormalizer.php',
'GuzzleHttp\\Psr7\\UriResolver' => $vendorDir . '/guzzlehttp/psr7/src/UriResolver.php',
'GuzzleHttp\\Psr7\\Utils' => $vendorDir . '/guzzlehttp/psr7/src/Utils.php',
'GuzzleHttp\\RedirectMiddleware' => $vendorDir . '/guzzlehttp/guzzle/src/RedirectMiddleware.php',
'GuzzleHttp\\RequestOptions' => $vendorDir . '/guzzlehttp/guzzle/src/RequestOptions.php',
'GuzzleHttp\\RetryMiddleware' => $vendorDir . '/guzzlehttp/guzzle/src/RetryMiddleware.php',
'GuzzleHttp\\TransferStats' => $vendorDir . '/guzzlehttp/guzzle/src/TransferStats.php',
'GuzzleHttp\\UriTemplate' => $vendorDir . '/guzzlehttp/guzzle/src/UriTemplate.php',
'GuzzleHttp\\Utils' => $vendorDir . '/guzzlehttp/guzzle/src/Utils.php',
'Hoa\\Consistency\\Autoloader' => $vendorDir . '/hoa/consistency/Autoloader.php',
'Hoa\\Consistency\\Consistency' => $vendorDir . '/hoa/consistency/Consistency.php',
'Hoa\\Consistency\\Exception' => $vendorDir . '/hoa/consistency/Exception.php',
'Hoa\\Consistency\\Test\\Unit\\Autoloader' => $vendorDir . '/hoa/consistency/Test/Unit/Autoloader.php',
'Hoa\\Consistency\\Test\\Unit\\Consistency' => $vendorDir . '/hoa/consistency/Test/Unit/Consistency.php',
'Hoa\\Consistency\\Test\\Unit\\Exception' => $vendorDir . '/hoa/consistency/Test/Unit/Exception.php',
'Hoa\\Consistency\\Test\\Unit\\Xcallable' => $vendorDir . '/hoa/consistency/Test/Unit/Xcallable.php',
'Hoa\\Consistency\\Xcallable' => $vendorDir . '/hoa/consistency/Xcallable.php',
'Hoa\\Console\\Bin\\Termcap' => $vendorDir . '/hoa/console/Bin/Termcap.php',
'Hoa\\Console\\Chrome\\Editor' => $vendorDir . '/hoa/console/Chrome/Editor.php',
'Hoa\\Console\\Chrome\\Exception' => $vendorDir . '/hoa/console/Chrome/Exception.php',
'Hoa\\Console\\Chrome\\Pager' => $vendorDir . '/hoa/console/Chrome/Pager.php',
'Hoa\\Console\\Chrome\\Text' => $vendorDir . '/hoa/console/Chrome/Text.php',
'Hoa\\Console\\Console' => $vendorDir . '/hoa/console/Console.php',
'Hoa\\Console\\Cursor' => $vendorDir . '/hoa/console/Cursor.php',
'Hoa\\Console\\Dispatcher\\Kit' => $vendorDir . '/hoa/console/Dispatcher/Kit.php',
'Hoa\\Console\\Exception' => $vendorDir . '/hoa/console/Exception.php',
'Hoa\\Console\\GetOption' => $vendorDir . '/hoa/console/GetOption.php',
'Hoa\\Console\\Input' => $vendorDir . '/hoa/console/Input.php',
'Hoa\\Console\\Mouse' => $vendorDir . '/hoa/console/Mouse.php',
'Hoa\\Console\\Output' => $vendorDir . '/hoa/console/Output.php',
'Hoa\\Console\\Parser' => $vendorDir . '/hoa/console/Parser.php',
'Hoa\\Console\\Processus' => $vendorDir . '/hoa/console/Processus.php',
'Hoa\\Console\\Readline\\Autocompleter\\Aggregate' => $vendorDir . '/hoa/console/Readline/Autocompleter/Aggregate.php',
'Hoa\\Console\\Readline\\Autocompleter\\Autocompleter' => $vendorDir . '/hoa/console/Readline/Autocompleter/Autocompleter.php',
'Hoa\\Console\\Readline\\Autocompleter\\Path' => $vendorDir . '/hoa/console/Readline/Autocompleter/Path.php',
'Hoa\\Console\\Readline\\Autocompleter\\Word' => $vendorDir . '/hoa/console/Readline/Autocompleter/Word.php',
'Hoa\\Console\\Readline\\Password' => $vendorDir . '/hoa/console/Readline/Password.php',
'Hoa\\Console\\Readline\\Readline' => $vendorDir . '/hoa/console/Readline/Readline.php',
'Hoa\\Console\\Test\\Unit\\Console' => $vendorDir . '/hoa/console/Test/Unit/Console.php',
'Hoa\\Console\\Test\\Unit\\Cursor' => $vendorDir . '/hoa/console/Test/Unit/Cursor.php',
'Hoa\\Console\\Test\\Unit\\GetOption' => $vendorDir . '/hoa/console/Test/Unit/GetOption.php',
'Hoa\\Console\\Test\\Unit\\Input' => $vendorDir . '/hoa/console/Test/Unit/Input.php',
'Hoa\\Console\\Test\\Unit\\Mouse' => $vendorDir . '/hoa/console/Test/Unit/Mouse.php',
'Hoa\\Console\\Test\\Unit\\Output' => $vendorDir . '/hoa/console/Test/Unit/Output.php',
'Hoa\\Console\\Test\\Unit\\Parser' => $vendorDir . '/hoa/console/Test/Unit/Parser.php',
'Hoa\\Console\\Test\\Unit\\Readline\\Autocompleter\\Aggregate' => $vendorDir . '/hoa/console/Test/Unit/Readline/Autocompleter/Aggregate.php',
'Hoa\\Console\\Test\\Unit\\Readline\\Autocompleter\\Path' => $vendorDir . '/hoa/console/Test/Unit/Readline/Autocompleter/Path.php',
'Hoa\\Console\\Test\\Unit\\Readline\\Autocompleter\\Word' => $vendorDir . '/hoa/console/Test/Unit/Readline/Autocompleter/Word.php',
'Hoa\\Console\\Test\\Unit\\Readline\\Password' => $vendorDir . '/hoa/console/Test/Unit/Readline/Password.php',
'Hoa\\Console\\Test\\Unit\\Tput' => $vendorDir . '/hoa/console/Test/Unit/Tput.php',
'Hoa\\Console\\Test\\Unit\\Window' => $vendorDir . '/hoa/console/Test/Unit/Window.php',
'Hoa\\Console\\Tput' => $vendorDir . '/hoa/console/Tput.php',
'Hoa\\Console\\Window' => $vendorDir . '/hoa/console/Window.php',
'Hoa\\Event\\Bucket' => $vendorDir . '/hoa/event/Bucket.php',
'Hoa\\Event\\Event' => $vendorDir . '/hoa/event/Event.php',
'Hoa\\Event\\Exception' => $vendorDir . '/hoa/event/Exception.php',
'Hoa\\Event\\Listenable' => $vendorDir . '/hoa/event/Listenable.php',
'Hoa\\Event\\Listener' => $vendorDir . '/hoa/event/Listener.php',
'Hoa\\Event\\Listens' => $vendorDir . '/hoa/event/Listens.php',
'Hoa\\Event\\Source' => $vendorDir . '/hoa/event/Source.php',
'Hoa\\Event\\Test\\Unit\\Bucket' => $vendorDir . '/hoa/event/Test/Unit/Bucket.php',
'Hoa\\Event\\Test\\Unit\\Event' => $vendorDir . '/hoa/event/Test/Unit/Event.php',
'Hoa\\Event\\Test\\Unit\\Exception' => $vendorDir . '/hoa/event/Test/Unit/Exception.php',
'Hoa\\Event\\Test\\Unit\\Listenable' => $vendorDir . '/hoa/event/Test/Unit/Listenable.php',
'Hoa\\Event\\Test\\Unit\\Listener' => $vendorDir . '/hoa/event/Test/Unit/Listener.php',
'Hoa\\Event\\Test\\Unit\\Listens' => $vendorDir . '/hoa/event/Test/Unit/Listens.php',
'Hoa\\Event\\Test\\Unit\\Source' => $vendorDir . '/hoa/event/Test/Unit/Source.php',
'Hoa\\Exception\\Error' => $vendorDir . '/hoa/exception/Error.php',
'Hoa\\Exception\\Exception' => $vendorDir . '/hoa/exception/Exception.php',
'Hoa\\Exception\\Group' => $vendorDir . '/hoa/exception/Group.php',
'Hoa\\Exception\\Idle' => $vendorDir . '/hoa/exception/Idle.php',
'Hoa\\Exception\\Test\\Unit\\Error' => $vendorDir . '/hoa/exception/Test/Unit/Error.php',
'Hoa\\Exception\\Test\\Unit\\Exception' => $vendorDir . '/hoa/exception/Test/Unit/Exception.php',
'Hoa\\Exception\\Test\\Unit\\Group' => $vendorDir . '/hoa/exception/Test/Unit/Group.php',
'Hoa\\Exception\\Test\\Unit\\Idle' => $vendorDir . '/hoa/exception/Test/Unit/Idle.php',
'Hoa\\File\\Directory' => $vendorDir . '/hoa/file/Directory.php',
'Hoa\\File\\Exception\\Exception' => $vendorDir . '/hoa/file/Exception/Exception.php',
'Hoa\\File\\Exception\\FileDoesNotExist' => $vendorDir . '/hoa/file/Exception/FileDoesNotExist.php',
'Hoa\\File\\File' => $vendorDir . '/hoa/file/File.php',
'Hoa\\File\\Finder' => $vendorDir . '/hoa/file/Finder.php',
'Hoa\\File\\Generic' => $vendorDir . '/hoa/file/Generic.php',
'Hoa\\File\\Link\\Link' => $vendorDir . '/hoa/file/Link/Link.php',
'Hoa\\File\\Link\\Read' => $vendorDir . '/hoa/file/Link/Read.php',
'Hoa\\File\\Link\\ReadWrite' => $vendorDir . '/hoa/file/Link/ReadWrite.php',
'Hoa\\File\\Link\\Write' => $vendorDir . '/hoa/file/Link/Write.php',
'Hoa\\File\\Read' => $vendorDir . '/hoa/file/Read.php',
'Hoa\\File\\ReadWrite' => $vendorDir . '/hoa/file/ReadWrite.php',
'Hoa\\File\\SplFileInfo' => $vendorDir . '/hoa/file/SplFileInfo.php',
'Hoa\\File\\Temporary\\Read' => $vendorDir . '/hoa/file/Temporary/Read.php',
'Hoa\\File\\Temporary\\ReadWrite' => $vendorDir . '/hoa/file/Temporary/ReadWrite.php',
'Hoa\\File\\Temporary\\Temporary' => $vendorDir . '/hoa/file/Temporary/Temporary.php',
'Hoa\\File\\Temporary\\Write' => $vendorDir . '/hoa/file/Temporary/Write.php',
'Hoa\\File\\Watcher' => $vendorDir . '/hoa/file/Watcher.php',
'Hoa\\File\\Write' => $vendorDir . '/hoa/file/Write.php',
'Hoa\\Iterator\\Aggregate' => $vendorDir . '/hoa/iterator/Aggregate.php',
'Hoa\\Iterator\\Append' => $vendorDir . '/hoa/iterator/Append.php',
'Hoa\\Iterator\\Buffer' => $vendorDir . '/hoa/iterator/Buffer.php',
'Hoa\\Iterator\\CallbackFilter' => $vendorDir . '/hoa/iterator/CallbackFilter.php',
'Hoa\\Iterator\\CallbackGenerator' => $vendorDir . '/hoa/iterator/CallbackGenerator.php',
'Hoa\\Iterator\\Counter' => $vendorDir . '/hoa/iterator/Counter.php',
'Hoa\\Iterator\\Demultiplexer' => $vendorDir . '/hoa/iterator/Demultiplexer.php',
'Hoa\\Iterator\\Directory' => $vendorDir . '/hoa/iterator/Directory.php',
'Hoa\\Iterator\\Exception' => $vendorDir . '/hoa/iterator/Exception.php',
'Hoa\\Iterator\\FileSystem' => $vendorDir . '/hoa/iterator/FileSystem.php',
'Hoa\\Iterator\\Filter' => $vendorDir . '/hoa/iterator/Filter.php',
'Hoa\\Iterator\\Glob' => $vendorDir . '/hoa/iterator/Glob.php',
'Hoa\\Iterator\\Infinite' => $vendorDir . '/hoa/iterator/Infinite.php',
'Hoa\\Iterator\\Iterator' => $vendorDir . '/hoa/iterator/Iterator.php',
'Hoa\\Iterator\\IteratorIterator' => $vendorDir . '/hoa/iterator/IteratorIterator.php',
'Hoa\\Iterator\\Limit' => $vendorDir . '/hoa/iterator/Limit.php',
'Hoa\\Iterator\\Lookahead' => $vendorDir . '/hoa/iterator/Lookahead.php',
'Hoa\\Iterator\\Lookbehind' => $vendorDir . '/hoa/iterator/Lookbehind.php',
'Hoa\\Iterator\\Map' => $vendorDir . '/hoa/iterator/Map.php',
'Hoa\\Iterator\\Mock' => $vendorDir . '/hoa/iterator/Mock.php',
'Hoa\\Iterator\\Multiple' => $vendorDir . '/hoa/iterator/Multiple.php',
'Hoa\\Iterator\\NoRewind' => $vendorDir . '/hoa/iterator/NoRewind.php',
'Hoa\\Iterator\\Outer' => $vendorDir . '/hoa/iterator/Outer.php',
'Hoa\\Iterator\\Recursive\\CallbackFilter' => $vendorDir . '/hoa/iterator/Recursive/CallbackFilter.php',
'Hoa\\Iterator\\Recursive\\Directory' => $vendorDir . '/hoa/iterator/Recursive/Directory.php',
'Hoa\\Iterator\\Recursive\\Filter' => $vendorDir . '/hoa/iterator/Recursive/Filter.php',
'Hoa\\Iterator\\Recursive\\Iterator' => $vendorDir . '/hoa/iterator/Recursive/Iterator.php',
'Hoa\\Iterator\\Recursive\\Map' => $vendorDir . '/hoa/iterator/Recursive/Map.php',
'Hoa\\Iterator\\Recursive\\Mock' => $vendorDir . '/hoa/iterator/Recursive/Mock.php',
'Hoa\\Iterator\\Recursive\\Recursive' => $vendorDir . '/hoa/iterator/Recursive/Recursive.php',
'Hoa\\Iterator\\Recursive\\RegularExpression' => $vendorDir . '/hoa/iterator/Recursive/RegularExpression.php',
'Hoa\\Iterator\\RegularExpression' => $vendorDir . '/hoa/iterator/RegularExpression.php',
'Hoa\\Iterator\\Repeater' => $vendorDir . '/hoa/iterator/Repeater.php',
'Hoa\\Iterator\\Seekable' => $vendorDir . '/hoa/iterator/Seekable.php',
'Hoa\\Iterator\\SplFileInfo' => $vendorDir . '/hoa/iterator/SplFileInfo.php',
'Hoa\\Iterator\\Test\\Unit\\Append' => $vendorDir . '/hoa/iterator/Test/Unit/Append.php',
'Hoa\\Iterator\\Test\\Unit\\Buffer' => $vendorDir . '/hoa/iterator/Test/Unit/Buffer.php',
'Hoa\\Iterator\\Test\\Unit\\CallbackFilter' => $vendorDir . '/hoa/iterator/Test/Unit/CallbackFilter.php',
'Hoa\\Iterator\\Test\\Unit\\CallbackGenerator' => $vendorDir . '/hoa/iterator/Test/Unit/CallbackGenerator.php',
'Hoa\\Iterator\\Test\\Unit\\Counter' => $vendorDir . '/hoa/iterator/Test/Unit/Counter.php',
'Hoa\\Iterator\\Test\\Unit\\Demultiplexer' => $vendorDir . '/hoa/iterator/Test/Unit/Demultiplexer.php',
'Hoa\\Iterator\\Test\\Unit\\Directory' => $vendorDir . '/hoa/iterator/Test/Unit/Directory.php',
'Hoa\\Iterator\\Test\\Unit\\FileSystem' => $vendorDir . '/hoa/iterator/Test/Unit/FileSystem.php',
'Hoa\\Iterator\\Test\\Unit\\Filter' => $vendorDir . '/hoa/iterator/Test/Unit/Filter.php',
'Hoa\\Iterator\\Test\\Unit\\Infinite' => $vendorDir . '/hoa/iterator/Test/Unit/Infinite.php',
'Hoa\\Iterator\\Test\\Unit\\IteratorIterator' => $vendorDir . '/hoa/iterator/Test/Unit/IteratorIterator.php',
'Hoa\\Iterator\\Test\\Unit\\Limit' => $vendorDir . '/hoa/iterator/Test/Unit/Limit.php',
'Hoa\\Iterator\\Test\\Unit\\Lookahead' => $vendorDir . '/hoa/iterator/Test/Unit/Lookahead.php',
'Hoa\\Iterator\\Test\\Unit\\Lookbehind' => $vendorDir . '/hoa/iterator/Test/Unit/Lookbehind.php',
'Hoa\\Iterator\\Test\\Unit\\Map' => $vendorDir . '/hoa/iterator/Test/Unit/Map.php',
'Hoa\\Iterator\\Test\\Unit\\Mock' => $vendorDir . '/hoa/iterator/Test/Unit/Mock.php',
'Hoa\\Iterator\\Test\\Unit\\Multiple' => $vendorDir . '/hoa/iterator/Test/Unit/Multiple.php',
'Hoa\\Iterator\\Test\\Unit\\NoRewind' => $vendorDir . '/hoa/iterator/Test/Unit/NoRewind.php',
'Hoa\\Iterator\\Test\\Unit\\RegularExpression' => $vendorDir . '/hoa/iterator/Test/Unit/RegularExpression.php',
'Hoa\\Iterator\\Test\\Unit\\Repeater' => $vendorDir . '/hoa/iterator/Test/Unit/Repeater.php',
'Hoa\\Iterator\\Test\\Unit\\SplFileInfo' => $vendorDir . '/hoa/iterator/Test/Unit/SplFileInfo.php',
'Hoa\\Protocol\\Bin\\Resolve' => $vendorDir . '/hoa/protocol/Bin/Resolve.php',
'Hoa\\Protocol\\Exception' => $vendorDir . '/hoa/protocol/Exception.php',
'Hoa\\Protocol\\Node\\Library' => $vendorDir . '/hoa/protocol/Node/Library.php',
'Hoa\\Protocol\\Node\\Node' => $vendorDir . '/hoa/protocol/Node/Node.php',
'Hoa\\Protocol\\Protocol' => $vendorDir . '/hoa/protocol/Protocol.php',
'Hoa\\Protocol\\Test\\Unit\\Exception' => $vendorDir . '/hoa/protocol/Test/Unit/Exception.php',
'Hoa\\Protocol\\Test\\Unit\\Node\\Library' => $vendorDir . '/hoa/protocol/Test/Unit/Node/Library.php',
'Hoa\\Protocol\\Test\\Unit\\Node\\Node' => $vendorDir . '/hoa/protocol/Test/Unit/Node/Node.php',
'Hoa\\Protocol\\Test\\Unit\\Protocol' => $vendorDir . '/hoa/protocol/Test/Unit/Protocol.php',
'Hoa\\Protocol\\Test\\Unit\\Wrapper' => $vendorDir . '/hoa/protocol/Test/Unit/Wrapper.php',
'Hoa\\Protocol\\Wrapper' => $vendorDir . '/hoa/protocol/Wrapper.php',
'Hoa\\Stream\\Bucket' => $vendorDir . '/hoa/stream/Bucket.php',
'Hoa\\Stream\\Composite' => $vendorDir . '/hoa/stream/Composite.php',
'Hoa\\Stream\\Context' => $vendorDir . '/hoa/stream/Context.php',
'Hoa\\Stream\\Exception' => $vendorDir . '/hoa/stream/Exception.php',
'Hoa\\Stream\\Filter\\Basic' => $vendorDir . '/hoa/stream/Filter/Basic.php',
'Hoa\\Stream\\Filter\\Exception' => $vendorDir . '/hoa/stream/Filter/Exception.php',
'Hoa\\Stream\\Filter\\Filter' => $vendorDir . '/hoa/stream/Filter/Filter.php',
'Hoa\\Stream\\Filter\\LateComputed' => $vendorDir . '/hoa/stream/Filter/LateComputed.php',
'Hoa\\Stream\\IStream\\Bufferable' => $vendorDir . '/hoa/stream/IStream/Bufferable.php',
'Hoa\\Stream\\IStream\\In' => $vendorDir . '/hoa/stream/IStream/In.php',
'Hoa\\Stream\\IStream\\Lockable' => $vendorDir . '/hoa/stream/IStream/Lockable.php',
'Hoa\\Stream\\IStream\\Out' => $vendorDir . '/hoa/stream/IStream/Out.php',
'Hoa\\Stream\\IStream\\Pathable' => $vendorDir . '/hoa/stream/IStream/Pathable.php',
'Hoa\\Stream\\IStream\\Pointable' => $vendorDir . '/hoa/stream/IStream/Pointable.php',
'Hoa\\Stream\\IStream\\Statable' => $vendorDir . '/hoa/stream/IStream/Statable.php',
'Hoa\\Stream\\IStream\\Stream' => $vendorDir . '/hoa/stream/IStream/Stream.php',
'Hoa\\Stream\\IStream\\Structural' => $vendorDir . '/hoa/stream/IStream/Structural.php',
'Hoa\\Stream\\IStream\\Touchable' => $vendorDir . '/hoa/stream/IStream/Touchable.php',
'Hoa\\Stream\\Stream' => $vendorDir . '/hoa/stream/Stream.php',
'Hoa\\Stream\\Test\\Integration\\Filter\\Filter' => $vendorDir . '/hoa/stream/Test/Integration/Filter/Filter.php',
'Hoa\\Stream\\Test\\Integration\\Filter\\LateComputed' => $vendorDir . '/hoa/stream/Test/Integration/Filter/LateComputed.php',
'Hoa\\Stream\\Test\\Integration\\Stream' => $vendorDir . '/hoa/stream/Test/Integration/Stream.php',
'Hoa\\Stream\\Test\\Unit\\Bucket' => $vendorDir . '/hoa/stream/Test/Unit/Bucket.php',
'Hoa\\Stream\\Test\\Unit\\Composite' => $vendorDir . '/hoa/stream/Test/Unit/Composite.php',
'Hoa\\Stream\\Test\\Unit\\Context' => $vendorDir . '/hoa/stream/Test/Unit/Context.php',
'Hoa\\Stream\\Test\\Unit\\Exception' => $vendorDir . '/hoa/stream/Test/Unit/Exception.php',
'Hoa\\Stream\\Test\\Unit\\Filter\\Basic' => $vendorDir . '/hoa/stream/Test/Unit/Filter/Basic.php',
'Hoa\\Stream\\Test\\Unit\\Filter\\Exception' => $vendorDir . '/hoa/stream/Test/Unit/Filter/Exception.php',
'Hoa\\Stream\\Test\\Unit\\Filter\\Filter' => $vendorDir . '/hoa/stream/Test/Unit/Filter/Filter.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Bufferable' => $vendorDir . '/hoa/stream/Test/Unit/IStream/Bufferable.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\In' => $vendorDir . '/hoa/stream/Test/Unit/IStream/In.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Lockable' => $vendorDir . '/hoa/stream/Test/Unit/IStream/Lockable.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Out' => $vendorDir . '/hoa/stream/Test/Unit/IStream/Out.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Pathable' => $vendorDir . '/hoa/stream/Test/Unit/IStream/Pathable.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Pointable' => $vendorDir . '/hoa/stream/Test/Unit/IStream/Pointable.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Statable' => $vendorDir . '/hoa/stream/Test/Unit/IStream/Statable.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Stream' => $vendorDir . '/hoa/stream/Test/Unit/IStream/Stream.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Structural' => $vendorDir . '/hoa/stream/Test/Unit/IStream/Structural.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Touchable' => $vendorDir . '/hoa/stream/Test/Unit/IStream/Touchable.php',
'Hoa\\Stream\\Test\\Unit\\Stream' => $vendorDir . '/hoa/stream/Test/Unit/Stream.php',
'Hoa\\Stream\\Test\\Unit\\Wrapper\\Exception' => $vendorDir . '/hoa/stream/Test/Unit/Wrapper/Exception.php',
'Hoa\\Stream\\Test\\Unit\\Wrapper\\IWrapper\\File' => $vendorDir . '/hoa/stream/Test/Unit/Wrapper/IWrapper/File.php',
'Hoa\\Stream\\Test\\Unit\\Wrapper\\IWrapper\\IWrapper' => $vendorDir . '/hoa/stream/Test/Unit/Wrapper/IWrapper/IWrapper.php',
'Hoa\\Stream\\Test\\Unit\\Wrapper\\IWrapper\\Stream' => $vendorDir . '/hoa/stream/Test/Unit/Wrapper/IWrapper/Stream.php',
'Hoa\\Stream\\Test\\Unit\\Wrapper\\Wrapper' => $vendorDir . '/hoa/stream/Test/Unit/Wrapper/Wrapper.php',
'Hoa\\Stream\\Wrapper\\Exception' => $vendorDir . '/hoa/stream/Wrapper/Exception.php',
'Hoa\\Stream\\Wrapper\\IWrapper\\File' => $vendorDir . '/hoa/stream/Wrapper/IWrapper/File.php',
'Hoa\\Stream\\Wrapper\\IWrapper\\IWrapper' => $vendorDir . '/hoa/stream/Wrapper/IWrapper/IWrapper.php',
'Hoa\\Stream\\Wrapper\\IWrapper\\Stream' => $vendorDir . '/hoa/stream/Wrapper/IWrapper/Stream.php',
'Hoa\\Stream\\Wrapper\\Wrapper' => $vendorDir . '/hoa/stream/Wrapper/Wrapper.php',
'Hoa\\Ustring\\Bin\\Fromcode' => $vendorDir . '/hoa/ustring/Bin/Fromcode.php',
'Hoa\\Ustring\\Bin\\Tocode' => $vendorDir . '/hoa/ustring/Bin/Tocode.php',
'Hoa\\Ustring\\Exception' => $vendorDir . '/hoa/ustring/Exception.php',
'Hoa\\Ustring\\Search' => $vendorDir . '/hoa/ustring/Search.php',
'Hoa\\Ustring\\Test\\Unit\\Issue' => $vendorDir . '/hoa/ustring/Test/Unit/Issue.php',
'Hoa\\Ustring\\Test\\Unit\\Search' => $vendorDir . '/hoa/ustring/Test/Unit/Search.php',
'Hoa\\Ustring\\Test\\Unit\\Ustring' => $vendorDir . '/hoa/ustring/Test/Unit/Ustring.php',
'Hoa\\Ustring\\Ustring' => $vendorDir . '/hoa/ustring/Ustring.php',
'Humbug\\FileGetContents' => $vendorDir . '/padraic/humbug_get_contents/src/FileGetContents.php',
'Humbug\\SelfUpdate\\Exception\\ExceptionInterface' => $vendorDir . '/padraic/phar-updater/src/Exception/ExceptionInterface.php',
'Humbug\\SelfUpdate\\Exception\\FilesystemException' => $vendorDir . '/padraic/phar-updater/src/Exception/FilesystemException.php',
'Humbug\\SelfUpdate\\Exception\\HttpRequestException' => $vendorDir . '/padraic/phar-updater/src/Exception/HttpRequestException.php',
'Humbug\\SelfUpdate\\Exception\\InvalidArgumentException' => $vendorDir . '/padraic/phar-updater/src/Exception/InvalidArgumentException.php',
'Humbug\\SelfUpdate\\Exception\\JsonParsingException' => $vendorDir . '/padraic/phar-updater/src/Exception/JsonParsingException.php',
'Humbug\\SelfUpdate\\Exception\\NoSignatureException' => $vendorDir . '/padraic/phar-updater/src/Exception/NoSignatureException.php',
'Humbug\\SelfUpdate\\Exception\\RuntimeException' => $vendorDir . '/padraic/phar-updater/src/Exception/RuntimeException.php',
'Humbug\\SelfUpdate\\Strategy\\GithubStrategy' => $vendorDir . '/padraic/phar-updater/src/Strategy/GithubStrategy.php',
'Humbug\\SelfUpdate\\Strategy\\ShaStrategy' => $vendorDir . '/padraic/phar-updater/src/Strategy/ShaStrategy.php',
'Humbug\\SelfUpdate\\Strategy\\StrategyInterface' => $vendorDir . '/padraic/phar-updater/src/Strategy/StrategyInterface.php',
'Humbug\\SelfUpdate\\Updater' => $vendorDir . '/padraic/phar-updater/src/Updater.php',
'Humbug\\SelfUpdate\\VersionParser' => $vendorDir . '/padraic/phar-updater/src/VersionParser.php',
'JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
'JsonSchema\\Constraints\\BaseConstraint' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Constraints/BaseConstraint.php',
'JsonSchema\\Constraints\\CollectionConstraint' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Constraints/CollectionConstraint.php',
'JsonSchema\\Constraints\\Constraint' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Constraints/Constraint.php',
'JsonSchema\\Constraints\\ConstraintInterface' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Constraints/ConstraintInterface.php',
'JsonSchema\\Constraints\\EnumConstraint' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Constraints/EnumConstraint.php',
'JsonSchema\\Constraints\\Factory' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Constraints/Factory.php',
'JsonSchema\\Constraints\\FormatConstraint' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Constraints/FormatConstraint.php',
'JsonSchema\\Constraints\\NumberConstraint' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Constraints/NumberConstraint.php',
'JsonSchema\\Constraints\\ObjectConstraint' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Constraints/ObjectConstraint.php',
'JsonSchema\\Constraints\\SchemaConstraint' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Constraints/SchemaConstraint.php',
'JsonSchema\\Constraints\\StringConstraint' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Constraints/StringConstraint.php',
'JsonSchema\\Constraints\\TypeCheck\\LooseTypeCheck' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeCheck/LooseTypeCheck.php',
'JsonSchema\\Constraints\\TypeCheck\\StrictTypeCheck' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeCheck/StrictTypeCheck.php',
'JsonSchema\\Constraints\\TypeCheck\\TypeCheckInterface' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeCheck/TypeCheckInterface.php',
'JsonSchema\\Constraints\\TypeConstraint' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeConstraint.php',
'JsonSchema\\Constraints\\UndefinedConstraint' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Constraints/UndefinedConstraint.php',
'JsonSchema\\Entity\\JsonPointer' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Entity/JsonPointer.php',
'JsonSchema\\Exception\\ExceptionInterface' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Exception/ExceptionInterface.php',
'JsonSchema\\Exception\\InvalidArgumentException' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidArgumentException.php',
'JsonSchema\\Exception\\InvalidConfigException' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidConfigException.php',
'JsonSchema\\Exception\\InvalidSchemaException' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidSchemaException.php',
'JsonSchema\\Exception\\InvalidSchemaMediaTypeException' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidSchemaMediaTypeException.php',
'JsonSchema\\Exception\\InvalidSourceUriException' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidSourceUriException.php',
'JsonSchema\\Exception\\JsonDecodingException' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Exception/JsonDecodingException.php',
'JsonSchema\\Exception\\ResourceNotFoundException' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Exception/ResourceNotFoundException.php',
'JsonSchema\\Exception\\RuntimeException' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Exception/RuntimeException.php',
'JsonSchema\\Exception\\UnresolvableJsonPointerException' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Exception/UnresolvableJsonPointerException.php',
'JsonSchema\\Exception\\UriResolverException' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Exception/UriResolverException.php',
'JsonSchema\\Exception\\ValidationException' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Exception/ValidationException.php',
'JsonSchema\\Iterator\\ObjectIterator' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Iterator/ObjectIterator.php',
'JsonSchema\\Rfc3339' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Rfc3339.php',
'JsonSchema\\SchemaStorage' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/SchemaStorage.php',
'JsonSchema\\SchemaStorageInterface' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/SchemaStorageInterface.php',
'JsonSchema\\UriResolverInterface' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/UriResolverInterface.php',
'JsonSchema\\UriRetrieverInterface' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/UriRetrieverInterface.php',
'JsonSchema\\Uri\\Retrievers\\AbstractRetriever' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/AbstractRetriever.php',
'JsonSchema\\Uri\\Retrievers\\Curl' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/Curl.php',
'JsonSchema\\Uri\\Retrievers\\FileGetContents' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/FileGetContents.php',
'JsonSchema\\Uri\\Retrievers\\PredefinedArray' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/PredefinedArray.php',
'JsonSchema\\Uri\\Retrievers\\UriRetrieverInterface' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/UriRetrieverInterface.php',
'JsonSchema\\Uri\\UriResolver' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Uri/UriResolver.php',
'JsonSchema\\Uri\\UriRetriever' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Uri/UriRetriever.php',
'JsonSchema\\Validator' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Validator.php',
'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'PHPUnit\\Exception' => $vendorDir . '/phpunit/phpunit/src/Exception.php',
'PHPUnit\\Framework\\Assert' => $vendorDir . '/phpunit/phpunit/src/Framework/Assert.php',
'PHPUnit\\Framework\\AssertionFailedError' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/AssertionFailedError.php',
'PHPUnit\\Framework\\CodeCoverageException' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/CodeCoverageException.php',
'PHPUnit\\Framework\\Constraint\\ArrayHasKey' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/ArrayHasKey.php',
'PHPUnit\\Framework\\Constraint\\ArraySubset' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/ArraySubset.php',
'PHPUnit\\Framework\\Constraint\\Attribute' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Attribute.php',
'PHPUnit\\Framework\\Constraint\\Callback' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Callback.php',
'PHPUnit\\Framework\\Constraint\\ClassHasAttribute' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/ClassHasAttribute.php',
'PHPUnit\\Framework\\Constraint\\ClassHasStaticAttribute' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/ClassHasStaticAttribute.php',
'PHPUnit\\Framework\\Constraint\\Composite' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Composite.php',
'PHPUnit\\Framework\\Constraint\\Constraint' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Constraint.php',
'PHPUnit\\Framework\\Constraint\\Count' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Count.php',
'PHPUnit\\Framework\\Constraint\\DirectoryExists' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/DirectoryExists.php',
'PHPUnit\\Framework\\Constraint\\Exception' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Exception.php',
'PHPUnit\\Framework\\Constraint\\ExceptionCode' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/ExceptionCode.php',
'PHPUnit\\Framework\\Constraint\\ExceptionMessage' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/ExceptionMessage.php',
'PHPUnit\\Framework\\Constraint\\ExceptionMessageRegularExpression' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/ExceptionMessageRegularExpression.php',
'PHPUnit\\Framework\\Constraint\\FileExists' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/FileExists.php',
'PHPUnit\\Framework\\Constraint\\GreaterThan' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/GreaterThan.php',
'PHPUnit\\Framework\\Constraint\\IsAnything' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsAnything.php',
'PHPUnit\\Framework\\Constraint\\IsEmpty' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsEmpty.php',
'PHPUnit\\Framework\\Constraint\\IsEqual' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsEqual.php',
'PHPUnit\\Framework\\Constraint\\IsFalse' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsFalse.php',
'PHPUnit\\Framework\\Constraint\\IsFinite' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsFinite.php',
'PHPUnit\\Framework\\Constraint\\IsIdentical' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php',
'PHPUnit\\Framework\\Constraint\\IsInfinite' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsInfinite.php',
'PHPUnit\\Framework\\Constraint\\IsInstanceOf' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsInstanceOf.php',
'PHPUnit\\Framework\\Constraint\\IsJson' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsJson.php',
'PHPUnit\\Framework\\Constraint\\IsNan' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsNan.php',
'PHPUnit\\Framework\\Constraint\\IsNull' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsNull.php',
'PHPUnit\\Framework\\Constraint\\IsReadable' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsReadable.php',
'PHPUnit\\Framework\\Constraint\\IsTrue' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsTrue.php',
'PHPUnit\\Framework\\Constraint\\IsType' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsType.php',
'PHPUnit\\Framework\\Constraint\\IsWritable' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsWritable.php',
'PHPUnit\\Framework\\Constraint\\JsonMatches' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/JsonMatches.php',
'PHPUnit\\Framework\\Constraint\\JsonMatchesErrorMessageProvider' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/JsonMatchesErrorMessageProvider.php',
'PHPUnit\\Framework\\Constraint\\LessThan' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/LessThan.php',
'PHPUnit\\Framework\\Constraint\\LogicalAnd' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/LogicalAnd.php',
'PHPUnit\\Framework\\Constraint\\LogicalNot' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/LogicalNot.php',
'PHPUnit\\Framework\\Constraint\\LogicalOr' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/LogicalOr.php',
'PHPUnit\\Framework\\Constraint\\LogicalXor' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/LogicalXor.php',
'PHPUnit\\Framework\\Constraint\\ObjectHasAttribute' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/ObjectHasAttribute.php',
'PHPUnit\\Framework\\Constraint\\RegularExpression' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/RegularExpression.php',
'PHPUnit\\Framework\\Constraint\\SameSize' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/SameSize.php',
'PHPUnit\\Framework\\Constraint\\StringContains' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/StringContains.php',
'PHPUnit\\Framework\\Constraint\\StringEndsWith' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/StringEndsWith.php',
'PHPUnit\\Framework\\Constraint\\StringMatchesFormatDescription' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/StringMatchesFormatDescription.php',
'PHPUnit\\Framework\\Constraint\\StringStartsWith' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/StringStartsWith.php',
'PHPUnit\\Framework\\Constraint\\TraversableContains' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/TraversableContains.php',
'PHPUnit\\Framework\\Constraint\\TraversableContainsEqual' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/TraversableContainsEqual.php',
'PHPUnit\\Framework\\Constraint\\TraversableContainsIdentical' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/TraversableContainsIdentical.php',
'PHPUnit\\Framework\\Constraint\\TraversableContainsOnly' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/TraversableContainsOnly.php',
'PHPUnit\\Framework\\CoveredCodeNotExecutedException' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/CoveredCodeNotExecutedException.php',
'PHPUnit\\Framework\\DataProviderTestSuite' => $vendorDir . '/phpunit/phpunit/src/Framework/DataProviderTestSuite.php',
'PHPUnit\\Framework\\Error\\Deprecated' => $vendorDir . '/phpunit/phpunit/src/Framework/Error/Deprecated.php',
'PHPUnit\\Framework\\Error\\Error' => $vendorDir . '/phpunit/phpunit/src/Framework/Error/Error.php',
'PHPUnit\\Framework\\Error\\Notice' => $vendorDir . '/phpunit/phpunit/src/Framework/Error/Notice.php',
'PHPUnit\\Framework\\Error\\Warning' => $vendorDir . '/phpunit/phpunit/src/Framework/Error/Warning.php',
'PHPUnit\\Framework\\Exception' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/Exception.php',
'PHPUnit\\Framework\\ExceptionWrapper' => $vendorDir . '/phpunit/phpunit/src/Framework/ExceptionWrapper.php',
'PHPUnit\\Framework\\ExpectationFailedException' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/ExpectationFailedException.php',
'PHPUnit\\Framework\\IncompleteTest' => $vendorDir . '/phpunit/phpunit/src/Framework/IncompleteTest.php',
'PHPUnit\\Framework\\IncompleteTestCase' => $vendorDir . '/phpunit/phpunit/src/Framework/IncompleteTestCase.php',
'PHPUnit\\Framework\\IncompleteTestError' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/IncompleteTestError.php',
'PHPUnit\\Framework\\InvalidArgumentException' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/InvalidArgumentException.php',
'PHPUnit\\Framework\\InvalidCoversTargetException' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/InvalidCoversTargetException.php',
'PHPUnit\\Framework\\InvalidDataProviderException' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/InvalidDataProviderException.php',
'PHPUnit\\Framework\\InvalidParameterGroupException' => $vendorDir . '/phpunit/phpunit/src/Framework/InvalidParameterGroupException.php',
'PHPUnit\\Framework\\MissingCoversAnnotationException' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/MissingCoversAnnotationException.php',
'PHPUnit\\Framework\\MockObject\\Api' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Api/Api.php',
'PHPUnit\\Framework\\MockObject\\BadMethodCallException' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Exception/BadMethodCallException.php',
'PHPUnit\\Framework\\MockObject\\Builder\\Identity' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Builder/Identity.php',
'PHPUnit\\Framework\\MockObject\\Builder\\InvocationMocker' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationMocker.php',
'PHPUnit\\Framework\\MockObject\\Builder\\InvocationStubber' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationStubber.php',
'PHPUnit\\Framework\\MockObject\\Builder\\Match_' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Builder/Match_.php',
'PHPUnit\\Framework\\MockObject\\Builder\\MethodNameMatch' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Builder/MethodNameMatch.php',
'PHPUnit\\Framework\\MockObject\\Builder\\ParametersMatch' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Builder/ParametersMatch.php',
'PHPUnit\\Framework\\MockObject\\Builder\\Stub' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Builder/Stub.php',
'PHPUnit\\Framework\\MockObject\\ConfigurableMethod' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/ConfigurableMethod.php',
'PHPUnit\\Framework\\MockObject\\ConfigurableMethodsAlreadyInitializedException' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Exception/ConfigurableMethodsAlreadyInitializedException.php',
'PHPUnit\\Framework\\MockObject\\Exception' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Exception/Exception.php',
'PHPUnit\\Framework\\MockObject\\Generator' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Generator.php',
'PHPUnit\\Framework\\MockObject\\IncompatibleReturnValueException' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Exception/IncompatibleReturnValueException.php',
'PHPUnit\\Framework\\MockObject\\Invocation' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Invocation.php',
'PHPUnit\\Framework\\MockObject\\InvocationHandler' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/InvocationHandler.php',
'PHPUnit\\Framework\\MockObject\\Matcher' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Matcher.php',
'PHPUnit\\Framework\\MockObject\\Method' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Api/Method.php',
'PHPUnit\\Framework\\MockObject\\MethodNameConstraint' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/MethodNameConstraint.php',
'PHPUnit\\Framework\\MockObject\\MockBuilder' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/MockBuilder.php',
'PHPUnit\\Framework\\MockObject\\MockClass' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/MockClass.php',
'PHPUnit\\Framework\\MockObject\\MockMethod' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/MockMethod.php',
'PHPUnit\\Framework\\MockObject\\MockMethodSet' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/MockMethodSet.php',
'PHPUnit\\Framework\\MockObject\\MockObject' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/MockObject.php',
'PHPUnit\\Framework\\MockObject\\MockTrait' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/MockTrait.php',
'PHPUnit\\Framework\\MockObject\\MockType' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/MockType.php',
'PHPUnit\\Framework\\MockObject\\MockedCloneMethod' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Api/MockedCloneMethod.php',
'PHPUnit\\Framework\\MockObject\\Rule\\AnyInvokedCount' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Rule/AnyInvokedCount.php',
'PHPUnit\\Framework\\MockObject\\Rule\\AnyParameters' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Rule/AnyParameters.php',
'PHPUnit\\Framework\\MockObject\\Rule\\ConsecutiveParameters' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Rule/ConsecutiveParameters.php',
'PHPUnit\\Framework\\MockObject\\Rule\\InvocationOrder' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Rule/InvocationOrder.php',
'PHPUnit\\Framework\\MockObject\\Rule\\InvokedAtIndex' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtIndex.php',
'PHPUnit\\Framework\\MockObject\\Rule\\InvokedAtLeastCount' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtLeastCount.php',
'PHPUnit\\Framework\\MockObject\\Rule\\InvokedAtLeastOnce' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtLeastOnce.php',
'PHPUnit\\Framework\\MockObject\\Rule\\InvokedAtMostCount' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtMostCount.php',
'PHPUnit\\Framework\\MockObject\\Rule\\InvokedCount' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedCount.php',
'PHPUnit\\Framework\\MockObject\\Rule\\MethodName' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Rule/MethodName.php',
'PHPUnit\\Framework\\MockObject\\Rule\\Parameters' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Rule/Parameters.php',
'PHPUnit\\Framework\\MockObject\\Rule\\ParametersRule' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Rule/ParametersRule.php',
'PHPUnit\\Framework\\MockObject\\RuntimeException' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Exception/RuntimeException.php',
'PHPUnit\\Framework\\MockObject\\Stub' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Stub.php',
'PHPUnit\\Framework\\MockObject\\Stub\\ConsecutiveCalls' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Stub/ConsecutiveCalls.php',
'PHPUnit\\Framework\\MockObject\\Stub\\Exception' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Stub/Exception.php',
'PHPUnit\\Framework\\MockObject\\Stub\\ReturnArgument' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnArgument.php',
'PHPUnit\\Framework\\MockObject\\Stub\\ReturnCallback' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnCallback.php',
'PHPUnit\\Framework\\MockObject\\Stub\\ReturnReference' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnReference.php',
'PHPUnit\\Framework\\MockObject\\Stub\\ReturnSelf' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnSelf.php',
'PHPUnit\\Framework\\MockObject\\Stub\\ReturnStub' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnStub.php',
'PHPUnit\\Framework\\MockObject\\Stub\\ReturnValueMap' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnValueMap.php',
'PHPUnit\\Framework\\MockObject\\Stub\\Stub' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Stub/Stub.php',
'PHPUnit\\Framework\\MockObject\\UnmockedCloneMethod' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Api/UnmockedCloneMethod.php',
'PHPUnit\\Framework\\MockObject\\Verifiable' => $vendorDir . '/phpunit/phpunit/src/Framework/MockObject/Verifiable.php',
'PHPUnit\\Framework\\NoChildTestSuiteException' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/NoChildTestSuiteException.php',
'PHPUnit\\Framework\\OutputError' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/OutputError.php',
'PHPUnit\\Framework\\PHPTAssertionFailedError' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/PHPTAssertionFailedError.php',
'PHPUnit\\Framework\\RiskyTestError' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/RiskyTestError.php',
'PHPUnit\\Framework\\SelfDescribing' => $vendorDir . '/phpunit/phpunit/src/Framework/SelfDescribing.php',
'PHPUnit\\Framework\\SkippedTest' => $vendorDir . '/phpunit/phpunit/src/Framework/SkippedTest.php',
'PHPUnit\\Framework\\SkippedTestCase' => $vendorDir . '/phpunit/phpunit/src/Framework/SkippedTestCase.php',
'PHPUnit\\Framework\\SkippedTestError' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/SkippedTestError.php',
'PHPUnit\\Framework\\SkippedTestSuiteError' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/SkippedTestSuiteError.php',
'PHPUnit\\Framework\\SyntheticError' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/SyntheticError.php',
'PHPUnit\\Framework\\SyntheticSkippedError' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/SyntheticSkippedError.php',
'PHPUnit\\Framework\\Test' => $vendorDir . '/phpunit/phpunit/src/Framework/Test.php',
'PHPUnit\\Framework\\TestBuilder' => $vendorDir . '/phpunit/phpunit/src/Framework/TestBuilder.php',
'PHPUnit\\Framework\\TestCase' => $vendorDir . '/phpunit/phpunit/src/Framework/TestCase.php',
'PHPUnit\\Framework\\TestFailure' => $vendorDir . '/phpunit/phpunit/src/Framework/TestFailure.php',
'PHPUnit\\Framework\\TestListener' => $vendorDir . '/phpunit/phpunit/src/Framework/TestListener.php',
'PHPUnit\\Framework\\TestListenerDefaultImplementation' => $vendorDir . '/phpunit/phpunit/src/Framework/TestListenerDefaultImplementation.php',
'PHPUnit\\Framework\\TestResult' => $vendorDir . '/phpunit/phpunit/src/Framework/TestResult.php',
'PHPUnit\\Framework\\TestSuite' => $vendorDir . '/phpunit/phpunit/src/Framework/TestSuite.php',
'PHPUnit\\Framework\\TestSuiteIterator' => $vendorDir . '/phpunit/phpunit/src/Framework/TestSuiteIterator.php',
'PHPUnit\\Framework\\UnintentionallyCoveredCodeError' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/UnintentionallyCoveredCodeError.php',
'PHPUnit\\Framework\\Warning' => $vendorDir . '/phpunit/phpunit/src/Framework/Exception/Warning.php',
'PHPUnit\\Framework\\WarningTestCase' => $vendorDir . '/phpunit/phpunit/src/Framework/WarningTestCase.php',
'PHPUnit\\Runner\\AfterIncompleteTestHook' => $vendorDir . '/phpunit/phpunit/src/Runner/Hook/AfterIncompleteTestHook.php',
'PHPUnit\\Runner\\AfterLastTestHook' => $vendorDir . '/phpunit/phpunit/src/Runner/Hook/AfterLastTestHook.php',
'PHPUnit\\Runner\\AfterRiskyTestHook' => $vendorDir . '/phpunit/phpunit/src/Runner/Hook/AfterRiskyTestHook.php',
'PHPUnit\\Runner\\AfterSkippedTestHook' => $vendorDir . '/phpunit/phpunit/src/Runner/Hook/AfterSkippedTestHook.php',
'PHPUnit\\Runner\\AfterSuccessfulTestHook' => $vendorDir . '/phpunit/phpunit/src/Runner/Hook/AfterSuccessfulTestHook.php',
'PHPUnit\\Runner\\AfterTestErrorHook' => $vendorDir . '/phpunit/phpunit/src/Runner/Hook/AfterTestErrorHook.php',
'PHPUnit\\Runner\\AfterTestFailureHook' => $vendorDir . '/phpunit/phpunit/src/Runner/Hook/AfterTestFailureHook.php',
'PHPUnit\\Runner\\AfterTestHook' => $vendorDir . '/phpunit/phpunit/src/Runner/Hook/AfterTestHook.php',
'PHPUnit\\Runner\\AfterTestWarningHook' => $vendorDir . '/phpunit/phpunit/src/Runner/Hook/AfterTestWarningHook.php',
'PHPUnit\\Runner\\BaseTestRunner' => $vendorDir . '/phpunit/phpunit/src/Runner/BaseTestRunner.php',
'PHPUnit\\Runner\\BeforeFirstTestHook' => $vendorDir . '/phpunit/phpunit/src/Runner/Hook/BeforeFirstTestHook.php',
'PHPUnit\\Runner\\BeforeTestHook' => $vendorDir . '/phpunit/phpunit/src/Runner/Hook/BeforeTestHook.php',
'PHPUnit\\Runner\\DefaultTestResultCache' => $vendorDir . '/phpunit/phpunit/src/Runner/DefaultTestResultCache.php',
'PHPUnit\\Runner\\Exception' => $vendorDir . '/phpunit/phpunit/src/Runner/Exception.php',
'PHPUnit\\Runner\\Filter\\ExcludeGroupFilterIterator' => $vendorDir . '/phpunit/phpunit/src/Runner/Filter/ExcludeGroupFilterIterator.php',
'PHPUnit\\Runner\\Filter\\Factory' => $vendorDir . '/phpunit/phpunit/src/Runner/Filter/Factory.php',
'PHPUnit\\Runner\\Filter\\GroupFilterIterator' => $vendorDir . '/phpunit/phpunit/src/Runner/Filter/GroupFilterIterator.php',
'PHPUnit\\Runner\\Filter\\IncludeGroupFilterIterator' => $vendorDir . '/phpunit/phpunit/src/Runner/Filter/IncludeGroupFilterIterator.php',
'PHPUnit\\Runner\\Filter\\NameFilterIterator' => $vendorDir . '/phpunit/phpunit/src/Runner/Filter/NameFilterIterator.php',
'PHPUnit\\Runner\\Hook' => $vendorDir . '/phpunit/phpunit/src/Runner/Hook/Hook.php',
'PHPUnit\\Runner\\NullTestResultCache' => $vendorDir . '/phpunit/phpunit/src/Runner/NullTestResultCache.php',
'PHPUnit\\Runner\\PhptTestCase' => $vendorDir . '/phpunit/phpunit/src/Runner/PhptTestCase.php',
'PHPUnit\\Runner\\ResultCacheExtension' => $vendorDir . '/phpunit/phpunit/src/Runner/ResultCacheExtension.php',
'PHPUnit\\Runner\\StandardTestSuiteLoader' => $vendorDir . '/phpunit/phpunit/src/Runner/StandardTestSuiteLoader.php',
'PHPUnit\\Runner\\TestHook' => $vendorDir . '/phpunit/phpunit/src/Runner/Hook/TestHook.php',
'PHPUnit\\Runner\\TestListenerAdapter' => $vendorDir . '/phpunit/phpunit/src/Runner/Hook/TestListenerAdapter.php',
'PHPUnit\\Runner\\TestResultCache' => $vendorDir . '/phpunit/phpunit/src/Runner/TestResultCache.php',
'PHPUnit\\Runner\\TestSuiteLoader' => $vendorDir . '/phpunit/phpunit/src/Runner/TestSuiteLoader.php',
'PHPUnit\\Runner\\TestSuiteSorter' => $vendorDir . '/phpunit/phpunit/src/Runner/TestSuiteSorter.php',
'PHPUnit\\Runner\\Version' => $vendorDir . '/phpunit/phpunit/src/Runner/Version.php',
'PHPUnit\\TextUI\\Command' => $vendorDir . '/phpunit/phpunit/src/TextUI/Command.php',
'PHPUnit\\TextUI\\Exception' => $vendorDir . '/phpunit/phpunit/src/TextUI/Exception.php',
'PHPUnit\\TextUI\\Help' => $vendorDir . '/phpunit/phpunit/src/TextUI/Help.php',
'PHPUnit\\TextUI\\ResultPrinter' => $vendorDir . '/phpunit/phpunit/src/TextUI/ResultPrinter.php',
'PHPUnit\\TextUI\\TestRunner' => $vendorDir . '/phpunit/phpunit/src/TextUI/TestRunner.php',
'PHPUnit\\Util\\Annotation\\DocBlock' => $vendorDir . '/phpunit/phpunit/src/Util/Annotation/DocBlock.php',
'PHPUnit\\Util\\Annotation\\Registry' => $vendorDir . '/phpunit/phpunit/src/Util/Annotation/Registry.php',
'PHPUnit\\Util\\Blacklist' => $vendorDir . '/phpunit/phpunit/src/Util/Blacklist.php',
'PHPUnit\\Util\\Color' => $vendorDir . '/phpunit/phpunit/src/Util/Color.php',
'PHPUnit\\Util\\Configuration' => $vendorDir . '/phpunit/phpunit/src/Util/Configuration.php',
'PHPUnit\\Util\\ConfigurationGenerator' => $vendorDir . '/phpunit/phpunit/src/Util/ConfigurationGenerator.php',
'PHPUnit\\Util\\ErrorHandler' => $vendorDir . '/phpunit/phpunit/src/Util/ErrorHandler.php',
'PHPUnit\\Util\\Exception' => $vendorDir . '/phpunit/phpunit/src/Util/Exception.php',
'PHPUnit\\Util\\FileLoader' => $vendorDir . '/phpunit/phpunit/src/Util/FileLoader.php',
'PHPUnit\\Util\\Filesystem' => $vendorDir . '/phpunit/phpunit/src/Util/Filesystem.php',
'PHPUnit\\Util\\Filter' => $vendorDir . '/phpunit/phpunit/src/Util/Filter.php',
'PHPUnit\\Util\\Getopt' => $vendorDir . '/phpunit/phpunit/src/Util/Getopt.php',
'PHPUnit\\Util\\GlobalState' => $vendorDir . '/phpunit/phpunit/src/Util/GlobalState.php',
'PHPUnit\\Util\\InvalidDataSetException' => $vendorDir . '/phpunit/phpunit/src/Util/InvalidDataSetException.php',
'PHPUnit\\Util\\Json' => $vendorDir . '/phpunit/phpunit/src/Util/Json.php',
'PHPUnit\\Util\\Log\\JUnit' => $vendorDir . '/phpunit/phpunit/src/Util/Log/JUnit.php',
'PHPUnit\\Util\\Log\\TeamCity' => $vendorDir . '/phpunit/phpunit/src/Util/Log/TeamCity.php',
'PHPUnit\\Util\\PHP\\AbstractPhpProcess' => $vendorDir . '/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php',
'PHPUnit\\Util\\PHP\\DefaultPhpProcess' => $vendorDir . '/phpunit/phpunit/src/Util/PHP/DefaultPhpProcess.php',
'PHPUnit\\Util\\PHP\\WindowsPhpProcess' => $vendorDir . '/phpunit/phpunit/src/Util/PHP/WindowsPhpProcess.php',
'PHPUnit\\Util\\Printer' => $vendorDir . '/phpunit/phpunit/src/Util/Printer.php',
'PHPUnit\\Util\\RegularExpression' => $vendorDir . '/phpunit/phpunit/src/Util/RegularExpression.php',
'PHPUnit\\Util\\Test' => $vendorDir . '/phpunit/phpunit/src/Util/Test.php',
'PHPUnit\\Util\\TestDox\\CliTestDoxPrinter' => $vendorDir . '/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php',
'PHPUnit\\Util\\TestDox\\HtmlResultPrinter' => $vendorDir . '/phpunit/phpunit/src/Util/TestDox/HtmlResultPrinter.php',
'PHPUnit\\Util\\TestDox\\NamePrettifier' => $vendorDir . '/phpunit/phpunit/src/Util/TestDox/NamePrettifier.php',
'PHPUnit\\Util\\TestDox\\ResultPrinter' => $vendorDir . '/phpunit/phpunit/src/Util/TestDox/ResultPrinter.php',
'PHPUnit\\Util\\TestDox\\TestDoxPrinter' => $vendorDir . '/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php',
'PHPUnit\\Util\\TestDox\\TextResultPrinter' => $vendorDir . '/phpunit/phpunit/src/Util/TestDox/TextResultPrinter.php',
'PHPUnit\\Util\\TestDox\\XmlResultPrinter' => $vendorDir . '/phpunit/phpunit/src/Util/TestDox/XmlResultPrinter.php',
'PHPUnit\\Util\\TextTestListRenderer' => $vendorDir . '/phpunit/phpunit/src/Util/TextTestListRenderer.php',
'PHPUnit\\Util\\Type' => $vendorDir . '/phpunit/phpunit/src/Util/Type.php',
'PHPUnit\\Util\\VersionComparisonOperator' => $vendorDir . '/phpunit/phpunit/src/Util/VersionComparisonOperator.php',
'PHPUnit\\Util\\XdebugFilterScriptGenerator' => $vendorDir . '/phpunit/phpunit/src/Util/XdebugFilterScriptGenerator.php',
'PHPUnit\\Util\\Xml' => $vendorDir . '/phpunit/phpunit/src/Util/Xml.php',
'PHPUnit\\Util\\XmlTestListRenderer' => $vendorDir . '/phpunit/phpunit/src/Util/XmlTestListRenderer.php',
'PHP_Token' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_TokenWithScope' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_TokenWithScopeAndVisibility' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ABSTRACT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_AMPERSAND' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_AND_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ARRAY' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ARRAY_CAST' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_AS' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_AT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_BACKTICK' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_BAD_CHARACTER' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_BOOLEAN_AND' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_BOOLEAN_OR' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_BOOL_CAST' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_BREAK' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CALLABLE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CARET' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CASE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CATCH' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CHARACTER' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CLASS' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CLASS_C' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CLASS_NAME_CONSTANT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CLONE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CLOSE_BRACKET' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CLOSE_CURLY' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CLOSE_SQUARE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CLOSE_TAG' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_COALESCE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_COALESCE_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_COLON' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_COMMA' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_COMMENT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CONCAT_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CONST' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CONSTANT_ENCAPSED_STRING' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CONTINUE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CURLY_OPEN' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DEC' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DECLARE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DEFAULT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DIR' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DIV' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DIV_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DNUMBER' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DO' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DOC_COMMENT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DOLLAR' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DOLLAR_OPEN_CURLY_BRACES' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DOT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DOUBLE_ARROW' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DOUBLE_CAST' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DOUBLE_COLON' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DOUBLE_QUOTES' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ECHO' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ELLIPSIS' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ELSE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ELSEIF' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_EMPTY' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ENCAPSED_AND_WHITESPACE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ENDDECLARE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ENDFOR' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ENDFOREACH' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ENDIF' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ENDSWITCH' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ENDWHILE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_END_HEREDOC' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_EVAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_EXCLAMATION_MARK' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_EXIT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_EXTENDS' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_FILE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_FINAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_FINALLY' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_FN' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_FOR' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_FOREACH' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_FUNCTION' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_FUNC_C' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_GLOBAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_GOTO' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_GT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_HALT_COMPILER' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_IF' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_IMPLEMENTS' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_INC' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_INCLUDE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_INCLUDE_ONCE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_INLINE_HTML' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_INSTANCEOF' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_INSTEADOF' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_INTERFACE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_INT_CAST' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ISSET' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_IS_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_IS_GREATER_OR_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_IS_IDENTICAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_IS_NOT_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_IS_NOT_IDENTICAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_IS_SMALLER_OR_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_Includes' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LINE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LIST' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LNUMBER' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LOGICAL_AND' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LOGICAL_OR' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LOGICAL_XOR' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_METHOD_C' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_MINUS' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_MINUS_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_MOD_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_MULT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_MUL_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_NAMESPACE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_NEW' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_NS_C' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_NS_SEPARATOR' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_NUM_STRING' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_OBJECT_CAST' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_OBJECT_OPERATOR' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_OPEN_BRACKET' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_OPEN_CURLY' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_OPEN_SQUARE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_OPEN_TAG' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_OPEN_TAG_WITH_ECHO' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_OR_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PAAMAYIM_NEKUDOTAYIM' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PERCENT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PIPE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PLUS' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PLUS_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_POW' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_POW_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PRINT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PRIVATE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PROTECTED' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PUBLIC' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_QUESTION_MARK' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_REQUIRE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_REQUIRE_ONCE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_RETURN' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_SEMICOLON' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_SL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_SL_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_SPACESHIP' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_SR' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_SR_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_START_HEREDOC' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_STATIC' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_STRING' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_STRING_CAST' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_STRING_VARNAME' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_SWITCH' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_Stream' => $vendorDir . '/phpunit/php-token-stream/src/Token/Stream.php',
'PHP_Token_Stream_CachingFactory' => $vendorDir . '/phpunit/php-token-stream/src/Token/Stream/CachingFactory.php',
'PHP_Token_THROW' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_TILDE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_TRAIT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_TRAIT_C' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_TRY' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_UNSET' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_UNSET_CAST' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_USE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_USE_FUNCTION' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_Util' => $vendorDir . '/phpunit/php-token-stream/src/Token/Util.php',
'PHP_Token_VAR' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_VARIABLE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_WHILE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_WHITESPACE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_XOR_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_YIELD' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_YIELD_FROM' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PharIo\\Manifest\\Application' => $vendorDir . '/phar-io/manifest/src/values/Application.php',
'PharIo\\Manifest\\ApplicationName' => $vendorDir . '/phar-io/manifest/src/values/ApplicationName.php',
'PharIo\\Manifest\\Author' => $vendorDir . '/phar-io/manifest/src/values/Author.php',
'PharIo\\Manifest\\AuthorCollection' => $vendorDir . '/phar-io/manifest/src/values/AuthorCollection.php',
'PharIo\\Manifest\\AuthorCollectionIterator' => $vendorDir . '/phar-io/manifest/src/values/AuthorCollectionIterator.php',
'PharIo\\Manifest\\AuthorElement' => $vendorDir . '/phar-io/manifest/src/xml/AuthorElement.php',
'PharIo\\Manifest\\AuthorElementCollection' => $vendorDir . '/phar-io/manifest/src/xml/AuthorElementCollection.php',
'PharIo\\Manifest\\BundledComponent' => $vendorDir . '/phar-io/manifest/src/values/BundledComponent.php',
'PharIo\\Manifest\\BundledComponentCollection' => $vendorDir . '/phar-io/manifest/src/values/BundledComponentCollection.php',
'PharIo\\Manifest\\BundledComponentCollectionIterator' => $vendorDir . '/phar-io/manifest/src/values/BundledComponentCollectionIterator.php',
'PharIo\\Manifest\\BundlesElement' => $vendorDir . '/phar-io/manifest/src/xml/BundlesElement.php',
'PharIo\\Manifest\\ComponentElement' => $vendorDir . '/phar-io/manifest/src/xml/ComponentElement.php',
'PharIo\\Manifest\\ComponentElementCollection' => $vendorDir . '/phar-io/manifest/src/xml/ComponentElementCollection.php',
'PharIo\\Manifest\\ContainsElement' => $vendorDir . '/phar-io/manifest/src/xml/ContainsElement.php',
'PharIo\\Manifest\\CopyrightElement' => $vendorDir . '/phar-io/manifest/src/xml/CopyrightElement.php',
'PharIo\\Manifest\\CopyrightInformation' => $vendorDir . '/phar-io/manifest/src/values/CopyrightInformation.php',
'PharIo\\Manifest\\ElementCollection' => $vendorDir . '/phar-io/manifest/src/xml/ElementCollection.php',
'PharIo\\Manifest\\ElementCollectionException' => $vendorDir . '/phar-io/manifest/src/exceptions/ElementCollectionException.php',
'PharIo\\Manifest\\Email' => $vendorDir . '/phar-io/manifest/src/values/Email.php',
'PharIo\\Manifest\\Exception' => $vendorDir . '/phar-io/manifest/src/exceptions/Exception.php',
'PharIo\\Manifest\\ExtElement' => $vendorDir . '/phar-io/manifest/src/xml/ExtElement.php',
'PharIo\\Manifest\\ExtElementCollection' => $vendorDir . '/phar-io/manifest/src/xml/ExtElementCollection.php',
'PharIo\\Manifest\\Extension' => $vendorDir . '/phar-io/manifest/src/values/Extension.php',
'PharIo\\Manifest\\ExtensionElement' => $vendorDir . '/phar-io/manifest/src/xml/ExtensionElement.php',
'PharIo\\Manifest\\InvalidApplicationNameException' => $vendorDir . '/phar-io/manifest/src/exceptions/InvalidApplicationNameException.php',
'PharIo\\Manifest\\InvalidEmailException' => $vendorDir . '/phar-io/manifest/src/exceptions/InvalidEmailException.php',
'PharIo\\Manifest\\InvalidUrlException' => $vendorDir . '/phar-io/manifest/src/exceptions/InvalidUrlException.php',
'PharIo\\Manifest\\Library' => $vendorDir . '/phar-io/manifest/src/values/Library.php',
'PharIo\\Manifest\\License' => $vendorDir . '/phar-io/manifest/src/values/License.php',
'PharIo\\Manifest\\LicenseElement' => $vendorDir . '/phar-io/manifest/src/xml/LicenseElement.php',
'PharIo\\Manifest\\Manifest' => $vendorDir . '/phar-io/manifest/src/values/Manifest.php',
'PharIo\\Manifest\\ManifestDocument' => $vendorDir . '/phar-io/manifest/src/xml/ManifestDocument.php',
'PharIo\\Manifest\\ManifestDocumentException' => $vendorDir . '/phar-io/manifest/src/exceptions/ManifestDocumentException.php',
'PharIo\\Manifest\\ManifestDocumentLoadingException' => $vendorDir . '/phar-io/manifest/src/exceptions/ManifestDocumentLoadingException.php',
'PharIo\\Manifest\\ManifestDocumentMapper' => $vendorDir . '/phar-io/manifest/src/ManifestDocumentMapper.php',
'PharIo\\Manifest\\ManifestDocumentMapperException' => $vendorDir . '/phar-io/manifest/src/exceptions/ManifestDocumentMapperException.php',
'PharIo\\Manifest\\ManifestElement' => $vendorDir . '/phar-io/manifest/src/xml/ManifestElement.php',
'PharIo\\Manifest\\ManifestElementException' => $vendorDir . '/phar-io/manifest/src/exceptions/ManifestElementException.php',
'PharIo\\Manifest\\ManifestLoader' => $vendorDir . '/phar-io/manifest/src/ManifestLoader.php',
'PharIo\\Manifest\\ManifestLoaderException' => $vendorDir . '/phar-io/manifest/src/exceptions/ManifestLoaderException.php',
'PharIo\\Manifest\\ManifestSerializer' => $vendorDir . '/phar-io/manifest/src/ManifestSerializer.php',
'PharIo\\Manifest\\PhpElement' => $vendorDir . '/phar-io/manifest/src/xml/PhpElement.php',
'PharIo\\Manifest\\PhpExtensionRequirement' => $vendorDir . '/phar-io/manifest/src/values/PhpExtensionRequirement.php',
'PharIo\\Manifest\\PhpVersionRequirement' => $vendorDir . '/phar-io/manifest/src/values/PhpVersionRequirement.php',
'PharIo\\Manifest\\Requirement' => $vendorDir . '/phar-io/manifest/src/values/Requirement.php',
'PharIo\\Manifest\\RequirementCollection' => $vendorDir . '/phar-io/manifest/src/values/RequirementCollection.php',
'PharIo\\Manifest\\RequirementCollectionIterator' => $vendorDir . '/phar-io/manifest/src/values/RequirementCollectionIterator.php',
'PharIo\\Manifest\\RequiresElement' => $vendorDir . '/phar-io/manifest/src/xml/RequiresElement.php',
'PharIo\\Manifest\\Type' => $vendorDir . '/phar-io/manifest/src/values/Type.php',
'PharIo\\Manifest\\Url' => $vendorDir . '/phar-io/manifest/src/values/Url.php',
'PharIo\\Version\\AbstractVersionConstraint' => $vendorDir . '/phar-io/version/src/constraints/AbstractVersionConstraint.php',
'PharIo\\Version\\AndVersionConstraintGroup' => $vendorDir . '/phar-io/version/src/constraints/AndVersionConstraintGroup.php',
'PharIo\\Version\\AnyVersionConstraint' => $vendorDir . '/phar-io/version/src/constraints/AnyVersionConstraint.php',
'PharIo\\Version\\ExactVersionConstraint' => $vendorDir . '/phar-io/version/src/constraints/ExactVersionConstraint.php',
'PharIo\\Version\\Exception' => $vendorDir . '/phar-io/version/src/exceptions/Exception.php',
'PharIo\\Version\\GreaterThanOrEqualToVersionConstraint' => $vendorDir . '/phar-io/version/src/constraints/GreaterThanOrEqualToVersionConstraint.php',
'PharIo\\Version\\InvalidPreReleaseSuffixException' => $vendorDir . '/phar-io/version/src/exceptions/InvalidPreReleaseSuffixException.php',
'PharIo\\Version\\InvalidVersionException' => $vendorDir . '/phar-io/version/src/exceptions/InvalidVersionException.php',
'PharIo\\Version\\NoPreReleaseSuffixException' => $vendorDir . '/phar-io/version/src/exceptions/NoPreReleaseSuffixException.php',
'PharIo\\Version\\OrVersionConstraintGroup' => $vendorDir . '/phar-io/version/src/constraints/OrVersionConstraintGroup.php',
'PharIo\\Version\\PreReleaseSuffix' => $vendorDir . '/phar-io/version/src/PreReleaseSuffix.php',
'PharIo\\Version\\SpecificMajorAndMinorVersionConstraint' => $vendorDir . '/phar-io/version/src/constraints/SpecificMajorAndMinorVersionConstraint.php',
'PharIo\\Version\\SpecificMajorVersionConstraint' => $vendorDir . '/phar-io/version/src/constraints/SpecificMajorVersionConstraint.php',
'PharIo\\Version\\UnsupportedVersionConstraintException' => $vendorDir . '/phar-io/version/src/exceptions/UnsupportedVersionConstraintException.php',
'PharIo\\Version\\Version' => $vendorDir . '/phar-io/version/src/Version.php',
'PharIo\\Version\\VersionConstraint' => $vendorDir . '/phar-io/version/src/constraints/VersionConstraint.php',
'PharIo\\Version\\VersionConstraintParser' => $vendorDir . '/phar-io/version/src/VersionConstraintParser.php',
'PharIo\\Version\\VersionConstraintValue' => $vendorDir . '/phar-io/version/src/VersionConstraintValue.php',
'PharIo\\Version\\VersionNumber' => $vendorDir . '/phar-io/version/src/VersionNumber.php',
'PhpAmqpLib\\Channel\\AMQPChannel' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Channel/AMQPChannel.php',
'PhpAmqpLib\\Channel\\AbstractChannel' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Channel/AbstractChannel.php',
'PhpAmqpLib\\Connection\\AMQPLazyConnection' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPLazyConnection.php',
'PhpAmqpLib\\Connection\\AMQPLazySSLConnection' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPLazySSLConnection.php',
'PhpAmqpLib\\Connection\\AMQPLazySocketConnection' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPLazySocketConnection.php',
'PhpAmqpLib\\Connection\\AMQPSSLConnection' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPSSLConnection.php',
'PhpAmqpLib\\Connection\\AMQPSocketConnection' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPSocketConnection.php',
'PhpAmqpLib\\Connection\\AMQPStreamConnection' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPStreamConnection.php',
'PhpAmqpLib\\Connection\\AbstractConnection' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AbstractConnection.php',
'PhpAmqpLib\\Connection\\Heartbeat\\PCNTLHeartbeatSender' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Connection/Heartbeat/PCNTLHeartbeatSender.php',
'PhpAmqpLib\\Exception\\AMQPBasicCancelException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPBasicCancelException.php',
'PhpAmqpLib\\Exception\\AMQPChannelClosedException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPChannelClosedException.php',
'PhpAmqpLib\\Exception\\AMQPConnectionBlockedException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPConnectionBlockedException.php',
'PhpAmqpLib\\Exception\\AMQPConnectionClosedException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPConnectionClosedException.php',
'PhpAmqpLib\\Exception\\AMQPDataReadException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPDataReadException.php',
'PhpAmqpLib\\Exception\\AMQPEmptyDeliveryTagException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPEmptyDeliveryTagException.php',
'PhpAmqpLib\\Exception\\AMQPExceptionInterface' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPExceptionInterface.php',
'PhpAmqpLib\\Exception\\AMQPHeartbeatMissedException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPHeartbeatMissedException.php',
'PhpAmqpLib\\Exception\\AMQPIOException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPIOException.php',
'PhpAmqpLib\\Exception\\AMQPIOWaitException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPIOWaitException.php',
'PhpAmqpLib\\Exception\\AMQPInvalidArgumentException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPInvalidArgumentException.php',
'PhpAmqpLib\\Exception\\AMQPInvalidFrameException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPInvalidFrameException.php',
'PhpAmqpLib\\Exception\\AMQPLogicException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPLogicException.php',
'PhpAmqpLib\\Exception\\AMQPNoDataException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPNoDataException.php',
'PhpAmqpLib\\Exception\\AMQPNotImplementedException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPNotImplementedException.php',
'PhpAmqpLib\\Exception\\AMQPOutOfBoundsException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPOutOfBoundsException.php',
'PhpAmqpLib\\Exception\\AMQPOutOfRangeException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPOutOfRangeException.php',
'PhpAmqpLib\\Exception\\AMQPProtocolChannelException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPProtocolChannelException.php',
'PhpAmqpLib\\Exception\\AMQPProtocolException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPProtocolException.php',
'PhpAmqpLib\\Exception\\AMQPRuntimeException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPRuntimeException.php',
'PhpAmqpLib\\Exception\\AMQPSocketException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPSocketException.php',
'PhpAmqpLib\\Exception\\AMQPTimeoutException' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPTimeoutException.php',
'PhpAmqpLib\\Exchange\\AMQPExchangeType' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Exchange/AMQPExchangeType.php',
'PhpAmqpLib\\Helper\\Assert' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Assert.php',
'PhpAmqpLib\\Helper\\BigInteger' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/BigInteger.php',
'PhpAmqpLib\\Helper\\DebugHelper' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/DebugHelper.php',
'PhpAmqpLib\\Helper\\MiscHelper' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/MiscHelper.php',
'PhpAmqpLib\\Helper\\Protocol\\MethodMap080' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/MethodMap080.php',
'PhpAmqpLib\\Helper\\Protocol\\MethodMap091' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/MethodMap091.php',
'PhpAmqpLib\\Helper\\Protocol\\Protocol080' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/Protocol080.php',
'PhpAmqpLib\\Helper\\Protocol\\Protocol091' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/Protocol091.php',
'PhpAmqpLib\\Helper\\Protocol\\Wait080' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/Wait080.php',
'PhpAmqpLib\\Helper\\Protocol\\Wait091' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/Wait091.php',
'PhpAmqpLib\\Helper\\SocketConstants' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/SocketConstants.php',
'PhpAmqpLib\\Message\\AMQPMessage' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Message/AMQPMessage.php',
'PhpAmqpLib\\Package' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Package.php',
'PhpAmqpLib\\Wire\\AMQPAbstractCollection' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPAbstractCollection.php',
'PhpAmqpLib\\Wire\\AMQPArray' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPArray.php',
'PhpAmqpLib\\Wire\\AMQPDecimal' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPDecimal.php',
'PhpAmqpLib\\Wire\\AMQPReader' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPReader.php',
'PhpAmqpLib\\Wire\\AMQPTable' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPTable.php',
'PhpAmqpLib\\Wire\\AMQPWriter' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPWriter.php',
'PhpAmqpLib\\Wire\\AbstractClient' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AbstractClient.php',
'PhpAmqpLib\\Wire\\Constants' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/Constants.php',
'PhpAmqpLib\\Wire\\Constants080' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/Constants080.php',
'PhpAmqpLib\\Wire\\Constants091' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/Constants091.php',
'PhpAmqpLib\\Wire\\IO\\AbstractIO' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/IO/AbstractIO.php',
'PhpAmqpLib\\Wire\\IO\\SocketIO' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/IO/SocketIO.php',
'PhpAmqpLib\\Wire\\IO\\StreamIO' => $vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/IO/StreamIO.php',
'Predis\\Autoloader' => $vendorDir . '/predis/predis/src/Autoloader.php',
'Predis\\Client' => $vendorDir . '/predis/predis/src/Client.php',
'Predis\\ClientContextInterface' => $vendorDir . '/predis/predis/src/ClientContextInterface.php',
'Predis\\ClientException' => $vendorDir . '/predis/predis/src/ClientException.php',
'Predis\\ClientInterface' => $vendorDir . '/predis/predis/src/ClientInterface.php',
'Predis\\Cluster\\ClusterStrategy' => $vendorDir . '/predis/predis/src/Cluster/ClusterStrategy.php',
'Predis\\Cluster\\Distributor\\DistributorInterface' => $vendorDir . '/predis/predis/src/Cluster/Distributor/DistributorInterface.php',
'Predis\\Cluster\\Distributor\\EmptyRingException' => $vendorDir . '/predis/predis/src/Cluster/Distributor/EmptyRingException.php',
'Predis\\Cluster\\Distributor\\HashRing' => $vendorDir . '/predis/predis/src/Cluster/Distributor/HashRing.php',
'Predis\\Cluster\\Distributor\\KetamaRing' => $vendorDir . '/predis/predis/src/Cluster/Distributor/KetamaRing.php',
'Predis\\Cluster\\Hash\\CRC16' => $vendorDir . '/predis/predis/src/Cluster/Hash/CRC16.php',
'Predis\\Cluster\\Hash\\HashGeneratorInterface' => $vendorDir . '/predis/predis/src/Cluster/Hash/HashGeneratorInterface.php',
'Predis\\Cluster\\PredisStrategy' => $vendorDir . '/predis/predis/src/Cluster/PredisStrategy.php',
'Predis\\Cluster\\RedisStrategy' => $vendorDir . '/predis/predis/src/Cluster/RedisStrategy.php',
'Predis\\Cluster\\StrategyInterface' => $vendorDir . '/predis/predis/src/Cluster/StrategyInterface.php',
'Predis\\Collection\\Iterator\\CursorBasedIterator' => $vendorDir . '/predis/predis/src/Collection/Iterator/CursorBasedIterator.php',
'Predis\\Collection\\Iterator\\HashKey' => $vendorDir . '/predis/predis/src/Collection/Iterator/HashKey.php',
'Predis\\Collection\\Iterator\\Keyspace' => $vendorDir . '/predis/predis/src/Collection/Iterator/Keyspace.php',
'Predis\\Collection\\Iterator\\ListKey' => $vendorDir . '/predis/predis/src/Collection/Iterator/ListKey.php',
'Predis\\Collection\\Iterator\\SetKey' => $vendorDir . '/predis/predis/src/Collection/Iterator/SetKey.php',
'Predis\\Collection\\Iterator\\SortedSetKey' => $vendorDir . '/predis/predis/src/Collection/Iterator/SortedSetKey.php',
'Predis\\Command\\Command' => $vendorDir . '/predis/predis/src/Command/Command.php',
'Predis\\Command\\CommandInterface' => $vendorDir . '/predis/predis/src/Command/CommandInterface.php',
'Predis\\Command\\ConnectionAuth' => $vendorDir . '/predis/predis/src/Command/ConnectionAuth.php',
'Predis\\Command\\ConnectionEcho' => $vendorDir . '/predis/predis/src/Command/ConnectionEcho.php',
'Predis\\Command\\ConnectionPing' => $vendorDir . '/predis/predis/src/Command/ConnectionPing.php',
'Predis\\Command\\ConnectionQuit' => $vendorDir . '/predis/predis/src/Command/ConnectionQuit.php',
'Predis\\Command\\ConnectionSelect' => $vendorDir . '/predis/predis/src/Command/ConnectionSelect.php',
'Predis\\Command\\GeospatialGeoAdd' => $vendorDir . '/predis/predis/src/Command/GeospatialGeoAdd.php',
'Predis\\Command\\GeospatialGeoDist' => $vendorDir . '/predis/predis/src/Command/GeospatialGeoDist.php',
'Predis\\Command\\GeospatialGeoHash' => $vendorDir . '/predis/predis/src/Command/GeospatialGeoHash.php',
'Predis\\Command\\GeospatialGeoPos' => $vendorDir . '/predis/predis/src/Command/GeospatialGeoPos.php',
'Predis\\Command\\GeospatialGeoRadius' => $vendorDir . '/predis/predis/src/Command/GeospatialGeoRadius.php',
'Predis\\Command\\GeospatialGeoRadiusByMember' => $vendorDir . '/predis/predis/src/Command/GeospatialGeoRadiusByMember.php',
'Predis\\Command\\HashDelete' => $vendorDir . '/predis/predis/src/Command/HashDelete.php',
'Predis\\Command\\HashExists' => $vendorDir . '/predis/predis/src/Command/HashExists.php',
'Predis\\Command\\HashGet' => $vendorDir . '/predis/predis/src/Command/HashGet.php',
'Predis\\Command\\HashGetAll' => $vendorDir . '/predis/predis/src/Command/HashGetAll.php',
'Predis\\Command\\HashGetMultiple' => $vendorDir . '/predis/predis/src/Command/HashGetMultiple.php',
'Predis\\Command\\HashIncrementBy' => $vendorDir . '/predis/predis/src/Command/HashIncrementBy.php',
'Predis\\Command\\HashIncrementByFloat' => $vendorDir . '/predis/predis/src/Command/HashIncrementByFloat.php',
'Predis\\Command\\HashKeys' => $vendorDir . '/predis/predis/src/Command/HashKeys.php',
'Predis\\Command\\HashLength' => $vendorDir . '/predis/predis/src/Command/HashLength.php',
'Predis\\Command\\HashScan' => $vendorDir . '/predis/predis/src/Command/HashScan.php',
'Predis\\Command\\HashSet' => $vendorDir . '/predis/predis/src/Command/HashSet.php',
'Predis\\Command\\HashSetMultiple' => $vendorDir . '/predis/predis/src/Command/HashSetMultiple.php',
'Predis\\Command\\HashSetPreserve' => $vendorDir . '/predis/predis/src/Command/HashSetPreserve.php',
'Predis\\Command\\HashStringLength' => $vendorDir . '/predis/predis/src/Command/HashStringLength.php',
'Predis\\Command\\HashValues' => $vendorDir . '/predis/predis/src/Command/HashValues.php',
'Predis\\Command\\HyperLogLogAdd' => $vendorDir . '/predis/predis/src/Command/HyperLogLogAdd.php',
'Predis\\Command\\HyperLogLogCount' => $vendorDir . '/predis/predis/src/Command/HyperLogLogCount.php',
'Predis\\Command\\HyperLogLogMerge' => $vendorDir . '/predis/predis/src/Command/HyperLogLogMerge.php',
'Predis\\Command\\KeyDelete' => $vendorDir . '/predis/predis/src/Command/KeyDelete.php',
'Predis\\Command\\KeyDump' => $vendorDir . '/predis/predis/src/Command/KeyDump.php',
'Predis\\Command\\KeyExists' => $vendorDir . '/predis/predis/src/Command/KeyExists.php',
'Predis\\Command\\KeyExpire' => $vendorDir . '/predis/predis/src/Command/KeyExpire.php',
'Predis\\Command\\KeyExpireAt' => $vendorDir . '/predis/predis/src/Command/KeyExpireAt.php',
'Predis\\Command\\KeyKeys' => $vendorDir . '/predis/predis/src/Command/KeyKeys.php',
'Predis\\Command\\KeyMigrate' => $vendorDir . '/predis/predis/src/Command/KeyMigrate.php',
'Predis\\Command\\KeyMove' => $vendorDir . '/predis/predis/src/Command/KeyMove.php',
'Predis\\Command\\KeyPersist' => $vendorDir . '/predis/predis/src/Command/KeyPersist.php',
'Predis\\Command\\KeyPreciseExpire' => $vendorDir . '/predis/predis/src/Command/KeyPreciseExpire.php',
'Predis\\Command\\KeyPreciseExpireAt' => $vendorDir . '/predis/predis/src/Command/KeyPreciseExpireAt.php',
'Predis\\Command\\KeyPreciseTimeToLive' => $vendorDir . '/predis/predis/src/Command/KeyPreciseTimeToLive.php',
'Predis\\Command\\KeyRandom' => $vendorDir . '/predis/predis/src/Command/KeyRandom.php',
'Predis\\Command\\KeyRename' => $vendorDir . '/predis/predis/src/Command/KeyRename.php',
'Predis\\Command\\KeyRenamePreserve' => $vendorDir . '/predis/predis/src/Command/KeyRenamePreserve.php',
'Predis\\Command\\KeyRestore' => $vendorDir . '/predis/predis/src/Command/KeyRestore.php',
'Predis\\Command\\KeyScan' => $vendorDir . '/predis/predis/src/Command/KeyScan.php',
'Predis\\Command\\KeySort' => $vendorDir . '/predis/predis/src/Command/KeySort.php',
'Predis\\Command\\KeyTimeToLive' => $vendorDir . '/predis/predis/src/Command/KeyTimeToLive.php',
'Predis\\Command\\KeyType' => $vendorDir . '/predis/predis/src/Command/KeyType.php',
'Predis\\Command\\ListIndex' => $vendorDir . '/predis/predis/src/Command/ListIndex.php',
'Predis\\Command\\ListInsert' => $vendorDir . '/predis/predis/src/Command/ListInsert.php',
'Predis\\Command\\ListLength' => $vendorDir . '/predis/predis/src/Command/ListLength.php',
'Predis\\Command\\ListPopFirst' => $vendorDir . '/predis/predis/src/Command/ListPopFirst.php',
'Predis\\Command\\ListPopFirstBlocking' => $vendorDir . '/predis/predis/src/Command/ListPopFirstBlocking.php',
'Predis\\Command\\ListPopLast' => $vendorDir . '/predis/predis/src/Command/ListPopLast.php',
'Predis\\Command\\ListPopLastBlocking' => $vendorDir . '/predis/predis/src/Command/ListPopLastBlocking.php',
'Predis\\Command\\ListPopLastPushHead' => $vendorDir . '/predis/predis/src/Command/ListPopLastPushHead.php',
'Predis\\Command\\ListPopLastPushHeadBlocking' => $vendorDir . '/predis/predis/src/Command/ListPopLastPushHeadBlocking.php',
'Predis\\Command\\ListPushHead' => $vendorDir . '/predis/predis/src/Command/ListPushHead.php',
'Predis\\Command\\ListPushHeadX' => $vendorDir . '/predis/predis/src/Command/ListPushHeadX.php',
'Predis\\Command\\ListPushTail' => $vendorDir . '/predis/predis/src/Command/ListPushTail.php',
'Predis\\Command\\ListPushTailX' => $vendorDir . '/predis/predis/src/Command/ListPushTailX.php',
'Predis\\Command\\ListRange' => $vendorDir . '/predis/predis/src/Command/ListRange.php',
'Predis\\Command\\ListRemove' => $vendorDir . '/predis/predis/src/Command/ListRemove.php',
'Predis\\Command\\ListSet' => $vendorDir . '/predis/predis/src/Command/ListSet.php',
'Predis\\Command\\ListTrim' => $vendorDir . '/predis/predis/src/Command/ListTrim.php',
'Predis\\Command\\PrefixableCommandInterface' => $vendorDir . '/predis/predis/src/Command/PrefixableCommandInterface.php',
'Predis\\Command\\Processor\\KeyPrefixProcessor' => $vendorDir . '/predis/predis/src/Command/Processor/KeyPrefixProcessor.php',
'Predis\\Command\\Processor\\ProcessorChain' => $vendorDir . '/predis/predis/src/Command/Processor/ProcessorChain.php',
'Predis\\Command\\Processor\\ProcessorInterface' => $vendorDir . '/predis/predis/src/Command/Processor/ProcessorInterface.php',
'Predis\\Command\\PubSubPublish' => $vendorDir . '/predis/predis/src/Command/PubSubPublish.php',
'Predis\\Command\\PubSubPubsub' => $vendorDir . '/predis/predis/src/Command/PubSubPubsub.php',
'Predis\\Command\\PubSubSubscribe' => $vendorDir . '/predis/predis/src/Command/PubSubSubscribe.php',
'Predis\\Command\\PubSubSubscribeByPattern' => $vendorDir . '/predis/predis/src/Command/PubSubSubscribeByPattern.php',
'Predis\\Command\\PubSubUnsubscribe' => $vendorDir . '/predis/predis/src/Command/PubSubUnsubscribe.php',
'Predis\\Command\\PubSubUnsubscribeByPattern' => $vendorDir . '/predis/predis/src/Command/PubSubUnsubscribeByPattern.php',
'Predis\\Command\\RawCommand' => $vendorDir . '/predis/predis/src/Command/RawCommand.php',
'Predis\\Command\\ScriptCommand' => $vendorDir . '/predis/predis/src/Command/ScriptCommand.php',
'Predis\\Command\\ServerBackgroundRewriteAOF' => $vendorDir . '/predis/predis/src/Command/ServerBackgroundRewriteAOF.php',
'Predis\\Command\\ServerBackgroundSave' => $vendorDir . '/predis/predis/src/Command/ServerBackgroundSave.php',
'Predis\\Command\\ServerClient' => $vendorDir . '/predis/predis/src/Command/ServerClient.php',
'Predis\\Command\\ServerCommand' => $vendorDir . '/predis/predis/src/Command/ServerCommand.php',
'Predis\\Command\\ServerConfig' => $vendorDir . '/predis/predis/src/Command/ServerConfig.php',
'Predis\\Command\\ServerDatabaseSize' => $vendorDir . '/predis/predis/src/Command/ServerDatabaseSize.php',
'Predis\\Command\\ServerEval' => $vendorDir . '/predis/predis/src/Command/ServerEval.php',
'Predis\\Command\\ServerEvalSHA' => $vendorDir . '/predis/predis/src/Command/ServerEvalSHA.php',
'Predis\\Command\\ServerFlushAll' => $vendorDir . '/predis/predis/src/Command/ServerFlushAll.php',
'Predis\\Command\\ServerFlushDatabase' => $vendorDir . '/predis/predis/src/Command/ServerFlushDatabase.php',
'Predis\\Command\\ServerInfo' => $vendorDir . '/predis/predis/src/Command/ServerInfo.php',
'Predis\\Command\\ServerInfoV26x' => $vendorDir . '/predis/predis/src/Command/ServerInfoV26x.php',
'Predis\\Command\\ServerLastSave' => $vendorDir . '/predis/predis/src/Command/ServerLastSave.php',
'Predis\\Command\\ServerMonitor' => $vendorDir . '/predis/predis/src/Command/ServerMonitor.php',
'Predis\\Command\\ServerObject' => $vendorDir . '/predis/predis/src/Command/ServerObject.php',
'Predis\\Command\\ServerSave' => $vendorDir . '/predis/predis/src/Command/ServerSave.php',
'Predis\\Command\\ServerScript' => $vendorDir . '/predis/predis/src/Command/ServerScript.php',
'Predis\\Command\\ServerSentinel' => $vendorDir . '/predis/predis/src/Command/ServerSentinel.php',
'Predis\\Command\\ServerShutdown' => $vendorDir . '/predis/predis/src/Command/ServerShutdown.php',
'Predis\\Command\\ServerSlaveOf' => $vendorDir . '/predis/predis/src/Command/ServerSlaveOf.php',
'Predis\\Command\\ServerSlowlog' => $vendorDir . '/predis/predis/src/Command/ServerSlowlog.php',
'Predis\\Command\\ServerTime' => $vendorDir . '/predis/predis/src/Command/ServerTime.php',
'Predis\\Command\\SetAdd' => $vendorDir . '/predis/predis/src/Command/SetAdd.php',
'Predis\\Command\\SetCardinality' => $vendorDir . '/predis/predis/src/Command/SetCardinality.php',
'Predis\\Command\\SetDifference' => $vendorDir . '/predis/predis/src/Command/SetDifference.php',
'Predis\\Command\\SetDifferenceStore' => $vendorDir . '/predis/predis/src/Command/SetDifferenceStore.php',
'Predis\\Command\\SetIntersection' => $vendorDir . '/predis/predis/src/Command/SetIntersection.php',
'Predis\\Command\\SetIntersectionStore' => $vendorDir . '/predis/predis/src/Command/SetIntersectionStore.php',
'Predis\\Command\\SetIsMember' => $vendorDir . '/predis/predis/src/Command/SetIsMember.php',
'Predis\\Command\\SetMembers' => $vendorDir . '/predis/predis/src/Command/SetMembers.php',
'Predis\\Command\\SetMove' => $vendorDir . '/predis/predis/src/Command/SetMove.php',
'Predis\\Command\\SetPop' => $vendorDir . '/predis/predis/src/Command/SetPop.php',
'Predis\\Command\\SetRandomMember' => $vendorDir . '/predis/predis/src/Command/SetRandomMember.php',
'Predis\\Command\\SetRemove' => $vendorDir . '/predis/predis/src/Command/SetRemove.php',
'Predis\\Command\\SetScan' => $vendorDir . '/predis/predis/src/Command/SetScan.php',
'Predis\\Command\\SetUnion' => $vendorDir . '/predis/predis/src/Command/SetUnion.php',
'Predis\\Command\\SetUnionStore' => $vendorDir . '/predis/predis/src/Command/SetUnionStore.php',
'Predis\\Command\\StringAppend' => $vendorDir . '/predis/predis/src/Command/StringAppend.php',
'Predis\\Command\\StringBitCount' => $vendorDir . '/predis/predis/src/Command/StringBitCount.php',
'Predis\\Command\\StringBitField' => $vendorDir . '/predis/predis/src/Command/StringBitField.php',
'Predis\\Command\\StringBitOp' => $vendorDir . '/predis/predis/src/Command/StringBitOp.php',
'Predis\\Command\\StringBitPos' => $vendorDir . '/predis/predis/src/Command/StringBitPos.php',
'Predis\\Command\\StringDecrement' => $vendorDir . '/predis/predis/src/Command/StringDecrement.php',
'Predis\\Command\\StringDecrementBy' => $vendorDir . '/predis/predis/src/Command/StringDecrementBy.php',
'Predis\\Command\\StringGet' => $vendorDir . '/predis/predis/src/Command/StringGet.php',
'Predis\\Command\\StringGetBit' => $vendorDir . '/predis/predis/src/Command/StringGetBit.php',
'Predis\\Command\\StringGetMultiple' => $vendorDir . '/predis/predis/src/Command/StringGetMultiple.php',
'Predis\\Command\\StringGetRange' => $vendorDir . '/predis/predis/src/Command/StringGetRange.php',
'Predis\\Command\\StringGetSet' => $vendorDir . '/predis/predis/src/Command/StringGetSet.php',
'Predis\\Command\\StringIncrement' => $vendorDir . '/predis/predis/src/Command/StringIncrement.php',
'Predis\\Command\\StringIncrementBy' => $vendorDir . '/predis/predis/src/Command/StringIncrementBy.php',
'Predis\\Command\\StringIncrementByFloat' => $vendorDir . '/predis/predis/src/Command/StringIncrementByFloat.php',
'Predis\\Command\\StringPreciseSetExpire' => $vendorDir . '/predis/predis/src/Command/StringPreciseSetExpire.php',
'Predis\\Command\\StringSet' => $vendorDir . '/predis/predis/src/Command/StringSet.php',
'Predis\\Command\\StringSetBit' => $vendorDir . '/predis/predis/src/Command/StringSetBit.php',
'Predis\\Command\\StringSetExpire' => $vendorDir . '/predis/predis/src/Command/StringSetExpire.php',
'Predis\\Command\\StringSetMultiple' => $vendorDir . '/predis/predis/src/Command/StringSetMultiple.php',
'Predis\\Command\\StringSetMultiplePreserve' => $vendorDir . '/predis/predis/src/Command/StringSetMultiplePreserve.php',
'Predis\\Command\\StringSetPreserve' => $vendorDir . '/predis/predis/src/Command/StringSetPreserve.php',
'Predis\\Command\\StringSetRange' => $vendorDir . '/predis/predis/src/Command/StringSetRange.php',
'Predis\\Command\\StringStrlen' => $vendorDir . '/predis/predis/src/Command/StringStrlen.php',
'Predis\\Command\\StringSubstr' => $vendorDir . '/predis/predis/src/Command/StringSubstr.php',
'Predis\\Command\\TransactionDiscard' => $vendorDir . '/predis/predis/src/Command/TransactionDiscard.php',
'Predis\\Command\\TransactionExec' => $vendorDir . '/predis/predis/src/Command/TransactionExec.php',
'Predis\\Command\\TransactionMulti' => $vendorDir . '/predis/predis/src/Command/TransactionMulti.php',
'Predis\\Command\\TransactionUnwatch' => $vendorDir . '/predis/predis/src/Command/TransactionUnwatch.php',
'Predis\\Command\\TransactionWatch' => $vendorDir . '/predis/predis/src/Command/TransactionWatch.php',
'Predis\\Command\\ZSetAdd' => $vendorDir . '/predis/predis/src/Command/ZSetAdd.php',
'Predis\\Command\\ZSetCardinality' => $vendorDir . '/predis/predis/src/Command/ZSetCardinality.php',
'Predis\\Command\\ZSetCount' => $vendorDir . '/predis/predis/src/Command/ZSetCount.php',
'Predis\\Command\\ZSetIncrementBy' => $vendorDir . '/predis/predis/src/Command/ZSetIncrementBy.php',
'Predis\\Command\\ZSetIntersectionStore' => $vendorDir . '/predis/predis/src/Command/ZSetIntersectionStore.php',
'Predis\\Command\\ZSetLexCount' => $vendorDir . '/predis/predis/src/Command/ZSetLexCount.php',
'Predis\\Command\\ZSetRange' => $vendorDir . '/predis/predis/src/Command/ZSetRange.php',
'Predis\\Command\\ZSetRangeByLex' => $vendorDir . '/predis/predis/src/Command/ZSetRangeByLex.php',
'Predis\\Command\\ZSetRangeByScore' => $vendorDir . '/predis/predis/src/Command/ZSetRangeByScore.php',
'Predis\\Command\\ZSetRank' => $vendorDir . '/predis/predis/src/Command/ZSetRank.php',
'Predis\\Command\\ZSetRemove' => $vendorDir . '/predis/predis/src/Command/ZSetRemove.php',
'Predis\\Command\\ZSetRemoveRangeByLex' => $vendorDir . '/predis/predis/src/Command/ZSetRemoveRangeByLex.php',
'Predis\\Command\\ZSetRemoveRangeByRank' => $vendorDir . '/predis/predis/src/Command/ZSetRemoveRangeByRank.php',
'Predis\\Command\\ZSetRemoveRangeByScore' => $vendorDir . '/predis/predis/src/Command/ZSetRemoveRangeByScore.php',
'Predis\\Command\\ZSetReverseRange' => $vendorDir . '/predis/predis/src/Command/ZSetReverseRange.php',
'Predis\\Command\\ZSetReverseRangeByLex' => $vendorDir . '/predis/predis/src/Command/ZSetReverseRangeByLex.php',
'Predis\\Command\\ZSetReverseRangeByScore' => $vendorDir . '/predis/predis/src/Command/ZSetReverseRangeByScore.php',
'Predis\\Command\\ZSetReverseRank' => $vendorDir . '/predis/predis/src/Command/ZSetReverseRank.php',
'Predis\\Command\\ZSetScan' => $vendorDir . '/predis/predis/src/Command/ZSetScan.php',
'Predis\\Command\\ZSetScore' => $vendorDir . '/predis/predis/src/Command/ZSetScore.php',
'Predis\\Command\\ZSetUnionStore' => $vendorDir . '/predis/predis/src/Command/ZSetUnionStore.php',
'Predis\\CommunicationException' => $vendorDir . '/predis/predis/src/CommunicationException.php',
'Predis\\Configuration\\ClusterOption' => $vendorDir . '/predis/predis/src/Configuration/ClusterOption.php',
'Predis\\Configuration\\ConnectionFactoryOption' => $vendorDir . '/predis/predis/src/Configuration/ConnectionFactoryOption.php',
'Predis\\Configuration\\ExceptionsOption' => $vendorDir . '/predis/predis/src/Configuration/ExceptionsOption.php',
'Predis\\Configuration\\OptionInterface' => $vendorDir . '/predis/predis/src/Configuration/OptionInterface.php',
'Predis\\Configuration\\Options' => $vendorDir . '/predis/predis/src/Configuration/Options.php',
'Predis\\Configuration\\OptionsInterface' => $vendorDir . '/predis/predis/src/Configuration/OptionsInterface.php',
'Predis\\Configuration\\PrefixOption' => $vendorDir . '/predis/predis/src/Configuration/PrefixOption.php',
'Predis\\Configuration\\ProfileOption' => $vendorDir . '/predis/predis/src/Configuration/ProfileOption.php',
'Predis\\Configuration\\ReplicationOption' => $vendorDir . '/predis/predis/src/Configuration/ReplicationOption.php',
'Predis\\Connection\\AbstractConnection' => $vendorDir . '/predis/predis/src/Connection/AbstractConnection.php',
'Predis\\Connection\\AggregateConnectionInterface' => $vendorDir . '/predis/predis/src/Connection/AggregateConnectionInterface.php',
'Predis\\Connection\\Aggregate\\ClusterInterface' => $vendorDir . '/predis/predis/src/Connection/Aggregate/ClusterInterface.php',
'Predis\\Connection\\Aggregate\\MasterSlaveReplication' => $vendorDir . '/predis/predis/src/Connection/Aggregate/MasterSlaveReplication.php',
'Predis\\Connection\\Aggregate\\PredisCluster' => $vendorDir . '/predis/predis/src/Connection/Aggregate/PredisCluster.php',
'Predis\\Connection\\Aggregate\\RedisCluster' => $vendorDir . '/predis/predis/src/Connection/Aggregate/RedisCluster.php',
'Predis\\Connection\\Aggregate\\ReplicationInterface' => $vendorDir . '/predis/predis/src/Connection/Aggregate/ReplicationInterface.php',
'Predis\\Connection\\Aggregate\\SentinelReplication' => $vendorDir . '/predis/predis/src/Connection/Aggregate/SentinelReplication.php',
'Predis\\Connection\\CompositeConnectionInterface' => $vendorDir . '/predis/predis/src/Connection/CompositeConnectionInterface.php',
'Predis\\Connection\\CompositeStreamConnection' => $vendorDir . '/predis/predis/src/Connection/CompositeStreamConnection.php',
'Predis\\Connection\\ConnectionException' => $vendorDir . '/predis/predis/src/Connection/ConnectionException.php',
'Predis\\Connection\\ConnectionInterface' => $vendorDir . '/predis/predis/src/Connection/ConnectionInterface.php',
'Predis\\Connection\\Factory' => $vendorDir . '/predis/predis/src/Connection/Factory.php',
'Predis\\Connection\\FactoryInterface' => $vendorDir . '/predis/predis/src/Connection/FactoryInterface.php',
'Predis\\Connection\\NodeConnectionInterface' => $vendorDir . '/predis/predis/src/Connection/NodeConnectionInterface.php',
'Predis\\Connection\\Parameters' => $vendorDir . '/predis/predis/src/Connection/Parameters.php',
'Predis\\Connection\\ParametersInterface' => $vendorDir . '/predis/predis/src/Connection/ParametersInterface.php',
'Predis\\Connection\\PhpiredisSocketConnection' => $vendorDir . '/predis/predis/src/Connection/PhpiredisSocketConnection.php',
'Predis\\Connection\\PhpiredisStreamConnection' => $vendorDir . '/predis/predis/src/Connection/PhpiredisStreamConnection.php',
'Predis\\Connection\\StreamConnection' => $vendorDir . '/predis/predis/src/Connection/StreamConnection.php',
'Predis\\Connection\\WebdisConnection' => $vendorDir . '/predis/predis/src/Connection/WebdisConnection.php',
'Predis\\Monitor\\Consumer' => $vendorDir . '/predis/predis/src/Monitor/Consumer.php',
'Predis\\NotSupportedException' => $vendorDir . '/predis/predis/src/NotSupportedException.php',
'Predis\\Pipeline\\Atomic' => $vendorDir . '/predis/predis/src/Pipeline/Atomic.php',
'Predis\\Pipeline\\ConnectionErrorProof' => $vendorDir . '/predis/predis/src/Pipeline/ConnectionErrorProof.php',
'Predis\\Pipeline\\FireAndForget' => $vendorDir . '/predis/predis/src/Pipeline/FireAndForget.php',
'Predis\\Pipeline\\Pipeline' => $vendorDir . '/predis/predis/src/Pipeline/Pipeline.php',
'Predis\\PredisException' => $vendorDir . '/predis/predis/src/PredisException.php',
'Predis\\Profile\\Factory' => $vendorDir . '/predis/predis/src/Profile/Factory.php',
'Predis\\Profile\\ProfileInterface' => $vendorDir . '/predis/predis/src/Profile/ProfileInterface.php',
'Predis\\Profile\\RedisProfile' => $vendorDir . '/predis/predis/src/Profile/RedisProfile.php',
'Predis\\Profile\\RedisUnstable' => $vendorDir . '/predis/predis/src/Profile/RedisUnstable.php',
'Predis\\Profile\\RedisVersion200' => $vendorDir . '/predis/predis/src/Profile/RedisVersion200.php',
'Predis\\Profile\\RedisVersion220' => $vendorDir . '/predis/predis/src/Profile/RedisVersion220.php',
'Predis\\Profile\\RedisVersion240' => $vendorDir . '/predis/predis/src/Profile/RedisVersion240.php',
'Predis\\Profile\\RedisVersion260' => $vendorDir . '/predis/predis/src/Profile/RedisVersion260.php',
'Predis\\Profile\\RedisVersion280' => $vendorDir . '/predis/predis/src/Profile/RedisVersion280.php',
'Predis\\Profile\\RedisVersion300' => $vendorDir . '/predis/predis/src/Profile/RedisVersion300.php',
'Predis\\Profile\\RedisVersion320' => $vendorDir . '/predis/predis/src/Profile/RedisVersion320.php',
'Predis\\Protocol\\ProtocolException' => $vendorDir . '/predis/predis/src/Protocol/ProtocolException.php',
'Predis\\Protocol\\ProtocolProcessorInterface' => $vendorDir . '/predis/predis/src/Protocol/ProtocolProcessorInterface.php',
'Predis\\Protocol\\RequestSerializerInterface' => $vendorDir . '/predis/predis/src/Protocol/RequestSerializerInterface.php',
'Predis\\Protocol\\ResponseReaderInterface' => $vendorDir . '/predis/predis/src/Protocol/ResponseReaderInterface.php',
'Predis\\Protocol\\Text\\CompositeProtocolProcessor' => $vendorDir . '/predis/predis/src/Protocol/Text/CompositeProtocolProcessor.php',
'Predis\\Protocol\\Text\\Handler\\BulkResponse' => $vendorDir . '/predis/predis/src/Protocol/Text/Handler/BulkResponse.php',
'Predis\\Protocol\\Text\\Handler\\ErrorResponse' => $vendorDir . '/predis/predis/src/Protocol/Text/Handler/ErrorResponse.php',
'Predis\\Protocol\\Text\\Handler\\IntegerResponse' => $vendorDir . '/predis/predis/src/Protocol/Text/Handler/IntegerResponse.php',
'Predis\\Protocol\\Text\\Handler\\MultiBulkResponse' => $vendorDir . '/predis/predis/src/Protocol/Text/Handler/MultiBulkResponse.php',
'Predis\\Protocol\\Text\\Handler\\ResponseHandlerInterface' => $vendorDir . '/predis/predis/src/Protocol/Text/Handler/ResponseHandlerInterface.php',
'Predis\\Protocol\\Text\\Handler\\StatusResponse' => $vendorDir . '/predis/predis/src/Protocol/Text/Handler/StatusResponse.php',
'Predis\\Protocol\\Text\\Handler\\StreamableMultiBulkResponse' => $vendorDir . '/predis/predis/src/Protocol/Text/Handler/StreamableMultiBulkResponse.php',
'Predis\\Protocol\\Text\\ProtocolProcessor' => $vendorDir . '/predis/predis/src/Protocol/Text/ProtocolProcessor.php',
'Predis\\Protocol\\Text\\RequestSerializer' => $vendorDir . '/predis/predis/src/Protocol/Text/RequestSerializer.php',
'Predis\\Protocol\\Text\\ResponseReader' => $vendorDir . '/predis/predis/src/Protocol/Text/ResponseReader.php',
'Predis\\PubSub\\AbstractConsumer' => $vendorDir . '/predis/predis/src/PubSub/AbstractConsumer.php',
'Predis\\PubSub\\Consumer' => $vendorDir . '/predis/predis/src/PubSub/Consumer.php',
'Predis\\PubSub\\DispatcherLoop' => $vendorDir . '/predis/predis/src/PubSub/DispatcherLoop.php',
'Predis\\Replication\\MissingMasterException' => $vendorDir . '/predis/predis/src/Replication/MissingMasterException.php',
'Predis\\Replication\\ReplicationStrategy' => $vendorDir . '/predis/predis/src/Replication/ReplicationStrategy.php',
'Predis\\Replication\\RoleException' => $vendorDir . '/predis/predis/src/Replication/RoleException.php',
'Predis\\Response\\Error' => $vendorDir . '/predis/predis/src/Response/Error.php',
'Predis\\Response\\ErrorInterface' => $vendorDir . '/predis/predis/src/Response/ErrorInterface.php',
'Predis\\Response\\Iterator\\MultiBulk' => $vendorDir . '/predis/predis/src/Response/Iterator/MultiBulk.php',
'Predis\\Response\\Iterator\\MultiBulkIterator' => $vendorDir . '/predis/predis/src/Response/Iterator/MultiBulkIterator.php',
'Predis\\Response\\Iterator\\MultiBulkTuple' => $vendorDir . '/predis/predis/src/Response/Iterator/MultiBulkTuple.php',
'Predis\\Response\\ResponseInterface' => $vendorDir . '/predis/predis/src/Response/ResponseInterface.php',
'Predis\\Response\\ServerException' => $vendorDir . '/predis/predis/src/Response/ServerException.php',
'Predis\\Response\\Status' => $vendorDir . '/predis/predis/src/Response/Status.php',
'Predis\\Session\\Handler' => $vendorDir . '/predis/predis/src/Session/Handler.php',
'Predis\\Transaction\\AbortedMultiExecException' => $vendorDir . '/predis/predis/src/Transaction/AbortedMultiExecException.php',
'Predis\\Transaction\\MultiExec' => $vendorDir . '/predis/predis/src/Transaction/MultiExec.php',
'Predis\\Transaction\\MultiExecState' => $vendorDir . '/predis/predis/src/Transaction/MultiExecState.php',
'Prophecy\\Argument' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument.php',
'Prophecy\\Argument\\ArgumentsWildcard' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/ArgumentsWildcard.php',
'Prophecy\\Argument\\Token\\AnyValueToken' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/AnyValueToken.php',
'Prophecy\\Argument\\Token\\AnyValuesToken' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/AnyValuesToken.php',
'Prophecy\\Argument\\Token\\ApproximateValueToken' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/ApproximateValueToken.php',
'Prophecy\\Argument\\Token\\ArrayCountToken' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/ArrayCountToken.php',
'Prophecy\\Argument\\Token\\ArrayEntryToken' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/ArrayEntryToken.php',
'Prophecy\\Argument\\Token\\ArrayEveryEntryToken' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/ArrayEveryEntryToken.php',
'Prophecy\\Argument\\Token\\CallbackToken' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/CallbackToken.php',
'Prophecy\\Argument\\Token\\ExactValueToken' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/ExactValueToken.php',
'Prophecy\\Argument\\Token\\IdenticalValueToken' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/IdenticalValueToken.php',
'Prophecy\\Argument\\Token\\InArrayToken' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/InArrayToken.php',
'Prophecy\\Argument\\Token\\LogicalAndToken' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/LogicalAndToken.php',
'Prophecy\\Argument\\Token\\LogicalNotToken' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/LogicalNotToken.php',
'Prophecy\\Argument\\Token\\NotInArrayToken' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/NotInArrayToken.php',
'Prophecy\\Argument\\Token\\ObjectStateToken' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/ObjectStateToken.php',
'Prophecy\\Argument\\Token\\StringContainsToken' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/StringContainsToken.php',
'Prophecy\\Argument\\Token\\TokenInterface' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/TokenInterface.php',
'Prophecy\\Argument\\Token\\TypeToken' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Argument/Token/TypeToken.php',
'Prophecy\\Call\\Call' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Call/Call.php',
'Prophecy\\Call\\CallCenter' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Call/CallCenter.php',
'Prophecy\\Comparator\\ClosureComparator' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Comparator/ClosureComparator.php',
'Prophecy\\Comparator\\Factory' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Comparator/Factory.php',
'Prophecy\\Comparator\\ProphecyComparator' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Comparator/ProphecyComparator.php',
'Prophecy\\Doubler\\CachedDoubler' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/CachedDoubler.php',
'Prophecy\\Doubler\\ClassPatch\\ClassPatchInterface' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ClassPatchInterface.php',
'Prophecy\\Doubler\\ClassPatch\\DisableConstructorPatch' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/DisableConstructorPatch.php',
'Prophecy\\Doubler\\ClassPatch\\HhvmExceptionPatch' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/HhvmExceptionPatch.php',
'Prophecy\\Doubler\\ClassPatch\\KeywordPatch' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/KeywordPatch.php',
'Prophecy\\Doubler\\ClassPatch\\MagicCallPatch' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/MagicCallPatch.php',
'Prophecy\\Doubler\\ClassPatch\\ProphecySubjectPatch' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php',
'Prophecy\\Doubler\\ClassPatch\\ReflectionClassNewInstancePatch' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ReflectionClassNewInstancePatch.php',
'Prophecy\\Doubler\\ClassPatch\\SplFileInfoPatch' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/SplFileInfoPatch.php',
'Prophecy\\Doubler\\ClassPatch\\ThrowablePatch' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ThrowablePatch.php',
'Prophecy\\Doubler\\ClassPatch\\TraversablePatch' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/TraversablePatch.php',
'Prophecy\\Doubler\\DoubleInterface' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/DoubleInterface.php',
'Prophecy\\Doubler\\Doubler' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/Doubler.php',
'Prophecy\\Doubler\\Generator\\ClassCodeGenerator' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassCodeGenerator.php',
'Prophecy\\Doubler\\Generator\\ClassCreator' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassCreator.php',
'Prophecy\\Doubler\\Generator\\ClassMirror' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassMirror.php',
'Prophecy\\Doubler\\Generator\\Node\\ArgumentNode' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ArgumentNode.php',
'Prophecy\\Doubler\\Generator\\Node\\ArgumentTypeNode' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ArgumentTypeNode.php',
'Prophecy\\Doubler\\Generator\\Node\\ClassNode' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ClassNode.php',
'Prophecy\\Doubler\\Generator\\Node\\MethodNode' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/MethodNode.php',
'Prophecy\\Doubler\\Generator\\Node\\ReturnTypeNode' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ReturnTypeNode.php',
'Prophecy\\Doubler\\Generator\\Node\\TypeNodeAbstract' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/TypeNodeAbstract.php',
'Prophecy\\Doubler\\Generator\\ReflectionInterface' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/ReflectionInterface.php',
'Prophecy\\Doubler\\Generator\\TypeHintReference' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/TypeHintReference.php',
'Prophecy\\Doubler\\LazyDouble' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/LazyDouble.php',
'Prophecy\\Doubler\\NameGenerator' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Doubler/NameGenerator.php',
'Prophecy\\Exception\\Call\\UnexpectedCallException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Call/UnexpectedCallException.php',
'Prophecy\\Exception\\Doubler\\ClassCreatorException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/ClassCreatorException.php',
'Prophecy\\Exception\\Doubler\\ClassMirrorException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/ClassMirrorException.php',
'Prophecy\\Exception\\Doubler\\ClassNotFoundException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/ClassNotFoundException.php',
'Prophecy\\Exception\\Doubler\\DoubleException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/DoubleException.php',
'Prophecy\\Exception\\Doubler\\DoublerException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/DoublerException.php',
'Prophecy\\Exception\\Doubler\\InterfaceNotFoundException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/InterfaceNotFoundException.php',
'Prophecy\\Exception\\Doubler\\MethodNotExtendableException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/MethodNotExtendableException.php',
'Prophecy\\Exception\\Doubler\\MethodNotFoundException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/MethodNotFoundException.php',
'Prophecy\\Exception\\Doubler\\ReturnByReferenceException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/ReturnByReferenceException.php',
'Prophecy\\Exception\\Exception' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Exception.php',
'Prophecy\\Exception\\InvalidArgumentException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/InvalidArgumentException.php',
'Prophecy\\Exception\\Prediction\\AggregateException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Prediction/AggregateException.php',
'Prophecy\\Exception\\Prediction\\FailedPredictionException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Prediction/FailedPredictionException.php',
'Prophecy\\Exception\\Prediction\\NoCallsException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Prediction/NoCallsException.php',
'Prophecy\\Exception\\Prediction\\PredictionException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Prediction/PredictionException.php',
'Prophecy\\Exception\\Prediction\\UnexpectedCallsCountException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Prediction/UnexpectedCallsCountException.php',
'Prophecy\\Exception\\Prediction\\UnexpectedCallsException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Prediction/UnexpectedCallsException.php',
'Prophecy\\Exception\\Prophecy\\MethodProphecyException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Prophecy/MethodProphecyException.php',
'Prophecy\\Exception\\Prophecy\\ObjectProphecyException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Prophecy/ObjectProphecyException.php',
'Prophecy\\Exception\\Prophecy\\ProphecyException' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Exception/Prophecy/ProphecyException.php',
'Prophecy\\PhpDocumentor\\ClassAndInterfaceTagRetriever' => $vendorDir . '/phpspec/prophecy/src/Prophecy/PhpDocumentor/ClassAndInterfaceTagRetriever.php',
'Prophecy\\PhpDocumentor\\ClassTagRetriever' => $vendorDir . '/phpspec/prophecy/src/Prophecy/PhpDocumentor/ClassTagRetriever.php',
'Prophecy\\PhpDocumentor\\LegacyClassTagRetriever' => $vendorDir . '/phpspec/prophecy/src/Prophecy/PhpDocumentor/LegacyClassTagRetriever.php',
'Prophecy\\PhpDocumentor\\MethodTagRetrieverInterface' => $vendorDir . '/phpspec/prophecy/src/Prophecy/PhpDocumentor/MethodTagRetrieverInterface.php',
'Prophecy\\Prediction\\CallPrediction' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Prediction/CallPrediction.php',
'Prophecy\\Prediction\\CallTimesPrediction' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Prediction/CallTimesPrediction.php',
'Prophecy\\Prediction\\CallbackPrediction' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Prediction/CallbackPrediction.php',
'Prophecy\\Prediction\\NoCallsPrediction' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Prediction/NoCallsPrediction.php',
'Prophecy\\Prediction\\PredictionInterface' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Prediction/PredictionInterface.php',
'Prophecy\\Promise\\CallbackPromise' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Promise/CallbackPromise.php',
'Prophecy\\Promise\\PromiseInterface' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Promise/PromiseInterface.php',
'Prophecy\\Promise\\ReturnArgumentPromise' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Promise/ReturnArgumentPromise.php',
'Prophecy\\Promise\\ReturnPromise' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Promise/ReturnPromise.php',
'Prophecy\\Promise\\ThrowPromise' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Promise/ThrowPromise.php',
'Prophecy\\Prophecy\\MethodProphecy' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Prophecy/MethodProphecy.php',
'Prophecy\\Prophecy\\ObjectProphecy' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Prophecy/ObjectProphecy.php',
'Prophecy\\Prophecy\\ProphecyInterface' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Prophecy/ProphecyInterface.php',
'Prophecy\\Prophecy\\ProphecySubjectInterface' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Prophecy/ProphecySubjectInterface.php',
'Prophecy\\Prophecy\\Revealer' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Prophecy/Revealer.php',
'Prophecy\\Prophecy\\RevealerInterface' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Prophecy/RevealerInterface.php',
'Prophecy\\Prophet' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Prophet.php',
'Prophecy\\Util\\ExportUtil' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Util/ExportUtil.php',
'Prophecy\\Util\\StringUtil' => $vendorDir . '/phpspec/prophecy/src/Prophecy/Util/StringUtil.php',
'Psr\\Container\\ContainerExceptionInterface' => $vendorDir . '/psr/container/src/ContainerExceptionInterface.php',
'Psr\\Container\\ContainerInterface' => $vendorDir . '/psr/container/src/ContainerInterface.php',
'Psr\\Container\\NotFoundExceptionInterface' => $vendorDir . '/psr/container/src/NotFoundExceptionInterface.php',
'Psr\\Http\\Message\\MessageInterface' => $vendorDir . '/psr/http-message/src/MessageInterface.php',
'Psr\\Http\\Message\\RequestInterface' => $vendorDir . '/psr/http-message/src/RequestInterface.php',
'Psr\\Http\\Message\\ResponseInterface' => $vendorDir . '/psr/http-message/src/ResponseInterface.php',
'Psr\\Http\\Message\\ServerRequestInterface' => $vendorDir . '/psr/http-message/src/ServerRequestInterface.php',
'Psr\\Http\\Message\\StreamInterface' => $vendorDir . '/psr/http-message/src/StreamInterface.php',
'Psr\\Http\\Message\\UploadedFileInterface' => $vendorDir . '/psr/http-message/src/UploadedFileInterface.php',
'Psr\\Http\\Message\\UriInterface' => $vendorDir . '/psr/http-message/src/UriInterface.php',
'SebastianBergmann\\CodeCoverage\\CodeCoverage' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage.php',
'SebastianBergmann\\CodeCoverage\\CoveredCodeNotExecutedException' => $vendorDir . '/phpunit/php-code-coverage/src/Exception/CoveredCodeNotExecutedException.php',
'SebastianBergmann\\CodeCoverage\\Driver\\Driver' => $vendorDir . '/phpunit/php-code-coverage/src/Driver/Driver.php',
'SebastianBergmann\\CodeCoverage\\Driver\\PCOV' => $vendorDir . '/phpunit/php-code-coverage/src/Driver/PCOV.php',
'SebastianBergmann\\CodeCoverage\\Driver\\PHPDBG' => $vendorDir . '/phpunit/php-code-coverage/src/Driver/PHPDBG.php',
'SebastianBergmann\\CodeCoverage\\Driver\\Xdebug' => $vendorDir . '/phpunit/php-code-coverage/src/Driver/Xdebug.php',
'SebastianBergmann\\CodeCoverage\\Exception' => $vendorDir . '/phpunit/php-code-coverage/src/Exception/Exception.php',
'SebastianBergmann\\CodeCoverage\\Filter' => $vendorDir . '/phpunit/php-code-coverage/src/Filter.php',
'SebastianBergmann\\CodeCoverage\\InvalidArgumentException' => $vendorDir . '/phpunit/php-code-coverage/src/Exception/InvalidArgumentException.php',
'SebastianBergmann\\CodeCoverage\\MissingCoversAnnotationException' => $vendorDir . '/phpunit/php-code-coverage/src/Exception/MissingCoversAnnotationException.php',
'SebastianBergmann\\CodeCoverage\\Node\\AbstractNode' => $vendorDir . '/phpunit/php-code-coverage/src/Node/AbstractNode.php',
'SebastianBergmann\\CodeCoverage\\Node\\Builder' => $vendorDir . '/phpunit/php-code-coverage/src/Node/Builder.php',
'SebastianBergmann\\CodeCoverage\\Node\\Directory' => $vendorDir . '/phpunit/php-code-coverage/src/Node/Directory.php',
'SebastianBergmann\\CodeCoverage\\Node\\File' => $vendorDir . '/phpunit/php-code-coverage/src/Node/File.php',
'SebastianBergmann\\CodeCoverage\\Node\\Iterator' => $vendorDir . '/phpunit/php-code-coverage/src/Node/Iterator.php',
'SebastianBergmann\\CodeCoverage\\Report\\Clover' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Clover.php',
'SebastianBergmann\\CodeCoverage\\Report\\Crap4j' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Crap4j.php',
'SebastianBergmann\\CodeCoverage\\Report\\Html\\Dashboard' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Html/Renderer/Dashboard.php',
'SebastianBergmann\\CodeCoverage\\Report\\Html\\Directory' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Html/Renderer/Directory.php',
'SebastianBergmann\\CodeCoverage\\Report\\Html\\Facade' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Html/Facade.php',
'SebastianBergmann\\CodeCoverage\\Report\\Html\\File' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Html/Renderer/File.php',
'SebastianBergmann\\CodeCoverage\\Report\\Html\\Renderer' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Html/Renderer.php',
'SebastianBergmann\\CodeCoverage\\Report\\PHP' => $vendorDir . '/phpunit/php-code-coverage/src/Report/PHP.php',
'SebastianBergmann\\CodeCoverage\\Report\\Text' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Text.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\BuildInformation' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Xml/BuildInformation.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Coverage' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Xml/Coverage.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Directory' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Xml/Directory.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Facade' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Xml/Facade.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\File' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Xml/File.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Method' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Xml/Method.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Node' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Xml/Node.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Project' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Xml/Project.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Report' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Xml/Report.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Source' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Xml/Source.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Tests' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Xml/Tests.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Totals' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Xml/Totals.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Unit' => $vendorDir . '/phpunit/php-code-coverage/src/Report/Xml/Unit.php',
'SebastianBergmann\\CodeCoverage\\RuntimeException' => $vendorDir . '/phpunit/php-code-coverage/src/Exception/RuntimeException.php',
'SebastianBergmann\\CodeCoverage\\UnintentionallyCoveredCodeException' => $vendorDir . '/phpunit/php-code-coverage/src/Exception/UnintentionallyCoveredCodeException.php',
'SebastianBergmann\\CodeCoverage\\Util' => $vendorDir . '/phpunit/php-code-coverage/src/Util.php',
'SebastianBergmann\\CodeCoverage\\Version' => $vendorDir . '/phpunit/php-code-coverage/src/Version.php',
'SebastianBergmann\\CodeUnitReverseLookup\\Wizard' => $vendorDir . '/sebastian/code-unit-reverse-lookup/src/Wizard.php',
'SebastianBergmann\\Comparator\\ArrayComparator' => $vendorDir . '/sebastian/comparator/src/ArrayComparator.php',
'SebastianBergmann\\Comparator\\Comparator' => $vendorDir . '/sebastian/comparator/src/Comparator.php',
'SebastianBergmann\\Comparator\\ComparisonFailure' => $vendorDir . '/sebastian/comparator/src/ComparisonFailure.php',
'SebastianBergmann\\Comparator\\DOMNodeComparator' => $vendorDir . '/sebastian/comparator/src/DOMNodeComparator.php',
'SebastianBergmann\\Comparator\\DateTimeComparator' => $vendorDir . '/sebastian/comparator/src/DateTimeComparator.php',
'SebastianBergmann\\Comparator\\DoubleComparator' => $vendorDir . '/sebastian/comparator/src/DoubleComparator.php',
'SebastianBergmann\\Comparator\\ExceptionComparator' => $vendorDir . '/sebastian/comparator/src/ExceptionComparator.php',
'SebastianBergmann\\Comparator\\Factory' => $vendorDir . '/sebastian/comparator/src/Factory.php',
'SebastianBergmann\\Comparator\\MockObjectComparator' => $vendorDir . '/sebastian/comparator/src/MockObjectComparator.php',
'SebastianBergmann\\Comparator\\NumericComparator' => $vendorDir . '/sebastian/comparator/src/NumericComparator.php',
'SebastianBergmann\\Comparator\\ObjectComparator' => $vendorDir . '/sebastian/comparator/src/ObjectComparator.php',
'SebastianBergmann\\Comparator\\ResourceComparator' => $vendorDir . '/sebastian/comparator/src/ResourceComparator.php',
'SebastianBergmann\\Comparator\\ScalarComparator' => $vendorDir . '/sebastian/comparator/src/ScalarComparator.php',
'SebastianBergmann\\Comparator\\SplObjectStorageComparator' => $vendorDir . '/sebastian/comparator/src/SplObjectStorageComparator.php',
'SebastianBergmann\\Comparator\\TypeComparator' => $vendorDir . '/sebastian/comparator/src/TypeComparator.php',
'SebastianBergmann\\Diff\\Chunk' => $vendorDir . '/sebastian/diff/src/Chunk.php',
'SebastianBergmann\\Diff\\ConfigurationException' => $vendorDir . '/sebastian/diff/src/Exception/ConfigurationException.php',
'SebastianBergmann\\Diff\\Diff' => $vendorDir . '/sebastian/diff/src/Diff.php',
'SebastianBergmann\\Diff\\Differ' => $vendorDir . '/sebastian/diff/src/Differ.php',
'SebastianBergmann\\Diff\\Exception' => $vendorDir . '/sebastian/diff/src/Exception/Exception.php',
'SebastianBergmann\\Diff\\InvalidArgumentException' => $vendorDir . '/sebastian/diff/src/Exception/InvalidArgumentException.php',
'SebastianBergmann\\Diff\\Line' => $vendorDir . '/sebastian/diff/src/Line.php',
'SebastianBergmann\\Diff\\LongestCommonSubsequenceCalculator' => $vendorDir . '/sebastian/diff/src/LongestCommonSubsequenceCalculator.php',
'SebastianBergmann\\Diff\\MemoryEfficientLongestCommonSubsequenceCalculator' => $vendorDir . '/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php',
'SebastianBergmann\\Diff\\Output\\AbstractChunkOutputBuilder' => $vendorDir . '/sebastian/diff/src/Output/AbstractChunkOutputBuilder.php',
'SebastianBergmann\\Diff\\Output\\DiffOnlyOutputBuilder' => $vendorDir . '/sebastian/diff/src/Output/DiffOnlyOutputBuilder.php',
'SebastianBergmann\\Diff\\Output\\DiffOutputBuilderInterface' => $vendorDir . '/sebastian/diff/src/Output/DiffOutputBuilderInterface.php',
'SebastianBergmann\\Diff\\Output\\StrictUnifiedDiffOutputBuilder' => $vendorDir . '/sebastian/diff/src/Output/StrictUnifiedDiffOutputBuilder.php',
'SebastianBergmann\\Diff\\Output\\UnifiedDiffOutputBuilder' => $vendorDir . '/sebastian/diff/src/Output/UnifiedDiffOutputBuilder.php',
'SebastianBergmann\\Diff\\Parser' => $vendorDir . '/sebastian/diff/src/Parser.php',
'SebastianBergmann\\Diff\\TimeEfficientLongestCommonSubsequenceCalculator' => $vendorDir . '/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php',
'SebastianBergmann\\Environment\\Console' => $vendorDir . '/sebastian/environment/src/Console.php',
'SebastianBergmann\\Environment\\OperatingSystem' => $vendorDir . '/sebastian/environment/src/OperatingSystem.php',
'SebastianBergmann\\Environment\\Runtime' => $vendorDir . '/sebastian/environment/src/Runtime.php',
'SebastianBergmann\\Exporter\\Exporter' => $vendorDir . '/sebastian/exporter/src/Exporter.php',
'SebastianBergmann\\FileIterator\\Facade' => $vendorDir . '/phpunit/php-file-iterator/src/Facade.php',
'SebastianBergmann\\FileIterator\\Factory' => $vendorDir . '/phpunit/php-file-iterator/src/Factory.php',
'SebastianBergmann\\FileIterator\\Iterator' => $vendorDir . '/phpunit/php-file-iterator/src/Iterator.php',
'SebastianBergmann\\GlobalState\\Blacklist' => $vendorDir . '/sebastian/global-state/src/Blacklist.php',
'SebastianBergmann\\GlobalState\\CodeExporter' => $vendorDir . '/sebastian/global-state/src/CodeExporter.php',
'SebastianBergmann\\GlobalState\\Exception' => $vendorDir . '/sebastian/global-state/src/exceptions/Exception.php',
'SebastianBergmann\\GlobalState\\Restorer' => $vendorDir . '/sebastian/global-state/src/Restorer.php',
'SebastianBergmann\\GlobalState\\RuntimeException' => $vendorDir . '/sebastian/global-state/src/exceptions/RuntimeException.php',
'SebastianBergmann\\GlobalState\\Snapshot' => $vendorDir . '/sebastian/global-state/src/Snapshot.php',
'SebastianBergmann\\ObjectEnumerator\\Enumerator' => $vendorDir . '/sebastian/object-enumerator/src/Enumerator.php',
'SebastianBergmann\\ObjectEnumerator\\Exception' => $vendorDir . '/sebastian/object-enumerator/src/Exception.php',
'SebastianBergmann\\ObjectEnumerator\\InvalidArgumentException' => $vendorDir . '/sebastian/object-enumerator/src/InvalidArgumentException.php',
'SebastianBergmann\\ObjectReflector\\Exception' => $vendorDir . '/sebastian/object-reflector/src/Exception.php',
'SebastianBergmann\\ObjectReflector\\InvalidArgumentException' => $vendorDir . '/sebastian/object-reflector/src/InvalidArgumentException.php',
'SebastianBergmann\\ObjectReflector\\ObjectReflector' => $vendorDir . '/sebastian/object-reflector/src/ObjectReflector.php',
'SebastianBergmann\\RecursionContext\\Context' => $vendorDir . '/sebastian/recursion-context/src/Context.php',
'SebastianBergmann\\RecursionContext\\Exception' => $vendorDir . '/sebastian/recursion-context/src/Exception.php',
'SebastianBergmann\\RecursionContext\\InvalidArgumentException' => $vendorDir . '/sebastian/recursion-context/src/InvalidArgumentException.php',
'SebastianBergmann\\ResourceOperations\\ResourceOperations' => $vendorDir . '/sebastian/resource-operations/src/ResourceOperations.php',
'SebastianBergmann\\Timer\\Exception' => $vendorDir . '/phpunit/php-timer/src/Exception.php',
'SebastianBergmann\\Timer\\RuntimeException' => $vendorDir . '/phpunit/php-timer/src/RuntimeException.php',
'SebastianBergmann\\Timer\\Timer' => $vendorDir . '/phpunit/php-timer/src/Timer.php',
'SebastianBergmann\\Type\\CallableType' => $vendorDir . '/sebastian/type/src/CallableType.php',
'SebastianBergmann\\Type\\Exception' => $vendorDir . '/sebastian/type/src/exception/Exception.php',
'SebastianBergmann\\Type\\GenericObjectType' => $vendorDir . '/sebastian/type/src/GenericObjectType.php',
'SebastianBergmann\\Type\\IterableType' => $vendorDir . '/sebastian/type/src/IterableType.php',
'SebastianBergmann\\Type\\NullType' => $vendorDir . '/sebastian/type/src/NullType.php',
'SebastianBergmann\\Type\\ObjectType' => $vendorDir . '/sebastian/type/src/ObjectType.php',
'SebastianBergmann\\Type\\RuntimeException' => $vendorDir . '/sebastian/type/src/exception/RuntimeException.php',
'SebastianBergmann\\Type\\SimpleType' => $vendorDir . '/sebastian/type/src/SimpleType.php',
'SebastianBergmann\\Type\\Type' => $vendorDir . '/sebastian/type/src/Type.php',
'SebastianBergmann\\Type\\TypeName' => $vendorDir . '/sebastian/type/src/TypeName.php',
'SebastianBergmann\\Type\\UnknownType' => $vendorDir . '/sebastian/type/src/UnknownType.php',
'SebastianBergmann\\Type\\VoidType' => $vendorDir . '/sebastian/type/src/VoidType.php',
'SebastianBergmann\\Version' => $vendorDir . '/sebastian/version/src/Version.php',
'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'Symfony\\Component\\BrowserKit\\AbstractBrowser' => $vendorDir . '/symfony/browser-kit/AbstractBrowser.php',
'Symfony\\Component\\BrowserKit\\Client' => $vendorDir . '/symfony/browser-kit/Client.php',
'Symfony\\Component\\BrowserKit\\Cookie' => $vendorDir . '/symfony/browser-kit/Cookie.php',
'Symfony\\Component\\BrowserKit\\CookieJar' => $vendorDir . '/symfony/browser-kit/CookieJar.php',
'Symfony\\Component\\BrowserKit\\Exception\\BadMethodCallException' => $vendorDir . '/symfony/browser-kit/Exception/BadMethodCallException.php',
'Symfony\\Component\\BrowserKit\\History' => $vendorDir . '/symfony/browser-kit/History.php',
'Symfony\\Component\\BrowserKit\\HttpBrowser' => $vendorDir . '/symfony/browser-kit/HttpBrowser.php',
'Symfony\\Component\\BrowserKit\\Request' => $vendorDir . '/symfony/browser-kit/Request.php',
'Symfony\\Component\\BrowserKit\\Response' => $vendorDir . '/symfony/browser-kit/Response.php',
'Symfony\\Component\\BrowserKit\\Test\\Constraint\\BrowserCookieValueSame' => $vendorDir . '/symfony/browser-kit/Test/Constraint/BrowserCookieValueSame.php',
'Symfony\\Component\\BrowserKit\\Test\\Constraint\\BrowserHasCookie' => $vendorDir . '/symfony/browser-kit/Test/Constraint/BrowserHasCookie.php',
'Symfony\\Component\\Console\\Application' => $vendorDir . '/symfony/console/Application.php',
'Symfony\\Component\\Console\\CommandLoader\\CommandLoaderInterface' => $vendorDir . '/symfony/console/CommandLoader/CommandLoaderInterface.php',
'Symfony\\Component\\Console\\CommandLoader\\ContainerCommandLoader' => $vendorDir . '/symfony/console/CommandLoader/ContainerCommandLoader.php',
'Symfony\\Component\\Console\\CommandLoader\\FactoryCommandLoader' => $vendorDir . '/symfony/console/CommandLoader/FactoryCommandLoader.php',
'Symfony\\Component\\Console\\Command\\Command' => $vendorDir . '/symfony/console/Command/Command.php',
'Symfony\\Component\\Console\\Command\\HelpCommand' => $vendorDir . '/symfony/console/Command/HelpCommand.php',
'Symfony\\Component\\Console\\Command\\ListCommand' => $vendorDir . '/symfony/console/Command/ListCommand.php',
'Symfony\\Component\\Console\\Command\\LockableTrait' => $vendorDir . '/symfony/console/Command/LockableTrait.php',
'Symfony\\Component\\Console\\ConsoleEvents' => $vendorDir . '/symfony/console/ConsoleEvents.php',
'Symfony\\Component\\Console\\DependencyInjection\\AddConsoleCommandPass' => $vendorDir . '/symfony/console/DependencyInjection/AddConsoleCommandPass.php',
'Symfony\\Component\\Console\\Descriptor\\ApplicationDescription' => $vendorDir . '/symfony/console/Descriptor/ApplicationDescription.php',
'Symfony\\Component\\Console\\Descriptor\\Descriptor' => $vendorDir . '/symfony/console/Descriptor/Descriptor.php',
'Symfony\\Component\\Console\\Descriptor\\DescriptorInterface' => $vendorDir . '/symfony/console/Descriptor/DescriptorInterface.php',
'Symfony\\Component\\Console\\Descriptor\\JsonDescriptor' => $vendorDir . '/symfony/console/Descriptor/JsonDescriptor.php',
'Symfony\\Component\\Console\\Descriptor\\MarkdownDescriptor' => $vendorDir . '/symfony/console/Descriptor/MarkdownDescriptor.php',
'Symfony\\Component\\Console\\Descriptor\\TextDescriptor' => $vendorDir . '/symfony/console/Descriptor/TextDescriptor.php',
'Symfony\\Component\\Console\\Descriptor\\XmlDescriptor' => $vendorDir . '/symfony/console/Descriptor/XmlDescriptor.php',
'Symfony\\Component\\Console\\EventListener\\ErrorListener' => $vendorDir . '/symfony/console/EventListener/ErrorListener.php',
'Symfony\\Component\\Console\\Event\\ConsoleCommandEvent' => $vendorDir . '/symfony/console/Event/ConsoleCommandEvent.php',
'Symfony\\Component\\Console\\Event\\ConsoleErrorEvent' => $vendorDir . '/symfony/console/Event/ConsoleErrorEvent.php',
'Symfony\\Component\\Console\\Event\\ConsoleEvent' => $vendorDir . '/symfony/console/Event/ConsoleEvent.php',
'Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent' => $vendorDir . '/symfony/console/Event/ConsoleTerminateEvent.php',
'Symfony\\Component\\Console\\Exception\\CommandNotFoundException' => $vendorDir . '/symfony/console/Exception/CommandNotFoundException.php',
'Symfony\\Component\\Console\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/console/Exception/ExceptionInterface.php',
'Symfony\\Component\\Console\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/console/Exception/InvalidArgumentException.php',
'Symfony\\Component\\Console\\Exception\\InvalidOptionException' => $vendorDir . '/symfony/console/Exception/InvalidOptionException.php',
'Symfony\\Component\\Console\\Exception\\LogicException' => $vendorDir . '/symfony/console/Exception/LogicException.php',
'Symfony\\Component\\Console\\Exception\\MissingInputException' => $vendorDir . '/symfony/console/Exception/MissingInputException.php',
'Symfony\\Component\\Console\\Exception\\NamespaceNotFoundException' => $vendorDir . '/symfony/console/Exception/NamespaceNotFoundException.php',
'Symfony\\Component\\Console\\Exception\\RuntimeException' => $vendorDir . '/symfony/console/Exception/RuntimeException.php',
'Symfony\\Component\\Console\\Formatter\\OutputFormatter' => $vendorDir . '/symfony/console/Formatter/OutputFormatter.php',
'Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface' => $vendorDir . '/symfony/console/Formatter/OutputFormatterInterface.php',
'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyle' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyle.php',
'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleInterface' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyleInterface.php',
'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleStack' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyleStack.php',
'Symfony\\Component\\Console\\Formatter\\WrappableOutputFormatterInterface' => $vendorDir . '/symfony/console/Formatter/WrappableOutputFormatterInterface.php',
'Symfony\\Component\\Console\\Helper\\DebugFormatterHelper' => $vendorDir . '/symfony/console/Helper/DebugFormatterHelper.php',
'Symfony\\Component\\Console\\Helper\\DescriptorHelper' => $vendorDir . '/symfony/console/Helper/DescriptorHelper.php',
'Symfony\\Component\\Console\\Helper\\Dumper' => $vendorDir . '/symfony/console/Helper/Dumper.php',
'Symfony\\Component\\Console\\Helper\\FormatterHelper' => $vendorDir . '/symfony/console/Helper/FormatterHelper.php',
'Symfony\\Component\\Console\\Helper\\Helper' => $vendorDir . '/symfony/console/Helper/Helper.php',
'Symfony\\Component\\Console\\Helper\\HelperInterface' => $vendorDir . '/symfony/console/Helper/HelperInterface.php',
'Symfony\\Component\\Console\\Helper\\HelperSet' => $vendorDir . '/symfony/console/Helper/HelperSet.php',
'Symfony\\Component\\Console\\Helper\\InputAwareHelper' => $vendorDir . '/symfony/console/Helper/InputAwareHelper.php',
'Symfony\\Component\\Console\\Helper\\ProcessHelper' => $vendorDir . '/symfony/console/Helper/ProcessHelper.php',
'Symfony\\Component\\Console\\Helper\\ProgressBar' => $vendorDir . '/symfony/console/Helper/ProgressBar.php',
'Symfony\\Component\\Console\\Helper\\ProgressIndicator' => $vendorDir . '/symfony/console/Helper/ProgressIndicator.php',
'Symfony\\Component\\Console\\Helper\\QuestionHelper' => $vendorDir . '/symfony/console/Helper/QuestionHelper.php',
'Symfony\\Component\\Console\\Helper\\SymfonyQuestionHelper' => $vendorDir . '/symfony/console/Helper/SymfonyQuestionHelper.php',
'Symfony\\Component\\Console\\Helper\\Table' => $vendorDir . '/symfony/console/Helper/Table.php',
'Symfony\\Component\\Console\\Helper\\TableCell' => $vendorDir . '/symfony/console/Helper/TableCell.php',
'Symfony\\Component\\Console\\Helper\\TableRows' => $vendorDir . '/symfony/console/Helper/TableRows.php',
'Symfony\\Component\\Console\\Helper\\TableSeparator' => $vendorDir . '/symfony/console/Helper/TableSeparator.php',
'Symfony\\Component\\Console\\Helper\\TableStyle' => $vendorDir . '/symfony/console/Helper/TableStyle.php',
'Symfony\\Component\\Console\\Input\\ArgvInput' => $vendorDir . '/symfony/console/Input/ArgvInput.php',
'Symfony\\Component\\Console\\Input\\ArrayInput' => $vendorDir . '/symfony/console/Input/ArrayInput.php',
'Symfony\\Component\\Console\\Input\\Input' => $vendorDir . '/symfony/console/Input/Input.php',
'Symfony\\Component\\Console\\Input\\InputArgument' => $vendorDir . '/symfony/console/Input/InputArgument.php',
'Symfony\\Component\\Console\\Input\\InputAwareInterface' => $vendorDir . '/symfony/console/Input/InputAwareInterface.php',
'Symfony\\Component\\Console\\Input\\InputDefinition' => $vendorDir . '/symfony/console/Input/InputDefinition.php',
'Symfony\\Component\\Console\\Input\\InputInterface' => $vendorDir . '/symfony/console/Input/InputInterface.php',
'Symfony\\Component\\Console\\Input\\InputOption' => $vendorDir . '/symfony/console/Input/InputOption.php',
'Symfony\\Component\\Console\\Input\\StreamableInputInterface' => $vendorDir . '/symfony/console/Input/StreamableInputInterface.php',
'Symfony\\Component\\Console\\Input\\StringInput' => $vendorDir . '/symfony/console/Input/StringInput.php',
'Symfony\\Component\\Console\\Logger\\ConsoleLogger' => $vendorDir . '/symfony/console/Logger/ConsoleLogger.php',
'Symfony\\Component\\Console\\Output\\BufferedOutput' => $vendorDir . '/symfony/console/Output/BufferedOutput.php',
'Symfony\\Component\\Console\\Output\\ConsoleOutput' => $vendorDir . '/symfony/console/Output/ConsoleOutput.php',
'Symfony\\Component\\Console\\Output\\ConsoleOutputInterface' => $vendorDir . '/symfony/console/Output/ConsoleOutputInterface.php',
'Symfony\\Component\\Console\\Output\\ConsoleSectionOutput' => $vendorDir . '/symfony/console/Output/ConsoleSectionOutput.php',
'Symfony\\Component\\Console\\Output\\NullOutput' => $vendorDir . '/symfony/console/Output/NullOutput.php',
'Symfony\\Component\\Console\\Output\\Output' => $vendorDir . '/symfony/console/Output/Output.php',
'Symfony\\Component\\Console\\Output\\OutputInterface' => $vendorDir . '/symfony/console/Output/OutputInterface.php',
'Symfony\\Component\\Console\\Output\\StreamOutput' => $vendorDir . '/symfony/console/Output/StreamOutput.php',
'Symfony\\Component\\Console\\Output\\TrimmedBufferOutput' => $vendorDir . '/symfony/console/Output/TrimmedBufferOutput.php',
'Symfony\\Component\\Console\\Question\\ChoiceQuestion' => $vendorDir . '/symfony/console/Question/ChoiceQuestion.php',
'Symfony\\Component\\Console\\Question\\ConfirmationQuestion' => $vendorDir . '/symfony/console/Question/ConfirmationQuestion.php',
'Symfony\\Component\\Console\\Question\\Question' => $vendorDir . '/symfony/console/Question/Question.php',
'Symfony\\Component\\Console\\Style\\OutputStyle' => $vendorDir . '/symfony/console/Style/OutputStyle.php',
'Symfony\\Component\\Console\\Style\\StyleInterface' => $vendorDir . '/symfony/console/Style/StyleInterface.php',
'Symfony\\Component\\Console\\Style\\SymfonyStyle' => $vendorDir . '/symfony/console/Style/SymfonyStyle.php',
'Symfony\\Component\\Console\\Terminal' => $vendorDir . '/symfony/console/Terminal.php',
'Symfony\\Component\\Console\\Tester\\ApplicationTester' => $vendorDir . '/symfony/console/Tester/ApplicationTester.php',
'Symfony\\Component\\Console\\Tester\\CommandTester' => $vendorDir . '/symfony/console/Tester/CommandTester.php',
'Symfony\\Component\\Console\\Tester\\TesterTrait' => $vendorDir . '/symfony/console/Tester/TesterTrait.php',
'Symfony\\Component\\CssSelector\\CssSelectorConverter' => $vendorDir . '/symfony/css-selector/CssSelectorConverter.php',
'Symfony\\Component\\CssSelector\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/css-selector/Exception/ExceptionInterface.php',
'Symfony\\Component\\CssSelector\\Exception\\ExpressionErrorException' => $vendorDir . '/symfony/css-selector/Exception/ExpressionErrorException.php',
'Symfony\\Component\\CssSelector\\Exception\\InternalErrorException' => $vendorDir . '/symfony/css-selector/Exception/InternalErrorException.php',
'Symfony\\Component\\CssSelector\\Exception\\ParseException' => $vendorDir . '/symfony/css-selector/Exception/ParseException.php',
'Symfony\\Component\\CssSelector\\Exception\\SyntaxErrorException' => $vendorDir . '/symfony/css-selector/Exception/SyntaxErrorException.php',
'Symfony\\Component\\CssSelector\\Node\\AbstractNode' => $vendorDir . '/symfony/css-selector/Node/AbstractNode.php',
'Symfony\\Component\\CssSelector\\Node\\AttributeNode' => $vendorDir . '/symfony/css-selector/Node/AttributeNode.php',
'Symfony\\Component\\CssSelector\\Node\\ClassNode' => $vendorDir . '/symfony/css-selector/Node/ClassNode.php',
'Symfony\\Component\\CssSelector\\Node\\CombinedSelectorNode' => $vendorDir . '/symfony/css-selector/Node/CombinedSelectorNode.php',
'Symfony\\Component\\CssSelector\\Node\\ElementNode' => $vendorDir . '/symfony/css-selector/Node/ElementNode.php',
'Symfony\\Component\\CssSelector\\Node\\FunctionNode' => $vendorDir . '/symfony/css-selector/Node/FunctionNode.php',
'Symfony\\Component\\CssSelector\\Node\\HashNode' => $vendorDir . '/symfony/css-selector/Node/HashNode.php',
'Symfony\\Component\\CssSelector\\Node\\NegationNode' => $vendorDir . '/symfony/css-selector/Node/NegationNode.php',
'Symfony\\Component\\CssSelector\\Node\\NodeInterface' => $vendorDir . '/symfony/css-selector/Node/NodeInterface.php',
'Symfony\\Component\\CssSelector\\Node\\PseudoNode' => $vendorDir . '/symfony/css-selector/Node/PseudoNode.php',
'Symfony\\Component\\CssSelector\\Node\\SelectorNode' => $vendorDir . '/symfony/css-selector/Node/SelectorNode.php',
'Symfony\\Component\\CssSelector\\Node\\Specificity' => $vendorDir . '/symfony/css-selector/Node/Specificity.php',
'Symfony\\Component\\CssSelector\\Parser\\Handler\\CommentHandler' => $vendorDir . '/symfony/css-selector/Parser/Handler/CommentHandler.php',
'Symfony\\Component\\CssSelector\\Parser\\Handler\\HandlerInterface' => $vendorDir . '/symfony/css-selector/Parser/Handler/HandlerInterface.php',
'Symfony\\Component\\CssSelector\\Parser\\Handler\\HashHandler' => $vendorDir . '/symfony/css-selector/Parser/Handler/HashHandler.php',
'Symfony\\Component\\CssSelector\\Parser\\Handler\\IdentifierHandler' => $vendorDir . '/symfony/css-selector/Parser/Handler/IdentifierHandler.php',
'Symfony\\Component\\CssSelector\\Parser\\Handler\\NumberHandler' => $vendorDir . '/symfony/css-selector/Parser/Handler/NumberHandler.php',
'Symfony\\Component\\CssSelector\\Parser\\Handler\\StringHandler' => $vendorDir . '/symfony/css-selector/Parser/Handler/StringHandler.php',
'Symfony\\Component\\CssSelector\\Parser\\Handler\\WhitespaceHandler' => $vendorDir . '/symfony/css-selector/Parser/Handler/WhitespaceHandler.php',
'Symfony\\Component\\CssSelector\\Parser\\Parser' => $vendorDir . '/symfony/css-selector/Parser/Parser.php',
'Symfony\\Component\\CssSelector\\Parser\\ParserInterface' => $vendorDir . '/symfony/css-selector/Parser/ParserInterface.php',
'Symfony\\Component\\CssSelector\\Parser\\Reader' => $vendorDir . '/symfony/css-selector/Parser/Reader.php',
'Symfony\\Component\\CssSelector\\Parser\\Shortcut\\ClassParser' => $vendorDir . '/symfony/css-selector/Parser/Shortcut/ClassParser.php',
'Symfony\\Component\\CssSelector\\Parser\\Shortcut\\ElementParser' => $vendorDir . '/symfony/css-selector/Parser/Shortcut/ElementParser.php',
'Symfony\\Component\\CssSelector\\Parser\\Shortcut\\EmptyStringParser' => $vendorDir . '/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php',
'Symfony\\Component\\CssSelector\\Parser\\Shortcut\\HashParser' => $vendorDir . '/symfony/css-selector/Parser/Shortcut/HashParser.php',
'Symfony\\Component\\CssSelector\\Parser\\Token' => $vendorDir . '/symfony/css-selector/Parser/Token.php',
'Symfony\\Component\\CssSelector\\Parser\\TokenStream' => $vendorDir . '/symfony/css-selector/Parser/TokenStream.php',
'Symfony\\Component\\CssSelector\\Parser\\Tokenizer\\Tokenizer' => $vendorDir . '/symfony/css-selector/Parser/Tokenizer/Tokenizer.php',
'Symfony\\Component\\CssSelector\\Parser\\Tokenizer\\TokenizerEscaping' => $vendorDir . '/symfony/css-selector/Parser/Tokenizer/TokenizerEscaping.php',
'Symfony\\Component\\CssSelector\\Parser\\Tokenizer\\TokenizerPatterns' => $vendorDir . '/symfony/css-selector/Parser/Tokenizer/TokenizerPatterns.php',
'Symfony\\Component\\CssSelector\\XPath\\Extension\\AbstractExtension' => $vendorDir . '/symfony/css-selector/XPath/Extension/AbstractExtension.php',
'Symfony\\Component\\CssSelector\\XPath\\Extension\\AttributeMatchingExtension' => $vendorDir . '/symfony/css-selector/XPath/Extension/AttributeMatchingExtension.php',
'Symfony\\Component\\CssSelector\\XPath\\Extension\\CombinationExtension' => $vendorDir . '/symfony/css-selector/XPath/Extension/CombinationExtension.php',
'Symfony\\Component\\CssSelector\\XPath\\Extension\\ExtensionInterface' => $vendorDir . '/symfony/css-selector/XPath/Extension/ExtensionInterface.php',
'Symfony\\Component\\CssSelector\\XPath\\Extension\\FunctionExtension' => $vendorDir . '/symfony/css-selector/XPath/Extension/FunctionExtension.php',
'Symfony\\Component\\CssSelector\\XPath\\Extension\\HtmlExtension' => $vendorDir . '/symfony/css-selector/XPath/Extension/HtmlExtension.php',
'Symfony\\Component\\CssSelector\\XPath\\Extension\\NodeExtension' => $vendorDir . '/symfony/css-selector/XPath/Extension/NodeExtension.php',
'Symfony\\Component\\CssSelector\\XPath\\Extension\\PseudoClassExtension' => $vendorDir . '/symfony/css-selector/XPath/Extension/PseudoClassExtension.php',
'Symfony\\Component\\CssSelector\\XPath\\Translator' => $vendorDir . '/symfony/css-selector/XPath/Translator.php',
'Symfony\\Component\\CssSelector\\XPath\\TranslatorInterface' => $vendorDir . '/symfony/css-selector/XPath/TranslatorInterface.php',
'Symfony\\Component\\CssSelector\\XPath\\XPathExpr' => $vendorDir . '/symfony/css-selector/XPath/XPathExpr.php',
'Symfony\\Component\\DomCrawler\\AbstractUriElement' => $vendorDir . '/symfony/dom-crawler/AbstractUriElement.php',
'Symfony\\Component\\DomCrawler\\Crawler' => $vendorDir . '/symfony/dom-crawler/Crawler.php',
'Symfony\\Component\\DomCrawler\\Field\\ChoiceFormField' => $vendorDir . '/symfony/dom-crawler/Field/ChoiceFormField.php',
'Symfony\\Component\\DomCrawler\\Field\\FileFormField' => $vendorDir . '/symfony/dom-crawler/Field/FileFormField.php',
'Symfony\\Component\\DomCrawler\\Field\\FormField' => $vendorDir . '/symfony/dom-crawler/Field/FormField.php',
'Symfony\\Component\\DomCrawler\\Field\\InputFormField' => $vendorDir . '/symfony/dom-crawler/Field/InputFormField.php',
'Symfony\\Component\\DomCrawler\\Field\\TextareaFormField' => $vendorDir . '/symfony/dom-crawler/Field/TextareaFormField.php',
'Symfony\\Component\\DomCrawler\\Form' => $vendorDir . '/symfony/dom-crawler/Form.php',
'Symfony\\Component\\DomCrawler\\FormFieldRegistry' => $vendorDir . '/symfony/dom-crawler/FormFieldRegistry.php',
'Symfony\\Component\\DomCrawler\\Image' => $vendorDir . '/symfony/dom-crawler/Image.php',
'Symfony\\Component\\DomCrawler\\Link' => $vendorDir . '/symfony/dom-crawler/Link.php',
'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorAttributeValueSame' => $vendorDir . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php',
'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorExists' => $vendorDir . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorExists.php',
'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorTextContains' => $vendorDir . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextContains.php',
'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorTextSame' => $vendorDir . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextSame.php',
'Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher' => $vendorDir . '/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php',
'Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcherInterface' => $vendorDir . '/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php',
'Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener' => $vendorDir . '/symfony/event-dispatcher/Debug/WrappedListener.php',
'Symfony\\Component\\EventDispatcher\\DependencyInjection\\AddEventAliasesPass' => $vendorDir . '/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php',
'Symfony\\Component\\EventDispatcher\\DependencyInjection\\RegisterListenersPass' => $vendorDir . '/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php',
'Symfony\\Component\\EventDispatcher\\Event' => $vendorDir . '/symfony/event-dispatcher/Event.php',
'Symfony\\Component\\EventDispatcher\\EventDispatcher' => $vendorDir . '/symfony/event-dispatcher/EventDispatcher.php',
'Symfony\\Component\\EventDispatcher\\EventDispatcherInterface' => $vendorDir . '/symfony/event-dispatcher/EventDispatcherInterface.php',
'Symfony\\Component\\EventDispatcher\\EventSubscriberInterface' => $vendorDir . '/symfony/event-dispatcher/EventSubscriberInterface.php',
'Symfony\\Component\\EventDispatcher\\GenericEvent' => $vendorDir . '/symfony/event-dispatcher/GenericEvent.php',
'Symfony\\Component\\EventDispatcher\\ImmutableEventDispatcher' => $vendorDir . '/symfony/event-dispatcher/ImmutableEventDispatcher.php',
'Symfony\\Component\\EventDispatcher\\LegacyEventDispatcherProxy' => $vendorDir . '/symfony/event-dispatcher/LegacyEventDispatcherProxy.php',
'Symfony\\Component\\EventDispatcher\\LegacyEventProxy' => $vendorDir . '/symfony/event-dispatcher/LegacyEventProxy.php',
'Symfony\\Component\\Finder\\Comparator\\Comparator' => $vendorDir . '/symfony/finder/Comparator/Comparator.php',
'Symfony\\Component\\Finder\\Comparator\\DateComparator' => $vendorDir . '/symfony/finder/Comparator/DateComparator.php',
'Symfony\\Component\\Finder\\Comparator\\NumberComparator' => $vendorDir . '/symfony/finder/Comparator/NumberComparator.php',
'Symfony\\Component\\Finder\\Exception\\AccessDeniedException' => $vendorDir . '/symfony/finder/Exception/AccessDeniedException.php',
'Symfony\\Component\\Finder\\Exception\\DirectoryNotFoundException' => $vendorDir . '/symfony/finder/Exception/DirectoryNotFoundException.php',
'Symfony\\Component\\Finder\\Finder' => $vendorDir . '/symfony/finder/Finder.php',
'Symfony\\Component\\Finder\\Gitignore' => $vendorDir . '/symfony/finder/Gitignore.php',
'Symfony\\Component\\Finder\\Glob' => $vendorDir . '/symfony/finder/Glob.php',
'Symfony\\Component\\Finder\\Iterator\\CustomFilterIterator' => $vendorDir . '/symfony/finder/Iterator/CustomFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\DateRangeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/DateRangeFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\DepthRangeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/DepthRangeFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\ExcludeDirectoryFilterIterator' => $vendorDir . '/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\FileTypeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/FileTypeFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\FilecontentFilterIterator' => $vendorDir . '/symfony/finder/Iterator/FilecontentFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\FilenameFilterIterator' => $vendorDir . '/symfony/finder/Iterator/FilenameFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\LazyIterator' => $vendorDir . '/symfony/finder/Iterator/LazyIterator.php',
'Symfony\\Component\\Finder\\Iterator\\MultiplePcreFilterIterator' => $vendorDir . '/symfony/finder/Iterator/MultiplePcreFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\PathFilterIterator' => $vendorDir . '/symfony/finder/Iterator/PathFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\RecursiveDirectoryIterator' => $vendorDir . '/symfony/finder/Iterator/RecursiveDirectoryIterator.php',
'Symfony\\Component\\Finder\\Iterator\\SizeRangeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/SizeRangeFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\SortableIterator' => $vendorDir . '/symfony/finder/Iterator/SortableIterator.php',
'Symfony\\Component\\Finder\\SplFileInfo' => $vendorDir . '/symfony/finder/SplFileInfo.php',
'Symfony\\Component\\Process\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/process/Exception/ExceptionInterface.php',
'Symfony\\Component\\Process\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/process/Exception/InvalidArgumentException.php',
'Symfony\\Component\\Process\\Exception\\LogicException' => $vendorDir . '/symfony/process/Exception/LogicException.php',
'Symfony\\Component\\Process\\Exception\\ProcessFailedException' => $vendorDir . '/symfony/process/Exception/ProcessFailedException.php',
'Symfony\\Component\\Process\\Exception\\ProcessSignaledException' => $vendorDir . '/symfony/process/Exception/ProcessSignaledException.php',
'Symfony\\Component\\Process\\Exception\\ProcessTimedOutException' => $vendorDir . '/symfony/process/Exception/ProcessTimedOutException.php',
'Symfony\\Component\\Process\\Exception\\RuntimeException' => $vendorDir . '/symfony/process/Exception/RuntimeException.php',
'Symfony\\Component\\Process\\ExecutableFinder' => $vendorDir . '/symfony/process/ExecutableFinder.php',
'Symfony\\Component\\Process\\InputStream' => $vendorDir . '/symfony/process/InputStream.php',
'Symfony\\Component\\Process\\PhpExecutableFinder' => $vendorDir . '/symfony/process/PhpExecutableFinder.php',
'Symfony\\Component\\Process\\PhpProcess' => $vendorDir . '/symfony/process/PhpProcess.php',
'Symfony\\Component\\Process\\Pipes\\AbstractPipes' => $vendorDir . '/symfony/process/Pipes/AbstractPipes.php',
'Symfony\\Component\\Process\\Pipes\\PipesInterface' => $vendorDir . '/symfony/process/Pipes/PipesInterface.php',
'Symfony\\Component\\Process\\Pipes\\UnixPipes' => $vendorDir . '/symfony/process/Pipes/UnixPipes.php',
'Symfony\\Component\\Process\\Pipes\\WindowsPipes' => $vendorDir . '/symfony/process/Pipes/WindowsPipes.php',
'Symfony\\Component\\Process\\Process' => $vendorDir . '/symfony/process/Process.php',
'Symfony\\Component\\Process\\ProcessUtils' => $vendorDir . '/symfony/process/ProcessUtils.php',
'Symfony\\Component\\Yaml\\Command\\LintCommand' => $vendorDir . '/symfony/yaml/Command/LintCommand.php',
'Symfony\\Component\\Yaml\\Dumper' => $vendorDir . '/symfony/yaml/Dumper.php',
'Symfony\\Component\\Yaml\\Escaper' => $vendorDir . '/symfony/yaml/Escaper.php',
'Symfony\\Component\\Yaml\\Exception\\DumpException' => $vendorDir . '/symfony/yaml/Exception/DumpException.php',
'Symfony\\Component\\Yaml\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/yaml/Exception/ExceptionInterface.php',
'Symfony\\Component\\Yaml\\Exception\\ParseException' => $vendorDir . '/symfony/yaml/Exception/ParseException.php',
'Symfony\\Component\\Yaml\\Exception\\RuntimeException' => $vendorDir . '/symfony/yaml/Exception/RuntimeException.php',
'Symfony\\Component\\Yaml\\Inline' => $vendorDir . '/symfony/yaml/Inline.php',
'Symfony\\Component\\Yaml\\Parser' => $vendorDir . '/symfony/yaml/Parser.php',
'Symfony\\Component\\Yaml\\Tag\\TaggedValue' => $vendorDir . '/symfony/yaml/Tag/TaggedValue.php',
'Symfony\\Component\\Yaml\\Unescaper' => $vendorDir . '/symfony/yaml/Unescaper.php',
'Symfony\\Component\\Yaml\\Yaml' => $vendorDir . '/symfony/yaml/Yaml.php',
'Symfony\\Contracts\\EventDispatcher\\Event' => $vendorDir . '/symfony/event-dispatcher-contracts/Event.php',
'Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface' => $vendorDir . '/symfony/event-dispatcher-contracts/EventDispatcherInterface.php',
'Symfony\\Contracts\\Service\\ResetInterface' => $vendorDir . '/symfony/service-contracts/ResetInterface.php',
'Symfony\\Contracts\\Service\\ServiceLocatorTrait' => $vendorDir . '/symfony/service-contracts/ServiceLocatorTrait.php',
'Symfony\\Contracts\\Service\\ServiceProviderInterface' => $vendorDir . '/symfony/service-contracts/ServiceProviderInterface.php',
'Symfony\\Contracts\\Service\\ServiceSubscriberInterface' => $vendorDir . '/symfony/service-contracts/ServiceSubscriberInterface.php',
'Symfony\\Contracts\\Service\\ServiceSubscriberTrait' => $vendorDir . '/symfony/service-contracts/ServiceSubscriberTrait.php',
'Symfony\\Contracts\\Service\\Test\\ServiceLocatorTest' => $vendorDir . '/symfony/service-contracts/Test/ServiceLocatorTest.php',
'Symfony\\Polyfill\\Ctype\\Ctype' => $vendorDir . '/symfony/polyfill-ctype/Ctype.php',
'Symfony\\Polyfill\\Intl\\Idn\\Idn' => $vendorDir . '/symfony/polyfill-intl-idn/Idn.php',
'Symfony\\Polyfill\\Intl\\Idn\\Info' => $vendorDir . '/symfony/polyfill-intl-idn/Info.php',
'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\DisallowedRanges' => $vendorDir . '/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php',
'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\Regex' => $vendorDir . '/symfony/polyfill-intl-idn/Resources/unidata/Regex.php',
'Symfony\\Polyfill\\Intl\\Normalizer\\Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Normalizer.php',
'Symfony\\Polyfill\\Mbstring\\Mbstring' => $vendorDir . '/symfony/polyfill-mbstring/Mbstring.php',
'Symfony\\Polyfill\\Php72\\Php72' => $vendorDir . '/symfony/polyfill-php72/Php72.php',
'Symfony\\Polyfill\\Php73\\Php73' => $vendorDir . '/symfony/polyfill-php73/Php73.php',
'Symfony\\Polyfill\\Php80\\Php80' => $vendorDir . '/symfony/polyfill-php80/Php80.php',
'Text_Template' => $vendorDir . '/phpunit/php-text-template/src/Template.php',
'TheSeer\\Tokenizer\\Exception' => $vendorDir . '/theseer/tokenizer/src/Exception.php',
'TheSeer\\Tokenizer\\NamespaceUri' => $vendorDir . '/theseer/tokenizer/src/NamespaceUri.php',
'TheSeer\\Tokenizer\\NamespaceUriException' => $vendorDir . '/theseer/tokenizer/src/NamespaceUriException.php',
'TheSeer\\Tokenizer\\Token' => $vendorDir . '/theseer/tokenizer/src/Token.php',
'TheSeer\\Tokenizer\\TokenCollection' => $vendorDir . '/theseer/tokenizer/src/TokenCollection.php',
'TheSeer\\Tokenizer\\TokenCollectionException' => $vendorDir . '/theseer/tokenizer/src/TokenCollectionException.php',
'TheSeer\\Tokenizer\\Tokenizer' => $vendorDir . '/theseer/tokenizer/src/Tokenizer.php',
'TheSeer\\Tokenizer\\XMLSerializer' => $vendorDir . '/theseer/tokenizer/src/XMLSerializer.php',
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
'Webmozart\\Assert\\Assert' => $vendorDir . '/webmozart/assert/src/Assert.php',
'Webmozart\\Assert\\InvalidArgumentException' => $vendorDir . '/webmozart/assert/src/InvalidArgumentException.php',
'Webmozart\\Assert\\Mixin' => $vendorDir . '/webmozart/assert/src/Mixin.php',
'phpDocumentor\\Reflection\\DocBlock' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock.php',
'phpDocumentor\\Reflection\\DocBlockFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlockFactory.php',
'phpDocumentor\\Reflection\\DocBlockFactoryInterface' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlockFactoryInterface.php',
'phpDocumentor\\Reflection\\DocBlock\\Description' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Description.php',
'phpDocumentor\\Reflection\\DocBlock\\DescriptionFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/DescriptionFactory.php',
'phpDocumentor\\Reflection\\DocBlock\\ExampleFinder' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/ExampleFinder.php',
'phpDocumentor\\Reflection\\DocBlock\\Serializer' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Serializer.php',
'phpDocumentor\\Reflection\\DocBlock\\StandardTagFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/StandardTagFactory.php',
'phpDocumentor\\Reflection\\DocBlock\\Tag' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tag.php',
'phpDocumentor\\Reflection\\DocBlock\\TagFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/TagFactory.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Author' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Author.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\BaseTag' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/BaseTag.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Covers' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Covers.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Deprecated' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Deprecated.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Example' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Example.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\StaticMethod' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/StaticMethod.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter\\AlignFormatter' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/AlignFormatter.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter\\PassthroughFormatter' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/PassthroughFormatter.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Generic' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Generic.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\InvalidTag' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/InvalidTag.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Link' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Link.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Method' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Method.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Param' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Param.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Property' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Property.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\PropertyRead' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyRead.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\PropertyWrite' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyWrite.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Fqsen' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Fqsen.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Reference' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Reference.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Url' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Url.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Return_' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Return_.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\See' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/See.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Since' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Since.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Source' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Source.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\TagWithType' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TagWithType.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Throws' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Throws.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Uses' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Uses.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Var_' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Var_.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Version' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Version.php',
'phpDocumentor\\Reflection\\Element' => $vendorDir . '/phpdocumentor/reflection-common/src/Element.php',
'phpDocumentor\\Reflection\\Exception\\PcreException' => $vendorDir . '/phpdocumentor/reflection-docblock/src/Exception/PcreException.php',
'phpDocumentor\\Reflection\\File' => $vendorDir . '/phpdocumentor/reflection-common/src/File.php',
'phpDocumentor\\Reflection\\Fqsen' => $vendorDir . '/phpdocumentor/reflection-common/src/Fqsen.php',
'phpDocumentor\\Reflection\\FqsenResolver' => $vendorDir . '/phpdocumentor/type-resolver/src/FqsenResolver.php',
'phpDocumentor\\Reflection\\Location' => $vendorDir . '/phpdocumentor/reflection-common/src/Location.php',
'phpDocumentor\\Reflection\\Project' => $vendorDir . '/phpdocumentor/reflection-common/src/Project.php',
'phpDocumentor\\Reflection\\ProjectFactory' => $vendorDir . '/phpdocumentor/reflection-common/src/ProjectFactory.php',
'phpDocumentor\\Reflection\\PseudoType' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoType.php',
'phpDocumentor\\Reflection\\PseudoTypes\\CallableString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/CallableString.php',
'phpDocumentor\\Reflection\\PseudoTypes\\False_' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/False_.php',
'phpDocumentor\\Reflection\\PseudoTypes\\HtmlEscapedString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/HtmlEscapedString.php',
'phpDocumentor\\Reflection\\PseudoTypes\\LiteralString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/LiteralString.php',
'phpDocumentor\\Reflection\\PseudoTypes\\LowercaseString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/LowercaseString.php',
'phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyLowercaseString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyLowercaseString.php',
'phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyString.php',
'phpDocumentor\\Reflection\\PseudoTypes\\NumericString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/NumericString.php',
'phpDocumentor\\Reflection\\PseudoTypes\\PositiveInteger' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.php',
'phpDocumentor\\Reflection\\PseudoTypes\\TraitString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/TraitString.php',
'phpDocumentor\\Reflection\\PseudoTypes\\True_' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/True_.php',
'phpDocumentor\\Reflection\\Type' => $vendorDir . '/phpdocumentor/type-resolver/src/Type.php',
'phpDocumentor\\Reflection\\TypeResolver' => $vendorDir . '/phpdocumentor/type-resolver/src/TypeResolver.php',
'phpDocumentor\\Reflection\\Types\\AbstractList' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/AbstractList.php',
'phpDocumentor\\Reflection\\Types\\AggregatedType' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/AggregatedType.php',
'phpDocumentor\\Reflection\\Types\\ArrayKey' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/ArrayKey.php',
'phpDocumentor\\Reflection\\Types\\Array_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Array_.php',
'phpDocumentor\\Reflection\\Types\\Boolean' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Boolean.php',
'phpDocumentor\\Reflection\\Types\\Callable_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Callable_.php',
'phpDocumentor\\Reflection\\Types\\ClassString' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/ClassString.php',
'phpDocumentor\\Reflection\\Types\\Collection' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Collection.php',
'phpDocumentor\\Reflection\\Types\\Compound' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Compound.php',
'phpDocumentor\\Reflection\\Types\\Context' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Context.php',
'phpDocumentor\\Reflection\\Types\\ContextFactory' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/ContextFactory.php',
'phpDocumentor\\Reflection\\Types\\Expression' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Expression.php',
'phpDocumentor\\Reflection\\Types\\Float_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Float_.php',
'phpDocumentor\\Reflection\\Types\\Integer' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Integer.php',
'phpDocumentor\\Reflection\\Types\\InterfaceString' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/InterfaceString.php',
'phpDocumentor\\Reflection\\Types\\Intersection' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Intersection.php',
'phpDocumentor\\Reflection\\Types\\Iterable_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Iterable_.php',
'phpDocumentor\\Reflection\\Types\\Mixed_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Mixed_.php',
'phpDocumentor\\Reflection\\Types\\Never_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Never_.php',
'phpDocumentor\\Reflection\\Types\\Null_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Null_.php',
'phpDocumentor\\Reflection\\Types\\Nullable' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Nullable.php',
'phpDocumentor\\Reflection\\Types\\Object_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Object_.php',
'phpDocumentor\\Reflection\\Types\\Parent_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Parent_.php',
'phpDocumentor\\Reflection\\Types\\Resource_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Resource_.php',
'phpDocumentor\\Reflection\\Types\\Scalar' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Scalar.php',
'phpDocumentor\\Reflection\\Types\\Self_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Self_.php',
'phpDocumentor\\Reflection\\Types\\Static_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Static_.php',
'phpDocumentor\\Reflection\\Types\\String_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/String_.php',
'phpDocumentor\\Reflection\\Types\\This' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/This.php',
'phpDocumentor\\Reflection\\Types\\Void_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Void_.php',
'phpDocumentor\\Reflection\\Utils' => $vendorDir . '/phpdocumentor/reflection-docblock/src/Utils.php',
'phpseclib\\Crypt\\AES' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/AES.php',
'phpseclib\\Crypt\\Base' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Base.php',
'phpseclib\\Crypt\\Blowfish' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php',
'phpseclib\\Crypt\\DES' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/DES.php',
'phpseclib\\Crypt\\Hash' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Hash.php',
'phpseclib\\Crypt\\RC2' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/RC2.php',
'phpseclib\\Crypt\\RC4' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/RC4.php',
'phpseclib\\Crypt\\RSA' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/RSA.php',
'phpseclib\\Crypt\\Random' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Random.php',
'phpseclib\\Crypt\\Rijndael' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php',
'phpseclib\\Crypt\\TripleDES' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php',
'phpseclib\\Crypt\\Twofish' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php',
'phpseclib\\File\\ANSI' => $vendorDir . '/phpseclib/phpseclib/phpseclib/File/ANSI.php',
'phpseclib\\File\\ASN1' => $vendorDir . '/phpseclib/phpseclib/phpseclib/File/ASN1.php',
'phpseclib\\File\\ASN1\\Element' => $vendorDir . '/phpseclib/phpseclib/phpseclib/File/ASN1/Element.php',
'phpseclib\\File\\X509' => $vendorDir . '/phpseclib/phpseclib/phpseclib/File/X509.php',
'phpseclib\\Math\\BigInteger' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Math/BigInteger.php',
'phpseclib\\Net\\SCP' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SCP.php',
'phpseclib\\Net\\SFTP' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SFTP.php',
'phpseclib\\Net\\SFTP\\Stream' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php',
'phpseclib\\Net\\SSH1' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SSH1.php',
'phpseclib\\Net\\SSH2' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SSH2.php',
'phpseclib\\System\\SSH\\Agent' => $vendorDir . '/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php',
'phpseclib\\System\\SSH\\Agent\\Identity' => $vendorDir . '/phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.php',
);
<?php











namespace Composer\Autoload;





























class ClassLoader
{
private $vendorDir;


 private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();


 private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();

private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
private $apcuPrefix;

private static $registeredLoaders = array();

public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
}

public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}

return array();
}

public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}

public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}

public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}

public function getClassMap()
{
return $this->classMap;
}




public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}









public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}

return;
}

$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;

return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}











public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {

 if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {

 $length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {

 $this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {

 $this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}








public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}










public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}






public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}







public function getUseIncludePath()
{
return $this->useIncludePath;
}







public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}






public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}






public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}






public function getApcuPrefix()
{
return $this->apcuPrefix;
}






public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);

if (null === $this->vendorDir) {
return;
}

if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}




public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));

if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}







public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);

return true;
}

return null;
}








public function findFile($class)
{

 if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}

$file = $this->findFileWithExtension($class, '.php');


 if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}

if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}

if (false === $file) {

 $this->missingClasses[$class] = true;
}

return $file;
}






public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}

private function findFileWithExtension($class, $ext)
{

 $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}


 foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}


 if (false !== $pos = strrpos($class, '\\')) {

 $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {

 $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}

if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}


 foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}


 if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}

return false;
}
}






function includeFile($file)
{
include $file;
}
<?php



namespace Composer\Autoload;

class ComposerStaticInit8d2576a0103fe25d0268c6cba2a989ff
{
public static $files = array (
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'e88992873b7765f9b5710cab95ba5dd7' => __DIR__ . '/..' . '/hoa/consistency/Prelude.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
'e3b2795a8a512b6083af088fb53afe6c' => __DIR__ . '/..' . '/codeception/codeception/functions.php',
'3e76f7f02b41af8cea96018933f6b7e3' => __DIR__ . '/..' . '/hoa/protocol/Wrapper.php',
'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php',
'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
'6124b4c8570aa390c21fafd04a26c69f' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/deep_copy.php',
'd9d39f82a605ebe5918f683dd402334c' => __DIR__ . '/..' . '/padraic/humbug_get_contents/src/function.php',
'3a50d90d85c7fe889a94ae1114b921ce' => __DIR__ . '/..' . '/padraic/humbug_get_contents/src/functions.php',
'2a3c2110e8e0295330dc3d11a4cbc4cb' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/TimeoutException.php',
);

public static $prefixLengthsPsr4 = array (
'p' => 
array (
'phpseclib\\' => 10,
'phpDocumentor\\Reflection\\' => 25,
),
'W' => 
array (
'Webmozart\\Assert\\' => 17,
),
'S' => 
array (
'Symfony\\Polyfill\\Php80\\' => 23,
'Symfony\\Polyfill\\Php73\\' => 23,
'Symfony\\Polyfill\\Php72\\' => 23,
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33,
'Symfony\\Polyfill\\Intl\\Idn\\' => 26,
'Symfony\\Polyfill\\Ctype\\' => 23,
'Symfony\\Contracts\\Service\\' => 26,
'Symfony\\Contracts\\EventDispatcher\\' => 34,
'Symfony\\Component\\Yaml\\' => 23,
'Symfony\\Component\\Process\\' => 26,
'Symfony\\Component\\Finder\\' => 25,
'Symfony\\Component\\EventDispatcher\\' => 34,
'Symfony\\Component\\DomCrawler\\' => 29,
'Symfony\\Component\\CssSelector\\' => 30,
'Symfony\\Component\\Console\\' => 26,
'Symfony\\Component\\BrowserKit\\' => 29,
),
'P' => 
array (
'Psr\\Http\\Message\\' => 17,
'Psr\\Container\\' => 14,
'Prophecy\\' => 9,
'Predis\\' => 7,
'PhpAmqpLib\\' => 11,
),
'J' => 
array (
'JsonSchema\\' => 11,
),
'H' => 
array (
'Humbug\\SelfUpdate\\' => 18,
'Humbug\\' => 7,
'Hoa\\Ustring\\' => 12,
'Hoa\\Stream\\' => 11,
'Hoa\\Protocol\\' => 13,
'Hoa\\Iterator\\' => 13,
'Hoa\\File\\' => 9,
'Hoa\\Exception\\' => 14,
'Hoa\\Event\\' => 10,
'Hoa\\Console\\' => 12,
'Hoa\\Consistency\\' => 16,
),
'G' => 
array (
'GuzzleHttp\\Psr7\\' => 16,
'GuzzleHttp\\Promise\\' => 19,
'GuzzleHttp\\' => 11,
),
'F' => 
array (
'Flow\\JSONPath\\' => 14,
'Facebook\\WebDriver\\' => 19,
),
'D' => 
array (
'Doctrine\\Instantiator\\' => 22,
'DeepCopy\\' => 9,
),
'C' => 
array (
'Composer\\CaBundle\\' => 18,
'Codeception\\PHPUnit\\' => 20,
'Codeception\\Extension\\' => 22,
'Codeception\\' => 12,
),
);

public static $prefixDirsPsr4 = array (
'phpseclib\\' => 
array (
0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib',
),
'phpDocumentor\\Reflection\\' => 
array (
0 => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src',
1 => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src',
2 => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src',
),
'Webmozart\\Assert\\' => 
array (
0 => __DIR__ . '/..' . '/webmozart/assert/src',
),
'Symfony\\Polyfill\\Php80\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
),
'Symfony\\Polyfill\\Php73\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php73',
),
'Symfony\\Polyfill\\Php72\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php72',
),
'Symfony\\Polyfill\\Mbstring\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
),
'Symfony\\Polyfill\\Intl\\Normalizer\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer',
),
'Symfony\\Polyfill\\Intl\\Idn\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn',
),
'Symfony\\Polyfill\\Ctype\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
),
'Symfony\\Contracts\\Service\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/service-contracts',
),
'Symfony\\Contracts\\EventDispatcher\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/event-dispatcher-contracts',
),
'Symfony\\Component\\Yaml\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/yaml',
),
'Symfony\\Component\\Process\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/process',
),
'Symfony\\Component\\Finder\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/finder',
),
'Symfony\\Component\\EventDispatcher\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/event-dispatcher',
),
'Symfony\\Component\\DomCrawler\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/dom-crawler',
),
'Symfony\\Component\\CssSelector\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/css-selector',
),
'Symfony\\Component\\Console\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/console',
),
'Symfony\\Component\\BrowserKit\\' => 
array (
0 => __DIR__ . '/..' . '/symfony/browser-kit',
),
'Psr\\Http\\Message\\' => 
array (
0 => __DIR__ . '/..' . '/psr/http-message/src',
),
'Psr\\Container\\' => 
array (
0 => __DIR__ . '/..' . '/psr/container/src',
),
'Prophecy\\' => 
array (
0 => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy',
),
'Predis\\' => 
array (
0 => __DIR__ . '/..' . '/predis/predis/src',
),
'PhpAmqpLib\\' => 
array (
0 => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib',
),
'JsonSchema\\' => 
array (
0 => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema',
),
'Humbug\\SelfUpdate\\' => 
array (
0 => __DIR__ . '/..' . '/padraic/phar-updater/src',
),
'Humbug\\' => 
array (
0 => __DIR__ . '/..' . '/padraic/humbug_get_contents/src',
),
'Hoa\\Ustring\\' => 
array (
0 => __DIR__ . '/..' . '/hoa/ustring',
),
'Hoa\\Stream\\' => 
array (
0 => __DIR__ . '/..' . '/hoa/stream',
),
'Hoa\\Protocol\\' => 
array (
0 => __DIR__ . '/..' . '/hoa/protocol',
),
'Hoa\\Iterator\\' => 
array (
0 => __DIR__ . '/..' . '/hoa/iterator',
),
'Hoa\\File\\' => 
array (
0 => __DIR__ . '/..' . '/hoa/file',
),
'Hoa\\Exception\\' => 
array (
0 => __DIR__ . '/..' . '/hoa/exception',
),
'Hoa\\Event\\' => 
array (
0 => __DIR__ . '/..' . '/hoa/event',
),
'Hoa\\Console\\' => 
array (
0 => __DIR__ . '/..' . '/hoa/console',
),
'Hoa\\Consistency\\' => 
array (
0 => __DIR__ . '/..' . '/hoa/consistency',
),
'GuzzleHttp\\Psr7\\' => 
array (
0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src',
),
'GuzzleHttp\\Promise\\' => 
array (
0 => __DIR__ . '/..' . '/guzzlehttp/promises/src',
),
'GuzzleHttp\\' => 
array (
0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',
),
'Flow\\JSONPath\\' => 
array (
0 => __DIR__ . '/..' . '/softcreatr/jsonpath/src',
),
'Facebook\\WebDriver\\' => 
array (
0 => __DIR__ . '/..' . '/php-webdriver/webdriver/lib',
),
'Doctrine\\Instantiator\\' => 
array (
0 => __DIR__ . '/..' . '/doctrine/instantiator/src/Doctrine/Instantiator',
),
'DeepCopy\\' => 
array (
0 => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy',
),
'Composer\\CaBundle\\' => 
array (
0 => __DIR__ . '/..' . '/composer/ca-bundle/src',
),
'Codeception\\PHPUnit\\' => 
array (
0 => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src',
),
'Codeception\\Extension\\' => 
array (
0 => __DIR__ . '/..' . '/codeception/codeception/ext',
),
'Codeception\\' => 
array (
0 => __DIR__ . '/..' . '/codeception/stub/src',
1 => __DIR__ . '/..' . '/codeception/codeception/src/Codeception',
),
);

public static $prefixesPsr0 = array (
'B' => 
array (
'Behat\\Gherkin' => 
array (
0 => __DIR__ . '/..' . '/behat/gherkin/src',
),
),
);

public static $classMap = array (
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Behat\\Gherkin\\Cache\\CacheInterface' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Cache/CacheInterface.php',
'Behat\\Gherkin\\Cache\\FileCache' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Cache/FileCache.php',
'Behat\\Gherkin\\Cache\\MemoryCache' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Cache/MemoryCache.php',
'Behat\\Gherkin\\Exception\\CacheException' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Exception/CacheException.php',
'Behat\\Gherkin\\Exception\\Exception' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Exception/Exception.php',
'Behat\\Gherkin\\Exception\\LexerException' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Exception/LexerException.php',
'Behat\\Gherkin\\Exception\\NodeException' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Exception/NodeException.php',
'Behat\\Gherkin\\Exception\\ParserException' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Exception/ParserException.php',
'Behat\\Gherkin\\Filter\\ComplexFilter' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Filter/ComplexFilter.php',
'Behat\\Gherkin\\Filter\\ComplexFilterInterface' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Filter/ComplexFilterInterface.php',
'Behat\\Gherkin\\Filter\\FeatureFilterInterface' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Filter/FeatureFilterInterface.php',
'Behat\\Gherkin\\Filter\\FilterInterface' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Filter/FilterInterface.php',
'Behat\\Gherkin\\Filter\\LineFilter' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Filter/LineFilter.php',
'Behat\\Gherkin\\Filter\\LineRangeFilter' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Filter/LineRangeFilter.php',
'Behat\\Gherkin\\Filter\\NameFilter' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Filter/NameFilter.php',
'Behat\\Gherkin\\Filter\\NarrativeFilter' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Filter/NarrativeFilter.php',
'Behat\\Gherkin\\Filter\\PathsFilter' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Filter/PathsFilter.php',
'Behat\\Gherkin\\Filter\\RoleFilter' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Filter/RoleFilter.php',
'Behat\\Gherkin\\Filter\\SimpleFilter' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Filter/SimpleFilter.php',
'Behat\\Gherkin\\Filter\\TagFilter' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Filter/TagFilter.php',
'Behat\\Gherkin\\Gherkin' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Gherkin.php',
'Behat\\Gherkin\\Keywords\\ArrayKeywords' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Keywords/ArrayKeywords.php',
'Behat\\Gherkin\\Keywords\\CachedArrayKeywords' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Keywords/CachedArrayKeywords.php',
'Behat\\Gherkin\\Keywords\\CucumberKeywords' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Keywords/CucumberKeywords.php',
'Behat\\Gherkin\\Keywords\\KeywordsDumper' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Keywords/KeywordsDumper.php',
'Behat\\Gherkin\\Keywords\\KeywordsInterface' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Keywords/KeywordsInterface.php',
'Behat\\Gherkin\\Lexer' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Lexer.php',
'Behat\\Gherkin\\Loader\\AbstractFileLoader' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Loader/AbstractFileLoader.php',
'Behat\\Gherkin\\Loader\\ArrayLoader' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Loader/ArrayLoader.php',
'Behat\\Gherkin\\Loader\\CucumberNDJsonAstLoader' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Loader/CucumberNDJsonAstLoader.php',
'Behat\\Gherkin\\Loader\\DirectoryLoader' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Loader/DirectoryLoader.php',
'Behat\\Gherkin\\Loader\\FileLoaderInterface' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Loader/FileLoaderInterface.php',
'Behat\\Gherkin\\Loader\\GherkinFileLoader' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Loader/GherkinFileLoader.php',
'Behat\\Gherkin\\Loader\\LoaderInterface' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Loader/LoaderInterface.php',
'Behat\\Gherkin\\Loader\\YamlFileLoader' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Loader/YamlFileLoader.php',
'Behat\\Gherkin\\Node\\ArgumentInterface' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Node/ArgumentInterface.php',
'Behat\\Gherkin\\Node\\BackgroundNode' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Node/BackgroundNode.php',
'Behat\\Gherkin\\Node\\ExampleNode' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Node/ExampleNode.php',
'Behat\\Gherkin\\Node\\ExampleTableNode' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Node/ExampleTableNode.php',
'Behat\\Gherkin\\Node\\FeatureNode' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Node/FeatureNode.php',
'Behat\\Gherkin\\Node\\KeywordNodeInterface' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Node/KeywordNodeInterface.php',
'Behat\\Gherkin\\Node\\NodeInterface' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Node/NodeInterface.php',
'Behat\\Gherkin\\Node\\OutlineNode' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Node/OutlineNode.php',
'Behat\\Gherkin\\Node\\PyStringNode' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Node/PyStringNode.php',
'Behat\\Gherkin\\Node\\ScenarioInterface' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Node/ScenarioInterface.php',
'Behat\\Gherkin\\Node\\ScenarioLikeInterface' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Node/ScenarioLikeInterface.php',
'Behat\\Gherkin\\Node\\ScenarioNode' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Node/ScenarioNode.php',
'Behat\\Gherkin\\Node\\StepContainerInterface' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Node/StepContainerInterface.php',
'Behat\\Gherkin\\Node\\StepNode' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Node/StepNode.php',
'Behat\\Gherkin\\Node\\TableNode' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Node/TableNode.php',
'Behat\\Gherkin\\Node\\TaggedNodeInterface' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Node/TaggedNodeInterface.php',
'Behat\\Gherkin\\Parser' => __DIR__ . '/..' . '/behat/gherkin/src/Behat/Gherkin/Parser.php',
'Codeception\\Actor' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Actor.php',
'Codeception\\Application' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Application.php',
'Codeception\\Codecept' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Codecept.php',
'Codeception\\Command\\Bootstrap' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/Bootstrap.php',
'Codeception\\Command\\Build' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/Build.php',
'Codeception\\Command\\Clean' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/Clean.php',
'Codeception\\Command\\Completion' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/Completion.php',
'Codeception\\Command\\CompletionFallback' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/CompletionFallback.php',
'Codeception\\Command\\ConfigValidate' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/ConfigValidate.php',
'Codeception\\Command\\Console' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/Console.php',
'Codeception\\Command\\DryRun' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/DryRun.php',
'Codeception\\Command\\GenerateCept' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/GenerateCept.php',
'Codeception\\Command\\GenerateCest' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/GenerateCest.php',
'Codeception\\Command\\GenerateEnvironment' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/GenerateEnvironment.php',
'Codeception\\Command\\GenerateFeature' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/GenerateFeature.php',
'Codeception\\Command\\GenerateGroup' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/GenerateGroup.php',
'Codeception\\Command\\GenerateHelper' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/GenerateHelper.php',
'Codeception\\Command\\GeneratePageObject' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/GeneratePageObject.php',
'Codeception\\Command\\GenerateScenarios' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/GenerateScenarios.php',
'Codeception\\Command\\GenerateSnapshot' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/GenerateSnapshot.php',
'Codeception\\Command\\GenerateStepObject' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/GenerateStepObject.php',
'Codeception\\Command\\GenerateSuite' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/GenerateSuite.php',
'Codeception\\Command\\GenerateTest' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/GenerateTest.php',
'Codeception\\Command\\GherkinSnippets' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/GherkinSnippets.php',
'Codeception\\Command\\GherkinSteps' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/GherkinSteps.php',
'Codeception\\Command\\Init' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/Init.php',
'Codeception\\Command\\Run' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/Run.php',
'Codeception\\Command\\SelfUpdate' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/SelfUpdate.php',
'Codeception\\Command\\Shared\\Config' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/Shared/Config.php',
'Codeception\\Command\\Shared\\FileSystem' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/Shared/FileSystem.php',
'Codeception\\Command\\Shared\\Style' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Command/Shared/Style.php',
'Codeception\\Configuration' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Configuration.php',
'Codeception\\Coverage\\Filter' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Coverage/Filter.php',
'Codeception\\Coverage\\PhpCodeCoverageFactory' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Coverage/PhpCodeCoverageFactory.php',
'Codeception\\Coverage\\Subscriber\\Local' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Coverage/Subscriber/Local.php',
'Codeception\\Coverage\\Subscriber\\LocalServer' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Coverage/Subscriber/LocalServer.php',
'Codeception\\Coverage\\Subscriber\\Printer' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Coverage/Subscriber/Printer.php',
'Codeception\\Coverage\\Subscriber\\RemoteServer' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Coverage/Subscriber/RemoteServer.php',
'Codeception\\Coverage\\SuiteSubscriber' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Coverage/SuiteSubscriber.php',
'Codeception\\CustomCommandInterface' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/CustomCommandInterface.php',
'Codeception\\Event\\DispatcherWrapper' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Event/DispatcherWrapper.php',
'Codeception\\Event\\FailEvent' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Event/FailEvent.php',
'Codeception\\Event\\PrintResultEvent' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Event/PrintResultEvent.php',
'Codeception\\Event\\StepEvent' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Event/StepEvent.php',
'Codeception\\Event\\SuiteEvent' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Event/SuiteEvent.php',
'Codeception\\Event\\TestEvent' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Event/TestEvent.php',
'Codeception\\Events' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Events.php',
'Codeception\\Example' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Example.php',
'Codeception\\Exception\\ConditionalAssertionFailed' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Exception/ConditionalAssertionFailed.php',
'Codeception\\Exception\\ConfigurationException' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Exception/ConfigurationException.php',
'Codeception\\Exception\\ConnectionException' => __DIR__ . '/..' . '/codeception/module-webdriver/src/Codeception/Exception/ConnectionException.php',
'Codeception\\Exception\\ContentNotFound' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Exception/ContentNotFound.php',
'Codeception\\Exception\\ElementNotFound' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Exception/ElementNotFound.php',
'Codeception\\Exception\\ExtensionException' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Exception/ExtensionException.php',
'Codeception\\Exception\\ExternalUrlException' => __DIR__ . '/..' . '/codeception/lib-innerbrowser/src/Codeception/Exception/ExternalUrlException.php',
'Codeception\\Exception\\InjectionException' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Exception/InjectionException.php',
'Codeception\\Exception\\MalformedLocatorException' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Exception/MalformedLocatorException.php',
'Codeception\\Exception\\ModuleConfigException' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Exception/ModuleConfigException.php',
'Codeception\\Exception\\ModuleConflictException' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Exception/ModuleConflictException.php',
'Codeception\\Exception\\ModuleException' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Exception/ModuleException.php',
'Codeception\\Exception\\ModuleRequireException' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Exception/ModuleRequireException.php',
'Codeception\\Exception\\ParseException' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Exception/ParseException.php',
'Codeception\\Exception\\RemoteException' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Exception/RemoteException.php',
'Codeception\\Exception\\TestParseException' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Exception/TestParseException.php',
'Codeception\\Exception\\TestRuntimeException' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Exception/TestRuntimeException.php',
'Codeception\\Extension' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Extension.php',
'Codeception\\Extension\\DotReporter' => __DIR__ . '/..' . '/codeception/codeception/ext/DotReporter.php',
'Codeception\\Extension\\Logger' => __DIR__ . '/..' . '/codeception/codeception/ext/Logger.php',
'Codeception\\Extension\\Recorder' => __DIR__ . '/..' . '/codeception/codeception/ext/Recorder.php',
'Codeception\\Extension\\RunBefore' => __DIR__ . '/..' . '/codeception/codeception/ext/RunBefore.php',
'Codeception\\Extension\\RunFailed' => __DIR__ . '/..' . '/codeception/codeception/ext/RunFailed.php',
'Codeception\\Extension\\RunProcess' => __DIR__ . '/..' . '/codeception/codeception/ext/RunProcess.php',
'Codeception\\Extension\\SimpleReporter' => __DIR__ . '/..' . '/codeception/codeception/ext/SimpleReporter.php',
'Codeception\\GroupObject' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/GroupObject.php',
'Codeception\\InitTemplate' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/InitTemplate.php',
'Codeception\\Lib\\Actor\\Shared\\Comment' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Actor/Shared/Comment.php',
'Codeception\\Lib\\Actor\\Shared\\Friend' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Actor/Shared/Friend.php',
'Codeception\\Lib\\Actor\\Shared\\Pause' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Actor/Shared/Pause.php',
'Codeception\\Lib\\Actor\\Shared\\Retry' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Actor/Shared/Retry.php',
'Codeception\\Lib\\Connector\\Guzzle' => __DIR__ . '/..' . '/codeception/module-phpbrowser/src/Codeception/Lib/Connector/Guzzle.php',
'Codeception\\Lib\\Connector\\Shared\\PhpSuperGlobalsConverter' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Connector/Shared/PhpSuperGlobalsConverter.php',
'Codeception\\Lib\\Console\\Colorizer' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Console/Colorizer.php',
'Codeception\\Lib\\Console\\DiffFactory' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Console/DiffFactory.php',
'Codeception\\Lib\\Console\\Message' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Console/Message.php',
'Codeception\\Lib\\Console\\MessageFactory' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Console/MessageFactory.php',
'Codeception\\Lib\\Console\\Output' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Console/Output.php',
'Codeception\\Lib\\Console\\ReplHistory' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Console/ReplHistory.php',
'Codeception\\Lib\\DbPopulator' => __DIR__ . '/..' . '/codeception/module-db/src/Codeception/Lib/DbPopulator.php',
'Codeception\\Lib\\Di' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Di.php',
'Codeception\\Lib\\Driver\\AmazonSQS' => __DIR__ . '/..' . '/codeception/module-queue/src/Codeception/Lib/Driver/AmazonSQS.php',
'Codeception\\Lib\\Driver\\Beanstalk' => __DIR__ . '/..' . '/codeception/module-queue/src/Codeception/Lib/Driver/Beanstalk.php',
'Codeception\\Lib\\Driver\\Db' => __DIR__ . '/..' . '/codeception/module-db/src/Codeception/Lib/Driver/Db.php',
'Codeception\\Lib\\Driver\\Iron' => __DIR__ . '/..' . '/codeception/module-queue/src/Codeception/Lib/Driver/Iron.php',
'Codeception\\Lib\\Driver\\MongoDb' => __DIR__ . '/..' . '/codeception/module-mongodb/src/Codeception/Lib/Driver/MongoDb.php',
'Codeception\\Lib\\Driver\\MySql' => __DIR__ . '/..' . '/codeception/module-db/src/Codeception/Lib/Driver/MySql.php',
'Codeception\\Lib\\Driver\\Oci' => __DIR__ . '/..' . '/codeception/module-db/src/Codeception/Lib/Driver/Oci.php',
'Codeception\\Lib\\Driver\\Pheanstalk4' => __DIR__ . '/..' . '/codeception/module-queue/src/Codeception/Lib/Driver/Pheanstalk4.php',
'Codeception\\Lib\\Driver\\PostgreSql' => __DIR__ . '/..' . '/codeception/module-db/src/Codeception/Lib/Driver/PostgreSql.php',
'Codeception\\Lib\\Driver\\SqlSrv' => __DIR__ . '/..' . '/codeception/module-db/src/Codeception/Lib/Driver/SqlSrv.php',
'Codeception\\Lib\\Driver\\Sqlite' => __DIR__ . '/..' . '/codeception/module-db/src/Codeception/Lib/Driver/Sqlite.php',
'Codeception\\Lib\\Framework' => __DIR__ . '/..' . '/codeception/lib-innerbrowser/src/Codeception/Lib/Framework.php',
'Codeception\\Lib\\Friend' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Friend.php',
'Codeception\\Lib\\Generator\\Actions' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Generator/Actions.php',
'Codeception\\Lib\\Generator\\Actor' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Generator/Actor.php',
'Codeception\\Lib\\Generator\\Cept' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Generator/Cept.php',
'Codeception\\Lib\\Generator\\Cest' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Generator/Cest.php',
'Codeception\\Lib\\Generator\\Feature' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Generator/Feature.php',
'Codeception\\Lib\\Generator\\GherkinSnippets' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Generator/GherkinSnippets.php',
'Codeception\\Lib\\Generator\\Group' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Generator/Group.php',
'Codeception\\Lib\\Generator\\Helper' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Generator/Helper.php',
'Codeception\\Lib\\Generator\\PageObject' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Generator/PageObject.php',
'Codeception\\Lib\\Generator\\Shared\\Classname' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Generator/Shared/Classname.php',
'Codeception\\Lib\\Generator\\Snapshot' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Generator/Snapshot.php',
'Codeception\\Lib\\Generator\\StepObject' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Generator/StepObject.php',
'Codeception\\Lib\\Generator\\Test' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Generator/Test.php',
'Codeception\\Lib\\GroupManager' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/GroupManager.php',
'Codeception\\Lib\\InnerBrowser' => __DIR__ . '/..' . '/codeception/lib-innerbrowser/src/Codeception/Lib/InnerBrowser.php',
'Codeception\\Lib\\Interfaces\\API' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Interfaces/API.php',
'Codeception\\Lib\\Interfaces\\ActiveRecord' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Interfaces/ActiveRecord.php',
'Codeception\\Lib\\Interfaces\\ConflictsWithModule' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Interfaces/ConflictsWithModule.php',
'Codeception\\Lib\\Interfaces\\DataMapper' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Interfaces/DataMapper.php',
'Codeception\\Lib\\Interfaces\\Db' => __DIR__ . '/..' . '/codeception/module-db/src/Codeception/Lib/Interfaces/Db.php',
'Codeception\\Lib\\Interfaces\\DependsOnModule' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Interfaces/DependsOnModule.php',
'Codeception\\Lib\\Interfaces\\DoctrineProvider' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Interfaces/DoctrineProvider.php',
'Codeception\\Lib\\Interfaces\\ElementLocator' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Interfaces/ElementLocator.php',
'Codeception\\Lib\\Interfaces\\MultiSession' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Interfaces/MultiSession.php',
'Codeception\\Lib\\Interfaces\\ORM' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Interfaces/ORM.php',
'Codeception\\Lib\\Interfaces\\PageSourceSaver' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Interfaces/PageSourceSaver.php',
'Codeception\\Lib\\Interfaces\\PartedModule' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Interfaces/PartedModule.php',
'Codeception\\Lib\\Interfaces\\Queue' => __DIR__ . '/..' . '/codeception/module-queue/src/Codeception/Lib/Interfaces/Queue.php',
'Codeception\\Lib\\Interfaces\\Remote' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Interfaces/Remote.php',
'Codeception\\Lib\\Interfaces\\RequiresPackage' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Interfaces/RequiresPackage.php',
'Codeception\\Lib\\Interfaces\\ScreenshotSaver' => __DIR__ . '/..' . '/codeception/module-webdriver/src/Codeception/Lib/Interfaces/ScreenshotSaver.php',
'Codeception\\Lib\\Interfaces\\SessionSnapshot' => __DIR__ . '/..' . '/codeception/module-webdriver/src/Codeception/Lib/Interfaces/SessionSnapshot.php',
'Codeception\\Lib\\Interfaces\\Web' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Interfaces/Web.php',
'Codeception\\Lib\\ModuleContainer' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/ModuleContainer.php',
'Codeception\\Lib\\Notification' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Notification.php',
'Codeception\\Lib\\ParamsLoader' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/ParamsLoader.php',
'Codeception\\Lib\\Parser' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Lib/Parser.php',
'Codeception\\Module' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Module.php',
'Codeception\\Module\\AMQP' => __DIR__ . '/..' . '/codeception/module-amqp/src/Codeception/Module/AMQP.php',
'Codeception\\Module\\AbstractAsserts' => __DIR__ . '/..' . '/codeception/module-asserts/src/Codeception/Module/AbstractAsserts.php',
'Codeception\\Module\\Apc' => __DIR__ . '/..' . '/codeception/module-apc/src/Codeception/Module/Apc.php',
'Codeception\\Module\\Asserts' => __DIR__ . '/..' . '/codeception/module-asserts/src/Codeception/Module/Asserts.php',
'Codeception\\Module\\Cli' => __DIR__ . '/..' . '/codeception/module-cli/src/Codeception/Module/Cli.php',
'Codeception\\Module\\Db' => __DIR__ . '/..' . '/codeception/module-db/src/Codeception/Module/Db.php',
'Codeception\\Module\\FTP' => __DIR__ . '/..' . '/codeception/module-ftp/src/Codeception/Module/FTP.php',
'Codeception\\Module\\Filesystem' => __DIR__ . '/..' . '/codeception/module-filesystem/src/Codeception/Module/Filesystem.php',
'Codeception\\Module\\Memcache' => __DIR__ . '/..' . '/codeception/module-memcache/src/Codeception/Module/Memcache.php',
'Codeception\\Module\\MongoDb' => __DIR__ . '/..' . '/codeception/module-mongodb/src/Codeception/Module/MongoDb.php',
'Codeception\\Module\\PhpBrowser' => __DIR__ . '/..' . '/codeception/module-phpbrowser/src/Codeception/Module/PhpBrowser.php',
'Codeception\\Module\\Queue' => __DIR__ . '/..' . '/codeception/module-queue/src/Codeception/Module/Queue.php',
'Codeception\\Module\\REST' => __DIR__ . '/..' . '/codeception/module-rest/src/Codeception/Module/REST.php',
'Codeception\\Module\\Redis' => __DIR__ . '/..' . '/codeception/module-redis/src/Codeception/Module/Redis.php',
'Codeception\\Module\\SOAP' => __DIR__ . '/..' . '/codeception/module-soap/src/Codeception/Module/SOAP.php',
'Codeception\\Module\\Sequence' => __DIR__ . '/..' . '/codeception/module-sequence/src/Codeception/Module/Sequence.php',
'Codeception\\Module\\WebDriver' => __DIR__ . '/..' . '/codeception/module-webdriver/src/Codeception/Module/WebDriver.php',
'Codeception\\PHPUnit\\ConsolePrinter' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/ConsolePrinter.php',
'Codeception\\PHPUnit\\Constraint\\Crawler' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/Constraint/Crawler.php',
'Codeception\\PHPUnit\\Constraint\\CrawlerNot' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/Constraint/CrawlerNot.php',
'Codeception\\PHPUnit\\Constraint\\JsonContains' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/Constraint/JsonContains.php',
'Codeception\\PHPUnit\\Constraint\\JsonType' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/Constraint/JsonType.php',
'Codeception\\PHPUnit\\Constraint\\Page' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/Constraint/Page.php',
'Codeception\\PHPUnit\\Constraint\\WebDriver' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/Constraint/WebDriver.php',
'Codeception\\PHPUnit\\Constraint\\WebDriverNot' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/Constraint/WebDriverNot.php',
'Codeception\\PHPUnit\\DispatcherWrapper' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/DispatcherWrapper.php',
'Codeception\\PHPUnit\\FilterTest' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/FilterTest.php',
'Codeception\\PHPUnit\\Init' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/Init.php',
'Codeception\\PHPUnit\\Listener' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/Listener.php',
'Codeception\\PHPUnit\\Log\\JUnit' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/Log/JUnit.php',
'Codeception\\PHPUnit\\Log\\PhpUnit' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/Log/PhpUnit.php',
'Codeception\\PHPUnit\\NonFinal\\JUnit' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/NonFinal/JUnit.php',
'Codeception\\PHPUnit\\NonFinal\\NameFilterIterator' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/NonFinal/NameFilterIterator.php',
'Codeception\\PHPUnit\\NonFinal\\TestRunner' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/NonFinal/TestRunner.php',
'Codeception\\PHPUnit\\ResultPrinter' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/ResultPrinter.php',
'Codeception\\PHPUnit\\ResultPrinter\\HTML' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/ResultPrinter/HTML.php',
'Codeception\\PHPUnit\\ResultPrinter\\Report' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/ResultPrinter/Report.php',
'Codeception\\PHPUnit\\ResultPrinter\\UI' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/ResultPrinter/UI.php',
'Codeception\\PHPUnit\\Runner' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/Runner.php',
'Codeception\\PHPUnit\\TestCase' => __DIR__ . '/..' . '/codeception/phpunit-wrapper/src/TestCase.php',
'Codeception\\Scenario' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Scenario.php',
'Codeception\\Snapshot' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Snapshot.php',
'Codeception\\Step' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Step.php',
'Codeception\\Step\\Action' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Step/Action.php',
'Codeception\\Step\\Argument\\FormattedOutput' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Step/Argument/FormattedOutput.php',
'Codeception\\Step\\Argument\\PasswordArgument' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Step/Argument/PasswordArgument.php',
'Codeception\\Step\\AsJson' => __DIR__ . '/..' . '/codeception/module-rest/src/Codeception/Step/AsJson.php',
'Codeception\\Step\\Assertion' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Step/Assertion.php',
'Codeception\\Step\\Comment' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Step/Comment.php',
'Codeception\\Step\\Condition' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Step/Condition.php',
'Codeception\\Step\\ConditionalAssertion' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Step/ConditionalAssertion.php',
'Codeception\\Step\\Executor' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Step/Executor.php',
'Codeception\\Step\\GeneratedStep' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Step/GeneratedStep.php',
'Codeception\\Step\\Incomplete' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Step/Incomplete.php',
'Codeception\\Step\\Meta' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Step/Meta.php',
'Codeception\\Step\\Retry' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Step/Retry.php',
'Codeception\\Step\\Skip' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Step/Skip.php',
'Codeception\\Step\\TryTo' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Step/TryTo.php',
'Codeception\\Stub' => __DIR__ . '/..' . '/codeception/stub/src/Stub.php',
'Codeception\\Stub\\ConsecutiveMap' => __DIR__ . '/..' . '/codeception/stub/src/Stub/ConsecutiveMap.php',
'Codeception\\Stub\\Expected' => __DIR__ . '/..' . '/codeception/stub/src/Stub/Expected.php',
'Codeception\\Stub\\StubMarshaler' => __DIR__ . '/..' . '/codeception/stub/src/Stub/StubMarshaler.php',
'Codeception\\Subscriber\\AutoRebuild' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Subscriber/AutoRebuild.php',
'Codeception\\Subscriber\\BeforeAfterTest' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Subscriber/BeforeAfterTest.php',
'Codeception\\Subscriber\\Bootstrap' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Subscriber/Bootstrap.php',
'Codeception\\Subscriber\\Console' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Subscriber/Console.php',
'Codeception\\Subscriber\\Dependencies' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Subscriber/Dependencies.php',
'Codeception\\Subscriber\\ErrorHandler' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Subscriber/ErrorHandler.php',
'Codeception\\Subscriber\\ExtensionLoader' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Subscriber/ExtensionLoader.php',
'Codeception\\Subscriber\\FailFast' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Subscriber/FailFast.php',
'Codeception\\Subscriber\\GracefulTermination' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Subscriber/GracefulTermination.php',
'Codeception\\Subscriber\\Module' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Subscriber/Module.php',
'Codeception\\Subscriber\\PrepareTest' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Subscriber/PrepareTest.php',
'Codeception\\Subscriber\\Shared\\StaticEvents' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Subscriber/Shared/StaticEvents.php',
'Codeception\\Suite' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Suite.php',
'Codeception\\SuiteManager' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/SuiteManager.php',
'Codeception\\Template\\Acceptance' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Template/Acceptance.php',
'Codeception\\Template\\Api' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Template/Api.php',
'Codeception\\Template\\Bootstrap' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Template/Bootstrap.php',
'Codeception\\Template\\Unit' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Template/Unit.php',
'Codeception\\Template\\Upgrade4' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Template/Upgrade4.php',
'Codeception\\TestInterface' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/TestInterface.php',
'Codeception\\Test\\Cept' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Cept.php',
'Codeception\\Test\\Cest' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Cest.php',
'Codeception\\Test\\Descriptor' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Descriptor.php',
'Codeception\\Test\\Feature\\AssertionCounter' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Feature/AssertionCounter.php',
'Codeception\\Test\\Feature\\CodeCoverage' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Feature/CodeCoverage.php',
'Codeception\\Test\\Feature\\ErrorLogger' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Feature/ErrorLogger.php',
'Codeception\\Test\\Feature\\IgnoreIfMetadataBlocked' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Feature/IgnoreIfMetadataBlocked.php',
'Codeception\\Test\\Feature\\MetadataCollector' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Feature/MetadataCollector.php',
'Codeception\\Test\\Feature\\ScenarioLoader' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Feature/ScenarioLoader.php',
'Codeception\\Test\\Feature\\Stub' => __DIR__ . '/..' . '/codeception/stub/src/Test/Feature/Stub.php',
'Codeception\\Test\\Gherkin' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Gherkin.php',
'Codeception\\Test\\Interfaces\\Dependent' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Interfaces/Dependent.php',
'Codeception\\Test\\Interfaces\\Descriptive' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Interfaces/Descriptive.php',
'Codeception\\Test\\Interfaces\\Plain' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Interfaces/Plain.php',
'Codeception\\Test\\Interfaces\\Reported' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Interfaces/Reported.php',
'Codeception\\Test\\Interfaces\\ScenarioDriven' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Interfaces/ScenarioDriven.php',
'Codeception\\Test\\Interfaces\\StrictCoverage' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Interfaces/StrictCoverage.php',
'Codeception\\Test\\Loader' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Loader.php',
'Codeception\\Test\\Loader\\Cept' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Loader/Cept.php',
'Codeception\\Test\\Loader\\Cest' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Loader/Cest.php',
'Codeception\\Test\\Loader\\Gherkin' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Loader/Gherkin.php',
'Codeception\\Test\\Loader\\LoaderInterface' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Loader/LoaderInterface.php',
'Codeception\\Test\\Loader\\Unit' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Loader/Unit.php',
'Codeception\\Test\\Metadata' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Metadata.php',
'Codeception\\Test\\Test' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Test.php',
'Codeception\\Test\\Unit' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Test/Unit.php',
'Codeception\\Util\\ActionSequence' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/ActionSequence.php',
'Codeception\\Util\\Annotation' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/Annotation.php',
'Codeception\\Util\\ArrayContainsComparator' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/ArrayContainsComparator.php',
'Codeception\\Util\\Autoload' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/Autoload.php',
'Codeception\\Util\\Debug' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/Debug.php',
'Codeception\\Util\\FileSystem' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/FileSystem.php',
'Codeception\\Util\\Fixtures' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/Fixtures.php',
'Codeception\\Util\\HttpCode' => __DIR__ . '/..' . '/codeception/lib-innerbrowser/src/Codeception/Util/HttpCode.php',
'Codeception\\Util\\JsonArray' => __DIR__ . '/..' . '/codeception/module-rest/src/Codeception/Util/JsonArray.php',
'Codeception\\Util\\JsonType' => __DIR__ . '/..' . '/codeception/module-rest/src/Codeception/Util/JsonType.php',
'Codeception\\Util\\Locator' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/Locator.php',
'Codeception\\Util\\Maybe' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/Maybe.php',
'Codeception\\Util\\PathResolver' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/PathResolver.php',
'Codeception\\Util\\ReflectionHelper' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/ReflectionHelper.php',
'Codeception\\Util\\ReflectionPropertyAccessor' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/ReflectionPropertyAccessor.php',
'Codeception\\Util\\Shared\\Asserts' => __DIR__ . '/..' . '/codeception/lib-asserts/src/Codeception/Util/Shared/Asserts.php',
'Codeception\\Util\\Shared\\InheritedAsserts' => __DIR__ . '/..' . '/codeception/lib-asserts/src/Codeception/Util/Shared/InheritedAsserts.php',
'Codeception\\Util\\Shared\\Namespaces' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/Shared/Namespaces.php',
'Codeception\\Util\\Soap' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/Soap.php',
'Codeception\\Util\\Stub' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/Stub.php',
'Codeception\\Util\\Template' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/Template.php',
'Codeception\\Util\\Uri' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/Uri.php',
'Codeception\\Util\\Xml' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/Xml.php',
'Codeception\\Util\\XmlBuilder' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/XmlBuilder.php',
'Codeception\\Util\\XmlStructure' => __DIR__ . '/..' . '/codeception/codeception/src/Codeception/Util/XmlStructure.php',
'Composer\\CaBundle\\CaBundle' => __DIR__ . '/..' . '/composer/ca-bundle/src/CaBundle.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'DeepCopy\\DeepCopy' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/DeepCopy.php',
'DeepCopy\\Exception\\CloneException' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Exception/CloneException.php',
'DeepCopy\\Exception\\PropertyException' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Exception/PropertyException.php',
'DeepCopy\\Filter\\Doctrine\\DoctrineCollectionFilter' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php',
'DeepCopy\\Filter\\Doctrine\\DoctrineEmptyCollectionFilter' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php',
'DeepCopy\\Filter\\Doctrine\\DoctrineProxyFilter' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineProxyFilter.php',
'DeepCopy\\Filter\\Filter' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Filter/Filter.php',
'DeepCopy\\Filter\\KeepFilter' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Filter/KeepFilter.php',
'DeepCopy\\Filter\\ReplaceFilter' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Filter/ReplaceFilter.php',
'DeepCopy\\Filter\\SetNullFilter' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Filter/SetNullFilter.php',
'DeepCopy\\Matcher\\Doctrine\\DoctrineProxyMatcher' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php',
'DeepCopy\\Matcher\\Matcher' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Matcher/Matcher.php',
'DeepCopy\\Matcher\\PropertyMatcher' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyMatcher.php',
'DeepCopy\\Matcher\\PropertyNameMatcher' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyNameMatcher.php',
'DeepCopy\\Matcher\\PropertyTypeMatcher' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyTypeMatcher.php',
'DeepCopy\\Reflection\\ReflectionHelper' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Reflection/ReflectionHelper.php',
'DeepCopy\\TypeFilter\\Date\\DateIntervalFilter' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/TypeFilter/Date/DateIntervalFilter.php',
'DeepCopy\\TypeFilter\\ReplaceFilter' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/TypeFilter/ReplaceFilter.php',
'DeepCopy\\TypeFilter\\ShallowCopyFilter' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/TypeFilter/ShallowCopyFilter.php',
'DeepCopy\\TypeFilter\\Spl\\ArrayObjectFilter' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/ArrayObjectFilter.php',
'DeepCopy\\TypeFilter\\Spl\\SplDoublyLinkedList' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedList.php',
'DeepCopy\\TypeFilter\\Spl\\SplDoublyLinkedListFilter' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedListFilter.php',
'DeepCopy\\TypeFilter\\TypeFilter' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/TypeFilter/TypeFilter.php',
'DeepCopy\\TypeMatcher\\TypeMatcher' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/TypeMatcher/TypeMatcher.php',
'Doctrine\\Instantiator\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/doctrine/instantiator/src/Doctrine/Instantiator/Exception/ExceptionInterface.php',
'Doctrine\\Instantiator\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/doctrine/instantiator/src/Doctrine/Instantiator/Exception/InvalidArgumentException.php',
'Doctrine\\Instantiator\\Exception\\UnexpectedValueException' => __DIR__ . '/..' . '/doctrine/instantiator/src/Doctrine/Instantiator/Exception/UnexpectedValueException.php',
'Doctrine\\Instantiator\\Instantiator' => __DIR__ . '/..' . '/doctrine/instantiator/src/Doctrine/Instantiator/Instantiator.php',
'Doctrine\\Instantiator\\InstantiatorInterface' => __DIR__ . '/..' . '/doctrine/instantiator/src/Doctrine/Instantiator/InstantiatorInterface.php',
'Facebook\\WebDriver\\AbstractWebDriverCheckboxOrRadio' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/AbstractWebDriverCheckboxOrRadio.php',
'Facebook\\WebDriver\\Chrome\\ChromeDevToolsDriver' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Chrome/ChromeDevToolsDriver.php',
'Facebook\\WebDriver\\Chrome\\ChromeDriver' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Chrome/ChromeDriver.php',
'Facebook\\WebDriver\\Chrome\\ChromeDriverService' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Chrome/ChromeDriverService.php',
'Facebook\\WebDriver\\Chrome\\ChromeOptions' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Chrome/ChromeOptions.php',
'Facebook\\WebDriver\\Cookie' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Cookie.php',
'Facebook\\WebDriver\\Exception\\DriverServerDiedException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/DriverServerDiedException.php',
'Facebook\\WebDriver\\Exception\\ElementClickInterceptedException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/ElementClickInterceptedException.php',
'Facebook\\WebDriver\\Exception\\ElementNotInteractableException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/ElementNotInteractableException.php',
'Facebook\\WebDriver\\Exception\\ElementNotSelectableException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/ElementNotSelectableException.php',
'Facebook\\WebDriver\\Exception\\ElementNotVisibleException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/ElementNotVisibleException.php',
'Facebook\\WebDriver\\Exception\\ExpectedException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/ExpectedException.php',
'Facebook\\WebDriver\\Exception\\IMEEngineActivationFailedException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/IMEEngineActivationFailedException.php',
'Facebook\\WebDriver\\Exception\\IMENotAvailableException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/IMENotAvailableException.php',
'Facebook\\WebDriver\\Exception\\IndexOutOfBoundsException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/IndexOutOfBoundsException.php',
'Facebook\\WebDriver\\Exception\\InsecureCertificateException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/InsecureCertificateException.php',
'Facebook\\WebDriver\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/InvalidArgumentException.php',
'Facebook\\WebDriver\\Exception\\InvalidCookieDomainException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/InvalidCookieDomainException.php',
'Facebook\\WebDriver\\Exception\\InvalidCoordinatesException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/InvalidCoordinatesException.php',
'Facebook\\WebDriver\\Exception\\InvalidElementStateException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/InvalidElementStateException.php',
'Facebook\\WebDriver\\Exception\\InvalidSelectorException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/InvalidSelectorException.php',
'Facebook\\WebDriver\\Exception\\InvalidSessionIdException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/InvalidSessionIdException.php',
'Facebook\\WebDriver\\Exception\\JavascriptErrorException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/JavascriptErrorException.php',
'Facebook\\WebDriver\\Exception\\MoveTargetOutOfBoundsException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/MoveTargetOutOfBoundsException.php',
'Facebook\\WebDriver\\Exception\\NoAlertOpenException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/NoAlertOpenException.php',
'Facebook\\WebDriver\\Exception\\NoCollectionException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/NoCollectionException.php',
'Facebook\\WebDriver\\Exception\\NoScriptResultException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/NoScriptResultException.php',
'Facebook\\WebDriver\\Exception\\NoStringException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/NoStringException.php',
'Facebook\\WebDriver\\Exception\\NoStringLengthException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/NoStringLengthException.php',
'Facebook\\WebDriver\\Exception\\NoStringWrapperException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/NoStringWrapperException.php',
'Facebook\\WebDriver\\Exception\\NoSuchAlertException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/NoSuchAlertException.php',
'Facebook\\WebDriver\\Exception\\NoSuchCollectionException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/NoSuchCollectionException.php',
'Facebook\\WebDriver\\Exception\\NoSuchCookieException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/NoSuchCookieException.php',
'Facebook\\WebDriver\\Exception\\NoSuchDocumentException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/NoSuchDocumentException.php',
'Facebook\\WebDriver\\Exception\\NoSuchDriverException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/NoSuchDriverException.php',
'Facebook\\WebDriver\\Exception\\NoSuchElementException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/NoSuchElementException.php',
'Facebook\\WebDriver\\Exception\\NoSuchFrameException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/NoSuchFrameException.php',
'Facebook\\WebDriver\\Exception\\NoSuchWindowException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/NoSuchWindowException.php',
'Facebook\\WebDriver\\Exception\\NullPointerException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/NullPointerException.php',
'Facebook\\WebDriver\\Exception\\ScriptTimeoutException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/ScriptTimeoutException.php',
'Facebook\\WebDriver\\Exception\\SessionNotCreatedException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/SessionNotCreatedException.php',
'Facebook\\WebDriver\\Exception\\StaleElementReferenceException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/StaleElementReferenceException.php',
'Facebook\\WebDriver\\Exception\\TimeoutException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/TimeoutException.php',
'Facebook\\WebDriver\\Exception\\UnableToCaptureScreenException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/UnableToCaptureScreenException.php',
'Facebook\\WebDriver\\Exception\\UnableToSetCookieException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/UnableToSetCookieException.php',
'Facebook\\WebDriver\\Exception\\UnexpectedAlertOpenException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/UnexpectedAlertOpenException.php',
'Facebook\\WebDriver\\Exception\\UnexpectedJavascriptException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/UnexpectedJavascriptException.php',
'Facebook\\WebDriver\\Exception\\UnexpectedTagNameException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/UnexpectedTagNameException.php',
'Facebook\\WebDriver\\Exception\\UnknownCommandException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/UnknownCommandException.php',
'Facebook\\WebDriver\\Exception\\UnknownErrorException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/UnknownErrorException.php',
'Facebook\\WebDriver\\Exception\\UnknownMethodException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/UnknownMethodException.php',
'Facebook\\WebDriver\\Exception\\UnknownServerException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/UnknownServerException.php',
'Facebook\\WebDriver\\Exception\\UnrecognizedExceptionException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/UnrecognizedExceptionException.php',
'Facebook\\WebDriver\\Exception\\UnsupportedOperationException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/UnsupportedOperationException.php',
'Facebook\\WebDriver\\Exception\\WebDriverCurlException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/WebDriverCurlException.php',
'Facebook\\WebDriver\\Exception\\WebDriverException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/WebDriverException.php',
'Facebook\\WebDriver\\Exception\\XPathLookupException' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Exception/XPathLookupException.php',
'Facebook\\WebDriver\\Firefox\\FirefoxDriver' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Firefox/FirefoxDriver.php',
'Facebook\\WebDriver\\Firefox\\FirefoxDriverService' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Firefox/FirefoxDriverService.php',
'Facebook\\WebDriver\\Firefox\\FirefoxOptions' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Firefox/FirefoxOptions.php',
'Facebook\\WebDriver\\Firefox\\FirefoxPreferences' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Firefox/FirefoxPreferences.php',
'Facebook\\WebDriver\\Firefox\\FirefoxProfile' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Firefox/FirefoxProfile.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverButtonReleaseAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverButtonReleaseAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverClickAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverClickAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverClickAndHoldAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverClickAndHoldAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverContextClickAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverContextClickAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverCoordinates' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverCoordinates.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverDoubleClickAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverDoubleClickAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverKeyDownAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverKeyDownAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverKeyUpAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverKeyUpAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverKeysRelatedAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverKeysRelatedAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverMouseAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverMouseAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverMouseMoveAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverMouseMoveAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverMoveToOffsetAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverMoveToOffsetAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverSendKeysAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverSendKeysAction.php',
'Facebook\\WebDriver\\Interactions\\Internal\\WebDriverSingleKeyAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Internal/WebDriverSingleKeyAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverDoubleTapAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverDoubleTapAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverDownAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverDownAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverFlickAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverFlickAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverFlickFromElementAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverFlickFromElementAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverLongPressAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverLongPressAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverMoveAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverMoveAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverScrollAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverScrollAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverScrollFromElementAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverScrollFromElementAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverTapAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverTapAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverTouchAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverTouchAction.php',
'Facebook\\WebDriver\\Interactions\\Touch\\WebDriverTouchScreen' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/Touch/WebDriverTouchScreen.php',
'Facebook\\WebDriver\\Interactions\\WebDriverActions' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/WebDriverActions.php',
'Facebook\\WebDriver\\Interactions\\WebDriverCompositeAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/WebDriverCompositeAction.php',
'Facebook\\WebDriver\\Interactions\\WebDriverTouchActions' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Interactions/WebDriverTouchActions.php',
'Facebook\\WebDriver\\Internal\\WebDriverLocatable' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Internal/WebDriverLocatable.php',
'Facebook\\WebDriver\\JavaScriptExecutor' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/JavaScriptExecutor.php',
'Facebook\\WebDriver\\Local\\LocalWebDriver' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Local/LocalWebDriver.php',
'Facebook\\WebDriver\\Net\\URLChecker' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Net/URLChecker.php',
'Facebook\\WebDriver\\Remote\\CustomWebDriverCommand' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/CustomWebDriverCommand.php',
'Facebook\\WebDriver\\Remote\\DesiredCapabilities' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/DesiredCapabilities.php',
'Facebook\\WebDriver\\Remote\\DriverCommand' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/DriverCommand.php',
'Facebook\\WebDriver\\Remote\\ExecuteMethod' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/ExecuteMethod.php',
'Facebook\\WebDriver\\Remote\\FileDetector' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/FileDetector.php',
'Facebook\\WebDriver\\Remote\\HttpCommandExecutor' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/HttpCommandExecutor.php',
'Facebook\\WebDriver\\Remote\\JsonWireCompat' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/JsonWireCompat.php',
'Facebook\\WebDriver\\Remote\\LocalFileDetector' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/LocalFileDetector.php',
'Facebook\\WebDriver\\Remote\\RemoteExecuteMethod' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/RemoteExecuteMethod.php',
'Facebook\\WebDriver\\Remote\\RemoteKeyboard' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/RemoteKeyboard.php',
'Facebook\\WebDriver\\Remote\\RemoteMouse' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/RemoteMouse.php',
'Facebook\\WebDriver\\Remote\\RemoteStatus' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/RemoteStatus.php',
'Facebook\\WebDriver\\Remote\\RemoteTargetLocator' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/RemoteTargetLocator.php',
'Facebook\\WebDriver\\Remote\\RemoteTouchScreen' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/RemoteTouchScreen.php',
'Facebook\\WebDriver\\Remote\\RemoteWebDriver' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/RemoteWebDriver.php',
'Facebook\\WebDriver\\Remote\\RemoteWebElement' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/RemoteWebElement.php',
'Facebook\\WebDriver\\Remote\\Service\\DriverCommandExecutor' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/Service/DriverCommandExecutor.php',
'Facebook\\WebDriver\\Remote\\Service\\DriverService' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/Service/DriverService.php',
'Facebook\\WebDriver\\Remote\\UselessFileDetector' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/UselessFileDetector.php',
'Facebook\\WebDriver\\Remote\\WebDriverBrowserType' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/WebDriverBrowserType.php',
'Facebook\\WebDriver\\Remote\\WebDriverCapabilityType' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/WebDriverCapabilityType.php',
'Facebook\\WebDriver\\Remote\\WebDriverCommand' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/WebDriverCommand.php',
'Facebook\\WebDriver\\Remote\\WebDriverResponse' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Remote/WebDriverResponse.php',
'Facebook\\WebDriver\\Support\\Events\\EventFiringWebDriver' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Support/Events/EventFiringWebDriver.php',
'Facebook\\WebDriver\\Support\\Events\\EventFiringWebDriverNavigation' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Support/Events/EventFiringWebDriverNavigation.php',
'Facebook\\WebDriver\\Support\\Events\\EventFiringWebElement' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Support/Events/EventFiringWebElement.php',
'Facebook\\WebDriver\\Support\\XPathEscaper' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/Support/XPathEscaper.php',
'Facebook\\WebDriver\\WebDriver' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriver.php',
'Facebook\\WebDriver\\WebDriverAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverAction.php',
'Facebook\\WebDriver\\WebDriverAlert' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverAlert.php',
'Facebook\\WebDriver\\WebDriverBy' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverBy.php',
'Facebook\\WebDriver\\WebDriverCapabilities' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverCapabilities.php',
'Facebook\\WebDriver\\WebDriverCheckboxes' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverCheckboxes.php',
'Facebook\\WebDriver\\WebDriverCommandExecutor' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverCommandExecutor.php',
'Facebook\\WebDriver\\WebDriverDimension' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverDimension.php',
'Facebook\\WebDriver\\WebDriverDispatcher' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverDispatcher.php',
'Facebook\\WebDriver\\WebDriverElement' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverElement.php',
'Facebook\\WebDriver\\WebDriverEventListener' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverEventListener.php',
'Facebook\\WebDriver\\WebDriverExpectedCondition' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverExpectedCondition.php',
'Facebook\\WebDriver\\WebDriverHasInputDevices' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverHasInputDevices.php',
'Facebook\\WebDriver\\WebDriverKeyboard' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverKeyboard.php',
'Facebook\\WebDriver\\WebDriverKeys' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverKeys.php',
'Facebook\\WebDriver\\WebDriverMouse' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverMouse.php',
'Facebook\\WebDriver\\WebDriverNavigation' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverNavigation.php',
'Facebook\\WebDriver\\WebDriverNavigationInterface' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverNavigationInterface.php',
'Facebook\\WebDriver\\WebDriverOptions' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverOptions.php',
'Facebook\\WebDriver\\WebDriverPlatform' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverPlatform.php',
'Facebook\\WebDriver\\WebDriverPoint' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverPoint.php',
'Facebook\\WebDriver\\WebDriverRadios' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverRadios.php',
'Facebook\\WebDriver\\WebDriverSearchContext' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverSearchContext.php',
'Facebook\\WebDriver\\WebDriverSelect' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverSelect.php',
'Facebook\\WebDriver\\WebDriverSelectInterface' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverSelectInterface.php',
'Facebook\\WebDriver\\WebDriverTargetLocator' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverTargetLocator.php',
'Facebook\\WebDriver\\WebDriverTimeouts' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverTimeouts.php',
'Facebook\\WebDriver\\WebDriverUpAction' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverUpAction.php',
'Facebook\\WebDriver\\WebDriverWait' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverWait.php',
'Facebook\\WebDriver\\WebDriverWindow' => __DIR__ . '/..' . '/php-webdriver/webdriver/lib/WebDriverWindow.php',
'Flow\\JSONPath\\AccessHelper' => __DIR__ . '/..' . '/softcreatr/jsonpath/src/AccessHelper.php',
'Flow\\JSONPath\\Filters\\AbstractFilter' => __DIR__ . '/..' . '/softcreatr/jsonpath/src/Filters/AbstractFilter.php',
'Flow\\JSONPath\\Filters\\IndexFilter' => __DIR__ . '/..' . '/softcreatr/jsonpath/src/Filters/IndexFilter.php',
'Flow\\JSONPath\\Filters\\IndexesFilter' => __DIR__ . '/..' . '/softcreatr/jsonpath/src/Filters/IndexesFilter.php',
'Flow\\JSONPath\\Filters\\QueryMatchFilter' => __DIR__ . '/..' . '/softcreatr/jsonpath/src/Filters/QueryMatchFilter.php',
'Flow\\JSONPath\\Filters\\QueryResultFilter' => __DIR__ . '/..' . '/softcreatr/jsonpath/src/Filters/QueryResultFilter.php',
'Flow\\JSONPath\\Filters\\RecursiveFilter' => __DIR__ . '/..' . '/softcreatr/jsonpath/src/Filters/RecursiveFilter.php',
'Flow\\JSONPath\\Filters\\SliceFilter' => __DIR__ . '/..' . '/softcreatr/jsonpath/src/Filters/SliceFilter.php',
'Flow\\JSONPath\\JSONPath' => __DIR__ . '/..' . '/softcreatr/jsonpath/src/JSONPath.php',
'Flow\\JSONPath\\JSONPathException' => __DIR__ . '/..' . '/softcreatr/jsonpath/src/JSONPathException.php',
'Flow\\JSONPath\\JSONPathLexer' => __DIR__ . '/..' . '/softcreatr/jsonpath/src/JSONPathLexer.php',
'Flow\\JSONPath\\JSONPathToken' => __DIR__ . '/..' . '/softcreatr/jsonpath/src/JSONPathToken.php',
'GuzzleHttp\\Client' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Client.php',
'GuzzleHttp\\ClientInterface' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/ClientInterface.php',
'GuzzleHttp\\Cookie\\CookieJar' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Cookie/CookieJar.php',
'GuzzleHttp\\Cookie\\CookieJarInterface' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php',
'GuzzleHttp\\Cookie\\FileCookieJar' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php',
'GuzzleHttp\\Cookie\\SessionCookieJar' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php',
'GuzzleHttp\\Cookie\\SetCookie' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Cookie/SetCookie.php',
'GuzzleHttp\\Exception\\BadResponseException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/BadResponseException.php',
'GuzzleHttp\\Exception\\ClientException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/ClientException.php',
'GuzzleHttp\\Exception\\ConnectException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/ConnectException.php',
'GuzzleHttp\\Exception\\GuzzleException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/GuzzleException.php',
'GuzzleHttp\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/InvalidArgumentException.php',
'GuzzleHttp\\Exception\\RequestException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/RequestException.php',
'GuzzleHttp\\Exception\\SeekException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/SeekException.php',
'GuzzleHttp\\Exception\\ServerException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/ServerException.php',
'GuzzleHttp\\Exception\\TooManyRedirectsException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php',
'GuzzleHttp\\Exception\\TransferException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/TransferException.php',
'GuzzleHttp\\HandlerStack' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/HandlerStack.php',
'GuzzleHttp\\Handler\\CurlFactory' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/CurlFactory.php',
'GuzzleHttp\\Handler\\CurlFactoryInterface' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php',
'GuzzleHttp\\Handler\\CurlHandler' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/CurlHandler.php',
'GuzzleHttp\\Handler\\CurlMultiHandler' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php',
'GuzzleHttp\\Handler\\EasyHandle' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/EasyHandle.php',
'GuzzleHttp\\Handler\\MockHandler' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/MockHandler.php',
'GuzzleHttp\\Handler\\Proxy' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/Proxy.php',
'GuzzleHttp\\Handler\\StreamHandler' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/StreamHandler.php',
'GuzzleHttp\\MessageFormatter' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/MessageFormatter.php',
'GuzzleHttp\\Middleware' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Middleware.php',
'GuzzleHttp\\Pool' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Pool.php',
'GuzzleHttp\\PrepareBodyMiddleware' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php',
'GuzzleHttp\\Promise\\AggregateException' => __DIR__ . '/..' . '/guzzlehttp/promises/src/AggregateException.php',
'GuzzleHttp\\Promise\\CancellationException' => __DIR__ . '/..' . '/guzzlehttp/promises/src/CancellationException.php',
'GuzzleHttp\\Promise\\Coroutine' => __DIR__ . '/..' . '/guzzlehttp/promises/src/Coroutine.php',
'GuzzleHttp\\Promise\\Create' => __DIR__ . '/..' . '/guzzlehttp/promises/src/Create.php',
'GuzzleHttp\\Promise\\Each' => __DIR__ . '/..' . '/guzzlehttp/promises/src/Each.php',
'GuzzleHttp\\Promise\\EachPromise' => __DIR__ . '/..' . '/guzzlehttp/promises/src/EachPromise.php',
'GuzzleHttp\\Promise\\FulfilledPromise' => __DIR__ . '/..' . '/guzzlehttp/promises/src/FulfilledPromise.php',
'GuzzleHttp\\Promise\\Is' => __DIR__ . '/..' . '/guzzlehttp/promises/src/Is.php',
'GuzzleHttp\\Promise\\Promise' => __DIR__ . '/..' . '/guzzlehttp/promises/src/Promise.php',
'GuzzleHttp\\Promise\\PromiseInterface' => __DIR__ . '/..' . '/guzzlehttp/promises/src/PromiseInterface.php',
'GuzzleHttp\\Promise\\PromisorInterface' => __DIR__ . '/..' . '/guzzlehttp/promises/src/PromisorInterface.php',
'GuzzleHttp\\Promise\\RejectedPromise' => __DIR__ . '/..' . '/guzzlehttp/promises/src/RejectedPromise.php',
'GuzzleHttp\\Promise\\RejectionException' => __DIR__ . '/..' . '/guzzlehttp/promises/src/RejectionException.php',
'GuzzleHttp\\Promise\\TaskQueue' => __DIR__ . '/..' . '/guzzlehttp/promises/src/TaskQueue.php',
'GuzzleHttp\\Promise\\TaskQueueInterface' => __DIR__ . '/..' . '/guzzlehttp/promises/src/TaskQueueInterface.php',
'GuzzleHttp\\Promise\\Utils' => __DIR__ . '/..' . '/guzzlehttp/promises/src/Utils.php',
'GuzzleHttp\\Psr7\\AppendStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/AppendStream.php',
'GuzzleHttp\\Psr7\\BufferStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/BufferStream.php',
'GuzzleHttp\\Psr7\\CachingStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/CachingStream.php',
'GuzzleHttp\\Psr7\\DroppingStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/DroppingStream.php',
'GuzzleHttp\\Psr7\\FnStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/FnStream.php',
'GuzzleHttp\\Psr7\\Header' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Header.php',
'GuzzleHttp\\Psr7\\InflateStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/InflateStream.php',
'GuzzleHttp\\Psr7\\LazyOpenStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/LazyOpenStream.php',
'GuzzleHttp\\Psr7\\LimitStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/LimitStream.php',
'GuzzleHttp\\Psr7\\Message' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Message.php',
'GuzzleHttp\\Psr7\\MessageTrait' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/MessageTrait.php',
'GuzzleHttp\\Psr7\\MimeType' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/MimeType.php',
'GuzzleHttp\\Psr7\\MultipartStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/MultipartStream.php',
'GuzzleHttp\\Psr7\\NoSeekStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/NoSeekStream.php',
'GuzzleHttp\\Psr7\\PumpStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/PumpStream.php',
'GuzzleHttp\\Psr7\\Query' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Query.php',
'GuzzleHttp\\Psr7\\Request' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Request.php',
'GuzzleHttp\\Psr7\\Response' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Response.php',
'GuzzleHttp\\Psr7\\Rfc7230' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Rfc7230.php',
'GuzzleHttp\\Psr7\\ServerRequest' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/ServerRequest.php',
'GuzzleHttp\\Psr7\\Stream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Stream.php',
'GuzzleHttp\\Psr7\\StreamDecoratorTrait' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/StreamDecoratorTrait.php',
'GuzzleHttp\\Psr7\\StreamWrapper' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/StreamWrapper.php',
'GuzzleHttp\\Psr7\\UploadedFile' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/UploadedFile.php',
'GuzzleHttp\\Psr7\\Uri' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Uri.php',
'GuzzleHttp\\Psr7\\UriNormalizer' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/UriNormalizer.php',
'GuzzleHttp\\Psr7\\UriResolver' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/UriResolver.php',
'GuzzleHttp\\Psr7\\Utils' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Utils.php',
'GuzzleHttp\\RedirectMiddleware' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/RedirectMiddleware.php',
'GuzzleHttp\\RequestOptions' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/RequestOptions.php',
'GuzzleHttp\\RetryMiddleware' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/RetryMiddleware.php',
'GuzzleHttp\\TransferStats' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/TransferStats.php',
'GuzzleHttp\\UriTemplate' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/UriTemplate.php',
'GuzzleHttp\\Utils' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Utils.php',
'Hoa\\Consistency\\Autoloader' => __DIR__ . '/..' . '/hoa/consistency/Autoloader.php',
'Hoa\\Consistency\\Consistency' => __DIR__ . '/..' . '/hoa/consistency/Consistency.php',
'Hoa\\Consistency\\Exception' => __DIR__ . '/..' . '/hoa/consistency/Exception.php',
'Hoa\\Consistency\\Test\\Unit\\Autoloader' => __DIR__ . '/..' . '/hoa/consistency/Test/Unit/Autoloader.php',
'Hoa\\Consistency\\Test\\Unit\\Consistency' => __DIR__ . '/..' . '/hoa/consistency/Test/Unit/Consistency.php',
'Hoa\\Consistency\\Test\\Unit\\Exception' => __DIR__ . '/..' . '/hoa/consistency/Test/Unit/Exception.php',
'Hoa\\Consistency\\Test\\Unit\\Xcallable' => __DIR__ . '/..' . '/hoa/consistency/Test/Unit/Xcallable.php',
'Hoa\\Consistency\\Xcallable' => __DIR__ . '/..' . '/hoa/consistency/Xcallable.php',
'Hoa\\Console\\Bin\\Termcap' => __DIR__ . '/..' . '/hoa/console/Bin/Termcap.php',
'Hoa\\Console\\Chrome\\Editor' => __DIR__ . '/..' . '/hoa/console/Chrome/Editor.php',
'Hoa\\Console\\Chrome\\Exception' => __DIR__ . '/..' . '/hoa/console/Chrome/Exception.php',
'Hoa\\Console\\Chrome\\Pager' => __DIR__ . '/..' . '/hoa/console/Chrome/Pager.php',
'Hoa\\Console\\Chrome\\Text' => __DIR__ . '/..' . '/hoa/console/Chrome/Text.php',
'Hoa\\Console\\Console' => __DIR__ . '/..' . '/hoa/console/Console.php',
'Hoa\\Console\\Cursor' => __DIR__ . '/..' . '/hoa/console/Cursor.php',
'Hoa\\Console\\Dispatcher\\Kit' => __DIR__ . '/..' . '/hoa/console/Dispatcher/Kit.php',
'Hoa\\Console\\Exception' => __DIR__ . '/..' . '/hoa/console/Exception.php',
'Hoa\\Console\\GetOption' => __DIR__ . '/..' . '/hoa/console/GetOption.php',
'Hoa\\Console\\Input' => __DIR__ . '/..' . '/hoa/console/Input.php',
'Hoa\\Console\\Mouse' => __DIR__ . '/..' . '/hoa/console/Mouse.php',
'Hoa\\Console\\Output' => __DIR__ . '/..' . '/hoa/console/Output.php',
'Hoa\\Console\\Parser' => __DIR__ . '/..' . '/hoa/console/Parser.php',
'Hoa\\Console\\Processus' => __DIR__ . '/..' . '/hoa/console/Processus.php',
'Hoa\\Console\\Readline\\Autocompleter\\Aggregate' => __DIR__ . '/..' . '/hoa/console/Readline/Autocompleter/Aggregate.php',
'Hoa\\Console\\Readline\\Autocompleter\\Autocompleter' => __DIR__ . '/..' . '/hoa/console/Readline/Autocompleter/Autocompleter.php',
'Hoa\\Console\\Readline\\Autocompleter\\Path' => __DIR__ . '/..' . '/hoa/console/Readline/Autocompleter/Path.php',
'Hoa\\Console\\Readline\\Autocompleter\\Word' => __DIR__ . '/..' . '/hoa/console/Readline/Autocompleter/Word.php',
'Hoa\\Console\\Readline\\Password' => __DIR__ . '/..' . '/hoa/console/Readline/Password.php',
'Hoa\\Console\\Readline\\Readline' => __DIR__ . '/..' . '/hoa/console/Readline/Readline.php',
'Hoa\\Console\\Test\\Unit\\Console' => __DIR__ . '/..' . '/hoa/console/Test/Unit/Console.php',
'Hoa\\Console\\Test\\Unit\\Cursor' => __DIR__ . '/..' . '/hoa/console/Test/Unit/Cursor.php',
'Hoa\\Console\\Test\\Unit\\GetOption' => __DIR__ . '/..' . '/hoa/console/Test/Unit/GetOption.php',
'Hoa\\Console\\Test\\Unit\\Input' => __DIR__ . '/..' . '/hoa/console/Test/Unit/Input.php',
'Hoa\\Console\\Test\\Unit\\Mouse' => __DIR__ . '/..' . '/hoa/console/Test/Unit/Mouse.php',
'Hoa\\Console\\Test\\Unit\\Output' => __DIR__ . '/..' . '/hoa/console/Test/Unit/Output.php',
'Hoa\\Console\\Test\\Unit\\Parser' => __DIR__ . '/..' . '/hoa/console/Test/Unit/Parser.php',
'Hoa\\Console\\Test\\Unit\\Readline\\Autocompleter\\Aggregate' => __DIR__ . '/..' . '/hoa/console/Test/Unit/Readline/Autocompleter/Aggregate.php',
'Hoa\\Console\\Test\\Unit\\Readline\\Autocompleter\\Path' => __DIR__ . '/..' . '/hoa/console/Test/Unit/Readline/Autocompleter/Path.php',
'Hoa\\Console\\Test\\Unit\\Readline\\Autocompleter\\Word' => __DIR__ . '/..' . '/hoa/console/Test/Unit/Readline/Autocompleter/Word.php',
'Hoa\\Console\\Test\\Unit\\Readline\\Password' => __DIR__ . '/..' . '/hoa/console/Test/Unit/Readline/Password.php',
'Hoa\\Console\\Test\\Unit\\Tput' => __DIR__ . '/..' . '/hoa/console/Test/Unit/Tput.php',
'Hoa\\Console\\Test\\Unit\\Window' => __DIR__ . '/..' . '/hoa/console/Test/Unit/Window.php',
'Hoa\\Console\\Tput' => __DIR__ . '/..' . '/hoa/console/Tput.php',
'Hoa\\Console\\Window' => __DIR__ . '/..' . '/hoa/console/Window.php',
'Hoa\\Event\\Bucket' => __DIR__ . '/..' . '/hoa/event/Bucket.php',
'Hoa\\Event\\Event' => __DIR__ . '/..' . '/hoa/event/Event.php',
'Hoa\\Event\\Exception' => __DIR__ . '/..' . '/hoa/event/Exception.php',
'Hoa\\Event\\Listenable' => __DIR__ . '/..' . '/hoa/event/Listenable.php',
'Hoa\\Event\\Listener' => __DIR__ . '/..' . '/hoa/event/Listener.php',
'Hoa\\Event\\Listens' => __DIR__ . '/..' . '/hoa/event/Listens.php',
'Hoa\\Event\\Source' => __DIR__ . '/..' . '/hoa/event/Source.php',
'Hoa\\Event\\Test\\Unit\\Bucket' => __DIR__ . '/..' . '/hoa/event/Test/Unit/Bucket.php',
'Hoa\\Event\\Test\\Unit\\Event' => __DIR__ . '/..' . '/hoa/event/Test/Unit/Event.php',
'Hoa\\Event\\Test\\Unit\\Exception' => __DIR__ . '/..' . '/hoa/event/Test/Unit/Exception.php',
'Hoa\\Event\\Test\\Unit\\Listenable' => __DIR__ . '/..' . '/hoa/event/Test/Unit/Listenable.php',
'Hoa\\Event\\Test\\Unit\\Listener' => __DIR__ . '/..' . '/hoa/event/Test/Unit/Listener.php',
'Hoa\\Event\\Test\\Unit\\Listens' => __DIR__ . '/..' . '/hoa/event/Test/Unit/Listens.php',
'Hoa\\Event\\Test\\Unit\\Source' => __DIR__ . '/..' . '/hoa/event/Test/Unit/Source.php',
'Hoa\\Exception\\Error' => __DIR__ . '/..' . '/hoa/exception/Error.php',
'Hoa\\Exception\\Exception' => __DIR__ . '/..' . '/hoa/exception/Exception.php',
'Hoa\\Exception\\Group' => __DIR__ . '/..' . '/hoa/exception/Group.php',
'Hoa\\Exception\\Idle' => __DIR__ . '/..' . '/hoa/exception/Idle.php',
'Hoa\\Exception\\Test\\Unit\\Error' => __DIR__ . '/..' . '/hoa/exception/Test/Unit/Error.php',
'Hoa\\Exception\\Test\\Unit\\Exception' => __DIR__ . '/..' . '/hoa/exception/Test/Unit/Exception.php',
'Hoa\\Exception\\Test\\Unit\\Group' => __DIR__ . '/..' . '/hoa/exception/Test/Unit/Group.php',
'Hoa\\Exception\\Test\\Unit\\Idle' => __DIR__ . '/..' . '/hoa/exception/Test/Unit/Idle.php',
'Hoa\\File\\Directory' => __DIR__ . '/..' . '/hoa/file/Directory.php',
'Hoa\\File\\Exception\\Exception' => __DIR__ . '/..' . '/hoa/file/Exception/Exception.php',
'Hoa\\File\\Exception\\FileDoesNotExist' => __DIR__ . '/..' . '/hoa/file/Exception/FileDoesNotExist.php',
'Hoa\\File\\File' => __DIR__ . '/..' . '/hoa/file/File.php',
'Hoa\\File\\Finder' => __DIR__ . '/..' . '/hoa/file/Finder.php',
'Hoa\\File\\Generic' => __DIR__ . '/..' . '/hoa/file/Generic.php',
'Hoa\\File\\Link\\Link' => __DIR__ . '/..' . '/hoa/file/Link/Link.php',
'Hoa\\File\\Link\\Read' => __DIR__ . '/..' . '/hoa/file/Link/Read.php',
'Hoa\\File\\Link\\ReadWrite' => __DIR__ . '/..' . '/hoa/file/Link/ReadWrite.php',
'Hoa\\File\\Link\\Write' => __DIR__ . '/..' . '/hoa/file/Link/Write.php',
'Hoa\\File\\Read' => __DIR__ . '/..' . '/hoa/file/Read.php',
'Hoa\\File\\ReadWrite' => __DIR__ . '/..' . '/hoa/file/ReadWrite.php',
'Hoa\\File\\SplFileInfo' => __DIR__ . '/..' . '/hoa/file/SplFileInfo.php',
'Hoa\\File\\Temporary\\Read' => __DIR__ . '/..' . '/hoa/file/Temporary/Read.php',
'Hoa\\File\\Temporary\\ReadWrite' => __DIR__ . '/..' . '/hoa/file/Temporary/ReadWrite.php',
'Hoa\\File\\Temporary\\Temporary' => __DIR__ . '/..' . '/hoa/file/Temporary/Temporary.php',
'Hoa\\File\\Temporary\\Write' => __DIR__ . '/..' . '/hoa/file/Temporary/Write.php',
'Hoa\\File\\Watcher' => __DIR__ . '/..' . '/hoa/file/Watcher.php',
'Hoa\\File\\Write' => __DIR__ . '/..' . '/hoa/file/Write.php',
'Hoa\\Iterator\\Aggregate' => __DIR__ . '/..' . '/hoa/iterator/Aggregate.php',
'Hoa\\Iterator\\Append' => __DIR__ . '/..' . '/hoa/iterator/Append.php',
'Hoa\\Iterator\\Buffer' => __DIR__ . '/..' . '/hoa/iterator/Buffer.php',
'Hoa\\Iterator\\CallbackFilter' => __DIR__ . '/..' . '/hoa/iterator/CallbackFilter.php',
'Hoa\\Iterator\\CallbackGenerator' => __DIR__ . '/..' . '/hoa/iterator/CallbackGenerator.php',
'Hoa\\Iterator\\Counter' => __DIR__ . '/..' . '/hoa/iterator/Counter.php',
'Hoa\\Iterator\\Demultiplexer' => __DIR__ . '/..' . '/hoa/iterator/Demultiplexer.php',
'Hoa\\Iterator\\Directory' => __DIR__ . '/..' . '/hoa/iterator/Directory.php',
'Hoa\\Iterator\\Exception' => __DIR__ . '/..' . '/hoa/iterator/Exception.php',
'Hoa\\Iterator\\FileSystem' => __DIR__ . '/..' . '/hoa/iterator/FileSystem.php',
'Hoa\\Iterator\\Filter' => __DIR__ . '/..' . '/hoa/iterator/Filter.php',
'Hoa\\Iterator\\Glob' => __DIR__ . '/..' . '/hoa/iterator/Glob.php',
'Hoa\\Iterator\\Infinite' => __DIR__ . '/..' . '/hoa/iterator/Infinite.php',
'Hoa\\Iterator\\Iterator' => __DIR__ . '/..' . '/hoa/iterator/Iterator.php',
'Hoa\\Iterator\\IteratorIterator' => __DIR__ . '/..' . '/hoa/iterator/IteratorIterator.php',
'Hoa\\Iterator\\Limit' => __DIR__ . '/..' . '/hoa/iterator/Limit.php',
'Hoa\\Iterator\\Lookahead' => __DIR__ . '/..' . '/hoa/iterator/Lookahead.php',
'Hoa\\Iterator\\Lookbehind' => __DIR__ . '/..' . '/hoa/iterator/Lookbehind.php',
'Hoa\\Iterator\\Map' => __DIR__ . '/..' . '/hoa/iterator/Map.php',
'Hoa\\Iterator\\Mock' => __DIR__ . '/..' . '/hoa/iterator/Mock.php',
'Hoa\\Iterator\\Multiple' => __DIR__ . '/..' . '/hoa/iterator/Multiple.php',
'Hoa\\Iterator\\NoRewind' => __DIR__ . '/..' . '/hoa/iterator/NoRewind.php',
'Hoa\\Iterator\\Outer' => __DIR__ . '/..' . '/hoa/iterator/Outer.php',
'Hoa\\Iterator\\Recursive\\CallbackFilter' => __DIR__ . '/..' . '/hoa/iterator/Recursive/CallbackFilter.php',
'Hoa\\Iterator\\Recursive\\Directory' => __DIR__ . '/..' . '/hoa/iterator/Recursive/Directory.php',
'Hoa\\Iterator\\Recursive\\Filter' => __DIR__ . '/..' . '/hoa/iterator/Recursive/Filter.php',
'Hoa\\Iterator\\Recursive\\Iterator' => __DIR__ . '/..' . '/hoa/iterator/Recursive/Iterator.php',
'Hoa\\Iterator\\Recursive\\Map' => __DIR__ . '/..' . '/hoa/iterator/Recursive/Map.php',
'Hoa\\Iterator\\Recursive\\Mock' => __DIR__ . '/..' . '/hoa/iterator/Recursive/Mock.php',
'Hoa\\Iterator\\Recursive\\Recursive' => __DIR__ . '/..' . '/hoa/iterator/Recursive/Recursive.php',
'Hoa\\Iterator\\Recursive\\RegularExpression' => __DIR__ . '/..' . '/hoa/iterator/Recursive/RegularExpression.php',
'Hoa\\Iterator\\RegularExpression' => __DIR__ . '/..' . '/hoa/iterator/RegularExpression.php',
'Hoa\\Iterator\\Repeater' => __DIR__ . '/..' . '/hoa/iterator/Repeater.php',
'Hoa\\Iterator\\Seekable' => __DIR__ . '/..' . '/hoa/iterator/Seekable.php',
'Hoa\\Iterator\\SplFileInfo' => __DIR__ . '/..' . '/hoa/iterator/SplFileInfo.php',
'Hoa\\Iterator\\Test\\Unit\\Append' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/Append.php',
'Hoa\\Iterator\\Test\\Unit\\Buffer' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/Buffer.php',
'Hoa\\Iterator\\Test\\Unit\\CallbackFilter' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/CallbackFilter.php',
'Hoa\\Iterator\\Test\\Unit\\CallbackGenerator' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/CallbackGenerator.php',
'Hoa\\Iterator\\Test\\Unit\\Counter' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/Counter.php',
'Hoa\\Iterator\\Test\\Unit\\Demultiplexer' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/Demultiplexer.php',
'Hoa\\Iterator\\Test\\Unit\\Directory' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/Directory.php',
'Hoa\\Iterator\\Test\\Unit\\FileSystem' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/FileSystem.php',
'Hoa\\Iterator\\Test\\Unit\\Filter' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/Filter.php',
'Hoa\\Iterator\\Test\\Unit\\Infinite' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/Infinite.php',
'Hoa\\Iterator\\Test\\Unit\\IteratorIterator' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/IteratorIterator.php',
'Hoa\\Iterator\\Test\\Unit\\Limit' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/Limit.php',
'Hoa\\Iterator\\Test\\Unit\\Lookahead' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/Lookahead.php',
'Hoa\\Iterator\\Test\\Unit\\Lookbehind' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/Lookbehind.php',
'Hoa\\Iterator\\Test\\Unit\\Map' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/Map.php',
'Hoa\\Iterator\\Test\\Unit\\Mock' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/Mock.php',
'Hoa\\Iterator\\Test\\Unit\\Multiple' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/Multiple.php',
'Hoa\\Iterator\\Test\\Unit\\NoRewind' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/NoRewind.php',
'Hoa\\Iterator\\Test\\Unit\\RegularExpression' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/RegularExpression.php',
'Hoa\\Iterator\\Test\\Unit\\Repeater' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/Repeater.php',
'Hoa\\Iterator\\Test\\Unit\\SplFileInfo' => __DIR__ . '/..' . '/hoa/iterator/Test/Unit/SplFileInfo.php',
'Hoa\\Protocol\\Bin\\Resolve' => __DIR__ . '/..' . '/hoa/protocol/Bin/Resolve.php',
'Hoa\\Protocol\\Exception' => __DIR__ . '/..' . '/hoa/protocol/Exception.php',
'Hoa\\Protocol\\Node\\Library' => __DIR__ . '/..' . '/hoa/protocol/Node/Library.php',
'Hoa\\Protocol\\Node\\Node' => __DIR__ . '/..' . '/hoa/protocol/Node/Node.php',
'Hoa\\Protocol\\Protocol' => __DIR__ . '/..' . '/hoa/protocol/Protocol.php',
'Hoa\\Protocol\\Test\\Unit\\Exception' => __DIR__ . '/..' . '/hoa/protocol/Test/Unit/Exception.php',
'Hoa\\Protocol\\Test\\Unit\\Node\\Library' => __DIR__ . '/..' . '/hoa/protocol/Test/Unit/Node/Library.php',
'Hoa\\Protocol\\Test\\Unit\\Node\\Node' => __DIR__ . '/..' . '/hoa/protocol/Test/Unit/Node/Node.php',
'Hoa\\Protocol\\Test\\Unit\\Protocol' => __DIR__ . '/..' . '/hoa/protocol/Test/Unit/Protocol.php',
'Hoa\\Protocol\\Test\\Unit\\Wrapper' => __DIR__ . '/..' . '/hoa/protocol/Test/Unit/Wrapper.php',
'Hoa\\Protocol\\Wrapper' => __DIR__ . '/..' . '/hoa/protocol/Wrapper.php',
'Hoa\\Stream\\Bucket' => __DIR__ . '/..' . '/hoa/stream/Bucket.php',
'Hoa\\Stream\\Composite' => __DIR__ . '/..' . '/hoa/stream/Composite.php',
'Hoa\\Stream\\Context' => __DIR__ . '/..' . '/hoa/stream/Context.php',
'Hoa\\Stream\\Exception' => __DIR__ . '/..' . '/hoa/stream/Exception.php',
'Hoa\\Stream\\Filter\\Basic' => __DIR__ . '/..' . '/hoa/stream/Filter/Basic.php',
'Hoa\\Stream\\Filter\\Exception' => __DIR__ . '/..' . '/hoa/stream/Filter/Exception.php',
'Hoa\\Stream\\Filter\\Filter' => __DIR__ . '/..' . '/hoa/stream/Filter/Filter.php',
'Hoa\\Stream\\Filter\\LateComputed' => __DIR__ . '/..' . '/hoa/stream/Filter/LateComputed.php',
'Hoa\\Stream\\IStream\\Bufferable' => __DIR__ . '/..' . '/hoa/stream/IStream/Bufferable.php',
'Hoa\\Stream\\IStream\\In' => __DIR__ . '/..' . '/hoa/stream/IStream/In.php',
'Hoa\\Stream\\IStream\\Lockable' => __DIR__ . '/..' . '/hoa/stream/IStream/Lockable.php',
'Hoa\\Stream\\IStream\\Out' => __DIR__ . '/..' . '/hoa/stream/IStream/Out.php',
'Hoa\\Stream\\IStream\\Pathable' => __DIR__ . '/..' . '/hoa/stream/IStream/Pathable.php',
'Hoa\\Stream\\IStream\\Pointable' => __DIR__ . '/..' . '/hoa/stream/IStream/Pointable.php',
'Hoa\\Stream\\IStream\\Statable' => __DIR__ . '/..' . '/hoa/stream/IStream/Statable.php',
'Hoa\\Stream\\IStream\\Stream' => __DIR__ . '/..' . '/hoa/stream/IStream/Stream.php',
'Hoa\\Stream\\IStream\\Structural' => __DIR__ . '/..' . '/hoa/stream/IStream/Structural.php',
'Hoa\\Stream\\IStream\\Touchable' => __DIR__ . '/..' . '/hoa/stream/IStream/Touchable.php',
'Hoa\\Stream\\Stream' => __DIR__ . '/..' . '/hoa/stream/Stream.php',
'Hoa\\Stream\\Test\\Integration\\Filter\\Filter' => __DIR__ . '/..' . '/hoa/stream/Test/Integration/Filter/Filter.php',
'Hoa\\Stream\\Test\\Integration\\Filter\\LateComputed' => __DIR__ . '/..' . '/hoa/stream/Test/Integration/Filter/LateComputed.php',
'Hoa\\Stream\\Test\\Integration\\Stream' => __DIR__ . '/..' . '/hoa/stream/Test/Integration/Stream.php',
'Hoa\\Stream\\Test\\Unit\\Bucket' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/Bucket.php',
'Hoa\\Stream\\Test\\Unit\\Composite' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/Composite.php',
'Hoa\\Stream\\Test\\Unit\\Context' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/Context.php',
'Hoa\\Stream\\Test\\Unit\\Exception' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/Exception.php',
'Hoa\\Stream\\Test\\Unit\\Filter\\Basic' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/Filter/Basic.php',
'Hoa\\Stream\\Test\\Unit\\Filter\\Exception' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/Filter/Exception.php',
'Hoa\\Stream\\Test\\Unit\\Filter\\Filter' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/Filter/Filter.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Bufferable' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/IStream/Bufferable.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\In' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/IStream/In.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Lockable' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/IStream/Lockable.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Out' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/IStream/Out.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Pathable' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/IStream/Pathable.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Pointable' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/IStream/Pointable.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Statable' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/IStream/Statable.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Stream' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/IStream/Stream.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Structural' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/IStream/Structural.php',
'Hoa\\Stream\\Test\\Unit\\IStream\\Touchable' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/IStream/Touchable.php',
'Hoa\\Stream\\Test\\Unit\\Stream' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/Stream.php',
'Hoa\\Stream\\Test\\Unit\\Wrapper\\Exception' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/Wrapper/Exception.php',
'Hoa\\Stream\\Test\\Unit\\Wrapper\\IWrapper\\File' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/Wrapper/IWrapper/File.php',
'Hoa\\Stream\\Test\\Unit\\Wrapper\\IWrapper\\IWrapper' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/Wrapper/IWrapper/IWrapper.php',
'Hoa\\Stream\\Test\\Unit\\Wrapper\\IWrapper\\Stream' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/Wrapper/IWrapper/Stream.php',
'Hoa\\Stream\\Test\\Unit\\Wrapper\\Wrapper' => __DIR__ . '/..' . '/hoa/stream/Test/Unit/Wrapper/Wrapper.php',
'Hoa\\Stream\\Wrapper\\Exception' => __DIR__ . '/..' . '/hoa/stream/Wrapper/Exception.php',
'Hoa\\Stream\\Wrapper\\IWrapper\\File' => __DIR__ . '/..' . '/hoa/stream/Wrapper/IWrapper/File.php',
'Hoa\\Stream\\Wrapper\\IWrapper\\IWrapper' => __DIR__ . '/..' . '/hoa/stream/Wrapper/IWrapper/IWrapper.php',
'Hoa\\Stream\\Wrapper\\IWrapper\\Stream' => __DIR__ . '/..' . '/hoa/stream/Wrapper/IWrapper/Stream.php',
'Hoa\\Stream\\Wrapper\\Wrapper' => __DIR__ . '/..' . '/hoa/stream/Wrapper/Wrapper.php',
'Hoa\\Ustring\\Bin\\Fromcode' => __DIR__ . '/..' . '/hoa/ustring/Bin/Fromcode.php',
'Hoa\\Ustring\\Bin\\Tocode' => __DIR__ . '/..' . '/hoa/ustring/Bin/Tocode.php',
'Hoa\\Ustring\\Exception' => __DIR__ . '/..' . '/hoa/ustring/Exception.php',
'Hoa\\Ustring\\Search' => __DIR__ . '/..' . '/hoa/ustring/Search.php',
'Hoa\\Ustring\\Test\\Unit\\Issue' => __DIR__ . '/..' . '/hoa/ustring/Test/Unit/Issue.php',
'Hoa\\Ustring\\Test\\Unit\\Search' => __DIR__ . '/..' . '/hoa/ustring/Test/Unit/Search.php',
'Hoa\\Ustring\\Test\\Unit\\Ustring' => __DIR__ . '/..' . '/hoa/ustring/Test/Unit/Ustring.php',
'Hoa\\Ustring\\Ustring' => __DIR__ . '/..' . '/hoa/ustring/Ustring.php',
'Humbug\\FileGetContents' => __DIR__ . '/..' . '/padraic/humbug_get_contents/src/FileGetContents.php',
'Humbug\\SelfUpdate\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/padraic/phar-updater/src/Exception/ExceptionInterface.php',
'Humbug\\SelfUpdate\\Exception\\FilesystemException' => __DIR__ . '/..' . '/padraic/phar-updater/src/Exception/FilesystemException.php',
'Humbug\\SelfUpdate\\Exception\\HttpRequestException' => __DIR__ . '/..' . '/padraic/phar-updater/src/Exception/HttpRequestException.php',
'Humbug\\SelfUpdate\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/padraic/phar-updater/src/Exception/InvalidArgumentException.php',
'Humbug\\SelfUpdate\\Exception\\JsonParsingException' => __DIR__ . '/..' . '/padraic/phar-updater/src/Exception/JsonParsingException.php',
'Humbug\\SelfUpdate\\Exception\\NoSignatureException' => __DIR__ . '/..' . '/padraic/phar-updater/src/Exception/NoSignatureException.php',
'Humbug\\SelfUpdate\\Exception\\RuntimeException' => __DIR__ . '/..' . '/padraic/phar-updater/src/Exception/RuntimeException.php',
'Humbug\\SelfUpdate\\Strategy\\GithubStrategy' => __DIR__ . '/..' . '/padraic/phar-updater/src/Strategy/GithubStrategy.php',
'Humbug\\SelfUpdate\\Strategy\\ShaStrategy' => __DIR__ . '/..' . '/padraic/phar-updater/src/Strategy/ShaStrategy.php',
'Humbug\\SelfUpdate\\Strategy\\StrategyInterface' => __DIR__ . '/..' . '/padraic/phar-updater/src/Strategy/StrategyInterface.php',
'Humbug\\SelfUpdate\\Updater' => __DIR__ . '/..' . '/padraic/phar-updater/src/Updater.php',
'Humbug\\SelfUpdate\\VersionParser' => __DIR__ . '/..' . '/padraic/phar-updater/src/VersionParser.php',
'JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
'JsonSchema\\Constraints\\BaseConstraint' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Constraints/BaseConstraint.php',
'JsonSchema\\Constraints\\CollectionConstraint' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Constraints/CollectionConstraint.php',
'JsonSchema\\Constraints\\Constraint' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Constraints/Constraint.php',
'JsonSchema\\Constraints\\ConstraintInterface' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Constraints/ConstraintInterface.php',
'JsonSchema\\Constraints\\EnumConstraint' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Constraints/EnumConstraint.php',
'JsonSchema\\Constraints\\Factory' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Constraints/Factory.php',
'JsonSchema\\Constraints\\FormatConstraint' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Constraints/FormatConstraint.php',
'JsonSchema\\Constraints\\NumberConstraint' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Constraints/NumberConstraint.php',
'JsonSchema\\Constraints\\ObjectConstraint' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Constraints/ObjectConstraint.php',
'JsonSchema\\Constraints\\SchemaConstraint' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Constraints/SchemaConstraint.php',
'JsonSchema\\Constraints\\StringConstraint' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Constraints/StringConstraint.php',
'JsonSchema\\Constraints\\TypeCheck\\LooseTypeCheck' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeCheck/LooseTypeCheck.php',
'JsonSchema\\Constraints\\TypeCheck\\StrictTypeCheck' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeCheck/StrictTypeCheck.php',
'JsonSchema\\Constraints\\TypeCheck\\TypeCheckInterface' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeCheck/TypeCheckInterface.php',
'JsonSchema\\Constraints\\TypeConstraint' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeConstraint.php',
'JsonSchema\\Constraints\\UndefinedConstraint' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Constraints/UndefinedConstraint.php',
'JsonSchema\\Entity\\JsonPointer' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Entity/JsonPointer.php',
'JsonSchema\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Exception/ExceptionInterface.php',
'JsonSchema\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidArgumentException.php',
'JsonSchema\\Exception\\InvalidConfigException' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidConfigException.php',
'JsonSchema\\Exception\\InvalidSchemaException' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidSchemaException.php',
'JsonSchema\\Exception\\InvalidSchemaMediaTypeException' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidSchemaMediaTypeException.php',
'JsonSchema\\Exception\\InvalidSourceUriException' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidSourceUriException.php',
'JsonSchema\\Exception\\JsonDecodingException' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Exception/JsonDecodingException.php',
'JsonSchema\\Exception\\ResourceNotFoundException' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Exception/ResourceNotFoundException.php',
'JsonSchema\\Exception\\RuntimeException' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Exception/RuntimeException.php',
'JsonSchema\\Exception\\UnresolvableJsonPointerException' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Exception/UnresolvableJsonPointerException.php',
'JsonSchema\\Exception\\UriResolverException' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Exception/UriResolverException.php',
'JsonSchema\\Exception\\ValidationException' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Exception/ValidationException.php',
'JsonSchema\\Iterator\\ObjectIterator' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Iterator/ObjectIterator.php',
'JsonSchema\\Rfc3339' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Rfc3339.php',
'JsonSchema\\SchemaStorage' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/SchemaStorage.php',
'JsonSchema\\SchemaStorageInterface' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/SchemaStorageInterface.php',
'JsonSchema\\UriResolverInterface' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/UriResolverInterface.php',
'JsonSchema\\UriRetrieverInterface' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/UriRetrieverInterface.php',
'JsonSchema\\Uri\\Retrievers\\AbstractRetriever' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/AbstractRetriever.php',
'JsonSchema\\Uri\\Retrievers\\Curl' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/Curl.php',
'JsonSchema\\Uri\\Retrievers\\FileGetContents' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/FileGetContents.php',
'JsonSchema\\Uri\\Retrievers\\PredefinedArray' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/PredefinedArray.php',
'JsonSchema\\Uri\\Retrievers\\UriRetrieverInterface' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/UriRetrieverInterface.php',
'JsonSchema\\Uri\\UriResolver' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Uri/UriResolver.php',
'JsonSchema\\Uri\\UriRetriever' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Uri/UriRetriever.php',
'JsonSchema\\Validator' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Validator.php',
'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'PHPUnit\\Exception' => __DIR__ . '/..' . '/phpunit/phpunit/src/Exception.php',
'PHPUnit\\Framework\\Assert' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Assert.php',
'PHPUnit\\Framework\\AssertionFailedError' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/AssertionFailedError.php',
'PHPUnit\\Framework\\CodeCoverageException' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/CodeCoverageException.php',
'PHPUnit\\Framework\\Constraint\\ArrayHasKey' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/ArrayHasKey.php',
'PHPUnit\\Framework\\Constraint\\ArraySubset' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/ArraySubset.php',
'PHPUnit\\Framework\\Constraint\\Attribute' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Attribute.php',
'PHPUnit\\Framework\\Constraint\\Callback' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Callback.php',
'PHPUnit\\Framework\\Constraint\\ClassHasAttribute' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/ClassHasAttribute.php',
'PHPUnit\\Framework\\Constraint\\ClassHasStaticAttribute' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/ClassHasStaticAttribute.php',
'PHPUnit\\Framework\\Constraint\\Composite' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Composite.php',
'PHPUnit\\Framework\\Constraint\\Constraint' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Constraint.php',
'PHPUnit\\Framework\\Constraint\\Count' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Count.php',
'PHPUnit\\Framework\\Constraint\\DirectoryExists' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/DirectoryExists.php',
'PHPUnit\\Framework\\Constraint\\Exception' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Exception.php',
'PHPUnit\\Framework\\Constraint\\ExceptionCode' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/ExceptionCode.php',
'PHPUnit\\Framework\\Constraint\\ExceptionMessage' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/ExceptionMessage.php',
'PHPUnit\\Framework\\Constraint\\ExceptionMessageRegularExpression' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/ExceptionMessageRegularExpression.php',
'PHPUnit\\Framework\\Constraint\\FileExists' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/FileExists.php',
'PHPUnit\\Framework\\Constraint\\GreaterThan' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/GreaterThan.php',
'PHPUnit\\Framework\\Constraint\\IsAnything' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/IsAnything.php',
'PHPUnit\\Framework\\Constraint\\IsEmpty' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/IsEmpty.php',
'PHPUnit\\Framework\\Constraint\\IsEqual' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/IsEqual.php',
'PHPUnit\\Framework\\Constraint\\IsFalse' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/IsFalse.php',
'PHPUnit\\Framework\\Constraint\\IsFinite' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/IsFinite.php',
'PHPUnit\\Framework\\Constraint\\IsIdentical' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php',
'PHPUnit\\Framework\\Constraint\\IsInfinite' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/IsInfinite.php',
'PHPUnit\\Framework\\Constraint\\IsInstanceOf' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/IsInstanceOf.php',
'PHPUnit\\Framework\\Constraint\\IsJson' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/IsJson.php',
'PHPUnit\\Framework\\Constraint\\IsNan' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/IsNan.php',
'PHPUnit\\Framework\\Constraint\\IsNull' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/IsNull.php',
'PHPUnit\\Framework\\Constraint\\IsReadable' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/IsReadable.php',
'PHPUnit\\Framework\\Constraint\\IsTrue' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/IsTrue.php',
'PHPUnit\\Framework\\Constraint\\IsType' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/IsType.php',
'PHPUnit\\Framework\\Constraint\\IsWritable' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/IsWritable.php',
'PHPUnit\\Framework\\Constraint\\JsonMatches' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/JsonMatches.php',
'PHPUnit\\Framework\\Constraint\\JsonMatchesErrorMessageProvider' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/JsonMatchesErrorMessageProvider.php',
'PHPUnit\\Framework\\Constraint\\LessThan' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/LessThan.php',
'PHPUnit\\Framework\\Constraint\\LogicalAnd' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/LogicalAnd.php',
'PHPUnit\\Framework\\Constraint\\LogicalNot' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/LogicalNot.php',
'PHPUnit\\Framework\\Constraint\\LogicalOr' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/LogicalOr.php',
'PHPUnit\\Framework\\Constraint\\LogicalXor' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/LogicalXor.php',
'PHPUnit\\Framework\\Constraint\\ObjectHasAttribute' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/ObjectHasAttribute.php',
'PHPUnit\\Framework\\Constraint\\RegularExpression' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/RegularExpression.php',
'PHPUnit\\Framework\\Constraint\\SameSize' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/SameSize.php',
'PHPUnit\\Framework\\Constraint\\StringContains' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/StringContains.php',
'PHPUnit\\Framework\\Constraint\\StringEndsWith' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/StringEndsWith.php',
'PHPUnit\\Framework\\Constraint\\StringMatchesFormatDescription' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/StringMatchesFormatDescription.php',
'PHPUnit\\Framework\\Constraint\\StringStartsWith' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/StringStartsWith.php',
'PHPUnit\\Framework\\Constraint\\TraversableContains' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/TraversableContains.php',
'PHPUnit\\Framework\\Constraint\\TraversableContainsEqual' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/TraversableContainsEqual.php',
'PHPUnit\\Framework\\Constraint\\TraversableContainsIdentical' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/TraversableContainsIdentical.php',
'PHPUnit\\Framework\\Constraint\\TraversableContainsOnly' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/TraversableContainsOnly.php',
'PHPUnit\\Framework\\CoveredCodeNotExecutedException' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/CoveredCodeNotExecutedException.php',
'PHPUnit\\Framework\\DataProviderTestSuite' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/DataProviderTestSuite.php',
'PHPUnit\\Framework\\Error\\Deprecated' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Error/Deprecated.php',
'PHPUnit\\Framework\\Error\\Error' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Error/Error.php',
'PHPUnit\\Framework\\Error\\Notice' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Error/Notice.php',
'PHPUnit\\Framework\\Error\\Warning' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Error/Warning.php',
'PHPUnit\\Framework\\Exception' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/Exception.php',
'PHPUnit\\Framework\\ExceptionWrapper' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/ExceptionWrapper.php',
'PHPUnit\\Framework\\ExpectationFailedException' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/ExpectationFailedException.php',
'PHPUnit\\Framework\\IncompleteTest' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/IncompleteTest.php',
'PHPUnit\\Framework\\IncompleteTestCase' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/IncompleteTestCase.php',
'PHPUnit\\Framework\\IncompleteTestError' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/IncompleteTestError.php',
'PHPUnit\\Framework\\InvalidArgumentException' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/InvalidArgumentException.php',
'PHPUnit\\Framework\\InvalidCoversTargetException' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/InvalidCoversTargetException.php',
'PHPUnit\\Framework\\InvalidDataProviderException' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/InvalidDataProviderException.php',
'PHPUnit\\Framework\\InvalidParameterGroupException' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/InvalidParameterGroupException.php',
'PHPUnit\\Framework\\MissingCoversAnnotationException' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/MissingCoversAnnotationException.php',
'PHPUnit\\Framework\\MockObject\\Api' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Api/Api.php',
'PHPUnit\\Framework\\MockObject\\BadMethodCallException' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Exception/BadMethodCallException.php',
'PHPUnit\\Framework\\MockObject\\Builder\\Identity' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Builder/Identity.php',
'PHPUnit\\Framework\\MockObject\\Builder\\InvocationMocker' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationMocker.php',
'PHPUnit\\Framework\\MockObject\\Builder\\InvocationStubber' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationStubber.php',
'PHPUnit\\Framework\\MockObject\\Builder\\Match_' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Builder/Match_.php',
'PHPUnit\\Framework\\MockObject\\Builder\\MethodNameMatch' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Builder/MethodNameMatch.php',
'PHPUnit\\Framework\\MockObject\\Builder\\ParametersMatch' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Builder/ParametersMatch.php',
'PHPUnit\\Framework\\MockObject\\Builder\\Stub' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Builder/Stub.php',
'PHPUnit\\Framework\\MockObject\\ConfigurableMethod' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/ConfigurableMethod.php',
'PHPUnit\\Framework\\MockObject\\ConfigurableMethodsAlreadyInitializedException' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Exception/ConfigurableMethodsAlreadyInitializedException.php',
'PHPUnit\\Framework\\MockObject\\Exception' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Exception/Exception.php',
'PHPUnit\\Framework\\MockObject\\Generator' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Generator.php',
'PHPUnit\\Framework\\MockObject\\IncompatibleReturnValueException' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Exception/IncompatibleReturnValueException.php',
'PHPUnit\\Framework\\MockObject\\Invocation' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Invocation.php',
'PHPUnit\\Framework\\MockObject\\InvocationHandler' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/InvocationHandler.php',
'PHPUnit\\Framework\\MockObject\\Matcher' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Matcher.php',
'PHPUnit\\Framework\\MockObject\\Method' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Api/Method.php',
'PHPUnit\\Framework\\MockObject\\MethodNameConstraint' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/MethodNameConstraint.php',
'PHPUnit\\Framework\\MockObject\\MockBuilder' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/MockBuilder.php',
'PHPUnit\\Framework\\MockObject\\MockClass' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/MockClass.php',
'PHPUnit\\Framework\\MockObject\\MockMethod' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/MockMethod.php',
'PHPUnit\\Framework\\MockObject\\MockMethodSet' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/MockMethodSet.php',
'PHPUnit\\Framework\\MockObject\\MockObject' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/MockObject.php',
'PHPUnit\\Framework\\MockObject\\MockTrait' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/MockTrait.php',
'PHPUnit\\Framework\\MockObject\\MockType' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/MockType.php',
'PHPUnit\\Framework\\MockObject\\MockedCloneMethod' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Api/MockedCloneMethod.php',
'PHPUnit\\Framework\\MockObject\\Rule\\AnyInvokedCount' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Rule/AnyInvokedCount.php',
'PHPUnit\\Framework\\MockObject\\Rule\\AnyParameters' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Rule/AnyParameters.php',
'PHPUnit\\Framework\\MockObject\\Rule\\ConsecutiveParameters' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Rule/ConsecutiveParameters.php',
'PHPUnit\\Framework\\MockObject\\Rule\\InvocationOrder' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Rule/InvocationOrder.php',
'PHPUnit\\Framework\\MockObject\\Rule\\InvokedAtIndex' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtIndex.php',
'PHPUnit\\Framework\\MockObject\\Rule\\InvokedAtLeastCount' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtLeastCount.php',
'PHPUnit\\Framework\\MockObject\\Rule\\InvokedAtLeastOnce' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtLeastOnce.php',
'PHPUnit\\Framework\\MockObject\\Rule\\InvokedAtMostCount' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtMostCount.php',
'PHPUnit\\Framework\\MockObject\\Rule\\InvokedCount' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedCount.php',
'PHPUnit\\Framework\\MockObject\\Rule\\MethodName' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Rule/MethodName.php',
'PHPUnit\\Framework\\MockObject\\Rule\\Parameters' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Rule/Parameters.php',
'PHPUnit\\Framework\\MockObject\\Rule\\ParametersRule' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Rule/ParametersRule.php',
'PHPUnit\\Framework\\MockObject\\RuntimeException' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Exception/RuntimeException.php',
'PHPUnit\\Framework\\MockObject\\Stub' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Stub.php',
'PHPUnit\\Framework\\MockObject\\Stub\\ConsecutiveCalls' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Stub/ConsecutiveCalls.php',
'PHPUnit\\Framework\\MockObject\\Stub\\Exception' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Stub/Exception.php',
'PHPUnit\\Framework\\MockObject\\Stub\\ReturnArgument' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnArgument.php',
'PHPUnit\\Framework\\MockObject\\Stub\\ReturnCallback' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnCallback.php',
'PHPUnit\\Framework\\MockObject\\Stub\\ReturnReference' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnReference.php',
'PHPUnit\\Framework\\MockObject\\Stub\\ReturnSelf' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnSelf.php',
'PHPUnit\\Framework\\MockObject\\Stub\\ReturnStub' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnStub.php',
'PHPUnit\\Framework\\MockObject\\Stub\\ReturnValueMap' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnValueMap.php',
'PHPUnit\\Framework\\MockObject\\Stub\\Stub' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Stub/Stub.php',
'PHPUnit\\Framework\\MockObject\\UnmockedCloneMethod' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Api/UnmockedCloneMethod.php',
'PHPUnit\\Framework\\MockObject\\Verifiable' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/MockObject/Verifiable.php',
'PHPUnit\\Framework\\NoChildTestSuiteException' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/NoChildTestSuiteException.php',
'PHPUnit\\Framework\\OutputError' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/OutputError.php',
'PHPUnit\\Framework\\PHPTAssertionFailedError' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/PHPTAssertionFailedError.php',
'PHPUnit\\Framework\\RiskyTestError' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/RiskyTestError.php',
'PHPUnit\\Framework\\SelfDescribing' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/SelfDescribing.php',
'PHPUnit\\Framework\\SkippedTest' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/SkippedTest.php',
'PHPUnit\\Framework\\SkippedTestCase' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/SkippedTestCase.php',
'PHPUnit\\Framework\\SkippedTestError' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/SkippedTestError.php',
'PHPUnit\\Framework\\SkippedTestSuiteError' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/SkippedTestSuiteError.php',
'PHPUnit\\Framework\\SyntheticError' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/SyntheticError.php',
'PHPUnit\\Framework\\SyntheticSkippedError' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/SyntheticSkippedError.php',
'PHPUnit\\Framework\\Test' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Test.php',
'PHPUnit\\Framework\\TestBuilder' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/TestBuilder.php',
'PHPUnit\\Framework\\TestCase' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/TestCase.php',
'PHPUnit\\Framework\\TestFailure' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/TestFailure.php',
'PHPUnit\\Framework\\TestListener' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/TestListener.php',
'PHPUnit\\Framework\\TestListenerDefaultImplementation' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/TestListenerDefaultImplementation.php',
'PHPUnit\\Framework\\TestResult' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/TestResult.php',
'PHPUnit\\Framework\\TestSuite' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/TestSuite.php',
'PHPUnit\\Framework\\TestSuiteIterator' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/TestSuiteIterator.php',
'PHPUnit\\Framework\\UnintentionallyCoveredCodeError' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/UnintentionallyCoveredCodeError.php',
'PHPUnit\\Framework\\Warning' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Exception/Warning.php',
'PHPUnit\\Framework\\WarningTestCase' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/WarningTestCase.php',
'PHPUnit\\Runner\\AfterIncompleteTestHook' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Hook/AfterIncompleteTestHook.php',
'PHPUnit\\Runner\\AfterLastTestHook' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Hook/AfterLastTestHook.php',
'PHPUnit\\Runner\\AfterRiskyTestHook' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Hook/AfterRiskyTestHook.php',
'PHPUnit\\Runner\\AfterSkippedTestHook' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Hook/AfterSkippedTestHook.php',
'PHPUnit\\Runner\\AfterSuccessfulTestHook' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Hook/AfterSuccessfulTestHook.php',
'PHPUnit\\Runner\\AfterTestErrorHook' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Hook/AfterTestErrorHook.php',
'PHPUnit\\Runner\\AfterTestFailureHook' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Hook/AfterTestFailureHook.php',
'PHPUnit\\Runner\\AfterTestHook' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Hook/AfterTestHook.php',
'PHPUnit\\Runner\\AfterTestWarningHook' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Hook/AfterTestWarningHook.php',
'PHPUnit\\Runner\\BaseTestRunner' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/BaseTestRunner.php',
'PHPUnit\\Runner\\BeforeFirstTestHook' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Hook/BeforeFirstTestHook.php',
'PHPUnit\\Runner\\BeforeTestHook' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Hook/BeforeTestHook.php',
'PHPUnit\\Runner\\DefaultTestResultCache' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/DefaultTestResultCache.php',
'PHPUnit\\Runner\\Exception' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Exception.php',
'PHPUnit\\Runner\\Filter\\ExcludeGroupFilterIterator' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Filter/ExcludeGroupFilterIterator.php',
'PHPUnit\\Runner\\Filter\\Factory' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Filter/Factory.php',
'PHPUnit\\Runner\\Filter\\GroupFilterIterator' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Filter/GroupFilterIterator.php',
'PHPUnit\\Runner\\Filter\\IncludeGroupFilterIterator' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Filter/IncludeGroupFilterIterator.php',
'PHPUnit\\Runner\\Filter\\NameFilterIterator' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Filter/NameFilterIterator.php',
'PHPUnit\\Runner\\Hook' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Hook/Hook.php',
'PHPUnit\\Runner\\NullTestResultCache' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/NullTestResultCache.php',
'PHPUnit\\Runner\\PhptTestCase' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/PhptTestCase.php',
'PHPUnit\\Runner\\ResultCacheExtension' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/ResultCacheExtension.php',
'PHPUnit\\Runner\\StandardTestSuiteLoader' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/StandardTestSuiteLoader.php',
'PHPUnit\\Runner\\TestHook' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Hook/TestHook.php',
'PHPUnit\\Runner\\TestListenerAdapter' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Hook/TestListenerAdapter.php',
'PHPUnit\\Runner\\TestResultCache' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/TestResultCache.php',
'PHPUnit\\Runner\\TestSuiteLoader' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/TestSuiteLoader.php',
'PHPUnit\\Runner\\TestSuiteSorter' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/TestSuiteSorter.php',
'PHPUnit\\Runner\\Version' => __DIR__ . '/..' . '/phpunit/phpunit/src/Runner/Version.php',
'PHPUnit\\TextUI\\Command' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/Command.php',
'PHPUnit\\TextUI\\Exception' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/Exception.php',
'PHPUnit\\TextUI\\Help' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/Help.php',
'PHPUnit\\TextUI\\ResultPrinter' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/ResultPrinter.php',
'PHPUnit\\TextUI\\TestRunner' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/TestRunner.php',
'PHPUnit\\Util\\Annotation\\DocBlock' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Annotation/DocBlock.php',
'PHPUnit\\Util\\Annotation\\Registry' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Annotation/Registry.php',
'PHPUnit\\Util\\Blacklist' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Blacklist.php',
'PHPUnit\\Util\\Color' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Color.php',
'PHPUnit\\Util\\Configuration' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Configuration.php',
'PHPUnit\\Util\\ConfigurationGenerator' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/ConfigurationGenerator.php',
'PHPUnit\\Util\\ErrorHandler' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/ErrorHandler.php',
'PHPUnit\\Util\\Exception' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Exception.php',
'PHPUnit\\Util\\FileLoader' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/FileLoader.php',
'PHPUnit\\Util\\Filesystem' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Filesystem.php',
'PHPUnit\\Util\\Filter' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Filter.php',
'PHPUnit\\Util\\Getopt' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Getopt.php',
'PHPUnit\\Util\\GlobalState' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/GlobalState.php',
'PHPUnit\\Util\\InvalidDataSetException' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/InvalidDataSetException.php',
'PHPUnit\\Util\\Json' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Json.php',
'PHPUnit\\Util\\Log\\JUnit' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Log/JUnit.php',
'PHPUnit\\Util\\Log\\TeamCity' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Log/TeamCity.php',
'PHPUnit\\Util\\PHP\\AbstractPhpProcess' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php',
'PHPUnit\\Util\\PHP\\DefaultPhpProcess' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/PHP/DefaultPhpProcess.php',
'PHPUnit\\Util\\PHP\\WindowsPhpProcess' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/PHP/WindowsPhpProcess.php',
'PHPUnit\\Util\\Printer' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Printer.php',
'PHPUnit\\Util\\RegularExpression' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/RegularExpression.php',
'PHPUnit\\Util\\Test' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Test.php',
'PHPUnit\\Util\\TestDox\\CliTestDoxPrinter' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php',
'PHPUnit\\Util\\TestDox\\HtmlResultPrinter' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/TestDox/HtmlResultPrinter.php',
'PHPUnit\\Util\\TestDox\\NamePrettifier' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/TestDox/NamePrettifier.php',
'PHPUnit\\Util\\TestDox\\ResultPrinter' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/TestDox/ResultPrinter.php',
'PHPUnit\\Util\\TestDox\\TestDoxPrinter' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php',
'PHPUnit\\Util\\TestDox\\TextResultPrinter' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/TestDox/TextResultPrinter.php',
'PHPUnit\\Util\\TestDox\\XmlResultPrinter' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/TestDox/XmlResultPrinter.php',
'PHPUnit\\Util\\TextTestListRenderer' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/TextTestListRenderer.php',
'PHPUnit\\Util\\Type' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Type.php',
'PHPUnit\\Util\\VersionComparisonOperator' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/VersionComparisonOperator.php',
'PHPUnit\\Util\\XdebugFilterScriptGenerator' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/XdebugFilterScriptGenerator.php',
'PHPUnit\\Util\\Xml' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Xml.php',
'PHPUnit\\Util\\XmlTestListRenderer' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/XmlTestListRenderer.php',
'PHP_Token' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_TokenWithScope' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_TokenWithScopeAndVisibility' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ABSTRACT' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_AMPERSAND' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_AND_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ARRAY' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ARRAY_CAST' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_AS' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_AT' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_BACKTICK' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_BAD_CHARACTER' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_BOOLEAN_AND' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_BOOLEAN_OR' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_BOOL_CAST' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_BREAK' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CALLABLE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CARET' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CASE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CATCH' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CHARACTER' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CLASS' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CLASS_C' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CLASS_NAME_CONSTANT' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CLONE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CLOSE_BRACKET' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CLOSE_CURLY' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CLOSE_SQUARE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CLOSE_TAG' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_COALESCE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_COALESCE_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_COLON' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_COMMA' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_COMMENT' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CONCAT_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CONST' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CONSTANT_ENCAPSED_STRING' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CONTINUE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_CURLY_OPEN' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DEC' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DECLARE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DEFAULT' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DIR' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DIV' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DIV_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DNUMBER' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DO' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DOC_COMMENT' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DOLLAR' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DOLLAR_OPEN_CURLY_BRACES' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DOT' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DOUBLE_ARROW' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DOUBLE_CAST' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DOUBLE_COLON' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_DOUBLE_QUOTES' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ECHO' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ELLIPSIS' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ELSE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ELSEIF' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_EMPTY' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ENCAPSED_AND_WHITESPACE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ENDDECLARE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ENDFOR' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ENDFOREACH' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ENDIF' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ENDSWITCH' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ENDWHILE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_END_HEREDOC' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_EVAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_EXCLAMATION_MARK' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_EXIT' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_EXTENDS' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_FILE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_FINAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_FINALLY' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_FN' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_FOR' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_FOREACH' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_FUNCTION' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_FUNC_C' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_GLOBAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_GOTO' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_GT' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_HALT_COMPILER' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_IF' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_IMPLEMENTS' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_INC' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_INCLUDE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_INCLUDE_ONCE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_INLINE_HTML' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_INSTANCEOF' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_INSTEADOF' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_INTERFACE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_INT_CAST' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_ISSET' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_IS_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_IS_GREATER_OR_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_IS_IDENTICAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_IS_NOT_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_IS_NOT_IDENTICAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_IS_SMALLER_OR_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_Includes' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LINE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LIST' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LNUMBER' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LOGICAL_AND' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LOGICAL_OR' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LOGICAL_XOR' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LT' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_METHOD_C' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_MINUS' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_MINUS_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_MOD_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_MULT' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_MUL_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_NAMESPACE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_NEW' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_NS_C' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_NS_SEPARATOR' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_NUM_STRING' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_OBJECT_CAST' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_OBJECT_OPERATOR' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_OPEN_BRACKET' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_OPEN_CURLY' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_OPEN_SQUARE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_OPEN_TAG' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_OPEN_TAG_WITH_ECHO' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_OR_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PAAMAYIM_NEKUDOTAYIM' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PERCENT' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PIPE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PLUS' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PLUS_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_POW' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_POW_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PRINT' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PRIVATE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PROTECTED' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_PUBLIC' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_QUESTION_MARK' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_REQUIRE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_REQUIRE_ONCE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_RETURN' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_SEMICOLON' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_SL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_SL_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_SPACESHIP' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_SR' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_SR_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_START_HEREDOC' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_STATIC' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_STRING' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_STRING_CAST' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_STRING_VARNAME' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_SWITCH' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_Stream' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token/Stream.php',
'PHP_Token_Stream_CachingFactory' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token/Stream/CachingFactory.php',
'PHP_Token_THROW' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_TILDE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_TRAIT' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_TRAIT_C' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_TRY' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_UNSET' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_UNSET_CAST' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_USE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_USE_FUNCTION' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_Util' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token/Util.php',
'PHP_Token_VAR' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_VARIABLE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_WHILE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_WHITESPACE' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_XOR_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_YIELD' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_YIELD_FROM' => __DIR__ . '/..' . '/phpunit/php-token-stream/src/Token.php',
'PharIo\\Manifest\\Application' => __DIR__ . '/..' . '/phar-io/manifest/src/values/Application.php',
'PharIo\\Manifest\\ApplicationName' => __DIR__ . '/..' . '/phar-io/manifest/src/values/ApplicationName.php',
'PharIo\\Manifest\\Author' => __DIR__ . '/..' . '/phar-io/manifest/src/values/Author.php',
'PharIo\\Manifest\\AuthorCollection' => __DIR__ . '/..' . '/phar-io/manifest/src/values/AuthorCollection.php',
'PharIo\\Manifest\\AuthorCollectionIterator' => __DIR__ . '/..' . '/phar-io/manifest/src/values/AuthorCollectionIterator.php',
'PharIo\\Manifest\\AuthorElement' => __DIR__ . '/..' . '/phar-io/manifest/src/xml/AuthorElement.php',
'PharIo\\Manifest\\AuthorElementCollection' => __DIR__ . '/..' . '/phar-io/manifest/src/xml/AuthorElementCollection.php',
'PharIo\\Manifest\\BundledComponent' => __DIR__ . '/..' . '/phar-io/manifest/src/values/BundledComponent.php',
'PharIo\\Manifest\\BundledComponentCollection' => __DIR__ . '/..' . '/phar-io/manifest/src/values/BundledComponentCollection.php',
'PharIo\\Manifest\\BundledComponentCollectionIterator' => __DIR__ . '/..' . '/phar-io/manifest/src/values/BundledComponentCollectionIterator.php',
'PharIo\\Manifest\\BundlesElement' => __DIR__ . '/..' . '/phar-io/manifest/src/xml/BundlesElement.php',
'PharIo\\Manifest\\ComponentElement' => __DIR__ . '/..' . '/phar-io/manifest/src/xml/ComponentElement.php',
'PharIo\\Manifest\\ComponentElementCollection' => __DIR__ . '/..' . '/phar-io/manifest/src/xml/ComponentElementCollection.php',
'PharIo\\Manifest\\ContainsElement' => __DIR__ . '/..' . '/phar-io/manifest/src/xml/ContainsElement.php',
'PharIo\\Manifest\\CopyrightElement' => __DIR__ . '/..' . '/phar-io/manifest/src/xml/CopyrightElement.php',
'PharIo\\Manifest\\CopyrightInformation' => __DIR__ . '/..' . '/phar-io/manifest/src/values/CopyrightInformation.php',
'PharIo\\Manifest\\ElementCollection' => __DIR__ . '/..' . '/phar-io/manifest/src/xml/ElementCollection.php',
'PharIo\\Manifest\\ElementCollectionException' => __DIR__ . '/..' . '/phar-io/manifest/src/exceptions/ElementCollectionException.php',
'PharIo\\Manifest\\Email' => __DIR__ . '/..' . '/phar-io/manifest/src/values/Email.php',
'PharIo\\Manifest\\Exception' => __DIR__ . '/..' . '/phar-io/manifest/src/exceptions/Exception.php',
'PharIo\\Manifest\\ExtElement' => __DIR__ . '/..' . '/phar-io/manifest/src/xml/ExtElement.php',
'PharIo\\Manifest\\ExtElementCollection' => __DIR__ . '/..' . '/phar-io/manifest/src/xml/ExtElementCollection.php',
'PharIo\\Manifest\\Extension' => __DIR__ . '/..' . '/phar-io/manifest/src/values/Extension.php',
'PharIo\\Manifest\\ExtensionElement' => __DIR__ . '/..' . '/phar-io/manifest/src/xml/ExtensionElement.php',
'PharIo\\Manifest\\InvalidApplicationNameException' => __DIR__ . '/..' . '/phar-io/manifest/src/exceptions/InvalidApplicationNameException.php',
'PharIo\\Manifest\\InvalidEmailException' => __DIR__ . '/..' . '/phar-io/manifest/src/exceptions/InvalidEmailException.php',
'PharIo\\Manifest\\InvalidUrlException' => __DIR__ . '/..' . '/phar-io/manifest/src/exceptions/InvalidUrlException.php',
'PharIo\\Manifest\\Library' => __DIR__ . '/..' . '/phar-io/manifest/src/values/Library.php',
'PharIo\\Manifest\\License' => __DIR__ . '/..' . '/phar-io/manifest/src/values/License.php',
'PharIo\\Manifest\\LicenseElement' => __DIR__ . '/..' . '/phar-io/manifest/src/xml/LicenseElement.php',
'PharIo\\Manifest\\Manifest' => __DIR__ . '/..' . '/phar-io/manifest/src/values/Manifest.php',
'PharIo\\Manifest\\ManifestDocument' => __DIR__ . '/..' . '/phar-io/manifest/src/xml/ManifestDocument.php',
'PharIo\\Manifest\\ManifestDocumentException' => __DIR__ . '/..' . '/phar-io/manifest/src/exceptions/ManifestDocumentException.php',
'PharIo\\Manifest\\ManifestDocumentLoadingException' => __DIR__ . '/..' . '/phar-io/manifest/src/exceptions/ManifestDocumentLoadingException.php',
'PharIo\\Manifest\\ManifestDocumentMapper' => __DIR__ . '/..' . '/phar-io/manifest/src/ManifestDocumentMapper.php',
'PharIo\\Manifest\\ManifestDocumentMapperException' => __DIR__ . '/..' . '/phar-io/manifest/src/exceptions/ManifestDocumentMapperException.php',
'PharIo\\Manifest\\ManifestElement' => __DIR__ . '/..' . '/phar-io/manifest/src/xml/ManifestElement.php',
'PharIo\\Manifest\\ManifestElementException' => __DIR__ . '/..' . '/phar-io/manifest/src/exceptions/ManifestElementException.php',
'PharIo\\Manifest\\ManifestLoader' => __DIR__ . '/..' . '/phar-io/manifest/src/ManifestLoader.php',
'PharIo\\Manifest\\ManifestLoaderException' => __DIR__ . '/..' . '/phar-io/manifest/src/exceptions/ManifestLoaderException.php',
'PharIo\\Manifest\\ManifestSerializer' => __DIR__ . '/..' . '/phar-io/manifest/src/ManifestSerializer.php',
'PharIo\\Manifest\\PhpElement' => __DIR__ . '/..' . '/phar-io/manifest/src/xml/PhpElement.php',
'PharIo\\Manifest\\PhpExtensionRequirement' => __DIR__ . '/..' . '/phar-io/manifest/src/values/PhpExtensionRequirement.php',
'PharIo\\Manifest\\PhpVersionRequirement' => __DIR__ . '/..' . '/phar-io/manifest/src/values/PhpVersionRequirement.php',
'PharIo\\Manifest\\Requirement' => __DIR__ . '/..' . '/phar-io/manifest/src/values/Requirement.php',
'PharIo\\Manifest\\RequirementCollection' => __DIR__ . '/..' . '/phar-io/manifest/src/values/RequirementCollection.php',
'PharIo\\Manifest\\RequirementCollectionIterator' => __DIR__ . '/..' . '/phar-io/manifest/src/values/RequirementCollectionIterator.php',
'PharIo\\Manifest\\RequiresElement' => __DIR__ . '/..' . '/phar-io/manifest/src/xml/RequiresElement.php',
'PharIo\\Manifest\\Type' => __DIR__ . '/..' . '/phar-io/manifest/src/values/Type.php',
'PharIo\\Manifest\\Url' => __DIR__ . '/..' . '/phar-io/manifest/src/values/Url.php',
'PharIo\\Version\\AbstractVersionConstraint' => __DIR__ . '/..' . '/phar-io/version/src/constraints/AbstractVersionConstraint.php',
'PharIo\\Version\\AndVersionConstraintGroup' => __DIR__ . '/..' . '/phar-io/version/src/constraints/AndVersionConstraintGroup.php',
'PharIo\\Version\\AnyVersionConstraint' => __DIR__ . '/..' . '/phar-io/version/src/constraints/AnyVersionConstraint.php',
'PharIo\\Version\\ExactVersionConstraint' => __DIR__ . '/..' . '/phar-io/version/src/constraints/ExactVersionConstraint.php',
'PharIo\\Version\\Exception' => __DIR__ . '/..' . '/phar-io/version/src/exceptions/Exception.php',
'PharIo\\Version\\GreaterThanOrEqualToVersionConstraint' => __DIR__ . '/..' . '/phar-io/version/src/constraints/GreaterThanOrEqualToVersionConstraint.php',
'PharIo\\Version\\InvalidPreReleaseSuffixException' => __DIR__ . '/..' . '/phar-io/version/src/exceptions/InvalidPreReleaseSuffixException.php',
'PharIo\\Version\\InvalidVersionException' => __DIR__ . '/..' . '/phar-io/version/src/exceptions/InvalidVersionException.php',
'PharIo\\Version\\NoPreReleaseSuffixException' => __DIR__ . '/..' . '/phar-io/version/src/exceptions/NoPreReleaseSuffixException.php',
'PharIo\\Version\\OrVersionConstraintGroup' => __DIR__ . '/..' . '/phar-io/version/src/constraints/OrVersionConstraintGroup.php',
'PharIo\\Version\\PreReleaseSuffix' => __DIR__ . '/..' . '/phar-io/version/src/PreReleaseSuffix.php',
'PharIo\\Version\\SpecificMajorAndMinorVersionConstraint' => __DIR__ . '/..' . '/phar-io/version/src/constraints/SpecificMajorAndMinorVersionConstraint.php',
'PharIo\\Version\\SpecificMajorVersionConstraint' => __DIR__ . '/..' . '/phar-io/version/src/constraints/SpecificMajorVersionConstraint.php',
'PharIo\\Version\\UnsupportedVersionConstraintException' => __DIR__ . '/..' . '/phar-io/version/src/exceptions/UnsupportedVersionConstraintException.php',
'PharIo\\Version\\Version' => __DIR__ . '/..' . '/phar-io/version/src/Version.php',
'PharIo\\Version\\VersionConstraint' => __DIR__ . '/..' . '/phar-io/version/src/constraints/VersionConstraint.php',
'PharIo\\Version\\VersionConstraintParser' => __DIR__ . '/..' . '/phar-io/version/src/VersionConstraintParser.php',
'PharIo\\Version\\VersionConstraintValue' => __DIR__ . '/..' . '/phar-io/version/src/VersionConstraintValue.php',
'PharIo\\Version\\VersionNumber' => __DIR__ . '/..' . '/phar-io/version/src/VersionNumber.php',
'PhpAmqpLib\\Channel\\AMQPChannel' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Channel/AMQPChannel.php',
'PhpAmqpLib\\Channel\\AbstractChannel' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Channel/AbstractChannel.php',
'PhpAmqpLib\\Connection\\AMQPLazyConnection' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPLazyConnection.php',
'PhpAmqpLib\\Connection\\AMQPLazySSLConnection' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPLazySSLConnection.php',
'PhpAmqpLib\\Connection\\AMQPLazySocketConnection' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPLazySocketConnection.php',
'PhpAmqpLib\\Connection\\AMQPSSLConnection' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPSSLConnection.php',
'PhpAmqpLib\\Connection\\AMQPSocketConnection' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPSocketConnection.php',
'PhpAmqpLib\\Connection\\AMQPStreamConnection' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPStreamConnection.php',
'PhpAmqpLib\\Connection\\AbstractConnection' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AbstractConnection.php',
'PhpAmqpLib\\Connection\\Heartbeat\\PCNTLHeartbeatSender' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Connection/Heartbeat/PCNTLHeartbeatSender.php',
'PhpAmqpLib\\Exception\\AMQPBasicCancelException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPBasicCancelException.php',
'PhpAmqpLib\\Exception\\AMQPChannelClosedException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPChannelClosedException.php',
'PhpAmqpLib\\Exception\\AMQPConnectionBlockedException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPConnectionBlockedException.php',
'PhpAmqpLib\\Exception\\AMQPConnectionClosedException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPConnectionClosedException.php',
'PhpAmqpLib\\Exception\\AMQPDataReadException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPDataReadException.php',
'PhpAmqpLib\\Exception\\AMQPEmptyDeliveryTagException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPEmptyDeliveryTagException.php',
'PhpAmqpLib\\Exception\\AMQPExceptionInterface' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPExceptionInterface.php',
'PhpAmqpLib\\Exception\\AMQPHeartbeatMissedException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPHeartbeatMissedException.php',
'PhpAmqpLib\\Exception\\AMQPIOException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPIOException.php',
'PhpAmqpLib\\Exception\\AMQPIOWaitException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPIOWaitException.php',
'PhpAmqpLib\\Exception\\AMQPInvalidArgumentException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPInvalidArgumentException.php',
'PhpAmqpLib\\Exception\\AMQPInvalidFrameException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPInvalidFrameException.php',
'PhpAmqpLib\\Exception\\AMQPLogicException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPLogicException.php',
'PhpAmqpLib\\Exception\\AMQPNoDataException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPNoDataException.php',
'PhpAmqpLib\\Exception\\AMQPNotImplementedException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPNotImplementedException.php',
'PhpAmqpLib\\Exception\\AMQPOutOfBoundsException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPOutOfBoundsException.php',
'PhpAmqpLib\\Exception\\AMQPOutOfRangeException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPOutOfRangeException.php',
'PhpAmqpLib\\Exception\\AMQPProtocolChannelException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPProtocolChannelException.php',
'PhpAmqpLib\\Exception\\AMQPProtocolException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPProtocolException.php',
'PhpAmqpLib\\Exception\\AMQPRuntimeException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPRuntimeException.php',
'PhpAmqpLib\\Exception\\AMQPSocketException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPSocketException.php',
'PhpAmqpLib\\Exception\\AMQPTimeoutException' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPTimeoutException.php',
'PhpAmqpLib\\Exchange\\AMQPExchangeType' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Exchange/AMQPExchangeType.php',
'PhpAmqpLib\\Helper\\Assert' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Assert.php',
'PhpAmqpLib\\Helper\\BigInteger' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/BigInteger.php',
'PhpAmqpLib\\Helper\\DebugHelper' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/DebugHelper.php',
'PhpAmqpLib\\Helper\\MiscHelper' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/MiscHelper.php',
'PhpAmqpLib\\Helper\\Protocol\\MethodMap080' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/MethodMap080.php',
'PhpAmqpLib\\Helper\\Protocol\\MethodMap091' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/MethodMap091.php',
'PhpAmqpLib\\Helper\\Protocol\\Protocol080' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/Protocol080.php',
'PhpAmqpLib\\Helper\\Protocol\\Protocol091' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/Protocol091.php',
'PhpAmqpLib\\Helper\\Protocol\\Wait080' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/Wait080.php',
'PhpAmqpLib\\Helper\\Protocol\\Wait091' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/Wait091.php',
'PhpAmqpLib\\Helper\\SocketConstants' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Helper/SocketConstants.php',
'PhpAmqpLib\\Message\\AMQPMessage' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Message/AMQPMessage.php',
'PhpAmqpLib\\Package' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Package.php',
'PhpAmqpLib\\Wire\\AMQPAbstractCollection' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPAbstractCollection.php',
'PhpAmqpLib\\Wire\\AMQPArray' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPArray.php',
'PhpAmqpLib\\Wire\\AMQPDecimal' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPDecimal.php',
'PhpAmqpLib\\Wire\\AMQPReader' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPReader.php',
'PhpAmqpLib\\Wire\\AMQPTable' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPTable.php',
'PhpAmqpLib\\Wire\\AMQPWriter' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPWriter.php',
'PhpAmqpLib\\Wire\\AbstractClient' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AbstractClient.php',
'PhpAmqpLib\\Wire\\Constants' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/Constants.php',
'PhpAmqpLib\\Wire\\Constants080' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/Constants080.php',
'PhpAmqpLib\\Wire\\Constants091' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/Constants091.php',
'PhpAmqpLib\\Wire\\IO\\AbstractIO' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/IO/AbstractIO.php',
'PhpAmqpLib\\Wire\\IO\\SocketIO' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/IO/SocketIO.php',
'PhpAmqpLib\\Wire\\IO\\StreamIO' => __DIR__ . '/..' . '/php-amqplib/php-amqplib/PhpAmqpLib/Wire/IO/StreamIO.php',
'Predis\\Autoloader' => __DIR__ . '/..' . '/predis/predis/src/Autoloader.php',
'Predis\\Client' => __DIR__ . '/..' . '/predis/predis/src/Client.php',
'Predis\\ClientContextInterface' => __DIR__ . '/..' . '/predis/predis/src/ClientContextInterface.php',
'Predis\\ClientException' => __DIR__ . '/..' . '/predis/predis/src/ClientException.php',
'Predis\\ClientInterface' => __DIR__ . '/..' . '/predis/predis/src/ClientInterface.php',
'Predis\\Cluster\\ClusterStrategy' => __DIR__ . '/..' . '/predis/predis/src/Cluster/ClusterStrategy.php',
'Predis\\Cluster\\Distributor\\DistributorInterface' => __DIR__ . '/..' . '/predis/predis/src/Cluster/Distributor/DistributorInterface.php',
'Predis\\Cluster\\Distributor\\EmptyRingException' => __DIR__ . '/..' . '/predis/predis/src/Cluster/Distributor/EmptyRingException.php',
'Predis\\Cluster\\Distributor\\HashRing' => __DIR__ . '/..' . '/predis/predis/src/Cluster/Distributor/HashRing.php',
'Predis\\Cluster\\Distributor\\KetamaRing' => __DIR__ . '/..' . '/predis/predis/src/Cluster/Distributor/KetamaRing.php',
'Predis\\Cluster\\Hash\\CRC16' => __DIR__ . '/..' . '/predis/predis/src/Cluster/Hash/CRC16.php',
'Predis\\Cluster\\Hash\\HashGeneratorInterface' => __DIR__ . '/..' . '/predis/predis/src/Cluster/Hash/HashGeneratorInterface.php',
'Predis\\Cluster\\PredisStrategy' => __DIR__ . '/..' . '/predis/predis/src/Cluster/PredisStrategy.php',
'Predis\\Cluster\\RedisStrategy' => __DIR__ . '/..' . '/predis/predis/src/Cluster/RedisStrategy.php',
'Predis\\Cluster\\StrategyInterface' => __DIR__ . '/..' . '/predis/predis/src/Cluster/StrategyInterface.php',
'Predis\\Collection\\Iterator\\CursorBasedIterator' => __DIR__ . '/..' . '/predis/predis/src/Collection/Iterator/CursorBasedIterator.php',
'Predis\\Collection\\Iterator\\HashKey' => __DIR__ . '/..' . '/predis/predis/src/Collection/Iterator/HashKey.php',
'Predis\\Collection\\Iterator\\Keyspace' => __DIR__ . '/..' . '/predis/predis/src/Collection/Iterator/Keyspace.php',
'Predis\\Collection\\Iterator\\ListKey' => __DIR__ . '/..' . '/predis/predis/src/Collection/Iterator/ListKey.php',
'Predis\\Collection\\Iterator\\SetKey' => __DIR__ . '/..' . '/predis/predis/src/Collection/Iterator/SetKey.php',
'Predis\\Collection\\Iterator\\SortedSetKey' => __DIR__ . '/..' . '/predis/predis/src/Collection/Iterator/SortedSetKey.php',
'Predis\\Command\\Command' => __DIR__ . '/..' . '/predis/predis/src/Command/Command.php',
'Predis\\Command\\CommandInterface' => __DIR__ . '/..' . '/predis/predis/src/Command/CommandInterface.php',
'Predis\\Command\\ConnectionAuth' => __DIR__ . '/..' . '/predis/predis/src/Command/ConnectionAuth.php',
'Predis\\Command\\ConnectionEcho' => __DIR__ . '/..' . '/predis/predis/src/Command/ConnectionEcho.php',
'Predis\\Command\\ConnectionPing' => __DIR__ . '/..' . '/predis/predis/src/Command/ConnectionPing.php',
'Predis\\Command\\ConnectionQuit' => __DIR__ . '/..' . '/predis/predis/src/Command/ConnectionQuit.php',
'Predis\\Command\\ConnectionSelect' => __DIR__ . '/..' . '/predis/predis/src/Command/ConnectionSelect.php',
'Predis\\Command\\GeospatialGeoAdd' => __DIR__ . '/..' . '/predis/predis/src/Command/GeospatialGeoAdd.php',
'Predis\\Command\\GeospatialGeoDist' => __DIR__ . '/..' . '/predis/predis/src/Command/GeospatialGeoDist.php',
'Predis\\Command\\GeospatialGeoHash' => __DIR__ . '/..' . '/predis/predis/src/Command/GeospatialGeoHash.php',
'Predis\\Command\\GeospatialGeoPos' => __DIR__ . '/..' . '/predis/predis/src/Command/GeospatialGeoPos.php',
'Predis\\Command\\GeospatialGeoRadius' => __DIR__ . '/..' . '/predis/predis/src/Command/GeospatialGeoRadius.php',
'Predis\\Command\\GeospatialGeoRadiusByMember' => __DIR__ . '/..' . '/predis/predis/src/Command/GeospatialGeoRadiusByMember.php',
'Predis\\Command\\HashDelete' => __DIR__ . '/..' . '/predis/predis/src/Command/HashDelete.php',
'Predis\\Command\\HashExists' => __DIR__ . '/..' . '/predis/predis/src/Command/HashExists.php',
'Predis\\Command\\HashGet' => __DIR__ . '/..' . '/predis/predis/src/Command/HashGet.php',
'Predis\\Command\\HashGetAll' => __DIR__ . '/..' . '/predis/predis/src/Command/HashGetAll.php',
'Predis\\Command\\HashGetMultiple' => __DIR__ . '/..' . '/predis/predis/src/Command/HashGetMultiple.php',
'Predis\\Command\\HashIncrementBy' => __DIR__ . '/..' . '/predis/predis/src/Command/HashIncrementBy.php',
'Predis\\Command\\HashIncrementByFloat' => __DIR__ . '/..' . '/predis/predis/src/Command/HashIncrementByFloat.php',
'Predis\\Command\\HashKeys' => __DIR__ . '/..' . '/predis/predis/src/Command/HashKeys.php',
'Predis\\Command\\HashLength' => __DIR__ . '/..' . '/predis/predis/src/Command/HashLength.php',
'Predis\\Command\\HashScan' => __DIR__ . '/..' . '/predis/predis/src/Command/HashScan.php',
'Predis\\Command\\HashSet' => __DIR__ . '/..' . '/predis/predis/src/Command/HashSet.php',
'Predis\\Command\\HashSetMultiple' => __DIR__ . '/..' . '/predis/predis/src/Command/HashSetMultiple.php',
'Predis\\Command\\HashSetPreserve' => __DIR__ . '/..' . '/predis/predis/src/Command/HashSetPreserve.php',
'Predis\\Command\\HashStringLength' => __DIR__ . '/..' . '/predis/predis/src/Command/HashStringLength.php',
'Predis\\Command\\HashValues' => __DIR__ . '/..' . '/predis/predis/src/Command/HashValues.php',
'Predis\\Command\\HyperLogLogAdd' => __DIR__ . '/..' . '/predis/predis/src/Command/HyperLogLogAdd.php',
'Predis\\Command\\HyperLogLogCount' => __DIR__ . '/..' . '/predis/predis/src/Command/HyperLogLogCount.php',
'Predis\\Command\\HyperLogLogMerge' => __DIR__ . '/..' . '/predis/predis/src/Command/HyperLogLogMerge.php',
'Predis\\Command\\KeyDelete' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyDelete.php',
'Predis\\Command\\KeyDump' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyDump.php',
'Predis\\Command\\KeyExists' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyExists.php',
'Predis\\Command\\KeyExpire' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyExpire.php',
'Predis\\Command\\KeyExpireAt' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyExpireAt.php',
'Predis\\Command\\KeyKeys' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyKeys.php',
'Predis\\Command\\KeyMigrate' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyMigrate.php',
'Predis\\Command\\KeyMove' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyMove.php',
'Predis\\Command\\KeyPersist' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyPersist.php',
'Predis\\Command\\KeyPreciseExpire' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyPreciseExpire.php',
'Predis\\Command\\KeyPreciseExpireAt' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyPreciseExpireAt.php',
'Predis\\Command\\KeyPreciseTimeToLive' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyPreciseTimeToLive.php',
'Predis\\Command\\KeyRandom' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyRandom.php',
'Predis\\Command\\KeyRename' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyRename.php',
'Predis\\Command\\KeyRenamePreserve' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyRenamePreserve.php',
'Predis\\Command\\KeyRestore' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyRestore.php',
'Predis\\Command\\KeyScan' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyScan.php',
'Predis\\Command\\KeySort' => __DIR__ . '/..' . '/predis/predis/src/Command/KeySort.php',
'Predis\\Command\\KeyTimeToLive' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyTimeToLive.php',
'Predis\\Command\\KeyType' => __DIR__ . '/..' . '/predis/predis/src/Command/KeyType.php',
'Predis\\Command\\ListIndex' => __DIR__ . '/..' . '/predis/predis/src/Command/ListIndex.php',
'Predis\\Command\\ListInsert' => __DIR__ . '/..' . '/predis/predis/src/Command/ListInsert.php',
'Predis\\Command\\ListLength' => __DIR__ . '/..' . '/predis/predis/src/Command/ListLength.php',
'Predis\\Command\\ListPopFirst' => __DIR__ . '/..' . '/predis/predis/src/Command/ListPopFirst.php',
'Predis\\Command\\ListPopFirstBlocking' => __DIR__ . '/..' . '/predis/predis/src/Command/ListPopFirstBlocking.php',
'Predis\\Command\\ListPopLast' => __DIR__ . '/..' . '/predis/predis/src/Command/ListPopLast.php',
'Predis\\Command\\ListPopLastBlocking' => __DIR__ . '/..' . '/predis/predis/src/Command/ListPopLastBlocking.php',
'Predis\\Command\\ListPopLastPushHead' => __DIR__ . '/..' . '/predis/predis/src/Command/ListPopLastPushHead.php',
'Predis\\Command\\ListPopLastPushHeadBlocking' => __DIR__ . '/..' . '/predis/predis/src/Command/ListPopLastPushHeadBlocking.php',
'Predis\\Command\\ListPushHead' => __DIR__ . '/..' . '/predis/predis/src/Command/ListPushHead.php',
'Predis\\Command\\ListPushHeadX' => __DIR__ . '/..' . '/predis/predis/src/Command/ListPushHeadX.php',
'Predis\\Command\\ListPushTail' => __DIR__ . '/..' . '/predis/predis/src/Command/ListPushTail.php',
'Predis\\Command\\ListPushTailX' => __DIR__ . '/..' . '/predis/predis/src/Command/ListPushTailX.php',
'Predis\\Command\\ListRange' => __DIR__ . '/..' . '/predis/predis/src/Command/ListRange.php',
'Predis\\Command\\ListRemove' => __DIR__ . '/..' . '/predis/predis/src/Command/ListRemove.php',
'Predis\\Command\\ListSet' => __DIR__ . '/..' . '/predis/predis/src/Command/ListSet.php',
'Predis\\Command\\ListTrim' => __DIR__ . '/..' . '/predis/predis/src/Command/ListTrim.php',
'Predis\\Command\\PrefixableCommandInterface' => __DIR__ . '/..' . '/predis/predis/src/Command/PrefixableCommandInterface.php',
'Predis\\Command\\Processor\\KeyPrefixProcessor' => __DIR__ . '/..' . '/predis/predis/src/Command/Processor/KeyPrefixProcessor.php',
'Predis\\Command\\Processor\\ProcessorChain' => __DIR__ . '/..' . '/predis/predis/src/Command/Processor/ProcessorChain.php',
'Predis\\Command\\Processor\\ProcessorInterface' => __DIR__ . '/..' . '/predis/predis/src/Command/Processor/ProcessorInterface.php',
'Predis\\Command\\PubSubPublish' => __DIR__ . '/..' . '/predis/predis/src/Command/PubSubPublish.php',
'Predis\\Command\\PubSubPubsub' => __DIR__ . '/..' . '/predis/predis/src/Command/PubSubPubsub.php',
'Predis\\Command\\PubSubSubscribe' => __DIR__ . '/..' . '/predis/predis/src/Command/PubSubSubscribe.php',
'Predis\\Command\\PubSubSubscribeByPattern' => __DIR__ . '/..' . '/predis/predis/src/Command/PubSubSubscribeByPattern.php',
'Predis\\Command\\PubSubUnsubscribe' => __DIR__ . '/..' . '/predis/predis/src/Command/PubSubUnsubscribe.php',
'Predis\\Command\\PubSubUnsubscribeByPattern' => __DIR__ . '/..' . '/predis/predis/src/Command/PubSubUnsubscribeByPattern.php',
'Predis\\Command\\RawCommand' => __DIR__ . '/..' . '/predis/predis/src/Command/RawCommand.php',
'Predis\\Command\\ScriptCommand' => __DIR__ . '/..' . '/predis/predis/src/Command/ScriptCommand.php',
'Predis\\Command\\ServerBackgroundRewriteAOF' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerBackgroundRewriteAOF.php',
'Predis\\Command\\ServerBackgroundSave' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerBackgroundSave.php',
'Predis\\Command\\ServerClient' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerClient.php',
'Predis\\Command\\ServerCommand' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerCommand.php',
'Predis\\Command\\ServerConfig' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerConfig.php',
'Predis\\Command\\ServerDatabaseSize' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerDatabaseSize.php',
'Predis\\Command\\ServerEval' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerEval.php',
'Predis\\Command\\ServerEvalSHA' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerEvalSHA.php',
'Predis\\Command\\ServerFlushAll' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerFlushAll.php',
'Predis\\Command\\ServerFlushDatabase' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerFlushDatabase.php',
'Predis\\Command\\ServerInfo' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerInfo.php',
'Predis\\Command\\ServerInfoV26x' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerInfoV26x.php',
'Predis\\Command\\ServerLastSave' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerLastSave.php',
'Predis\\Command\\ServerMonitor' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerMonitor.php',
'Predis\\Command\\ServerObject' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerObject.php',
'Predis\\Command\\ServerSave' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerSave.php',
'Predis\\Command\\ServerScript' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerScript.php',
'Predis\\Command\\ServerSentinel' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerSentinel.php',
'Predis\\Command\\ServerShutdown' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerShutdown.php',
'Predis\\Command\\ServerSlaveOf' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerSlaveOf.php',
'Predis\\Command\\ServerSlowlog' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerSlowlog.php',
'Predis\\Command\\ServerTime' => __DIR__ . '/..' . '/predis/predis/src/Command/ServerTime.php',
'Predis\\Command\\SetAdd' => __DIR__ . '/..' . '/predis/predis/src/Command/SetAdd.php',
'Predis\\Command\\SetCardinality' => __DIR__ . '/..' . '/predis/predis/src/Command/SetCardinality.php',
'Predis\\Command\\SetDifference' => __DIR__ . '/..' . '/predis/predis/src/Command/SetDifference.php',
'Predis\\Command\\SetDifferenceStore' => __DIR__ . '/..' . '/predis/predis/src/Command/SetDifferenceStore.php',
'Predis\\Command\\SetIntersection' => __DIR__ . '/..' . '/predis/predis/src/Command/SetIntersection.php',
'Predis\\Command\\SetIntersectionStore' => __DIR__ . '/..' . '/predis/predis/src/Command/SetIntersectionStore.php',
'Predis\\Command\\SetIsMember' => __DIR__ . '/..' . '/predis/predis/src/Command/SetIsMember.php',
'Predis\\Command\\SetMembers' => __DIR__ . '/..' . '/predis/predis/src/Command/SetMembers.php',
'Predis\\Command\\SetMove' => __DIR__ . '/..' . '/predis/predis/src/Command/SetMove.php',
'Predis\\Command\\SetPop' => __DIR__ . '/..' . '/predis/predis/src/Command/SetPop.php',
'Predis\\Command\\SetRandomMember' => __DIR__ . '/..' . '/predis/predis/src/Command/SetRandomMember.php',
'Predis\\Command\\SetRemove' => __DIR__ . '/..' . '/predis/predis/src/Command/SetRemove.php',
'Predis\\Command\\SetScan' => __DIR__ . '/..' . '/predis/predis/src/Command/SetScan.php',
'Predis\\Command\\SetUnion' => __DIR__ . '/..' . '/predis/predis/src/Command/SetUnion.php',
'Predis\\Command\\SetUnionStore' => __DIR__ . '/..' . '/predis/predis/src/Command/SetUnionStore.php',
'Predis\\Command\\StringAppend' => __DIR__ . '/..' . '/predis/predis/src/Command/StringAppend.php',
'Predis\\Command\\StringBitCount' => __DIR__ . '/..' . '/predis/predis/src/Command/StringBitCount.php',
'Predis\\Command\\StringBitField' => __DIR__ . '/..' . '/predis/predis/src/Command/StringBitField.php',
'Predis\\Command\\StringBitOp' => __DIR__ . '/..' . '/predis/predis/src/Command/StringBitOp.php',
'Predis\\Command\\StringBitPos' => __DIR__ . '/..' . '/predis/predis/src/Command/StringBitPos.php',
'Predis\\Command\\StringDecrement' => __DIR__ . '/..' . '/predis/predis/src/Command/StringDecrement.php',
'Predis\\Command\\StringDecrementBy' => __DIR__ . '/..' . '/predis/predis/src/Command/StringDecrementBy.php',
'Predis\\Command\\StringGet' => __DIR__ . '/..' . '/predis/predis/src/Command/StringGet.php',
'Predis\\Command\\StringGetBit' => __DIR__ . '/..' . '/predis/predis/src/Command/StringGetBit.php',
'Predis\\Command\\StringGetMultiple' => __DIR__ . '/..' . '/predis/predis/src/Command/StringGetMultiple.php',
'Predis\\Command\\StringGetRange' => __DIR__ . '/..' . '/predis/predis/src/Command/StringGetRange.php',
'Predis\\Command\\StringGetSet' => __DIR__ . '/..' . '/predis/predis/src/Command/StringGetSet.php',
'Predis\\Command\\StringIncrement' => __DIR__ . '/..' . '/predis/predis/src/Command/StringIncrement.php',
'Predis\\Command\\StringIncrementBy' => __DIR__ . '/..' . '/predis/predis/src/Command/StringIncrementBy.php',
'Predis\\Command\\StringIncrementByFloat' => __DIR__ . '/..' . '/predis/predis/src/Command/StringIncrementByFloat.php',
'Predis\\Command\\StringPreciseSetExpire' => __DIR__ . '/..' . '/predis/predis/src/Command/StringPreciseSetExpire.php',
'Predis\\Command\\StringSet' => __DIR__ . '/..' . '/predis/predis/src/Command/StringSet.php',
'Predis\\Command\\StringSetBit' => __DIR__ . '/..' . '/predis/predis/src/Command/StringSetBit.php',
'Predis\\Command\\StringSetExpire' => __DIR__ . '/..' . '/predis/predis/src/Command/StringSetExpire.php',
'Predis\\Command\\StringSetMultiple' => __DIR__ . '/..' . '/predis/predis/src/Command/StringSetMultiple.php',
'Predis\\Command\\StringSetMultiplePreserve' => __DIR__ . '/..' . '/predis/predis/src/Command/StringSetMultiplePreserve.php',
'Predis\\Command\\StringSetPreserve' => __DIR__ . '/..' . '/predis/predis/src/Command/StringSetPreserve.php',
'Predis\\Command\\StringSetRange' => __DIR__ . '/..' . '/predis/predis/src/Command/StringSetRange.php',
'Predis\\Command\\StringStrlen' => __DIR__ . '/..' . '/predis/predis/src/Command/StringStrlen.php',
'Predis\\Command\\StringSubstr' => __DIR__ . '/..' . '/predis/predis/src/Command/StringSubstr.php',
'Predis\\Command\\TransactionDiscard' => __DIR__ . '/..' . '/predis/predis/src/Command/TransactionDiscard.php',
'Predis\\Command\\TransactionExec' => __DIR__ . '/..' . '/predis/predis/src/Command/TransactionExec.php',
'Predis\\Command\\TransactionMulti' => __DIR__ . '/..' . '/predis/predis/src/Command/TransactionMulti.php',
'Predis\\Command\\TransactionUnwatch' => __DIR__ . '/..' . '/predis/predis/src/Command/TransactionUnwatch.php',
'Predis\\Command\\TransactionWatch' => __DIR__ . '/..' . '/predis/predis/src/Command/TransactionWatch.php',
'Predis\\Command\\ZSetAdd' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetAdd.php',
'Predis\\Command\\ZSetCardinality' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetCardinality.php',
'Predis\\Command\\ZSetCount' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetCount.php',
'Predis\\Command\\ZSetIncrementBy' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetIncrementBy.php',
'Predis\\Command\\ZSetIntersectionStore' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetIntersectionStore.php',
'Predis\\Command\\ZSetLexCount' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetLexCount.php',
'Predis\\Command\\ZSetRange' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetRange.php',
'Predis\\Command\\ZSetRangeByLex' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetRangeByLex.php',
'Predis\\Command\\ZSetRangeByScore' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetRangeByScore.php',
'Predis\\Command\\ZSetRank' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetRank.php',
'Predis\\Command\\ZSetRemove' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetRemove.php',
'Predis\\Command\\ZSetRemoveRangeByLex' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetRemoveRangeByLex.php',
'Predis\\Command\\ZSetRemoveRangeByRank' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetRemoveRangeByRank.php',
'Predis\\Command\\ZSetRemoveRangeByScore' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetRemoveRangeByScore.php',
'Predis\\Command\\ZSetReverseRange' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetReverseRange.php',
'Predis\\Command\\ZSetReverseRangeByLex' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetReverseRangeByLex.php',
'Predis\\Command\\ZSetReverseRangeByScore' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetReverseRangeByScore.php',
'Predis\\Command\\ZSetReverseRank' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetReverseRank.php',
'Predis\\Command\\ZSetScan' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetScan.php',
'Predis\\Command\\ZSetScore' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetScore.php',
'Predis\\Command\\ZSetUnionStore' => __DIR__ . '/..' . '/predis/predis/src/Command/ZSetUnionStore.php',
'Predis\\CommunicationException' => __DIR__ . '/..' . '/predis/predis/src/CommunicationException.php',
'Predis\\Configuration\\ClusterOption' => __DIR__ . '/..' . '/predis/predis/src/Configuration/ClusterOption.php',
'Predis\\Configuration\\ConnectionFactoryOption' => __DIR__ . '/..' . '/predis/predis/src/Configuration/ConnectionFactoryOption.php',
'Predis\\Configuration\\ExceptionsOption' => __DIR__ . '/..' . '/predis/predis/src/Configuration/ExceptionsOption.php',
'Predis\\Configuration\\OptionInterface' => __DIR__ . '/..' . '/predis/predis/src/Configuration/OptionInterface.php',
'Predis\\Configuration\\Options' => __DIR__ . '/..' . '/predis/predis/src/Configuration/Options.php',
'Predis\\Configuration\\OptionsInterface' => __DIR__ . '/..' . '/predis/predis/src/Configuration/OptionsInterface.php',
'Predis\\Configuration\\PrefixOption' => __DIR__ . '/..' . '/predis/predis/src/Configuration/PrefixOption.php',
'Predis\\Configuration\\ProfileOption' => __DIR__ . '/..' . '/predis/predis/src/Configuration/ProfileOption.php',
'Predis\\Configuration\\ReplicationOption' => __DIR__ . '/..' . '/predis/predis/src/Configuration/ReplicationOption.php',
'Predis\\Connection\\AbstractConnection' => __DIR__ . '/..' . '/predis/predis/src/Connection/AbstractConnection.php',
'Predis\\Connection\\AggregateConnectionInterface' => __DIR__ . '/..' . '/predis/predis/src/Connection/AggregateConnectionInterface.php',
'Predis\\Connection\\Aggregate\\ClusterInterface' => __DIR__ . '/..' . '/predis/predis/src/Connection/Aggregate/ClusterInterface.php',
'Predis\\Connection\\Aggregate\\MasterSlaveReplication' => __DIR__ . '/..' . '/predis/predis/src/Connection/Aggregate/MasterSlaveReplication.php',
'Predis\\Connection\\Aggregate\\PredisCluster' => __DIR__ . '/..' . '/predis/predis/src/Connection/Aggregate/PredisCluster.php',
'Predis\\Connection\\Aggregate\\RedisCluster' => __DIR__ . '/..' . '/predis/predis/src/Connection/Aggregate/RedisCluster.php',
'Predis\\Connection\\Aggregate\\ReplicationInterface' => __DIR__ . '/..' . '/predis/predis/src/Connection/Aggregate/ReplicationInterface.php',
'Predis\\Connection\\Aggregate\\SentinelReplication' => __DIR__ . '/..' . '/predis/predis/src/Connection/Aggregate/SentinelReplication.php',
'Predis\\Connection\\CompositeConnectionInterface' => __DIR__ . '/..' . '/predis/predis/src/Connection/CompositeConnectionInterface.php',
'Predis\\Connection\\CompositeStreamConnection' => __DIR__ . '/..' . '/predis/predis/src/Connection/CompositeStreamConnection.php',
'Predis\\Connection\\ConnectionException' => __DIR__ . '/..' . '/predis/predis/src/Connection/ConnectionException.php',
'Predis\\Connection\\ConnectionInterface' => __DIR__ . '/..' . '/predis/predis/src/Connection/ConnectionInterface.php',
'Predis\\Connection\\Factory' => __DIR__ . '/..' . '/predis/predis/src/Connection/Factory.php',
'Predis\\Connection\\FactoryInterface' => __DIR__ . '/..' . '/predis/predis/src/Connection/FactoryInterface.php',
'Predis\\Connection\\NodeConnectionInterface' => __DIR__ . '/..' . '/predis/predis/src/Connection/NodeConnectionInterface.php',
'Predis\\Connection\\Parameters' => __DIR__ . '/..' . '/predis/predis/src/Connection/Parameters.php',
'Predis\\Connection\\ParametersInterface' => __DIR__ . '/..' . '/predis/predis/src/Connection/ParametersInterface.php',
'Predis\\Connection\\PhpiredisSocketConnection' => __DIR__ . '/..' . '/predis/predis/src/Connection/PhpiredisSocketConnection.php',
'Predis\\Connection\\PhpiredisStreamConnection' => __DIR__ . '/..' . '/predis/predis/src/Connection/PhpiredisStreamConnection.php',
'Predis\\Connection\\StreamConnection' => __DIR__ . '/..' . '/predis/predis/src/Connection/StreamConnection.php',
'Predis\\Connection\\WebdisConnection' => __DIR__ . '/..' . '/predis/predis/src/Connection/WebdisConnection.php',
'Predis\\Monitor\\Consumer' => __DIR__ . '/..' . '/predis/predis/src/Monitor/Consumer.php',
'Predis\\NotSupportedException' => __DIR__ . '/..' . '/predis/predis/src/NotSupportedException.php',
'Predis\\Pipeline\\Atomic' => __DIR__ . '/..' . '/predis/predis/src/Pipeline/Atomic.php',
'Predis\\Pipeline\\ConnectionErrorProof' => __DIR__ . '/..' . '/predis/predis/src/Pipeline/ConnectionErrorProof.php',
'Predis\\Pipeline\\FireAndForget' => __DIR__ . '/..' . '/predis/predis/src/Pipeline/FireAndForget.php',
'Predis\\Pipeline\\Pipeline' => __DIR__ . '/..' . '/predis/predis/src/Pipeline/Pipeline.php',
'Predis\\PredisException' => __DIR__ . '/..' . '/predis/predis/src/PredisException.php',
'Predis\\Profile\\Factory' => __DIR__ . '/..' . '/predis/predis/src/Profile/Factory.php',
'Predis\\Profile\\ProfileInterface' => __DIR__ . '/..' . '/predis/predis/src/Profile/ProfileInterface.php',
'Predis\\Profile\\RedisProfile' => __DIR__ . '/..' . '/predis/predis/src/Profile/RedisProfile.php',
'Predis\\Profile\\RedisUnstable' => __DIR__ . '/..' . '/predis/predis/src/Profile/RedisUnstable.php',
'Predis\\Profile\\RedisVersion200' => __DIR__ . '/..' . '/predis/predis/src/Profile/RedisVersion200.php',
'Predis\\Profile\\RedisVersion220' => __DIR__ . '/..' . '/predis/predis/src/Profile/RedisVersion220.php',
'Predis\\Profile\\RedisVersion240' => __DIR__ . '/..' . '/predis/predis/src/Profile/RedisVersion240.php',
'Predis\\Profile\\RedisVersion260' => __DIR__ . '/..' . '/predis/predis/src/Profile/RedisVersion260.php',
'Predis\\Profile\\RedisVersion280' => __DIR__ . '/..' . '/predis/predis/src/Profile/RedisVersion280.php',
'Predis\\Profile\\RedisVersion300' => __DIR__ . '/..' . '/predis/predis/src/Profile/RedisVersion300.php',
'Predis\\Profile\\RedisVersion320' => __DIR__ . '/..' . '/predis/predis/src/Profile/RedisVersion320.php',
'Predis\\Protocol\\ProtocolException' => __DIR__ . '/..' . '/predis/predis/src/Protocol/ProtocolException.php',
'Predis\\Protocol\\ProtocolProcessorInterface' => __DIR__ . '/..' . '/predis/predis/src/Protocol/ProtocolProcessorInterface.php',
'Predis\\Protocol\\RequestSerializerInterface' => __DIR__ . '/..' . '/predis/predis/src/Protocol/RequestSerializerInterface.php',
'Predis\\Protocol\\ResponseReaderInterface' => __DIR__ . '/..' . '/predis/predis/src/Protocol/ResponseReaderInterface.php',
'Predis\\Protocol\\Text\\CompositeProtocolProcessor' => __DIR__ . '/..' . '/predis/predis/src/Protocol/Text/CompositeProtocolProcessor.php',
'Predis\\Protocol\\Text\\Handler\\BulkResponse' => __DIR__ . '/..' . '/predis/predis/src/Protocol/Text/Handler/BulkResponse.php',
'Predis\\Protocol\\Text\\Handler\\ErrorResponse' => __DIR__ . '/..' . '/predis/predis/src/Protocol/Text/Handler/ErrorResponse.php',
'Predis\\Protocol\\Text\\Handler\\IntegerResponse' => __DIR__ . '/..' . '/predis/predis/src/Protocol/Text/Handler/IntegerResponse.php',
'Predis\\Protocol\\Text\\Handler\\MultiBulkResponse' => __DIR__ . '/..' . '/predis/predis/src/Protocol/Text/Handler/MultiBulkResponse.php',
'Predis\\Protocol\\Text\\Handler\\ResponseHandlerInterface' => __DIR__ . '/..' . '/predis/predis/src/Protocol/Text/Handler/ResponseHandlerInterface.php',
'Predis\\Protocol\\Text\\Handler\\StatusResponse' => __DIR__ . '/..' . '/predis/predis/src/Protocol/Text/Handler/StatusResponse.php',
'Predis\\Protocol\\Text\\Handler\\StreamableMultiBulkResponse' => __DIR__ . '/..' . '/predis/predis/src/Protocol/Text/Handler/StreamableMultiBulkResponse.php',
'Predis\\Protocol\\Text\\ProtocolProcessor' => __DIR__ . '/..' . '/predis/predis/src/Protocol/Text/ProtocolProcessor.php',
'Predis\\Protocol\\Text\\RequestSerializer' => __DIR__ . '/..' . '/predis/predis/src/Protocol/Text/RequestSerializer.php',
'Predis\\Protocol\\Text\\ResponseReader' => __DIR__ . '/..' . '/predis/predis/src/Protocol/Text/ResponseReader.php',
'Predis\\PubSub\\AbstractConsumer' => __DIR__ . '/..' . '/predis/predis/src/PubSub/AbstractConsumer.php',
'Predis\\PubSub\\Consumer' => __DIR__ . '/..' . '/predis/predis/src/PubSub/Consumer.php',
'Predis\\PubSub\\DispatcherLoop' => __DIR__ . '/..' . '/predis/predis/src/PubSub/DispatcherLoop.php',
'Predis\\Replication\\MissingMasterException' => __DIR__ . '/..' . '/predis/predis/src/Replication/MissingMasterException.php',
'Predis\\Replication\\ReplicationStrategy' => __DIR__ . '/..' . '/predis/predis/src/Replication/ReplicationStrategy.php',
'Predis\\Replication\\RoleException' => __DIR__ . '/..' . '/predis/predis/src/Replication/RoleException.php',
'Predis\\Response\\Error' => __DIR__ . '/..' . '/predis/predis/src/Response/Error.php',
'Predis\\Response\\ErrorInterface' => __DIR__ . '/..' . '/predis/predis/src/Response/ErrorInterface.php',
'Predis\\Response\\Iterator\\MultiBulk' => __DIR__ . '/..' . '/predis/predis/src/Response/Iterator/MultiBulk.php',
'Predis\\Response\\Iterator\\MultiBulkIterator' => __DIR__ . '/..' . '/predis/predis/src/Response/Iterator/MultiBulkIterator.php',
'Predis\\Response\\Iterator\\MultiBulkTuple' => __DIR__ . '/..' . '/predis/predis/src/Response/Iterator/MultiBulkTuple.php',
'Predis\\Response\\ResponseInterface' => __DIR__ . '/..' . '/predis/predis/src/Response/ResponseInterface.php',
'Predis\\Response\\ServerException' => __DIR__ . '/..' . '/predis/predis/src/Response/ServerException.php',
'Predis\\Response\\Status' => __DIR__ . '/..' . '/predis/predis/src/Response/Status.php',
'Predis\\Session\\Handler' => __DIR__ . '/..' . '/predis/predis/src/Session/Handler.php',
'Predis\\Transaction\\AbortedMultiExecException' => __DIR__ . '/..' . '/predis/predis/src/Transaction/AbortedMultiExecException.php',
'Predis\\Transaction\\MultiExec' => __DIR__ . '/..' . '/predis/predis/src/Transaction/MultiExec.php',
'Predis\\Transaction\\MultiExecState' => __DIR__ . '/..' . '/predis/predis/src/Transaction/MultiExecState.php',
'Prophecy\\Argument' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument.php',
'Prophecy\\Argument\\ArgumentsWildcard' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/ArgumentsWildcard.php',
'Prophecy\\Argument\\Token\\AnyValueToken' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/AnyValueToken.php',
'Prophecy\\Argument\\Token\\AnyValuesToken' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/AnyValuesToken.php',
'Prophecy\\Argument\\Token\\ApproximateValueToken' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/ApproximateValueToken.php',
'Prophecy\\Argument\\Token\\ArrayCountToken' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/ArrayCountToken.php',
'Prophecy\\Argument\\Token\\ArrayEntryToken' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/ArrayEntryToken.php',
'Prophecy\\Argument\\Token\\ArrayEveryEntryToken' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/ArrayEveryEntryToken.php',
'Prophecy\\Argument\\Token\\CallbackToken' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/CallbackToken.php',
'Prophecy\\Argument\\Token\\ExactValueToken' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/ExactValueToken.php',
'Prophecy\\Argument\\Token\\IdenticalValueToken' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/IdenticalValueToken.php',
'Prophecy\\Argument\\Token\\InArrayToken' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/InArrayToken.php',
'Prophecy\\Argument\\Token\\LogicalAndToken' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/LogicalAndToken.php',
'Prophecy\\Argument\\Token\\LogicalNotToken' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/LogicalNotToken.php',
'Prophecy\\Argument\\Token\\NotInArrayToken' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/NotInArrayToken.php',
'Prophecy\\Argument\\Token\\ObjectStateToken' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/ObjectStateToken.php',
'Prophecy\\Argument\\Token\\StringContainsToken' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/StringContainsToken.php',
'Prophecy\\Argument\\Token\\TokenInterface' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/TokenInterface.php',
'Prophecy\\Argument\\Token\\TypeToken' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Argument/Token/TypeToken.php',
'Prophecy\\Call\\Call' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Call/Call.php',
'Prophecy\\Call\\CallCenter' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Call/CallCenter.php',
'Prophecy\\Comparator\\ClosureComparator' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Comparator/ClosureComparator.php',
'Prophecy\\Comparator\\Factory' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Comparator/Factory.php',
'Prophecy\\Comparator\\ProphecyComparator' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Comparator/ProphecyComparator.php',
'Prophecy\\Doubler\\CachedDoubler' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/CachedDoubler.php',
'Prophecy\\Doubler\\ClassPatch\\ClassPatchInterface' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ClassPatchInterface.php',
'Prophecy\\Doubler\\ClassPatch\\DisableConstructorPatch' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/DisableConstructorPatch.php',
'Prophecy\\Doubler\\ClassPatch\\HhvmExceptionPatch' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/HhvmExceptionPatch.php',
'Prophecy\\Doubler\\ClassPatch\\KeywordPatch' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/KeywordPatch.php',
'Prophecy\\Doubler\\ClassPatch\\MagicCallPatch' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/MagicCallPatch.php',
'Prophecy\\Doubler\\ClassPatch\\ProphecySubjectPatch' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php',
'Prophecy\\Doubler\\ClassPatch\\ReflectionClassNewInstancePatch' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ReflectionClassNewInstancePatch.php',
'Prophecy\\Doubler\\ClassPatch\\SplFileInfoPatch' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/SplFileInfoPatch.php',
'Prophecy\\Doubler\\ClassPatch\\ThrowablePatch' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ThrowablePatch.php',
'Prophecy\\Doubler\\ClassPatch\\TraversablePatch' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/TraversablePatch.php',
'Prophecy\\Doubler\\DoubleInterface' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/DoubleInterface.php',
'Prophecy\\Doubler\\Doubler' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/Doubler.php',
'Prophecy\\Doubler\\Generator\\ClassCodeGenerator' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassCodeGenerator.php',
'Prophecy\\Doubler\\Generator\\ClassCreator' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassCreator.php',
'Prophecy\\Doubler\\Generator\\ClassMirror' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassMirror.php',
'Prophecy\\Doubler\\Generator\\Node\\ArgumentNode' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ArgumentNode.php',
'Prophecy\\Doubler\\Generator\\Node\\ArgumentTypeNode' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ArgumentTypeNode.php',
'Prophecy\\Doubler\\Generator\\Node\\ClassNode' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ClassNode.php',
'Prophecy\\Doubler\\Generator\\Node\\MethodNode' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/MethodNode.php',
'Prophecy\\Doubler\\Generator\\Node\\ReturnTypeNode' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ReturnTypeNode.php',
'Prophecy\\Doubler\\Generator\\Node\\TypeNodeAbstract' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/TypeNodeAbstract.php',
'Prophecy\\Doubler\\Generator\\ReflectionInterface' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/ReflectionInterface.php',
'Prophecy\\Doubler\\Generator\\TypeHintReference' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/Generator/TypeHintReference.php',
'Prophecy\\Doubler\\LazyDouble' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/LazyDouble.php',
'Prophecy\\Doubler\\NameGenerator' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Doubler/NameGenerator.php',
'Prophecy\\Exception\\Call\\UnexpectedCallException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Call/UnexpectedCallException.php',
'Prophecy\\Exception\\Doubler\\ClassCreatorException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/ClassCreatorException.php',
'Prophecy\\Exception\\Doubler\\ClassMirrorException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/ClassMirrorException.php',
'Prophecy\\Exception\\Doubler\\ClassNotFoundException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/ClassNotFoundException.php',
'Prophecy\\Exception\\Doubler\\DoubleException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/DoubleException.php',
'Prophecy\\Exception\\Doubler\\DoublerException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/DoublerException.php',
'Prophecy\\Exception\\Doubler\\InterfaceNotFoundException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/InterfaceNotFoundException.php',
'Prophecy\\Exception\\Doubler\\MethodNotExtendableException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/MethodNotExtendableException.php',
'Prophecy\\Exception\\Doubler\\MethodNotFoundException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/MethodNotFoundException.php',
'Prophecy\\Exception\\Doubler\\ReturnByReferenceException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Doubler/ReturnByReferenceException.php',
'Prophecy\\Exception\\Exception' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Exception.php',
'Prophecy\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/InvalidArgumentException.php',
'Prophecy\\Exception\\Prediction\\AggregateException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Prediction/AggregateException.php',
'Prophecy\\Exception\\Prediction\\FailedPredictionException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Prediction/FailedPredictionException.php',
'Prophecy\\Exception\\Prediction\\NoCallsException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Prediction/NoCallsException.php',
'Prophecy\\Exception\\Prediction\\PredictionException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Prediction/PredictionException.php',
'Prophecy\\Exception\\Prediction\\UnexpectedCallsCountException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Prediction/UnexpectedCallsCountException.php',
'Prophecy\\Exception\\Prediction\\UnexpectedCallsException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Prediction/UnexpectedCallsException.php',
'Prophecy\\Exception\\Prophecy\\MethodProphecyException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Prophecy/MethodProphecyException.php',
'Prophecy\\Exception\\Prophecy\\ObjectProphecyException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Prophecy/ObjectProphecyException.php',
'Prophecy\\Exception\\Prophecy\\ProphecyException' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Exception/Prophecy/ProphecyException.php',
'Prophecy\\PhpDocumentor\\ClassAndInterfaceTagRetriever' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/PhpDocumentor/ClassAndInterfaceTagRetriever.php',
'Prophecy\\PhpDocumentor\\ClassTagRetriever' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/PhpDocumentor/ClassTagRetriever.php',
'Prophecy\\PhpDocumentor\\LegacyClassTagRetriever' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/PhpDocumentor/LegacyClassTagRetriever.php',
'Prophecy\\PhpDocumentor\\MethodTagRetrieverInterface' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/PhpDocumentor/MethodTagRetrieverInterface.php',
'Prophecy\\Prediction\\CallPrediction' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Prediction/CallPrediction.php',
'Prophecy\\Prediction\\CallTimesPrediction' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Prediction/CallTimesPrediction.php',
'Prophecy\\Prediction\\CallbackPrediction' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Prediction/CallbackPrediction.php',
'Prophecy\\Prediction\\NoCallsPrediction' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Prediction/NoCallsPrediction.php',
'Prophecy\\Prediction\\PredictionInterface' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Prediction/PredictionInterface.php',
'Prophecy\\Promise\\CallbackPromise' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Promise/CallbackPromise.php',
'Prophecy\\Promise\\PromiseInterface' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Promise/PromiseInterface.php',
'Prophecy\\Promise\\ReturnArgumentPromise' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Promise/ReturnArgumentPromise.php',
'Prophecy\\Promise\\ReturnPromise' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Promise/ReturnPromise.php',
'Prophecy\\Promise\\ThrowPromise' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Promise/ThrowPromise.php',
'Prophecy\\Prophecy\\MethodProphecy' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Prophecy/MethodProphecy.php',
'Prophecy\\Prophecy\\ObjectProphecy' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Prophecy/ObjectProphecy.php',
'Prophecy\\Prophecy\\ProphecyInterface' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Prophecy/ProphecyInterface.php',
'Prophecy\\Prophecy\\ProphecySubjectInterface' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Prophecy/ProphecySubjectInterface.php',
'Prophecy\\Prophecy\\Revealer' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Prophecy/Revealer.php',
'Prophecy\\Prophecy\\RevealerInterface' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Prophecy/RevealerInterface.php',
'Prophecy\\Prophet' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Prophet.php',
'Prophecy\\Util\\ExportUtil' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Util/ExportUtil.php',
'Prophecy\\Util\\StringUtil' => __DIR__ . '/..' . '/phpspec/prophecy/src/Prophecy/Util/StringUtil.php',
'Psr\\Container\\ContainerExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerExceptionInterface.php',
'Psr\\Container\\ContainerInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerInterface.php',
'Psr\\Container\\NotFoundExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/NotFoundExceptionInterface.php',
'Psr\\Http\\Message\\MessageInterface' => __DIR__ . '/..' . '/psr/http-message/src/MessageInterface.php',
'Psr\\Http\\Message\\RequestInterface' => __DIR__ . '/..' . '/psr/http-message/src/RequestInterface.php',
'Psr\\Http\\Message\\ResponseInterface' => __DIR__ . '/..' . '/psr/http-message/src/ResponseInterface.php',
'Psr\\Http\\Message\\ServerRequestInterface' => __DIR__ . '/..' . '/psr/http-message/src/ServerRequestInterface.php',
'Psr\\Http\\Message\\StreamInterface' => __DIR__ . '/..' . '/psr/http-message/src/StreamInterface.php',
'Psr\\Http\\Message\\UploadedFileInterface' => __DIR__ . '/..' . '/psr/http-message/src/UploadedFileInterface.php',
'Psr\\Http\\Message\\UriInterface' => __DIR__ . '/..' . '/psr/http-message/src/UriInterface.php',
'SebastianBergmann\\CodeCoverage\\CodeCoverage' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/CodeCoverage.php',
'SebastianBergmann\\CodeCoverage\\CoveredCodeNotExecutedException' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Exception/CoveredCodeNotExecutedException.php',
'SebastianBergmann\\CodeCoverage\\Driver\\Driver' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Driver/Driver.php',
'SebastianBergmann\\CodeCoverage\\Driver\\PCOV' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Driver/PCOV.php',
'SebastianBergmann\\CodeCoverage\\Driver\\PHPDBG' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Driver/PHPDBG.php',
'SebastianBergmann\\CodeCoverage\\Driver\\Xdebug' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Driver/Xdebug.php',
'SebastianBergmann\\CodeCoverage\\Exception' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Exception/Exception.php',
'SebastianBergmann\\CodeCoverage\\Filter' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Filter.php',
'SebastianBergmann\\CodeCoverage\\InvalidArgumentException' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Exception/InvalidArgumentException.php',
'SebastianBergmann\\CodeCoverage\\MissingCoversAnnotationException' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Exception/MissingCoversAnnotationException.php',
'SebastianBergmann\\CodeCoverage\\Node\\AbstractNode' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Node/AbstractNode.php',
'SebastianBergmann\\CodeCoverage\\Node\\Builder' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Node/Builder.php',
'SebastianBergmann\\CodeCoverage\\Node\\Directory' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Node/Directory.php',
'SebastianBergmann\\CodeCoverage\\Node\\File' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Node/File.php',
'SebastianBergmann\\CodeCoverage\\Node\\Iterator' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Node/Iterator.php',
'SebastianBergmann\\CodeCoverage\\Report\\Clover' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Clover.php',
'SebastianBergmann\\CodeCoverage\\Report\\Crap4j' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Crap4j.php',
'SebastianBergmann\\CodeCoverage\\Report\\Html\\Dashboard' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Html/Renderer/Dashboard.php',
'SebastianBergmann\\CodeCoverage\\Report\\Html\\Directory' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Html/Renderer/Directory.php',
'SebastianBergmann\\CodeCoverage\\Report\\Html\\Facade' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Html/Facade.php',
'SebastianBergmann\\CodeCoverage\\Report\\Html\\File' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Html/Renderer/File.php',
'SebastianBergmann\\CodeCoverage\\Report\\Html\\Renderer' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Html/Renderer.php',
'SebastianBergmann\\CodeCoverage\\Report\\PHP' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/PHP.php',
'SebastianBergmann\\CodeCoverage\\Report\\Text' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Text.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\BuildInformation' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Xml/BuildInformation.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Coverage' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Xml/Coverage.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Directory' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Xml/Directory.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Facade' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Xml/Facade.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\File' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Xml/File.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Method' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Xml/Method.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Node' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Xml/Node.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Project' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Xml/Project.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Report' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Xml/Report.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Source' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Xml/Source.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Tests' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Xml/Tests.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Totals' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Xml/Totals.php',
'SebastianBergmann\\CodeCoverage\\Report\\Xml\\Unit' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Report/Xml/Unit.php',
'SebastianBergmann\\CodeCoverage\\RuntimeException' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Exception/RuntimeException.php',
'SebastianBergmann\\CodeCoverage\\UnintentionallyCoveredCodeException' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Exception/UnintentionallyCoveredCodeException.php',
'SebastianBergmann\\CodeCoverage\\Util' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Util.php',
'SebastianBergmann\\CodeCoverage\\Version' => __DIR__ . '/..' . '/phpunit/php-code-coverage/src/Version.php',
'SebastianBergmann\\CodeUnitReverseLookup\\Wizard' => __DIR__ . '/..' . '/sebastian/code-unit-reverse-lookup/src/Wizard.php',
'SebastianBergmann\\Comparator\\ArrayComparator' => __DIR__ . '/..' . '/sebastian/comparator/src/ArrayComparator.php',
'SebastianBergmann\\Comparator\\Comparator' => __DIR__ . '/..' . '/sebastian/comparator/src/Comparator.php',
'SebastianBergmann\\Comparator\\ComparisonFailure' => __DIR__ . '/..' . '/sebastian/comparator/src/ComparisonFailure.php',
'SebastianBergmann\\Comparator\\DOMNodeComparator' => __DIR__ . '/..' . '/sebastian/comparator/src/DOMNodeComparator.php',
'SebastianBergmann\\Comparator\\DateTimeComparator' => __DIR__ . '/..' . '/sebastian/comparator/src/DateTimeComparator.php',
'SebastianBergmann\\Comparator\\DoubleComparator' => __DIR__ . '/..' . '/sebastian/comparator/src/DoubleComparator.php',
'SebastianBergmann\\Comparator\\ExceptionComparator' => __DIR__ . '/..' . '/sebastian/comparator/src/ExceptionComparator.php',
'SebastianBergmann\\Comparator\\Factory' => __DIR__ . '/..' . '/sebastian/comparator/src/Factory.php',
'SebastianBergmann\\Comparator\\MockObjectComparator' => __DIR__ . '/..' . '/sebastian/comparator/src/MockObjectComparator.php',
'SebastianBergmann\\Comparator\\NumericComparator' => __DIR__ . '/..' . '/sebastian/comparator/src/NumericComparator.php',
'SebastianBergmann\\Comparator\\ObjectComparator' => __DIR__ . '/..' . '/sebastian/comparator/src/ObjectComparator.php',
'SebastianBergmann\\Comparator\\ResourceComparator' => __DIR__ . '/..' . '/sebastian/comparator/src/ResourceComparator.php',
'SebastianBergmann\\Comparator\\ScalarComparator' => __DIR__ . '/..' . '/sebastian/comparator/src/ScalarComparator.php',
'SebastianBergmann\\Comparator\\SplObjectStorageComparator' => __DIR__ . '/..' . '/sebastian/comparator/src/SplObjectStorageComparator.php',
'SebastianBergmann\\Comparator\\TypeComparator' => __DIR__ . '/..' . '/sebastian/comparator/src/TypeComparator.php',
'SebastianBergmann\\Diff\\Chunk' => __DIR__ . '/..' . '/sebastian/diff/src/Chunk.php',
'SebastianBergmann\\Diff\\ConfigurationException' => __DIR__ . '/..' . '/sebastian/diff/src/Exception/ConfigurationException.php',
'SebastianBergmann\\Diff\\Diff' => __DIR__ . '/..' . '/sebastian/diff/src/Diff.php',
'SebastianBergmann\\Diff\\Differ' => __DIR__ . '/..' . '/sebastian/diff/src/Differ.php',
'SebastianBergmann\\Diff\\Exception' => __DIR__ . '/..' . '/sebastian/diff/src/Exception/Exception.php',
'SebastianBergmann\\Diff\\InvalidArgumentException' => __DIR__ . '/..' . '/sebastian/diff/src/Exception/InvalidArgumentException.php',
'SebastianBergmann\\Diff\\Line' => __DIR__ . '/..' . '/sebastian/diff/src/Line.php',
'SebastianBergmann\\Diff\\LongestCommonSubsequenceCalculator' => __DIR__ . '/..' . '/sebastian/diff/src/LongestCommonSubsequenceCalculator.php',
'SebastianBergmann\\Diff\\MemoryEfficientLongestCommonSubsequenceCalculator' => __DIR__ . '/..' . '/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php',
'SebastianBergmann\\Diff\\Output\\AbstractChunkOutputBuilder' => __DIR__ . '/..' . '/sebastian/diff/src/Output/AbstractChunkOutputBuilder.php',
'SebastianBergmann\\Diff\\Output\\DiffOnlyOutputBuilder' => __DIR__ . '/..' . '/sebastian/diff/src/Output/DiffOnlyOutputBuilder.php',
'SebastianBergmann\\Diff\\Output\\DiffOutputBuilderInterface' => __DIR__ . '/..' . '/sebastian/diff/src/Output/DiffOutputBuilderInterface.php',
'SebastianBergmann\\Diff\\Output\\StrictUnifiedDiffOutputBuilder' => __DIR__ . '/..' . '/sebastian/diff/src/Output/StrictUnifiedDiffOutputBuilder.php',
'SebastianBergmann\\Diff\\Output\\UnifiedDiffOutputBuilder' => __DIR__ . '/..' . '/sebastian/diff/src/Output/UnifiedDiffOutputBuilder.php',
'SebastianBergmann\\Diff\\Parser' => __DIR__ . '/..' . '/sebastian/diff/src/Parser.php',
'SebastianBergmann\\Diff\\TimeEfficientLongestCommonSubsequenceCalculator' => __DIR__ . '/..' . '/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php',
'SebastianBergmann\\Environment\\Console' => __DIR__ . '/..' . '/sebastian/environment/src/Console.php',
'SebastianBergmann\\Environment\\OperatingSystem' => __DIR__ . '/..' . '/sebastian/environment/src/OperatingSystem.php',
'SebastianBergmann\\Environment\\Runtime' => __DIR__ . '/..' . '/sebastian/environment/src/Runtime.php',
'SebastianBergmann\\Exporter\\Exporter' => __DIR__ . '/..' . '/sebastian/exporter/src/Exporter.php',
'SebastianBergmann\\FileIterator\\Facade' => __DIR__ . '/..' . '/phpunit/php-file-iterator/src/Facade.php',
'SebastianBergmann\\FileIterator\\Factory' => __DIR__ . '/..' . '/phpunit/php-file-iterator/src/Factory.php',
'SebastianBergmann\\FileIterator\\Iterator' => __DIR__ . '/..' . '/phpunit/php-file-iterator/src/Iterator.php',
'SebastianBergmann\\GlobalState\\Blacklist' => __DIR__ . '/..' . '/sebastian/global-state/src/Blacklist.php',
'SebastianBergmann\\GlobalState\\CodeExporter' => __DIR__ . '/..' . '/sebastian/global-state/src/CodeExporter.php',
'SebastianBergmann\\GlobalState\\Exception' => __DIR__ . '/..' . '/sebastian/global-state/src/exceptions/Exception.php',
'SebastianBergmann\\GlobalState\\Restorer' => __DIR__ . '/..' . '/sebastian/global-state/src/Restorer.php',
'SebastianBergmann\\GlobalState\\RuntimeException' => __DIR__ . '/..' . '/sebastian/global-state/src/exceptions/RuntimeException.php',
'SebastianBergmann\\GlobalState\\Snapshot' => __DIR__ . '/..' . '/sebastian/global-state/src/Snapshot.php',
'SebastianBergmann\\ObjectEnumerator\\Enumerator' => __DIR__ . '/..' . '/sebastian/object-enumerator/src/Enumerator.php',
'SebastianBergmann\\ObjectEnumerator\\Exception' => __DIR__ . '/..' . '/sebastian/object-enumerator/src/Exception.php',
'SebastianBergmann\\ObjectEnumerator\\InvalidArgumentException' => __DIR__ . '/..' . '/sebastian/object-enumerator/src/InvalidArgumentException.php',
'SebastianBergmann\\ObjectReflector\\Exception' => __DIR__ . '/..' . '/sebastian/object-reflector/src/Exception.php',
'SebastianBergmann\\ObjectReflector\\InvalidArgumentException' => __DIR__ . '/..' . '/sebastian/object-reflector/src/InvalidArgumentException.php',
'SebastianBergmann\\ObjectReflector\\ObjectReflector' => __DIR__ . '/..' . '/sebastian/object-reflector/src/ObjectReflector.php',
'SebastianBergmann\\RecursionContext\\Context' => __DIR__ . '/..' . '/sebastian/recursion-context/src/Context.php',
'SebastianBergmann\\RecursionContext\\Exception' => __DIR__ . '/..' . '/sebastian/recursion-context/src/Exception.php',
'SebastianBergmann\\RecursionContext\\InvalidArgumentException' => __DIR__ . '/..' . '/sebastian/recursion-context/src/InvalidArgumentException.php',
'SebastianBergmann\\ResourceOperations\\ResourceOperations' => __DIR__ . '/..' . '/sebastian/resource-operations/src/ResourceOperations.php',
'SebastianBergmann\\Timer\\Exception' => __DIR__ . '/..' . '/phpunit/php-timer/src/Exception.php',
'SebastianBergmann\\Timer\\RuntimeException' => __DIR__ . '/..' . '/phpunit/php-timer/src/RuntimeException.php',
'SebastianBergmann\\Timer\\Timer' => __DIR__ . '/..' . '/phpunit/php-timer/src/Timer.php',
'SebastianBergmann\\Type\\CallableType' => __DIR__ . '/..' . '/sebastian/type/src/CallableType.php',
'SebastianBergmann\\Type\\Exception' => __DIR__ . '/..' . '/sebastian/type/src/exception/Exception.php',
'SebastianBergmann\\Type\\GenericObjectType' => __DIR__ . '/..' . '/sebastian/type/src/GenericObjectType.php',
'SebastianBergmann\\Type\\IterableType' => __DIR__ . '/..' . '/sebastian/type/src/IterableType.php',
'SebastianBergmann\\Type\\NullType' => __DIR__ . '/..' . '/sebastian/type/src/NullType.php',
'SebastianBergmann\\Type\\ObjectType' => __DIR__ . '/..' . '/sebastian/type/src/ObjectType.php',
'SebastianBergmann\\Type\\RuntimeException' => __DIR__ . '/..' . '/sebastian/type/src/exception/RuntimeException.php',
'SebastianBergmann\\Type\\SimpleType' => __DIR__ . '/..' . '/sebastian/type/src/SimpleType.php',
'SebastianBergmann\\Type\\Type' => __DIR__ . '/..' . '/sebastian/type/src/Type.php',
'SebastianBergmann\\Type\\TypeName' => __DIR__ . '/..' . '/sebastian/type/src/TypeName.php',
'SebastianBergmann\\Type\\UnknownType' => __DIR__ . '/..' . '/sebastian/type/src/UnknownType.php',
'SebastianBergmann\\Type\\VoidType' => __DIR__ . '/..' . '/sebastian/type/src/VoidType.php',
'SebastianBergmann\\Version' => __DIR__ . '/..' . '/sebastian/version/src/Version.php',
'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'Symfony\\Component\\BrowserKit\\AbstractBrowser' => __DIR__ . '/..' . '/symfony/browser-kit/AbstractBrowser.php',
'Symfony\\Component\\BrowserKit\\Client' => __DIR__ . '/..' . '/symfony/browser-kit/Client.php',
'Symfony\\Component\\BrowserKit\\Cookie' => __DIR__ . '/..' . '/symfony/browser-kit/Cookie.php',
'Symfony\\Component\\BrowserKit\\CookieJar' => __DIR__ . '/..' . '/symfony/browser-kit/CookieJar.php',
'Symfony\\Component\\BrowserKit\\Exception\\BadMethodCallException' => __DIR__ . '/..' . '/symfony/browser-kit/Exception/BadMethodCallException.php',
'Symfony\\Component\\BrowserKit\\History' => __DIR__ . '/..' . '/symfony/browser-kit/History.php',
'Symfony\\Component\\BrowserKit\\HttpBrowser' => __DIR__ . '/..' . '/symfony/browser-kit/HttpBrowser.php',
'Symfony\\Component\\BrowserKit\\Request' => __DIR__ . '/..' . '/symfony/browser-kit/Request.php',
'Symfony\\Component\\BrowserKit\\Response' => __DIR__ . '/..' . '/symfony/browser-kit/Response.php',
'Symfony\\Component\\BrowserKit\\Test\\Constraint\\BrowserCookieValueSame' => __DIR__ . '/..' . '/symfony/browser-kit/Test/Constraint/BrowserCookieValueSame.php',
'Symfony\\Component\\BrowserKit\\Test\\Constraint\\BrowserHasCookie' => __DIR__ . '/..' . '/symfony/browser-kit/Test/Constraint/BrowserHasCookie.php',
'Symfony\\Component\\Console\\Application' => __DIR__ . '/..' . '/symfony/console/Application.php',
'Symfony\\Component\\Console\\CommandLoader\\CommandLoaderInterface' => __DIR__ . '/..' . '/symfony/console/CommandLoader/CommandLoaderInterface.php',
'Symfony\\Component\\Console\\CommandLoader\\ContainerCommandLoader' => __DIR__ . '/..' . '/symfony/console/CommandLoader/ContainerCommandLoader.php',
'Symfony\\Component\\Console\\CommandLoader\\FactoryCommandLoader' => __DIR__ . '/..' . '/symfony/console/CommandLoader/FactoryCommandLoader.php',
'Symfony\\Component\\Console\\Command\\Command' => __DIR__ . '/..' . '/symfony/console/Command/Command.php',
'Symfony\\Component\\Console\\Command\\HelpCommand' => __DIR__ . '/..' . '/symfony/console/Command/HelpCommand.php',
'Symfony\\Component\\Console\\Command\\ListCommand' => __DIR__ . '/..' . '/symfony/console/Command/ListCommand.php',
'Symfony\\Component\\Console\\Command\\LockableTrait' => __DIR__ . '/..' . '/symfony/console/Command/LockableTrait.php',
'Symfony\\Component\\Console\\ConsoleEvents' => __DIR__ . '/..' . '/symfony/console/ConsoleEvents.php',
'Symfony\\Component\\Console\\DependencyInjection\\AddConsoleCommandPass' => __DIR__ . '/..' . '/symfony/console/DependencyInjection/AddConsoleCommandPass.php',
'Symfony\\Component\\Console\\Descriptor\\ApplicationDescription' => __DIR__ . '/..' . '/symfony/console/Descriptor/ApplicationDescription.php',
'Symfony\\Component\\Console\\Descriptor\\Descriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/Descriptor.php',
'Symfony\\Component\\Console\\Descriptor\\DescriptorInterface' => __DIR__ . '/..' . '/symfony/console/Descriptor/DescriptorInterface.php',
'Symfony\\Component\\Console\\Descriptor\\JsonDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/JsonDescriptor.php',
'Symfony\\Component\\Console\\Descriptor\\MarkdownDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/MarkdownDescriptor.php',
'Symfony\\Component\\Console\\Descriptor\\TextDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/TextDescriptor.php',
'Symfony\\Component\\Console\\Descriptor\\XmlDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/XmlDescriptor.php',
'Symfony\\Component\\Console\\EventListener\\ErrorListener' => __DIR__ . '/..' . '/symfony/console/EventListener/ErrorListener.php',
'Symfony\\Component\\Console\\Event\\ConsoleCommandEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleCommandEvent.php',
'Symfony\\Component\\Console\\Event\\ConsoleErrorEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleErrorEvent.php',
'Symfony\\Component\\Console\\Event\\ConsoleEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleEvent.php',
'Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleTerminateEvent.php',
'Symfony\\Component\\Console\\Exception\\CommandNotFoundException' => __DIR__ . '/..' . '/symfony/console/Exception/CommandNotFoundException.php',
'Symfony\\Component\\Console\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/console/Exception/ExceptionInterface.php',
'Symfony\\Component\\Console\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/console/Exception/InvalidArgumentException.php',
'Symfony\\Component\\Console\\Exception\\InvalidOptionException' => __DIR__ . '/..' . '/symfony/console/Exception/InvalidOptionException.php',
'Symfony\\Component\\Console\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/console/Exception/LogicException.php',
'Symfony\\Component\\Console\\Exception\\MissingInputException' => __DIR__ . '/..' . '/symfony/console/Exception/MissingInputException.php',
'Symfony\\Component\\Console\\Exception\\NamespaceNotFoundException' => __DIR__ . '/..' . '/symfony/console/Exception/NamespaceNotFoundException.php',
'Symfony\\Component\\Console\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/console/Exception/RuntimeException.php',
'Symfony\\Component\\Console\\Formatter\\OutputFormatter' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatter.php',
'Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterInterface.php',
'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyle' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyle.php',
'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyleInterface.php',
'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleStack' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyleStack.php',
'Symfony\\Component\\Console\\Formatter\\WrappableOutputFormatterInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/WrappableOutputFormatterInterface.php',
'Symfony\\Component\\Console\\Helper\\DebugFormatterHelper' => __DIR__ . '/..' . '/symfony/console/Helper/DebugFormatterHelper.php',
'Symfony\\Component\\Console\\Helper\\DescriptorHelper' => __DIR__ . '/..' . '/symfony/console/Helper/DescriptorHelper.php',
'Symfony\\Component\\Console\\Helper\\Dumper' => __DIR__ . '/..' . '/symfony/console/Helper/Dumper.php',
'Symfony\\Component\\Console\\Helper\\FormatterHelper' => __DIR__ . '/..' . '/symfony/console/Helper/FormatterHelper.php',
'Symfony\\Component\\Console\\Helper\\Helper' => __DIR__ . '/..' . '/symfony/console/Helper/Helper.php',
'Symfony\\Component\\Console\\Helper\\HelperInterface' => __DIR__ . '/..' . '/symfony/console/Helper/HelperInterface.php',
'Symfony\\Component\\Console\\Helper\\HelperSet' => __DIR__ . '/..' . '/symfony/console/Helper/HelperSet.php',
'Symfony\\Component\\Console\\Helper\\InputAwareHelper' => __DIR__ . '/..' . '/symfony/console/Helper/InputAwareHelper.php',
'Symfony\\Component\\Console\\Helper\\ProcessHelper' => __DIR__ . '/..' . '/symfony/console/Helper/ProcessHelper.php',
'Symfony\\Component\\Console\\Helper\\ProgressBar' => __DIR__ . '/..' . '/symfony/console/Helper/ProgressBar.php',
'Symfony\\Component\\Console\\Helper\\ProgressIndicator' => __DIR__ . '/..' . '/symfony/console/Helper/ProgressIndicator.php',
'Symfony\\Component\\Console\\Helper\\QuestionHelper' => __DIR__ . '/..' . '/symfony/console/Helper/QuestionHelper.php',
'Symfony\\Component\\Console\\Helper\\SymfonyQuestionHelper' => __DIR__ . '/..' . '/symfony/console/Helper/SymfonyQuestionHelper.php',
'Symfony\\Component\\Console\\Helper\\Table' => __DIR__ . '/..' . '/symfony/console/Helper/Table.php',
'Symfony\\Component\\Console\\Helper\\TableCell' => __DIR__ . '/..' . '/symfony/console/Helper/TableCell.php',
'Symfony\\Component\\Console\\Helper\\TableRows' => __DIR__ . '/..' . '/symfony/console/Helper/TableRows.php',
'Symfony\\Component\\Console\\Helper\\TableSeparator' => __DIR__ . '/..' . '/symfony/console/Helper/TableSeparator.php',
'Symfony\\Component\\Console\\Helper\\TableStyle' => __DIR__ . '/..' . '/symfony/console/Helper/TableStyle.php',
'Symfony\\Component\\Console\\Input\\ArgvInput' => __DIR__ . '/..' . '/symfony/console/Input/ArgvInput.php',
'Symfony\\Component\\Console\\Input\\ArrayInput' => __DIR__ . '/..' . '/symfony/console/Input/ArrayInput.php',
'Symfony\\Component\\Console\\Input\\Input' => __DIR__ . '/..' . '/symfony/console/Input/Input.php',
'Symfony\\Component\\Console\\Input\\InputArgument' => __DIR__ . '/..' . '/symfony/console/Input/InputArgument.php',
'Symfony\\Component\\Console\\Input\\InputAwareInterface' => __DIR__ . '/..' . '/symfony/console/Input/InputAwareInterface.php',
'Symfony\\Component\\Console\\Input\\InputDefinition' => __DIR__ . '/..' . '/symfony/console/Input/InputDefinition.php',
'Symfony\\Component\\Console\\Input\\InputInterface' => __DIR__ . '/..' . '/symfony/console/Input/InputInterface.php',
'Symfony\\Component\\Console\\Input\\InputOption' => __DIR__ . '/..' . '/symfony/console/Input/InputOption.php',
'Symfony\\Component\\Console\\Input\\StreamableInputInterface' => __DIR__ . '/..' . '/symfony/console/Input/StreamableInputInterface.php',
'Symfony\\Component\\Console\\Input\\StringInput' => __DIR__ . '/..' . '/symfony/console/Input/StringInput.php',
'Symfony\\Component\\Console\\Logger\\ConsoleLogger' => __DIR__ . '/..' . '/symfony/console/Logger/ConsoleLogger.php',
'Symfony\\Component\\Console\\Output\\BufferedOutput' => __DIR__ . '/..' . '/symfony/console/Output/BufferedOutput.php',
'Symfony\\Component\\Console\\Output\\ConsoleOutput' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleOutput.php',
'Symfony\\Component\\Console\\Output\\ConsoleOutputInterface' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleOutputInterface.php',
'Symfony\\Component\\Console\\Output\\ConsoleSectionOutput' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleSectionOutput.php',
'Symfony\\Component\\Console\\Output\\NullOutput' => __DIR__ . '/..' . '/symfony/console/Output/NullOutput.php',
'Symfony\\Component\\Console\\Output\\Output' => __DIR__ . '/..' . '/symfony/console/Output/Output.php',
'Symfony\\Component\\Console\\Output\\OutputInterface' => __DIR__ . '/..' . '/symfony/console/Output/OutputInterface.php',
'Symfony\\Component\\Console\\Output\\StreamOutput' => __DIR__ . '/..' . '/symfony/console/Output/StreamOutput.php',
'Symfony\\Component\\Console\\Output\\TrimmedBufferOutput' => __DIR__ . '/..' . '/symfony/console/Output/TrimmedBufferOutput.php',
'Symfony\\Component\\Console\\Question\\ChoiceQuestion' => __DIR__ . '/..' . '/symfony/console/Question/ChoiceQuestion.php',
'Symfony\\Component\\Console\\Question\\ConfirmationQuestion' => __DIR__ . '/..' . '/symfony/console/Question/ConfirmationQuestion.php',
'Symfony\\Component\\Console\\Question\\Question' => __DIR__ . '/..' . '/symfony/console/Question/Question.php',
'Symfony\\Component\\Console\\Style\\OutputStyle' => __DIR__ . '/..' . '/symfony/console/Style/OutputStyle.php',
'Symfony\\Component\\Console\\Style\\StyleInterface' => __DIR__ . '/..' . '/symfony/console/Style/StyleInterface.php',
'Symfony\\Component\\Console\\Style\\SymfonyStyle' => __DIR__ . '/..' . '/symfony/console/Style/SymfonyStyle.php',
'Symfony\\Component\\Console\\Terminal' => __DIR__ . '/..' . '/symfony/console/Terminal.php',
'Symfony\\Component\\Console\\Tester\\ApplicationTester' => __DIR__ . '/..' . '/symfony/console/Tester/ApplicationTester.php',
'Symfony\\Component\\Console\\Tester\\CommandTester' => __DIR__ . '/..' . '/symfony/console/Tester/CommandTester.php',
'Symfony\\Component\\Console\\Tester\\TesterTrait' => __DIR__ . '/..' . '/symfony/console/Tester/TesterTrait.php',
'Symfony\\Component\\CssSelector\\CssSelectorConverter' => __DIR__ . '/..' . '/symfony/css-selector/CssSelectorConverter.php',
'Symfony\\Component\\CssSelector\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/css-selector/Exception/ExceptionInterface.php',
'Symfony\\Component\\CssSelector\\Exception\\ExpressionErrorException' => __DIR__ . '/..' . '/symfony/css-selector/Exception/ExpressionErrorException.php',
'Symfony\\Component\\CssSelector\\Exception\\InternalErrorException' => __DIR__ . '/..' . '/symfony/css-selector/Exception/InternalErrorException.php',
'Symfony\\Component\\CssSelector\\Exception\\ParseException' => __DIR__ . '/..' . '/symfony/css-selector/Exception/ParseException.php',
'Symfony\\Component\\CssSelector\\Exception\\SyntaxErrorException' => __DIR__ . '/..' . '/symfony/css-selector/Exception/SyntaxErrorException.php',
'Symfony\\Component\\CssSelector\\Node\\AbstractNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/AbstractNode.php',
'Symfony\\Component\\CssSelector\\Node\\AttributeNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/AttributeNode.php',
'Symfony\\Component\\CssSelector\\Node\\ClassNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/ClassNode.php',
'Symfony\\Component\\CssSelector\\Node\\CombinedSelectorNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/CombinedSelectorNode.php',
'Symfony\\Component\\CssSelector\\Node\\ElementNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/ElementNode.php',
'Symfony\\Component\\CssSelector\\Node\\FunctionNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/FunctionNode.php',
'Symfony\\Component\\CssSelector\\Node\\HashNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/HashNode.php',
'Symfony\\Component\\CssSelector\\Node\\NegationNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/NegationNode.php',
'Symfony\\Component\\CssSelector\\Node\\NodeInterface' => __DIR__ . '/..' . '/symfony/css-selector/Node/NodeInterface.php',
'Symfony\\Component\\CssSelector\\Node\\PseudoNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/PseudoNode.php',
'Symfony\\Component\\CssSelector\\Node\\SelectorNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/SelectorNode.php',
'Symfony\\Component\\CssSelector\\Node\\Specificity' => __DIR__ . '/..' . '/symfony/css-selector/Node/Specificity.php',
'Symfony\\Component\\CssSelector\\Parser\\Handler\\CommentHandler' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Handler/CommentHandler.php',
'Symfony\\Component\\CssSelector\\Parser\\Handler\\HandlerInterface' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Handler/HandlerInterface.php',
'Symfony\\Component\\CssSelector\\Parser\\Handler\\HashHandler' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Handler/HashHandler.php',
'Symfony\\Component\\CssSelector\\Parser\\Handler\\IdentifierHandler' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Handler/IdentifierHandler.php',
'Symfony\\Component\\CssSelector\\Parser\\Handler\\NumberHandler' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Handler/NumberHandler.php',
'Symfony\\Component\\CssSelector\\Parser\\Handler\\StringHandler' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Handler/StringHandler.php',
'Symfony\\Component\\CssSelector\\Parser\\Handler\\WhitespaceHandler' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Handler/WhitespaceHandler.php',
'Symfony\\Component\\CssSelector\\Parser\\Parser' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Parser.php',
'Symfony\\Component\\CssSelector\\Parser\\ParserInterface' => __DIR__ . '/..' . '/symfony/css-selector/Parser/ParserInterface.php',
'Symfony\\Component\\CssSelector\\Parser\\Reader' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Reader.php',
'Symfony\\Component\\CssSelector\\Parser\\Shortcut\\ClassParser' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Shortcut/ClassParser.php',
'Symfony\\Component\\CssSelector\\Parser\\Shortcut\\ElementParser' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Shortcut/ElementParser.php',
'Symfony\\Component\\CssSelector\\Parser\\Shortcut\\EmptyStringParser' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php',
'Symfony\\Component\\CssSelector\\Parser\\Shortcut\\HashParser' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Shortcut/HashParser.php',
'Symfony\\Component\\CssSelector\\Parser\\Token' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Token.php',
'Symfony\\Component\\CssSelector\\Parser\\TokenStream' => __DIR__ . '/..' . '/symfony/css-selector/Parser/TokenStream.php',
'Symfony\\Component\\CssSelector\\Parser\\Tokenizer\\Tokenizer' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Tokenizer/Tokenizer.php',
'Symfony\\Component\\CssSelector\\Parser\\Tokenizer\\TokenizerEscaping' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Tokenizer/TokenizerEscaping.php',
'Symfony\\Component\\CssSelector\\Parser\\Tokenizer\\TokenizerPatterns' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Tokenizer/TokenizerPatterns.php',
'Symfony\\Component\\CssSelector\\XPath\\Extension\\AbstractExtension' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Extension/AbstractExtension.php',
'Symfony\\Component\\CssSelector\\XPath\\Extension\\AttributeMatchingExtension' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Extension/AttributeMatchingExtension.php',
'Symfony\\Component\\CssSelector\\XPath\\Extension\\CombinationExtension' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Extension/CombinationExtension.php',
'Symfony\\Component\\CssSelector\\XPath\\Extension\\ExtensionInterface' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Extension/ExtensionInterface.php',
'Symfony\\Component\\CssSelector\\XPath\\Extension\\FunctionExtension' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Extension/FunctionExtension.php',
'Symfony\\Component\\CssSelector\\XPath\\Extension\\HtmlExtension' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Extension/HtmlExtension.php',
'Symfony\\Component\\CssSelector\\XPath\\Extension\\NodeExtension' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Extension/NodeExtension.php',
'Symfony\\Component\\CssSelector\\XPath\\Extension\\PseudoClassExtension' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Extension/PseudoClassExtension.php',
'Symfony\\Component\\CssSelector\\XPath\\Translator' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Translator.php',
'Symfony\\Component\\CssSelector\\XPath\\TranslatorInterface' => __DIR__ . '/..' . '/symfony/css-selector/XPath/TranslatorInterface.php',
'Symfony\\Component\\CssSelector\\XPath\\XPathExpr' => __DIR__ . '/..' . '/symfony/css-selector/XPath/XPathExpr.php',
'Symfony\\Component\\DomCrawler\\AbstractUriElement' => __DIR__ . '/..' . '/symfony/dom-crawler/AbstractUriElement.php',
'Symfony\\Component\\DomCrawler\\Crawler' => __DIR__ . '/..' . '/symfony/dom-crawler/Crawler.php',
'Symfony\\Component\\DomCrawler\\Field\\ChoiceFormField' => __DIR__ . '/..' . '/symfony/dom-crawler/Field/ChoiceFormField.php',
'Symfony\\Component\\DomCrawler\\Field\\FileFormField' => __DIR__ . '/..' . '/symfony/dom-crawler/Field/FileFormField.php',
'Symfony\\Component\\DomCrawler\\Field\\FormField' => __DIR__ . '/..' . '/symfony/dom-crawler/Field/FormField.php',
'Symfony\\Component\\DomCrawler\\Field\\InputFormField' => __DIR__ . '/..' . '/symfony/dom-crawler/Field/InputFormField.php',
'Symfony\\Component\\DomCrawler\\Field\\TextareaFormField' => __DIR__ . '/..' . '/symfony/dom-crawler/Field/TextareaFormField.php',
'Symfony\\Component\\DomCrawler\\Form' => __DIR__ . '/..' . '/symfony/dom-crawler/Form.php',
'Symfony\\Component\\DomCrawler\\FormFieldRegistry' => __DIR__ . '/..' . '/symfony/dom-crawler/FormFieldRegistry.php',
'Symfony\\Component\\DomCrawler\\Image' => __DIR__ . '/..' . '/symfony/dom-crawler/Image.php',
'Symfony\\Component\\DomCrawler\\Link' => __DIR__ . '/..' . '/symfony/dom-crawler/Link.php',
'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorAttributeValueSame' => __DIR__ . '/..' . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php',
'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorExists' => __DIR__ . '/..' . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorExists.php',
'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorTextContains' => __DIR__ . '/..' . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextContains.php',
'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorTextSame' => __DIR__ . '/..' . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextSame.php',
'Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher' => __DIR__ . '/..' . '/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php',
'Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcherInterface' => __DIR__ . '/..' . '/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php',
'Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener' => __DIR__ . '/..' . '/symfony/event-dispatcher/Debug/WrappedListener.php',
'Symfony\\Component\\EventDispatcher\\DependencyInjection\\AddEventAliasesPass' => __DIR__ . '/..' . '/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php',
'Symfony\\Component\\EventDispatcher\\DependencyInjection\\RegisterListenersPass' => __DIR__ . '/..' . '/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php',
'Symfony\\Component\\EventDispatcher\\Event' => __DIR__ . '/..' . '/symfony/event-dispatcher/Event.php',
'Symfony\\Component\\EventDispatcher\\EventDispatcher' => __DIR__ . '/..' . '/symfony/event-dispatcher/EventDispatcher.php',
'Symfony\\Component\\EventDispatcher\\EventDispatcherInterface' => __DIR__ . '/..' . '/symfony/event-dispatcher/EventDispatcherInterface.php',
'Symfony\\Component\\EventDispatcher\\EventSubscriberInterface' => __DIR__ . '/..' . '/symfony/event-dispatcher/EventSubscriberInterface.php',
'Symfony\\Component\\EventDispatcher\\GenericEvent' => __DIR__ . '/..' . '/symfony/event-dispatcher/GenericEvent.php',
'Symfony\\Component\\EventDispatcher\\ImmutableEventDispatcher' => __DIR__ . '/..' . '/symfony/event-dispatcher/ImmutableEventDispatcher.php',
'Symfony\\Component\\EventDispatcher\\LegacyEventDispatcherProxy' => __DIR__ . '/..' . '/symfony/event-dispatcher/LegacyEventDispatcherProxy.php',
'Symfony\\Component\\EventDispatcher\\LegacyEventProxy' => __DIR__ . '/..' . '/symfony/event-dispatcher/LegacyEventProxy.php',
'Symfony\\Component\\Finder\\Comparator\\Comparator' => __DIR__ . '/..' . '/symfony/finder/Comparator/Comparator.php',
'Symfony\\Component\\Finder\\Comparator\\DateComparator' => __DIR__ . '/..' . '/symfony/finder/Comparator/DateComparator.php',
'Symfony\\Component\\Finder\\Comparator\\NumberComparator' => __DIR__ . '/..' . '/symfony/finder/Comparator/NumberComparator.php',
'Symfony\\Component\\Finder\\Exception\\AccessDeniedException' => __DIR__ . '/..' . '/symfony/finder/Exception/AccessDeniedException.php',
'Symfony\\Component\\Finder\\Exception\\DirectoryNotFoundException' => __DIR__ . '/..' . '/symfony/finder/Exception/DirectoryNotFoundException.php',
'Symfony\\Component\\Finder\\Finder' => __DIR__ . '/..' . '/symfony/finder/Finder.php',
'Symfony\\Component\\Finder\\Gitignore' => __DIR__ . '/..' . '/symfony/finder/Gitignore.php',
'Symfony\\Component\\Finder\\Glob' => __DIR__ . '/..' . '/symfony/finder/Glob.php',
'Symfony\\Component\\Finder\\Iterator\\CustomFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/CustomFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\DateRangeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/DateRangeFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\DepthRangeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/DepthRangeFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\ExcludeDirectoryFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\FileTypeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FileTypeFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\FilecontentFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FilecontentFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\FilenameFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FilenameFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\LazyIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/LazyIterator.php',
'Symfony\\Component\\Finder\\Iterator\\MultiplePcreFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/MultiplePcreFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\PathFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/PathFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\RecursiveDirectoryIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/RecursiveDirectoryIterator.php',
'Symfony\\Component\\Finder\\Iterator\\SizeRangeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/SizeRangeFilterIterator.php',
'Symfony\\Component\\Finder\\Iterator\\SortableIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/SortableIterator.php',
'Symfony\\Component\\Finder\\SplFileInfo' => __DIR__ . '/..' . '/symfony/finder/SplFileInfo.php',
'Symfony\\Component\\Process\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/process/Exception/ExceptionInterface.php',
'Symfony\\Component\\Process\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/process/Exception/InvalidArgumentException.php',
'Symfony\\Component\\Process\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/process/Exception/LogicException.php',
'Symfony\\Component\\Process\\Exception\\ProcessFailedException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessFailedException.php',
'Symfony\\Component\\Process\\Exception\\ProcessSignaledException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessSignaledException.php',
'Symfony\\Component\\Process\\Exception\\ProcessTimedOutException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessTimedOutException.php',
'Symfony\\Component\\Process\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/process/Exception/RuntimeException.php',
'Symfony\\Component\\Process\\ExecutableFinder' => __DIR__ . '/..' . '/symfony/process/ExecutableFinder.php',
'Symfony\\Component\\Process\\InputStream' => __DIR__ . '/..' . '/symfony/process/InputStream.php',
'Symfony\\Component\\Process\\PhpExecutableFinder' => __DIR__ . '/..' . '/symfony/process/PhpExecutableFinder.php',
'Symfony\\Component\\Process\\PhpProcess' => __DIR__ . '/..' . '/symfony/process/PhpProcess.php',
'Symfony\\Component\\Process\\Pipes\\AbstractPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/AbstractPipes.php',
'Symfony\\Component\\Process\\Pipes\\PipesInterface' => __DIR__ . '/..' . '/symfony/process/Pipes/PipesInterface.php',
'Symfony\\Component\\Process\\Pipes\\UnixPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/UnixPipes.php',
'Symfony\\Component\\Process\\Pipes\\WindowsPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/WindowsPipes.php',
'Symfony\\Component\\Process\\Process' => __DIR__ . '/..' . '/symfony/process/Process.php',
'Symfony\\Component\\Process\\ProcessUtils' => __DIR__ . '/..' . '/symfony/process/ProcessUtils.php',
'Symfony\\Component\\Yaml\\Command\\LintCommand' => __DIR__ . '/..' . '/symfony/yaml/Command/LintCommand.php',
'Symfony\\Component\\Yaml\\Dumper' => __DIR__ . '/..' . '/symfony/yaml/Dumper.php',
'Symfony\\Component\\Yaml\\Escaper' => __DIR__ . '/..' . '/symfony/yaml/Escaper.php',
'Symfony\\Component\\Yaml\\Exception\\DumpException' => __DIR__ . '/..' . '/symfony/yaml/Exception/DumpException.php',
'Symfony\\Component\\Yaml\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/yaml/Exception/ExceptionInterface.php',
'Symfony\\Component\\Yaml\\Exception\\ParseException' => __DIR__ . '/..' . '/symfony/yaml/Exception/ParseException.php',
'Symfony\\Component\\Yaml\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/yaml/Exception/RuntimeException.php',
'Symfony\\Component\\Yaml\\Inline' => __DIR__ . '/..' . '/symfony/yaml/Inline.php',
'Symfony\\Component\\Yaml\\Parser' => __DIR__ . '/..' . '/symfony/yaml/Parser.php',
'Symfony\\Component\\Yaml\\Tag\\TaggedValue' => __DIR__ . '/..' . '/symfony/yaml/Tag/TaggedValue.php',
'Symfony\\Component\\Yaml\\Unescaper' => __DIR__ . '/..' . '/symfony/yaml/Unescaper.php',
'Symfony\\Component\\Yaml\\Yaml' => __DIR__ . '/..' . '/symfony/yaml/Yaml.php',
'Symfony\\Contracts\\EventDispatcher\\Event' => __DIR__ . '/..' . '/symfony/event-dispatcher-contracts/Event.php',
'Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface' => __DIR__ . '/..' . '/symfony/event-dispatcher-contracts/EventDispatcherInterface.php',
'Symfony\\Contracts\\Service\\ResetInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ResetInterface.php',
'Symfony\\Contracts\\Service\\ServiceLocatorTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceLocatorTrait.php',
'Symfony\\Contracts\\Service\\ServiceProviderInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceProviderInterface.php',
'Symfony\\Contracts\\Service\\ServiceSubscriberInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceSubscriberInterface.php',
'Symfony\\Contracts\\Service\\ServiceSubscriberTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceSubscriberTrait.php',
'Symfony\\Contracts\\Service\\Test\\ServiceLocatorTest' => __DIR__ . '/..' . '/symfony/service-contracts/Test/ServiceLocatorTest.php',
'Symfony\\Polyfill\\Ctype\\Ctype' => __DIR__ . '/..' . '/symfony/polyfill-ctype/Ctype.php',
'Symfony\\Polyfill\\Intl\\Idn\\Idn' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Idn.php',
'Symfony\\Polyfill\\Intl\\Idn\\Info' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Info.php',
'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\DisallowedRanges' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php',
'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\Regex' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Resources/unidata/Regex.php',
'Symfony\\Polyfill\\Intl\\Normalizer\\Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Normalizer.php',
'Symfony\\Polyfill\\Mbstring\\Mbstring' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/Mbstring.php',
'Symfony\\Polyfill\\Php72\\Php72' => __DIR__ . '/..' . '/symfony/polyfill-php72/Php72.php',
'Symfony\\Polyfill\\Php73\\Php73' => __DIR__ . '/..' . '/symfony/polyfill-php73/Php73.php',
'Symfony\\Polyfill\\Php80\\Php80' => __DIR__ . '/..' . '/symfony/polyfill-php80/Php80.php',
'Text_Template' => __DIR__ . '/..' . '/phpunit/php-text-template/src/Template.php',
'TheSeer\\Tokenizer\\Exception' => __DIR__ . '/..' . '/theseer/tokenizer/src/Exception.php',
'TheSeer\\Tokenizer\\NamespaceUri' => __DIR__ . '/..' . '/theseer/tokenizer/src/NamespaceUri.php',
'TheSeer\\Tokenizer\\NamespaceUriException' => __DIR__ . '/..' . '/theseer/tokenizer/src/NamespaceUriException.php',
'TheSeer\\Tokenizer\\Token' => __DIR__ . '/..' . '/theseer/tokenizer/src/Token.php',
'TheSeer\\Tokenizer\\TokenCollection' => __DIR__ . '/..' . '/theseer/tokenizer/src/TokenCollection.php',
'TheSeer\\Tokenizer\\TokenCollectionException' => __DIR__ . '/..' . '/theseer/tokenizer/src/TokenCollectionException.php',
'TheSeer\\Tokenizer\\Tokenizer' => __DIR__ . '/..' . '/theseer/tokenizer/src/Tokenizer.php',
'TheSeer\\Tokenizer\\XMLSerializer' => __DIR__ . '/..' . '/theseer/tokenizer/src/XMLSerializer.php',
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
'Webmozart\\Assert\\Assert' => __DIR__ . '/..' . '/webmozart/assert/src/Assert.php',
'Webmozart\\Assert\\InvalidArgumentException' => __DIR__ . '/..' . '/webmozart/assert/src/InvalidArgumentException.php',
'Webmozart\\Assert\\Mixin' => __DIR__ . '/..' . '/webmozart/assert/src/Mixin.php',
'phpDocumentor\\Reflection\\DocBlock' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock.php',
'phpDocumentor\\Reflection\\DocBlockFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlockFactory.php',
'phpDocumentor\\Reflection\\DocBlockFactoryInterface' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlockFactoryInterface.php',
'phpDocumentor\\Reflection\\DocBlock\\Description' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Description.php',
'phpDocumentor\\Reflection\\DocBlock\\DescriptionFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/DescriptionFactory.php',
'phpDocumentor\\Reflection\\DocBlock\\ExampleFinder' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/ExampleFinder.php',
'phpDocumentor\\Reflection\\DocBlock\\Serializer' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Serializer.php',
'phpDocumentor\\Reflection\\DocBlock\\StandardTagFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/StandardTagFactory.php',
'phpDocumentor\\Reflection\\DocBlock\\Tag' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tag.php',
'phpDocumentor\\Reflection\\DocBlock\\TagFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/TagFactory.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Author' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Author.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\BaseTag' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/BaseTag.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Covers' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Covers.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Deprecated' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Deprecated.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Example' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Example.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\StaticMethod' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/StaticMethod.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter\\AlignFormatter' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/AlignFormatter.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter\\PassthroughFormatter' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/PassthroughFormatter.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Generic' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Generic.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\InvalidTag' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/InvalidTag.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Link' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Link.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Method' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Method.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Param' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Param.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Property' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Property.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\PropertyRead' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyRead.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\PropertyWrite' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyWrite.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Fqsen' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Fqsen.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Reference' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Reference.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Url' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Url.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Return_' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Return_.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\See' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/See.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Since' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Since.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Source' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Source.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\TagWithType' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TagWithType.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Throws' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Throws.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Uses' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Uses.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Var_' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Var_.php',
'phpDocumentor\\Reflection\\DocBlock\\Tags\\Version' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Version.php',
'phpDocumentor\\Reflection\\Element' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/Element.php',
'phpDocumentor\\Reflection\\Exception\\PcreException' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/Exception/PcreException.php',
'phpDocumentor\\Reflection\\File' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/File.php',
'phpDocumentor\\Reflection\\Fqsen' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/Fqsen.php',
'phpDocumentor\\Reflection\\FqsenResolver' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/FqsenResolver.php',
'phpDocumentor\\Reflection\\Location' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/Location.php',
'phpDocumentor\\Reflection\\Project' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/Project.php',
'phpDocumentor\\Reflection\\ProjectFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/ProjectFactory.php',
'phpDocumentor\\Reflection\\PseudoType' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoType.php',
'phpDocumentor\\Reflection\\PseudoTypes\\CallableString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/CallableString.php',
'phpDocumentor\\Reflection\\PseudoTypes\\False_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/False_.php',
'phpDocumentor\\Reflection\\PseudoTypes\\HtmlEscapedString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/HtmlEscapedString.php',
'phpDocumentor\\Reflection\\PseudoTypes\\LiteralString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/LiteralString.php',
'phpDocumentor\\Reflection\\PseudoTypes\\LowercaseString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/LowercaseString.php',
'phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyLowercaseString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyLowercaseString.php',
'phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyString.php',
'phpDocumentor\\Reflection\\PseudoTypes\\NumericString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/NumericString.php',
'phpDocumentor\\Reflection\\PseudoTypes\\PositiveInteger' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.php',
'phpDocumentor\\Reflection\\PseudoTypes\\TraitString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/TraitString.php',
'phpDocumentor\\Reflection\\PseudoTypes\\True_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/True_.php',
'phpDocumentor\\Reflection\\Type' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Type.php',
'phpDocumentor\\Reflection\\TypeResolver' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/TypeResolver.php',
'phpDocumentor\\Reflection\\Types\\AbstractList' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/AbstractList.php',
'phpDocumentor\\Reflection\\Types\\AggregatedType' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/AggregatedType.php',
'phpDocumentor\\Reflection\\Types\\ArrayKey' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/ArrayKey.php',
'phpDocumentor\\Reflection\\Types\\Array_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Array_.php',
'phpDocumentor\\Reflection\\Types\\Boolean' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Boolean.php',
'phpDocumentor\\Reflection\\Types\\Callable_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Callable_.php',
'phpDocumentor\\Reflection\\Types\\ClassString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/ClassString.php',
'phpDocumentor\\Reflection\\Types\\Collection' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Collection.php',
'phpDocumentor\\Reflection\\Types\\Compound' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Compound.php',
'phpDocumentor\\Reflection\\Types\\Context' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Context.php',
'phpDocumentor\\Reflection\\Types\\ContextFactory' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/ContextFactory.php',
'phpDocumentor\\Reflection\\Types\\Expression' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Expression.php',
'phpDocumentor\\Reflection\\Types\\Float_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Float_.php',
'phpDocumentor\\Reflection\\Types\\Integer' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Integer.php',
'phpDocumentor\\Reflection\\Types\\InterfaceString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/InterfaceString.php',
'phpDocumentor\\Reflection\\Types\\Intersection' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Intersection.php',
'phpDocumentor\\Reflection\\Types\\Iterable_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Iterable_.php',
'phpDocumentor\\Reflection\\Types\\Mixed_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Mixed_.php',
'phpDocumentor\\Reflection\\Types\\Never_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Never_.php',
'phpDocumentor\\Reflection\\Types\\Null_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Null_.php',
'phpDocumentor\\Reflection\\Types\\Nullable' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Nullable.php',
'phpDocumentor\\Reflection\\Types\\Object_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Object_.php',
'phpDocumentor\\Reflection\\Types\\Parent_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Parent_.php',
'phpDocumentor\\Reflection\\Types\\Resource_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Resource_.php',
'phpDocumentor\\Reflection\\Types\\Scalar' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Scalar.php',
'phpDocumentor\\Reflection\\Types\\Self_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Self_.php',
'phpDocumentor\\Reflection\\Types\\Static_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Static_.php',
'phpDocumentor\\Reflection\\Types\\String_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/String_.php',
'phpDocumentor\\Reflection\\Types\\This' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/This.php',
'phpDocumentor\\Reflection\\Types\\Void_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Void_.php',
'phpDocumentor\\Reflection\\Utils' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/Utils.php',
'phpseclib\\Crypt\\AES' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/AES.php',
'phpseclib\\Crypt\\Base' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Base.php',
'phpseclib\\Crypt\\Blowfish' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php',
'phpseclib\\Crypt\\DES' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/DES.php',
'phpseclib\\Crypt\\Hash' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Hash.php',
'phpseclib\\Crypt\\RC2' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/RC2.php',
'phpseclib\\Crypt\\RC4' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/RC4.php',
'phpseclib\\Crypt\\RSA' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/RSA.php',
'phpseclib\\Crypt\\Random' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Random.php',
'phpseclib\\Crypt\\Rijndael' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php',
'phpseclib\\Crypt\\TripleDES' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php',
'phpseclib\\Crypt\\Twofish' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php',
'phpseclib\\File\\ANSI' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/File/ANSI.php',
'phpseclib\\File\\ASN1' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/File/ASN1.php',
'phpseclib\\File\\ASN1\\Element' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/File/ASN1/Element.php',
'phpseclib\\File\\X509' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/File/X509.php',
'phpseclib\\Math\\BigInteger' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Math/BigInteger.php',
'phpseclib\\Net\\SCP' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SCP.php',
'phpseclib\\Net\\SFTP' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SFTP.php',
'phpseclib\\Net\\SFTP\\Stream' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php',
'phpseclib\\Net\\SSH1' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SSH1.php',
'phpseclib\\Net\\SSH2' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SSH2.php',
'phpseclib\\System\\SSH\\Agent' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php',
'phpseclib\\System\\SSH\\Agent\\Identity' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.php',
);

public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit8d2576a0103fe25d0268c6cba2a989ff::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit8d2576a0103fe25d0268c6cba2a989ff::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInit8d2576a0103fe25d0268c6cba2a989ff::$prefixesPsr0;
$loader->classMap = ComposerStaticInit8d2576a0103fe25d0268c6cba2a989ff::$classMap;

}, null, ClassLoader::class);
}
}
<?php



$issues = array();

if (!(PHP_VERSION_ID >= 70200)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.0". You are running ' . PHP_VERSION . '.';
}

if ($issues) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
} elseif (!headers_sent()) {
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
}
}
trigger_error(
'Composer detected issues in your platform: ' . implode(' ', $issues),
E_USER_ERROR
);
}
<?php



$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
'phpseclib\\' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'),
'phpDocumentor\\Reflection\\' => array($vendorDir . '/phpdocumentor/reflection-common/src', $vendorDir . '/phpdocumentor/type-resolver/src', $vendorDir . '/phpdocumentor/reflection-docblock/src'),
'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'),
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
'Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'),
'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'),
'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'),
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'),
'Symfony\\Contracts\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher-contracts'),
'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'),
'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'),
'Symfony\\Component\\DomCrawler\\' => array($vendorDir . '/symfony/dom-crawler'),
'Symfony\\Component\\CssSelector\\' => array($vendorDir . '/symfony/css-selector'),
'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
'Symfony\\Component\\BrowserKit\\' => array($vendorDir . '/symfony/browser-kit'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
'Prophecy\\' => array($vendorDir . '/phpspec/prophecy/src/Prophecy'),
'Predis\\' => array($vendorDir . '/predis/predis/src'),
'PhpAmqpLib\\' => array($vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib'),
'JsonSchema\\' => array($vendorDir . '/justinrainbow/json-schema/src/JsonSchema'),
'Humbug\\SelfUpdate\\' => array($vendorDir . '/padraic/phar-updater/src'),
'Humbug\\' => array($vendorDir . '/padraic/humbug_get_contents/src'),
'Hoa\\Ustring\\' => array($vendorDir . '/hoa/ustring'),
'Hoa\\Stream\\' => array($vendorDir . '/hoa/stream'),
'Hoa\\Protocol\\' => array($vendorDir . '/hoa/protocol'),
'Hoa\\Iterator\\' => array($vendorDir . '/hoa/iterator'),
'Hoa\\File\\' => array($vendorDir . '/hoa/file'),
'Hoa\\Exception\\' => array($vendorDir . '/hoa/exception'),
'Hoa\\Event\\' => array($vendorDir . '/hoa/event'),
'Hoa\\Console\\' => array($vendorDir . '/hoa/console'),
'Hoa\\Consistency\\' => array($vendorDir . '/hoa/consistency'),
'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
'Flow\\JSONPath\\' => array($vendorDir . '/softcreatr/jsonpath/src'),
'Facebook\\WebDriver\\' => array($vendorDir . '/php-webdriver/webdriver/lib'),
'Doctrine\\Instantiator\\' => array($vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator'),
'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'),
'Composer\\CaBundle\\' => array($vendorDir . '/composer/ca-bundle/src'),
'Codeception\\PHPUnit\\' => array($vendorDir . '/codeception/phpunit-wrapper/src'),
'Codeception\\Extension\\' => array($vendorDir . '/codeception/codeception/ext'),
'Codeception\\' => array($vendorDir . '/codeception/stub/src', $vendorDir . '/codeception/codeception/src/Codeception'),
);
<?php











namespace Composer;

use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;








class InstalledVersions
{
private static $installed;
private static $canGetVendors;
private static $installedByVendor = array();







public static function getInstalledPackages()
{
$packages = array();
foreach (self::getInstalled() as $installed) {
$packages[] = array_keys($installed['versions']);
}

if (1 === \count($packages)) {
return $packages[0];
}

return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
}








public static function getInstalledPackagesByType($type)
{
$packagesByType = array();

foreach (self::getInstalled() as $installed) {
foreach ($installed['versions'] as $name => $package) {
if (isset($package['type']) && $package['type'] === $type) {
$packagesByType[] = $name;
}
}
}

return $packagesByType;
}










public static function isInstalled($packageName, $includeDevRequirements = true)
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
}
}

return false;
}













public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints($constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));

return $provided->matches($constraint);
}










public static function getVersionRanges($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}

$ranges = array();
if (isset($installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
}

return implode(' || ', $ranges);
}

throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}





public static function getVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}

if (!isset($installed['versions'][$packageName]['version'])) {
return null;
}

return $installed['versions'][$packageName]['version'];
}

throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}





public static function getPrettyVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}

if (!isset($installed['versions'][$packageName]['pretty_version'])) {
return null;
}

return $installed['versions'][$packageName]['pretty_version'];
}

throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}





public static function getReference($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}

if (!isset($installed['versions'][$packageName]['reference'])) {
return null;
}

return $installed['versions'][$packageName]['reference'];
}

throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}





public static function getInstallPath($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}

return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
}

throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}





public static function getRootPackage()
{
$installed = self::getInstalled();

return $installed[0]['root'];
}








public static function getRawData()
{
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);

if (null === self::$installed) {

 
 if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = include __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}

return self::$installed;
}







public static function getAllRawData()
{
return self::getInstalled();
}



















public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
}





private static function getInstalled()
{
if (null === self::$canGetVendors) {
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
}

$installed = array();

if (self::$canGetVendors) {
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
}
}
}
}

if (null === self::$installed) {

 
 if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = require __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
$installed[] = self::$installed;

return $installed;
}
}
<?php



$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
'Behat\\Gherkin' => array($vendorDir . '/behat/gherkin/src'),
);
<?php










namespace Composer\CaBundle;

use Psr\Log\LoggerInterface;
use Symfony\Component\Process\PhpProcess;





class CaBundle
{

private static $caPath;

private static $caFileValidity = array();

private static $useOpensslParse;






































public static function getSystemCaRootBundlePath(LoggerInterface $logger = null)
{
if (self::$caPath !== null) {
return self::$caPath;
}
$caBundlePaths = array();


 
 $caBundlePaths[] = self::getEnvVariable('SSL_CERT_FILE');


 
 $caBundlePaths[] = self::getEnvVariable('SSL_CERT_DIR');

$caBundlePaths[] = ini_get('openssl.cafile');
$caBundlePaths[] = ini_get('openssl.capath');

$otherLocations = array(
'/etc/pki/tls/certs/ca-bundle.crt', 
 '/etc/ssl/certs/ca-certificates.crt', 
 '/etc/ssl/ca-bundle.pem', 
 '/usr/local/share/certs/ca-root-nss.crt', 
 '/usr/ssl/certs/ca-bundle.crt', 
 '/opt/local/share/curl/curl-ca-bundle.crt', 
 '/usr/local/share/curl/curl-ca-bundle.crt', 
 '/usr/share/ssl/certs/ca-bundle.crt', 
 '/etc/ssl/cert.pem', 
 '/usr/local/etc/ssl/cert.pem', 
 '/usr/local/etc/openssl/cert.pem', 
 '/usr/local/etc/openssl@1.1/cert.pem', 
 );

foreach($otherLocations as $location) {
$otherLocations[] = dirname($location);
}

$caBundlePaths = array_merge($caBundlePaths, $otherLocations);

foreach ($caBundlePaths as $caBundle) {
if ($caBundle && self::caFileUsable($caBundle, $logger)) {
return self::$caPath = $caBundle;
}

if ($caBundle && self::caDirUsable($caBundle, $logger)) {
return self::$caPath = $caBundle;
}
}

return self::$caPath = static::getBundledCaBundlePath(); 
 }








public static function getBundledCaBundlePath()
{
$caBundleFile = __DIR__.'/../res/cacert.pem';


 
 if (0 === strpos($caBundleFile, 'phar://')) {
$tempCaBundleFile = tempnam(sys_get_temp_dir(), 'openssl-ca-bundle-');
if (false === $tempCaBundleFile) {
throw new \RuntimeException('Could not create a temporary file to store the bundled CA file');
}

file_put_contents(
$tempCaBundleFile,
file_get_contents($caBundleFile)
);

register_shutdown_function(function() use ($tempCaBundleFile) {
@unlink($tempCaBundleFile);
});

$caBundleFile = $tempCaBundleFile;
}

return $caBundleFile;
}









public static function validateCaFile($filename, LoggerInterface $logger = null)
{
static $warned = false;

if (isset(self::$caFileValidity[$filename])) {
return self::$caFileValidity[$filename];
}

$contents = file_get_contents($filename);


 
 if (!static::isOpensslParseSafe()) {
if (!$warned && $logger) {
$logger->warning(sprintf(
'Your version of PHP, %s, is affected by CVE-2013-6420 and cannot safely perform certificate validation, we strongly suggest you upgrade.',
PHP_VERSION
));
$warned = true;
}

$isValid = !empty($contents);
} elseif (is_string($contents) && strlen($contents) > 0) {
$contents = preg_replace("/^(\\-+(?:BEGIN|END))\\s+TRUSTED\\s+(CERTIFICATE\\-+)\$/m", '$1 $2', $contents);
if (null === $contents) {

 $isValid = false;
} else {
$isValid = (bool) openssl_x509_parse($contents);
}
} else {
$isValid = false;
}

if ($logger) {
$logger->debug('Checked CA file '.realpath($filename).': '.($isValid ? 'valid' : 'invalid'));
}

return self::$caFileValidity[$filename] = $isValid;
}









public static function isOpensslParseSafe()
{
if (null !== self::$useOpensslParse) {
return self::$useOpensslParse;
}

if (PHP_VERSION_ID >= 50600) {
return self::$useOpensslParse = true;
}


 
 
 
 if (
(PHP_VERSION_ID < 50400 && PHP_VERSION_ID >= 50328)
|| (PHP_VERSION_ID < 50500 && PHP_VERSION_ID >= 50423)
|| PHP_VERSION_ID >= 50507
) {

 return self::$useOpensslParse = true;
}

if (defined('PHP_WINDOWS_VERSION_BUILD')) {

 return self::$useOpensslParse = false;
}

$compareDistroVersionPrefix = function ($prefix, $fixedVersion) {
$regex = '{^'.preg_quote($prefix).'([0-9]+)$}';

if (preg_match($regex, PHP_VERSION, $m)) {
return ((int) $m[1]) >= $fixedVersion;
}

return false;
};


 if (
$compareDistroVersionPrefix('5.3.3-7+squeeze', 18) 
 || $compareDistroVersionPrefix('5.4.4-14+deb7u', 7) 
 || $compareDistroVersionPrefix('5.3.10-1ubuntu3.', 9) 
 ) {
return self::$useOpensslParse = true;
}


 if (!class_exists('Symfony\Component\Process\PhpProcess')) {
return self::$useOpensslParse = false;
}


 
 
 
 
 


 
 $cert = 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVwRENDQTR5Z0F3SUJBZ0lKQUp6dThyNnU2ZUJjTUEwR0NTcUdTSWIzRFFFQkJRVUFNSUhETVFzd0NRWUQKVlFRR0V3SkVSVEVjTUJvR0ExVUVDQXdUVG05eVpISm9aV2x1TFZkbGMzUm1ZV3hsYmpFUU1BNEdBMVVFQnd3SApTOE9Ed3Jac2JqRVVNQklHQTFVRUNnd0xVMlZyZEdsdmJrVnBibk14SHpBZEJnTlZCQXNNRmsxaGJHbGphVzkxCmN5QkRaWEowSUZObFkzUnBiMjR4SVRBZkJnTlZCQU1NR0cxaGJHbGphVzkxY3k1elpXdDBhVzl1WldsdWN5NWsKWlRFcU1DZ0dDU3FHU0liM0RRRUpBUlliYzNSbFptRnVMbVZ6YzJWeVFITmxhM1JwYjI1bGFXNXpMbVJsTUhVWQpaREU1TnpBd01UQXhNREF3TURBd1dnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBCkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEKQUFBQUFBQVhEVEUwTVRFeU9ERXhNemt6TlZvd2djTXhDekFKQmdOVkJBWVRBa1JGTVJ3d0dnWURWUVFJREJOTwpiM0prY21obGFXNHRWMlZ6ZEdaaGJHVnVNUkF3RGdZRFZRUUhEQWRMdzRQQ3RteHVNUlF3RWdZRFZRUUtEQXRUClpXdDBhVzl1UldsdWN6RWZNQjBHQTFVRUN3d1dUV0ZzYVdOcGIzVnpJRU5sY25RZ1UyVmpkR2x2YmpFaE1COEcKQTFVRUF3d1liV0ZzYVdOcGIzVnpMbk5sYTNScGIyNWxhVzV6TG1SbE1Tb3dLQVlKS29aSWh2Y05BUWtCRmh0egpkR1ZtWVc0dVpYTnpaWEpBYzJWcmRHbHZibVZwYm5NdVpHVXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCCkR3QXdnZ0VLQW9JQkFRRERBZjNobDdKWTBYY0ZuaXlFSnBTU0RxbjBPcUJyNlFQNjV1c0pQUnQvOFBhRG9xQnUKd0VZVC9OYSs2ZnNnUGpDMHVLOURaZ1dnMnRIV1dvYW5TYmxBTW96NVBINlorUzRTSFJaN2UyZERJalBqZGhqaAowbUxnMlVNTzV5cDBWNzk3R2dzOWxOdDZKUmZIODFNTjJvYlhXczROdHp0TE11RDZlZ3FwcjhkRGJyMzRhT3M4CnBrZHVpNVVhd1Raa3N5NXBMUEhxNWNNaEZHbTA2djY1Q0xvMFYyUGQ5K0tBb2tQclBjTjVLTEtlYno3bUxwazYKU01lRVhPS1A0aWRFcXh5UTdPN2ZCdUhNZWRzUWh1K3ByWTNzaTNCVXlLZlF0UDVDWm5YMmJwMHdLSHhYMTJEWAoxbmZGSXQ5RGJHdkhUY3lPdU4rblpMUEJtM3ZXeG50eUlJdlZBZ01CQUFHalFqQkFNQWtHQTFVZEV3UUNNQUF3CkVRWUpZSVpJQVliNFFnRUJCQVFEQWdlQU1Bc0dBMVVkRHdRRUF3SUZvREFUQmdOVkhTVUVEREFLQmdnckJnRUYKQlFjREFqQU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUFHMGZaWVlDVGJkajFYWWMrMVNub2FQUit2SThDOENhRAo4KzBVWWhkbnlVNGdnYTBCQWNEclk5ZTk0ZUVBdTZacXljRjZGakxxWFhkQWJvcHBXb2NyNlQ2R0QxeDMzQ2tsClZBcnpHL0t4UW9oR0QySmVxa2hJTWxEb214SE83a2EzOStPYThpMnZXTFZ5alU4QVp2V01BcnVIYTRFRU55RzcKbFcyQWFnYUZLRkNyOVRuWFRmcmR4R1ZFYnY3S1ZRNmJkaGc1cDVTanBXSDErTXEwM3VSM1pYUEJZZHlWODMxOQpvMGxWajFLRkkyRENML2xpV2lzSlJvb2YrMWNSMzVDdGQwd1lCY3BCNlRac2xNY09QbDc2ZHdLd0pnZUpvMlFnClpzZm1jMnZDMS9xT2xOdU5xLzBUenprVkd2OEVUVDNDZ2FVK1VYZTRYT1Z2a2NjZWJKbjJkZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K';
$script = <<<'EOT'

error_reporting(-1);
$info = openssl_x509_parse(base64_decode('%s'));
var_dump(PHP_VERSION, $info['issuer']['emailAddress'], $info['validFrom_time_t']);

EOT;
$script = '<'."?php\n".sprintf($script, $cert);

try {
$process = new PhpProcess($script);
$process->mustRun();
} catch (\Exception $e) {

 
 return self::$useOpensslParse = false;
}

$output = preg_split('{\r?\n}', trim($process->getOutput()));
$errorOutput = trim($process->getErrorOutput());

if (
is_array($output)
&& count($output) === 3
&& $output[0] === sprintf('string(%d) "%s"', strlen(PHP_VERSION), PHP_VERSION)
&& $output[1] === 'string(27) "stefan.esser@sektioneins.de"'
&& $output[2] === 'int(-1)'
&& preg_match('{openssl_x509_parse\(\): illegal (?:ASN1 data type for|length in) timestamp in - on line \d+}', $errorOutput)
) {

 return self::$useOpensslParse = true;
}

return self::$useOpensslParse = false;
}





public static function reset()
{
self::$caFileValidity = array();
self::$caPath = null;
self::$useOpensslParse = null;
}





private static function getEnvVariable($name)
{
if (isset($_SERVER[$name])) {
return (string) $_SERVER[$name];
}

if (PHP_SAPI === 'cli' && ($value = getenv($name)) !== false && $value !== null) {
return (string) $value;
}

return false;
}






private static function caFileUsable($certFile, LoggerInterface $logger = null)
{
return $certFile
&& static::isFile($certFile, $logger)
&& static::isReadable($certFile, $logger)
&& static::validateCaFile($certFile, $logger);
}






private static function caDirUsable($certDir, LoggerInterface $logger = null)
{
return $certDir
&& static::isDir($certDir, $logger)
&& static::isReadable($certDir, $logger)
&& static::glob($certDir . '/*', $logger);
}






private static function isFile($certFile, LoggerInterface $logger = null)
{
$isFile = @is_file($certFile);
if (!$isFile && $logger) {
$logger->debug(sprintf('Checked CA file %s does not exist or it is not a file.', $certFile));
}

return $isFile;
}






private static function isDir($certDir, LoggerInterface $logger = null)
{
$isDir = @is_dir($certDir);
if (!$isDir && $logger) {
$logger->debug(sprintf('Checked directory %s does not exist or it is not a directory.', $certDir));
}

return $isDir;
}






private static function isReadable($certFileOrDir, LoggerInterface $logger = null)
{
$isReadable = @is_readable($certFileOrDir);
if (!$isReadable && $logger) {
$logger->debug(sprintf('Checked file or directory %s is not readable.', $certFileOrDir));
}

return $isReadable;
}






private static function glob($pattern, LoggerInterface $logger = null)
{
$certs = glob($pattern);
if ($certs === false) {
if ($logger) {
$logger->debug(sprintf("An error occurred while trying to find certificates for pattern: %s", $pattern));
}
return false;
}

if (count($certs) === 0) {
if ($logger) {
$logger->debug(sprintf("No CA files found for pattern: %s", $pattern));
}
return false;
}

return true;
}
}
<?php







declare(strict_types=1);

namespace Flow\JSONPath;

use ArrayAccess;

use function abs;
use function array_key_exists;
use function array_keys;
use function array_slice;
use function array_values;
use function get_object_vars;
use function is_array;
use function is_int;
use function is_object;
use function method_exists;
use function property_exists;

class AccessHelper
{



public static function collectionKeys($collection): array
{
if (is_object($collection)) {
return array_keys(get_object_vars($collection));
}

return array_keys($collection);
}




public static function isCollectionType($collection): bool
{
return is_array($collection) || is_object($collection);
}




public static function keyExists($collection, $key, bool $magicIsAllowed = false): bool
{
if ($magicIsAllowed && is_object($collection) && method_exists($collection, '__get')) {
return true;
}

if (is_int($key) && $key < 0) {
$key = abs($key);
}

if (is_array($collection)) {
return array_key_exists($key, $collection);
}

if ($collection instanceof ArrayAccess) {
return $collection->offsetExists($key);
}

if (is_object($collection)) {
return property_exists($collection, (string)$key);
}

return false;
}







public static function getValue($collection, $key, bool $magicIsAllowed = false)
{
$return = null;

if (
$magicIsAllowed &&
is_object($collection) &&
!$collection instanceof ArrayAccess && method_exists($collection, '__get')
) {
$return = $collection->__get($key);
} elseif (is_object($collection) && !$collection instanceof ArrayAccess) {
$return = $collection->$key;
} elseif ($collection instanceof ArrayAccess) {
$return = $collection->offsetGet($key);
} elseif (is_array($collection)) {
if (is_int($key) && $key < 0) {
$return = array_slice($collection, $key, 1, false)[0];
} else {
$return = $collection[$key];
}
} elseif (is_int($key)) {
$return = self::getValueByIndex($collection, $key);
} else {
$return = $collection[$key];
}

return $return;
}









private static function getValueByIndex($collection, $key)
{
$i = 0;

foreach ($collection as $val) {
if ($i === $key) {
return $val;
}

++$i;
}

if ($key < 0) {
$total = $i;
$i = 0;

foreach ($collection as $val) {
if ($i - $total === $key) {
return $val;
}

++$i;
}
}

return null;
}




public static function setValue(&$collection, $key, $value)
{
if (is_object($collection) && !$collection instanceof ArrayAccess) {
return $collection->$key = $value;
}

if ($collection instanceof ArrayAccess) {
return $collection->offsetSet($key, $value);
}

return $collection[$key] = $value;
}




public static function unsetValue(&$collection, $key): void
{
if (is_object($collection) && !$collection instanceof ArrayAccess) {
unset($collection->$key);
}

if ($collection instanceof ArrayAccess) {
$collection->offsetUnset($key);
}

if (is_array($collection)) {
unset($collection[$key]);
}
}






public static function arrayValues($collection): array
{
if (is_array($collection)) {
return array_values($collection);
}

if (is_object($collection)) {
return array_values((array)$collection);
}

throw new JSONPathException("Invalid variable type for arrayValues");
}
}
<?php







declare(strict_types=1);

namespace Flow\JSONPath\Filters;

use Flow\JSONPath\{AccessHelper, JSONPathException};

class IndexFilter extends AbstractFilter
{





public function filter($collection): array
{
if (is_array($this->token->value)) {
$result = [];
foreach ($this->token->value as $value) {
if (AccessHelper::keyExists($collection, $value, $this->magicIsAllowed)) {
$result[] = AccessHelper::getValue($collection, $value, $this->magicIsAllowed);
}
}
return $result;
}

if (AccessHelper::keyExists($collection, $this->token->value, $this->magicIsAllowed)) {
return [
AccessHelper::getValue($collection, $this->token->value, $this->magicIsAllowed),
];
}

if ($this->token->value === '*') {
return AccessHelper::arrayValues($collection);
}

if ($this->token->value === 'length') {
return [
count($collection),
];
}

return [];
}
}
<?php







declare(strict_types=1);

namespace Flow\JSONPath\Filters;

use Flow\JSONPath\AccessHelper;

use function count;

class SliceFilter extends AbstractFilter
{



public function filter($collection): array
{
$length = count($collection);
$start = $this->token->value['start'];
$end = $this->token->value['end'];
$step = $this->token->value['step'] ?: 1;

if ($start === null) {
$start = 0;
}

if ($start < 0) {
$start = $length + $start;
if ($start < 0) {
$start = 0;
}
}

if ($end === null) {

 $end = $length;
}

if ($end < 0) {
$end = $length + $end;
}

$result = [];

for ($i = $start; $i < $end; $i += $step) {
$index = $i;

if ($i < 0) {
$index = $length + $i;
}

if (AccessHelper::keyExists($collection, $index, $this->magicIsAllowed)) {
$result[] = $collection[$index];
}
}

return $result;
}
}
<?php







declare(strict_types=1);

namespace Flow\JSONPath\Filters;

use Flow\JSONPath\AccessHelper;
use RuntimeException;

use function explode;
use function in_array;
use function is_array;
use function is_string;
use function preg_match;
use function preg_replace;
use function strpos;
use function strtolower;
use function substr;

class QueryMatchFilter extends AbstractFilter
{
protected const MATCH_QUERY_OPERATORS = '
      @(\.(?<key>[^\s<>!=]+)|\[["\']?(?<keySquare>.*?)["\']?\])
      (\s*(?<operator>==|=~|=|<>|!==|!=|>=|<=|>|<|in|!in|nin)\s*(?<comparisonValue>.+))?
    ';




public function filter($collection): array
{
preg_match('/^' . static::MATCH_QUERY_OPERATORS . '$/x', $this->token->value, $matches);

if (!isset($matches[1])) {
throw new RuntimeException('Malformed filter query');
}

$key = $matches['key'] ?: $matches['keySquare'];

if ($key === '') {
throw new RuntimeException('Malformed filter query: key was not set');
}

$operator = $matches['operator'] ?? null;
$comparisonValue = $matches['comparisonValue'] ?? null;

if (is_string($comparisonValue)) {
if (strpos($comparisonValue, "[") === 0 && substr($comparisonValue, -1) === "]") {
$comparisonValue = substr($comparisonValue, 1, -1);
$comparisonValue = preg_replace('/^[\'"]/', '', $comparisonValue);
$comparisonValue = preg_replace('/[\'"]$/', '', $comparisonValue);
$comparisonValue = preg_replace('/[\'"],[ ]*[\'"]/', ',', $comparisonValue);
$comparisonValue = array_map('trim', explode(",", $comparisonValue));
} else {
$comparisonValue = preg_replace('/^[\'"]/', '', $comparisonValue);
$comparisonValue = preg_replace('/[\'"]$/', '', $comparisonValue);

if (strtolower($comparisonValue) === 'false') {
$comparisonValue = false;
} elseif (strtolower($comparisonValue) === 'true') {
$comparisonValue = true;
} elseif (strtolower($comparisonValue) === 'null') {
$comparisonValue = null;
}
}
}

$return = [];

foreach ($collection as $value) {
if (AccessHelper::keyExists($value, $key, $this->magicIsAllowed)) {
$value1 = AccessHelper::getValue($value, $key, $this->magicIsAllowed);

if ($operator === null && $value1) {
$return[] = $value;
}



 if (($operator === '=' || $operator === '==') && $value1 == $comparisonValue) {
$return[] = $value;
}



 if (($operator === '!=' || $operator === '!==' || $operator === '<>') && $value1 != $comparisonValue) {
$return[] = $value;
}

if ($operator === '=~' && @preg_match($comparisonValue, $value1)) {
$return[] = $value;
}

if ($operator === '>' && $value1 > $comparisonValue) {
$return[] = $value;
}

if ($operator === '>=' && $value1 >= $comparisonValue) {
$return[] = $value;
}

if ($operator === '<' && $value1 < $comparisonValue) {
$return[] = $value;
}

if ($operator === '<=' && $value1 <= $comparisonValue) {
$return[] = $value;
}

if ($operator === 'in' && is_array($comparisonValue) && in_array($value1, $comparisonValue)) {
$return[] = $value;
}

if (
($operator === 'nin' || $operator === '!in') &&
is_array($comparisonValue) &&
!in_array($value1, $comparisonValue)
) {
$return[] = $value;
}
}
}

return $return;
}
}
<?php







declare(strict_types=1);

namespace Flow\JSONPath\Filters;

use ArrayAccess;
use Flow\JSONPath\{JSONPath, JSONPathToken};

abstract class AbstractFilter
{



protected $token;




protected $magicIsAllowed = false;




public function __construct(JSONPathToken $token, $options = false)
{
$this->token = $token;
$this->magicIsAllowed = (bool)($options & JSONPath::ALLOW_MAGIC);
}




abstract public function filter($collection): array;
}
<?php







declare(strict_types=1);

namespace Flow\JSONPath\Filters;

use Flow\JSONPath\{AccessHelper, JSONPathException};

use function count;
use function preg_match;

class QueryResultFilter extends AbstractFilter
{





public function filter($collection): array
{
preg_match('/@\.(?<key>\w+)\s*(?<operator>[-+*\/])\s*(?<numeric>\d+)/', $this->token->value, $matches);

$matchKey = $matches['key'];

if (AccessHelper::keyExists($collection, $matchKey, $this->magicIsAllowed)) {
$value = AccessHelper::getValue($collection, $matchKey, $this->magicIsAllowed);
} elseif ($matches['key'] === 'length') {
$value = count($collection);
} else {
return [];
}

switch ($matches['operator']) {
case '+':
$resultKey = $value + $matches['numeric'];
break;
case '*':
$resultKey = $value * $matches['numeric'];
break;
case '-':
$resultKey = $value - $matches['numeric'];
break;
case '/':
$resultKey = $value / $matches['numeric'];
break;
default:
throw new JSONPathException('Unsupported operator in expression');
}

$result = [];

if (AccessHelper::keyExists($collection, $resultKey, $this->magicIsAllowed)) {
$result[] = AccessHelper::getValue($collection, $resultKey, $this->magicIsAllowed);
}

return $result;
}
}
<?php







declare(strict_types=1);

namespace Flow\JSONPath\Filters;

use Flow\JSONPath\AccessHelper;

class IndexesFilter extends AbstractFilter
{



public function filter($collection): array
{
$return = [];

foreach ($this->token->value as $index) {
if (AccessHelper::keyExists($collection, $index, $this->magicIsAllowed)) {
$return[] = AccessHelper::getValue($collection, $index, $this->magicIsAllowed);
}
}

return $return;
}
}
<?php







declare(strict_types=1);

namespace Flow\JSONPath\Filters;

use Flow\JSONPath\{AccessHelper, JSONPathException};
use ArrayAccess;

class RecursiveFilter extends AbstractFilter
{





public function filter($collection): array
{
$result = [];

$this->recurse($result, $collection);

return $result;
}






private function recurse(array &$result, $data): void
{
$result[] = $data;

if (AccessHelper::isCollectionType($data)) {
foreach (AccessHelper::arrayValues($data) as $key => $value) {
$results[] = $value;

if (AccessHelper::isCollectionType($value)) {
$this->recurse($result, $value);
}
}
}
}
}
<?php







declare(strict_types=1);

namespace Flow\JSONPath;

use function explode;
use function in_array;
use function preg_match;
use function strlen;
use function substr;
use function trim;

class JSONPathLexer
{




public const MATCH_INDEX = '(?!\-)[\-\w]+ | \*'; 
 public const MATCH_INDEXES = '\s* -?\d+ [-?\d,\s]+'; 
 public const MATCH_SLICE = '[-\d:]+ | :'; 
 public const MATCH_QUERY_RESULT = '\s* \( .+? \) \s*'; 
 public const MATCH_QUERY_MATCH = '\s* \?\(.+?\) \s*'; 
 public const MATCH_INDEX_IN_SINGLE_QUOTES = '\s* \' (.+?)? \' \s*'; 
 public const MATCH_INDEX_IN_DOUBLE_QUOTES = '\s* " (.+?)? " \s*'; 






protected $expression = '';






protected $expressionLength = 0;

public function __construct(string $expression)
{
$expression = trim($expression);
$len = strlen($expression);

if ($len > 1) {
if ($expression[0] === '$') {
$expression = substr($expression, 1);
$len--;
}

if ($expression[0] !== '.' && $expression[0] !== '[') {
$expression = '.' . $expression;
$len++;
}

$this->expression = $expression;
$this->expressionLength = $len;
}
}




public function parseExpressionTokens(): array
{
$dotIndexDepth = 0;
$squareBracketDepth = 0;
$tokenValue = '';
$tokens = [];

for ($i = 0; $i < $this->expressionLength; $i++) {
$char = $this->expression[$i];

if (($squareBracketDepth === 0) && $char === '.') {
if ($this->lookAhead($i) === '.') {
$tokens[] = new JSONPathToken(JSONPathToken::T_RECURSIVE, null);
}

continue;
}

if ($char === '[') {
++$squareBracketDepth;

if ($squareBracketDepth === 1) {
continue;
}
}

if ($char === ']') {
--$squareBracketDepth;

if ($squareBracketDepth === 0) {
continue;
}
}




if ($squareBracketDepth > 0) {
$tokenValue .= $char;

if ($squareBracketDepth === 1 && $this->lookAhead($i) === ']') {
$tokens[] = $this->createToken($tokenValue);
$tokenValue = '';
}
}




if ($squareBracketDepth === 0) {
$tokenValue .= $char;


 if ($char === '.' && $dotIndexDepth > 1) {
$tokens[] = $this->createToken($tokenValue);
$tokenValue = '';
continue;
}

if ($this->atEnd($i) || in_array($this->lookAhead($i), ['.', '['])) {
$tokens[] = $this->createToken($tokenValue);
$tokenValue = '';
--$dotIndexDepth;
}
}
}

if ($tokenValue !== '') {
$tokens[] = $this->createToken($tokenValue);
}

return $tokens;
}

protected function lookAhead(int $pos, int $forward = 1): ?string
{
return $this->expression[$pos + $forward] ?? null;
}

protected function atEnd(int $pos): bool
{
return $pos === $this->expressionLength;
}




public function parseExpression(): array
{
return $this->parseExpressionTokens();
}




protected function createToken(string $value): JSONPathToken
{

 
 $tokenValue = $value;


$ret = null;

if (preg_match('/^(' . static::MATCH_INDEX . ')$/xu', $tokenValue, $matches)) {
if (preg_match('/^-?\d+$/', $tokenValue)) {
$tokenValue = (int)$tokenValue;
}

$ret = new JSONPathToken(JSONPathToken::T_INDEX, $tokenValue);
} elseif (preg_match('/^' . static::MATCH_INDEXES . '$/xu', $tokenValue, $matches)) {
$tokenValue = explode(',', trim($tokenValue, ','));

foreach ($tokenValue as $i => $v) {
$tokenValue[$i] = (int)trim($v);
}

$ret = new JSONPathToken(JSONPathToken::T_INDEXES, $tokenValue);
} elseif (preg_match('/^' . static::MATCH_SLICE . '$/xu', $tokenValue, $matches)) {
$parts = explode(':', $tokenValue);
$tokenValue = [
'start' => isset($parts[0]) && $parts[0] !== '' ? (int)$parts[0] : null,
'end' => isset($parts[1]) && $parts[1] !== '' ? (int)$parts[1] : null,
'step' => isset($parts[2]) && $parts[2] !== '' ? (int)$parts[2] : null,
];

$ret = new JSONPathToken(JSONPathToken::T_SLICE, $tokenValue);
} elseif (preg_match('/^' . static::MATCH_QUERY_RESULT . '$/xu', $tokenValue)) {
$tokenValue = substr($tokenValue, 1, -1);

$ret = new JSONPathToken(JSONPathToken::T_QUERY_RESULT, $tokenValue);
} elseif (preg_match('/^' . static::MATCH_QUERY_MATCH . '$/xu', $tokenValue)) {
$tokenValue = substr($tokenValue, 2, -1);

$ret = new JSONPathToken(JSONPathToken::T_QUERY_MATCH, $tokenValue);
} elseif (
preg_match('/^' . static::MATCH_INDEX_IN_SINGLE_QUOTES . '$/xu', $tokenValue, $matches) ||
preg_match('/^' . static::MATCH_INDEX_IN_DOUBLE_QUOTES . '$/xu', $tokenValue, $matches)
) {
if (isset($matches[1])) {
$tokenValue = $matches[1];
$tokenValue = trim($tokenValue);

$possibleArray = false;
if ($matches[0][0] === '"') {
$possibleArray = explode('","', $tokenValue);
} elseif ($matches[0][0] === "'") {
$possibleArray = explode("','", $tokenValue);
}
if ($possibleArray !== false && count($possibleArray) > 1) {
$tokenValue = $possibleArray;
}
} else {
$tokenValue = '';
}

$ret = new JSONPathToken(JSONPathToken::T_INDEX, $tokenValue);
}

if ($ret !== null) {
return $ret;
}

throw new JSONPathException("Unable to parse token {$tokenValue} in expression: $this->expression");
}
}
<?php







declare(strict_types=1);

namespace Flow\JSONPath;

use Exception;

class JSONPathException extends Exception
{
}
<?php







declare(strict_types=1);

namespace Flow\JSONPath;

use ArrayAccess;
use Countable;
use Iterator;
use JsonSerializable;

use function array_merge;
use function count;
use function crc32;
use function current;
use function end;
use function key;
use function next;
use function reset;

use const E_USER_DEPRECATED;

class JSONPath implements ArrayAccess, Iterator, JsonSerializable, Countable
{
public const ALLOW_MAGIC = true;




protected static $tokenCache = [];




protected $data = [];




protected $options = false;




final public function __construct($data = [], bool $options = false)
{
$this->data = $data;
$this->options = $options;
}








public function find(string $expression): self
{
$tokens = $this->parseTokens($expression);
$collectionData = [$this->data];

foreach ($tokens as $token) {

$filter = $token->buildFilter($this->options);
$filteredDataList = [];

foreach ($collectionData as $value) {
if (AccessHelper::isCollectionType($value)) {
$filteredDataList[] = $filter->filter($value);
}
}

if (!empty($filteredDataList)) {
$collectionData = array_merge(...$filteredDataList);
} else {
$collectionData = [];
}
}

return new static($collectionData, $this->options);
}




public function first()
{
$keys = AccessHelper::collectionKeys($this->data);

if (empty($keys)) {
return null;
}

$value = $this->data[$keys[0]] ?? null;

return AccessHelper::isCollectionType($value) ? new static($value, $this->options) : $value;
}






public function last()
{
$keys = AccessHelper::collectionKeys($this->data);

if (empty($keys)) {
return null;
}

$value = $this->data[end($keys)] ?: null;

return AccessHelper::isCollectionType($value) ? new static($value, $this->options) : $value;
}






public function firstKey()
{
$keys = AccessHelper::collectionKeys($this->data);

if (empty($keys)) {
return null;
}

return $keys[0];
}






public function lastKey()
{
$keys = AccessHelper::collectionKeys($this->data);

if (empty($keys) || end($keys) === false) {
return null;
}

return end($keys);
}




public function parseTokens(string $expression): array
{
$cacheKey = crc32($expression);

if (isset(static::$tokenCache[$cacheKey])) {
return static::$tokenCache[$cacheKey];
}

$lexer = new JSONPathLexer($expression);
$tokens = $lexer->parseExpression();

static::$tokenCache[$cacheKey] = $tokens;

return $tokens;
}

public function getData(): array
{
return $this->data;
}




public function data(): array
{
trigger_error(
'Calling JSONPath::data() is deprecated, please use JSONPath::getData() instead.',
E_USER_DEPRECATED
);

return $this->getData();
}





public function __get($key)
{
return $this->offsetExists($key) ? $this->offsetGet($key) : null;
}




public function offsetExists($offset): bool
{
return AccessHelper::keyExists($this->data, $offset);
}




public function offsetGet($offset)
{
$value = AccessHelper::getValue($this->data, $offset);

return AccessHelper::isCollectionType($value)
? new static($value, $this->options)
: $value;
}




public function offsetSet($offset, $value): void
{
if ($offset === null) {
$this->data[] = $value;
} else {
AccessHelper::setValue($this->data, $offset, $value);
}
}




public function offsetUnset($offset): void
{
AccessHelper::unsetValue($this->data, $offset);
}




public function jsonSerialize(): array
{
return $this->getData();
}




public function current()
{
$value = current($this->data);

return AccessHelper::isCollectionType($value) ? new static($value, $this->options) : $value;
}




public function next(): void
{
next($this->data);
}




public function key()
{
return key($this->data);
}




public function valid(): bool
{
return key($this->data) !== null;
}




public function rewind(): void
{
reset($this->data);
}




public function count(): int
{
return count($this->data);
}
}
<?php







declare(strict_types=1);

namespace Flow\JSONPath;

use function class_exists;
use function in_array;
use function ucfirst;

class JSONPathToken
{



public const T_INDEX = 'index';
public const T_RECURSIVE = 'recursive';
public const T_QUERY_RESULT = 'queryResult';
public const T_QUERY_MATCH = 'queryMatch';
public const T_SLICE = 'slice';
public const T_INDEXES = 'indexes';




public $type;

public $value;




public function __construct(string $type, $value)
{
$this->validateType($type);

$this->type = $type;
$this->value = $value;
}




public function validateType(string $type): void
{
if (!in_array($type, static::getTypes(), true)) {
throw new JSONPathException('Invalid token: ' . $type);
}
}

public static function getTypes(): array
{
return [
static::T_INDEX,
static::T_RECURSIVE,
static::T_QUERY_RESULT,
static::T_QUERY_MATCH,
static::T_SLICE,
static::T_INDEXES,
];
}




public function buildFilter(bool $options)
{
$filterClass = 'Flow\\JSONPath\\Filters\\' . ucfirst($this->type) . 'Filter';

if (!class_exists($filterClass)) {
throw new JSONPathException("No filter class exists for token [{$this->type}]");
}

return new $filterClass($this, $options);
}
}
<?php

declare(strict_types=1);

namespace Psr\Container;




interface ContainerInterface
{










public function get(string $id);












public function has(string $id);
}
<?php

namespace Psr\Container;




interface NotFoundExceptionInterface extends ContainerExceptionInterface
{
}
<?php

namespace Psr\Container;




interface ContainerExceptionInterface
{
}
<?php

namespace Psr\Http\Message;
















interface ResponseInterface extends MessageInterface
{








public function getStatusCode();





















public function withStatus($code, $reasonPhrase = '');














public function getReasonPhrase();
}
<?php

namespace Psr\Http\Message;




















interface RequestInterface extends MessageInterface
{
















public function getRequestTarget();


















public function withRequestTarget($requestTarget);






public function getMethod();
















public function withMethod($method);










public function getUri();































public function withUri(UriInterface $uri, $preserveHost = false);
}
<?php

namespace Psr\Http\Message;







































interface ServerRequestInterface extends RequestInterface
{









public function getServerParams();











public function getCookieParams();


















public function withCookieParams(array $cookies);













public function getQueryParams();























public function withQueryParams(array $query);













public function getUploadedFiles();












public function withUploadedFiles(array $uploadedFiles);
















public function getParsedBody();





























public function withParsedBody($data);












public function getAttributes();
















public function getAttribute($name, $default = null);
















public function withAttribute($name, $value);















public function withoutAttribute($name);
}
<?php

namespace Psr\Http\Message;













interface MessageInterface
{







public function getProtocolVersion();














public function withProtocolVersion($version);


























public function getHeaders();









public function hasHeader($name);















public function getHeader($name);




















public function getHeaderLine($name);
















public function withHeader($name, $value);

















public function withAddedHeader($name, $value);













public function withoutHeader($name);






public function getBody();














public function withBody(StreamInterface $body);
}
<?php

namespace Psr\Http\Message;








interface StreamInterface
{














public function __toString();






public function close();








public function detach();






public function getSize();







public function tell();






public function eof();






public function isSeekable();













public function seek($offset, $whence = SEEK_SET);











public function rewind();






public function isWritable();








public function write($string);






public function isReadable();











public function read($length);








public function getContents();













public function getMetadata($key = null);
}
<?php

namespace Psr\Http\Message;









interface UploadedFileInterface
{
















public function getStream();

































public function moveTo($targetPath);










public function getSize();















public function getError();














public function getClientFilename();














public function getClientMediaType();
}
<?php
namespace Psr\Http\Message;





















interface UriInterface
{














public function getScheme();



















public function getAuthority();
















public function getUserInfo();












public function getHost();
















public function getPort();


























public function getPath();





















public function getQuery();

















public function getFragment();
















public function withScheme($scheme);















public function withUserInfo($user, $password = null);













public function withHost($host);


















public function withPort($port);























public function withPath($path);
















public function withQuery($query);















public function withFragment($fragment);
























public function __toString();
}
<?php

namespace GuzzleHttp\Promise;





class EachPromise implements PromisorInterface
{
private $pending = [];

private $nextPendingIndex = 0;


private $iterable;


private $concurrency;


private $onFulfilled;


private $onRejected;


private $aggregate;


private $mutex;






















public function __construct($iterable, array $config = [])
{
$this->iterable = Create::iterFor($iterable);

if (isset($config['concurrency'])) {
$this->concurrency = $config['concurrency'];
}

if (isset($config['fulfilled'])) {
$this->onFulfilled = $config['fulfilled'];
}

if (isset($config['rejected'])) {
$this->onRejected = $config['rejected'];
}
}


public function promise()
{
if ($this->aggregate) {
return $this->aggregate;
}

try {
$this->createPromise();

$this->iterable->rewind();
$this->refillPending();
} catch (\Throwable $e) {




$this->aggregate->reject($e);
} catch (\Exception $e) {




$this->aggregate->reject($e);
}





return $this->aggregate;
}

private function createPromise()
{
$this->mutex = false;
$this->aggregate = new Promise(function () {
if ($this->checkIfFinished()) {
return;
}
reset($this->pending);

 
 while ($promise = current($this->pending)) {
next($this->pending);
$promise->wait();
if (Is::settled($this->aggregate)) {
return;
}
}
});


 $clearFn = function () {
$this->iterable = $this->concurrency = $this->pending = null;
$this->onFulfilled = $this->onRejected = null;
$this->nextPendingIndex = 0;
};

$this->aggregate->then($clearFn, $clearFn);
}

private function refillPending()
{
if (!$this->concurrency) {

 while ($this->addPending() && $this->advanceIterator());
return;
}


 $concurrency = is_callable($this->concurrency)
? call_user_func($this->concurrency, count($this->pending))
: $this->concurrency;
$concurrency = max($concurrency - count($this->pending), 0);

 if (!$concurrency) {
return;
}

 $this->addPending();

 
 
 
 while (--$concurrency
&& $this->advanceIterator()
&& $this->addPending());
}

private function addPending()
{
if (!$this->iterable || !$this->iterable->valid()) {
return false;
}

$promise = Create::promiseFor($this->iterable->current());
$key = $this->iterable->key();


 
 $idx = $this->nextPendingIndex++;

$this->pending[$idx] = $promise->then(
function ($value) use ($idx, $key) {
if ($this->onFulfilled) {
call_user_func(
$this->onFulfilled,
$value,
$key,
$this->aggregate
);
}
$this->step($idx);
},
function ($reason) use ($idx, $key) {
if ($this->onRejected) {
call_user_func(
$this->onRejected,
$reason,
$key,
$this->aggregate
);
}
$this->step($idx);
}
);

return true;
}

private function advanceIterator()
{

 
 if ($this->mutex) {
return false;
}

$this->mutex = true;

try {
$this->iterable->next();
$this->mutex = false;
return true;
} catch (\Throwable $e) {
$this->aggregate->reject($e);
$this->mutex = false;
return false;
} catch (\Exception $e) {
$this->aggregate->reject($e);
$this->mutex = false;
return false;
}
}

private function step($idx)
{

 if (Is::settled($this->aggregate)) {
return;
}

unset($this->pending[$idx]);


 
 
 if ($this->advanceIterator() && !$this->checkIfFinished()) {

 $this->refillPending();
}
}

private function checkIfFinished()
{
if (!$this->pending && !$this->iterable->valid()) {

 $this->aggregate->resolve(null);
return true;
}

return false;
}
}
<?php

namespace GuzzleHttp\Promise;

interface TaskQueueInterface
{





public function isEmpty();





public function add(callable $task);




public function run();
}
<?php

namespace GuzzleHttp\Promise;

final class Utils
{

















public static function queue(TaskQueueInterface $assign = null)
{
static $queue;

if ($assign) {
$queue = $assign;
} elseif (!$queue) {
$queue = new TaskQueue();
}

return $queue;
}









public static function task(callable $task)
{
$queue = self::queue();
$promise = new Promise([$queue, 'run']);
$queue->add(function () use ($task, $promise) {
try {
if (Is::pending($promise)) {
$promise->resolve($task());
}
} catch (\Throwable $e) {
$promise->reject($e);
} catch (\Exception $e) {
$promise->reject($e);
}
});

return $promise;
}















public static function inspect(PromiseInterface $promise)
{
try {
return [
'state' => PromiseInterface::FULFILLED,
'value' => $promise->wait()
];
} catch (RejectionException $e) {
return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()];
} catch (\Throwable $e) {
return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
} catch (\Exception $e) {
return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
}
}













public static function inspectAll($promises)
{
$results = [];
foreach ($promises as $key => $promise) {
$results[$key] = inspect($promise);
}

return $results;
}















public static function unwrap($promises)
{
$results = [];
foreach ($promises as $key => $promise) {
$results[$key] = $promise->wait();
}

return $results;
}














public static function all($promises, $recursive = false)
{
$results = [];
$promise = Each::of(
$promises,
function ($value, $idx) use (&$results) {
$results[$idx] = $value;
},
function ($reason, $idx, Promise $aggregate) {
$aggregate->reject($reason);
}
)->then(function () use (&$results) {
ksort($results);
return $results;
});

if (true === $recursive) {
$promise = $promise->then(function ($results) use ($recursive, &$promises) {
foreach ($promises as $promise) {
if (Is::pending($promise)) {
return self::all($promises, $recursive);
}
}
return $results;
});
}

return $promise;
}

















public static function some($count, $promises)
{
$results = [];
$rejections = [];

return Each::of(
$promises,
function ($value, $idx, PromiseInterface $p) use (&$results, $count) {
if (Is::settled($p)) {
return;
}
$results[$idx] = $value;
if (count($results) >= $count) {
$p->resolve(null);
}
},
function ($reason) use (&$rejections) {
$rejections[] = $reason;
}
)->then(
function () use (&$results, &$rejections, $count) {
if (count($results) !== $count) {
throw new AggregateException(
'Not enough promises to fulfill count',
$rejections
);
}
ksort($results);
return array_values($results);
}
);
}









public static function any($promises)
{
return self::some(1, $promises)->then(function ($values) {
return $values[0];
});
}













public static function settle($promises)
{
$results = [];

return Each::of(
$promises,
function ($value, $idx) use (&$results) {
$results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value];
},
function ($reason, $idx) use (&$results) {
$results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason];
}
)->then(function () use (&$results) {
ksort($results);
return $results;
});
}
}
<?php

namespace GuzzleHttp\Promise;






class Promise implements PromiseInterface
{
private $state = self::PENDING;
private $result;
private $cancelFn;
private $waitFn;
private $waitList;
private $handlers = [];





public function __construct(
callable $waitFn = null,
callable $cancelFn = null
) {
$this->waitFn = $waitFn;
$this->cancelFn = $cancelFn;
}

public function then(
callable $onFulfilled = null,
callable $onRejected = null
) {
if ($this->state === self::PENDING) {
$p = new Promise(null, [$this, 'cancel']);
$this->handlers[] = [$p, $onFulfilled, $onRejected];
$p->waitList = $this->waitList;
$p->waitList[] = $this;
return $p;
}


 if ($this->state === self::FULFILLED) {
$promise = Create::promiseFor($this->result);
return $onFulfilled ? $promise->then($onFulfilled) : $promise;
}


 
 $rejection = Create::rejectionFor($this->result);
return $onRejected ? $rejection->then(null, $onRejected) : $rejection;
}

public function otherwise(callable $onRejected)
{
return $this->then(null, $onRejected);
}

public function wait($unwrap = true)
{
$this->waitIfPending();

if ($this->result instanceof PromiseInterface) {
return $this->result->wait($unwrap);
}
if ($unwrap) {
if ($this->state === self::FULFILLED) {
return $this->result;
}

 throw Create::exceptionFor($this->result);
}
}

public function getState()
{
return $this->state;
}

public function cancel()
{
if ($this->state !== self::PENDING) {
return;
}

$this->waitFn = $this->waitList = null;

if ($this->cancelFn) {
$fn = $this->cancelFn;
$this->cancelFn = null;
try {
$fn();
} catch (\Throwable $e) {
$this->reject($e);
} catch (\Exception $e) {
$this->reject($e);
}
}


 
if ($this->state === self::PENDING) {
$this->reject(new CancellationException('Promise has been cancelled'));
}
}

public function resolve($value)
{
$this->settle(self::FULFILLED, $value);
}

public function reject($reason)
{
$this->settle(self::REJECTED, $reason);
}

private function settle($state, $value)
{
if ($this->state !== self::PENDING) {

 if ($state === $this->state && $value === $this->result) {
return;
}
throw $this->state === $state
? new \LogicException("The promise is already {$state}.")
: new \LogicException("Cannot change a {$this->state} promise to {$state}");
}

if ($value === $this) {
throw new \LogicException('Cannot fulfill or reject a promise with itself');
}


 $this->state = $state;
$this->result = $value;
$handlers = $this->handlers;
$this->handlers = null;
$this->waitList = $this->waitFn = null;
$this->cancelFn = null;

if (!$handlers) {
return;
}


 
 if (!is_object($value) || !method_exists($value, 'then')) {
$id = $state === self::FULFILLED ? 1 : 2;

 Utils::queue()->add(static function () use ($id, $value, $handlers) {
foreach ($handlers as $handler) {
self::callHandler($id, $value, $handler);
}
});
} elseif ($value instanceof Promise && Is::pending($value)) {

 $value->handlers = array_merge($value->handlers, $handlers);
} else {

 $value->then(
static function ($value) use ($handlers) {
foreach ($handlers as $handler) {
self::callHandler(1, $value, $handler);
}
},
static function ($reason) use ($handlers) {
foreach ($handlers as $handler) {
self::callHandler(2, $reason, $handler);
}
}
);
}
}








private static function callHandler($index, $value, array $handler)
{

$promise = $handler[0];


 
 if (Is::settled($promise)) {
return;
}

try {
if (isset($handler[$index])) {






$f = $handler[$index];
unset($handler);
$promise->resolve($f($value));
} elseif ($index === 1) {

 $promise->resolve($value);
} else {

 $promise->reject($value);
}
} catch (\Throwable $reason) {
$promise->reject($reason);
} catch (\Exception $reason) {
$promise->reject($reason);
}
}

private function waitIfPending()
{
if ($this->state !== self::PENDING) {
return;
} elseif ($this->waitFn) {
$this->invokeWaitFn();
} elseif ($this->waitList) {
$this->invokeWaitList();
} else {

 $this->reject('Cannot wait on a promise that has '
. 'no internal wait function. You must provide a wait '
. 'function when constructing the promise to be able to '
. 'wait on a promise.');
}

Utils::queue()->run();


if ($this->state === self::PENDING) {
$this->reject('Invoking the wait callback did not resolve the promise');
}
}

private function invokeWaitFn()
{
try {
$wfn = $this->waitFn;
$this->waitFn = null;
$wfn(true);
} catch (\Exception $reason) {
if ($this->state === self::PENDING) {

 
 $this->reject($reason);
} else {

 
 throw $reason;
}
}
}

private function invokeWaitList()
{
$waitList = $this->waitList;
$this->waitList = null;

foreach ($waitList as $result) {
do {
$result->waitIfPending();
$result = $result->result;
} while ($result instanceof Promise);

if ($result instanceof PromiseInterface) {
$result->wait(false);
}
}
}
}
<?php


if (!function_exists('GuzzleHttp\Promise\promise_for')) {
require __DIR__ . '/functions.php';
}
<?php

namespace GuzzleHttp\Promise;

use Exception;
use Generator;
use Throwable;





































final class Coroutine implements PromiseInterface
{



private $currentPromise;




private $generator;




private $result;

public function __construct(callable $generatorFn)
{
$this->generator = $generatorFn();
$this->result = new Promise(function () {
while (isset($this->currentPromise)) {
$this->currentPromise->wait();
}
});
try {
$this->nextCoroutine($this->generator->current());
} catch (\Exception $exception) {
$this->result->reject($exception);
} catch (Throwable $throwable) {
$this->result->reject($throwable);
}
}






public static function of(callable $generatorFn)
{
return new self($generatorFn);
}

public function then(
callable $onFulfilled = null,
callable $onRejected = null
) {
return $this->result->then($onFulfilled, $onRejected);
}

public function otherwise(callable $onRejected)
{
return $this->result->otherwise($onRejected);
}

public function wait($unwrap = true)
{
return $this->result->wait($unwrap);
}

public function getState()
{
return $this->result->getState();
}

public function resolve($value)
{
$this->result->resolve($value);
}

public function reject($reason)
{
$this->result->reject($reason);
}

public function cancel()
{
$this->currentPromise->cancel();
$this->result->cancel();
}

private function nextCoroutine($yielded)
{
$this->currentPromise = Create::promiseFor($yielded)
->then([$this, '_handleSuccess'], [$this, '_handleFailure']);
}




public function _handleSuccess($value)
{
unset($this->currentPromise);
try {
$next = $this->generator->send($value);
if ($this->generator->valid()) {
$this->nextCoroutine($next);
} else {
$this->result->resolve($value);
}
} catch (Exception $exception) {
$this->result->reject($exception);
} catch (Throwable $throwable) {
$this->result->reject($throwable);
}
}




public function _handleFailure($reason)
{
unset($this->currentPromise);
try {
$nextYield = $this->generator->throw(Create::exceptionFor($reason));

 $this->nextCoroutine($nextYield);
} catch (Exception $exception) {
$this->result->reject($exception);
} catch (Throwable $throwable) {
$this->result->reject($throwable);
}
}
}
<?php

namespace GuzzleHttp\Promise;






class RejectionException extends \RuntimeException
{

private $reason;





public function __construct($reason, $description = null)
{
$this->reason = $reason;

$message = 'The promise was rejected';

if ($description) {
$message .= ' with reason: ' . $description;
} elseif (is_string($reason)
|| (is_object($reason) && method_exists($reason, '__toString'))
) {
$message .= ' with reason: ' . $this->reason;
} elseif ($reason instanceof \JsonSerializable) {
$message .= ' with reason: '
. json_encode($this->reason, JSON_PRETTY_PRINT);
}

parent::__construct($message);
}






public function getReason()
{
return $this->reason;
}
}
<?php

namespace GuzzleHttp\Promise;

final class Is
{





public static function pending(PromiseInterface $promise)
{
return $promise->getState() === PromiseInterface::PENDING;
}






public static function settled(PromiseInterface $promise)
{
return $promise->getState() !== PromiseInterface::PENDING;
}






public static function fulfilled(PromiseInterface $promise)
{
return $promise->getState() === PromiseInterface::FULFILLED;
}






public static function rejected(PromiseInterface $promise)
{
return $promise->getState() === PromiseInterface::REJECTED;
}
}
<?php

namespace GuzzleHttp\Promise;







class RejectedPromise implements PromiseInterface
{
private $reason;

public function __construct($reason)
{
if (is_object($reason) && method_exists($reason, 'then')) {
throw new \InvalidArgumentException(
'You cannot create a RejectedPromise with a promise.'
);
}

$this->reason = $reason;
}

public function then(
callable $onFulfilled = null,
callable $onRejected = null
) {

 if (!$onRejected) {
return $this;
}

$queue = Utils::queue();
$reason = $this->reason;
$p = new Promise([$queue, 'run']);
$queue->add(static function () use ($p, $reason, $onRejected) {
if (Is::pending($p)) {
try {

 $p->resolve($onRejected($reason));
} catch (\Throwable $e) {

 $p->reject($e);
} catch (\Exception $e) {

 $p->reject($e);
}
}
});

return $p;
}

public function otherwise(callable $onRejected)
{
return $this->then(null, $onRejected);
}

public function wait($unwrap = true, $defaultDelivery = null)
{
if ($unwrap) {
throw Create::exceptionFor($this->reason);
}

return null;
}

public function getState()
{
return self::REJECTED;
}

public function resolve($value)
{
throw new \LogicException("Cannot resolve a rejected promise");
}

public function reject($reason)
{
if ($reason !== $this->reason) {
throw new \LogicException("Cannot reject a rejected promise");
}
}

public function cancel()
{

 }
}
<?php

namespace GuzzleHttp\Promise;







class FulfilledPromise implements PromiseInterface
{
private $value;

public function __construct($value)
{
if (is_object($value) && method_exists($value, 'then')) {
throw new \InvalidArgumentException(
'You cannot create a FulfilledPromise with a promise.'
);
}

$this->value = $value;
}

public function then(
callable $onFulfilled = null,
callable $onRejected = null
) {

 if (!$onFulfilled) {
return $this;
}

$queue = Utils::queue();
$p = new Promise([$queue, 'run']);
$value = $this->value;
$queue->add(static function () use ($p, $value, $onFulfilled) {
if (Is::pending($p)) {
try {
$p->resolve($onFulfilled($value));
} catch (\Throwable $e) {
$p->reject($e);
} catch (\Exception $e) {
$p->reject($e);
}
}
});

return $p;
}

public function otherwise(callable $onRejected)
{
return $this->then(null, $onRejected);
}

public function wait($unwrap = true, $defaultDelivery = null)
{
return $unwrap ? $this->value : null;
}

public function getState()
{
return self::FULFILLED;
}

public function resolve($value)
{
if ($value !== $this->value) {
throw new \LogicException("Cannot resolve a fulfilled promise");
}
}

public function reject($reason)
{
throw new \LogicException("Cannot reject a fulfilled promise");
}

public function cancel()
{

 }
}
<?php

namespace GuzzleHttp\Promise;




class CancellationException extends RejectionException
{
}
<?php

namespace GuzzleHttp\Promise;




















function queue(TaskQueueInterface $assign = null)
{
return Utils::queue($assign);
}











function task(callable $task)
{
return Utils::task($task);
}










function promise_for($value)
{
return Create::promiseFor($value);
}











function rejection_for($reason)
{
return Create::rejectionFor($reason);
}










function exception_for($reason)
{
return Create::exceptionFor($reason);
}










function iter_for($value)
{
return Create::iterFor($value);
}

















function inspect(PromiseInterface $promise)
{
return Utils::inspect($promise);
}















function inspect_all($promises)
{
return Utils::inspectAll($promises);
}

















function unwrap($promises)
{
return Utils::unwrap($promises);
}
















function all($promises, $recursive = false)
{
return Utils::all($promises, $recursive);
}



















function some($count, $promises)
{
return Utils::some($count, $promises);
}











function any($promises)
{
return Utils::any($promises);
}















function settle($promises)
{
return Utils::settle($promises);
}






















function each(
$iterable,
callable $onFulfilled = null,
callable $onRejected = null
) {
return Each::of($iterable, $onFulfilled, $onRejected);
}


















function each_limit(
$iterable,
$concurrency,
callable $onFulfilled = null,
callable $onRejected = null
) {
return Each::ofLimit($iterable, $concurrency, $onFulfilled, $onRejected);
}














function each_limit_all(
$iterable,
$concurrency,
callable $onFulfilled = null
) {
return Each::ofLimitAll($iterable, $concurrency, $onFulfilled);
}








function is_fulfilled(PromiseInterface $promise)
{
return Is::fulfilled($promise);
}








function is_rejected(PromiseInterface $promise)
{
return Is::rejected($promise);
}








function is_settled(PromiseInterface $promise)
{
return Is::settled($promise);
}










function coroutine(callable $generatorFn)
{
return Coroutine::of($generatorFn);
}
<?php

namespace GuzzleHttp\Promise;

final class Each
{



















public static function of(
$iterable,
callable $onFulfilled = null,
callable $onRejected = null
) {
return (new EachPromise($iterable, [
'fulfilled' => $onFulfilled,
'rejected' => $onRejected
]))->promise();
}
















public static function ofLimit(
$iterable,
$concurrency,
callable $onFulfilled = null,
callable $onRejected = null
) {
return (new EachPromise($iterable, [
'fulfilled' => $onFulfilled,
'rejected' => $onRejected,
'concurrency' => $concurrency
]))->promise();
}












public static function ofLimitAll(
$iterable,
$concurrency,
callable $onFulfilled = null
) {
return each_limit(
$iterable,
$concurrency,
$onFulfilled,
function ($reason, $idx, PromiseInterface $aggregate) {
$aggregate->reject($reason);
}
);
}
}
<?php

namespace GuzzleHttp\Promise;

final class Create
{







public static function promiseFor($value)
{
if ($value instanceof PromiseInterface) {
return $value;
}


 if (is_object($value) && method_exists($value, 'then')) {
$wfn = method_exists($value, 'wait') ? [$value, 'wait'] : null;
$cfn = method_exists($value, 'cancel') ? [$value, 'cancel'] : null;
$promise = new Promise($wfn, $cfn);
$value->then([$promise, 'resolve'], [$promise, 'reject']);
return $promise;
}

return new FulfilledPromise($value);
}









public static function rejectionFor($reason)
{
if ($reason instanceof PromiseInterface) {
return $reason;
}

return new RejectedPromise($reason);
}








public static function exceptionFor($reason)
{
if ($reason instanceof \Exception || $reason instanceof \Throwable) {
return $reason;
}

return new RejectionException($reason);
}








public static function iterFor($value)
{
if ($value instanceof \Iterator) {
return $value;
}

if (is_array($value)) {
return new \ArrayIterator($value);
}

return new \ArrayIterator([$value]);
}
}
<?php

namespace GuzzleHttp\Promise;










interface PromiseInterface
{
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';










public function then(
callable $onFulfilled = null,
callable $onRejected = null
);











public function otherwise(callable $onRejected);









public function getState();








public function resolve($value);








public function reject($reason);






public function cancel();
















public function wait($unwrap = true);
}
<?php

namespace GuzzleHttp\Promise;




interface PromisorInterface
{





public function promise();
}
<?php

namespace GuzzleHttp\Promise;










class TaskQueue implements TaskQueueInterface
{
private $enableShutdown = true;
private $queue = [];

public function __construct($withShutdown = true)
{
if ($withShutdown) {
register_shutdown_function(function () {
if ($this->enableShutdown) {

 $err = error_get_last();
if (!$err || ($err['type'] ^ E_ERROR)) {
$this->run();
}
}
});
}
}

public function isEmpty()
{
return !$this->queue;
}

public function add(callable $task)
{
$this->queue[] = $task;
}

public function run()
{
while ($task = array_shift($this->queue)) {

$task();
}
}












public function disableShutdown()
{
$this->enableShutdown = false;
}
}
<?php

namespace GuzzleHttp\Promise;




class AggregateException extends RejectionException
{
public function __construct($msg, array $reasons)
{
parent::__construct(
$reasons,
sprintf('%s; %d rejected promises', $msg, count($reasons))
);
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;




trait MessageTrait
{

private $headers = [];


private $headerNames = [];


private $protocol = '1.1';


private $stream;

public function getProtocolVersion()
{
return $this->protocol;
}

public function withProtocolVersion($version)
{
if ($this->protocol === $version) {
return $this;
}

$new = clone $this;
$new->protocol = $version;
return $new;
}

public function getHeaders()
{
return $this->headers;
}

public function hasHeader($header)
{
return isset($this->headerNames[strtolower($header)]);
}

public function getHeader($header)
{
$header = strtolower($header);

if (!isset($this->headerNames[$header])) {
return [];
}

$header = $this->headerNames[$header];

return $this->headers[$header];
}

public function getHeaderLine($header)
{
return implode(', ', $this->getHeader($header));
}

public function withHeader($header, $value)
{
$this->assertHeader($header);
$value = $this->normalizeHeaderValue($value);
$normalized = strtolower($header);

$new = clone $this;
if (isset($new->headerNames[$normalized])) {
unset($new->headers[$new->headerNames[$normalized]]);
}
$new->headerNames[$normalized] = $header;
$new->headers[$header] = $value;

return $new;
}

public function withAddedHeader($header, $value)
{
$this->assertHeader($header);
$value = $this->normalizeHeaderValue($value);
$normalized = strtolower($header);

$new = clone $this;
if (isset($new->headerNames[$normalized])) {
$header = $this->headerNames[$normalized];
$new->headers[$header] = array_merge($this->headers[$header], $value);
} else {
$new->headerNames[$normalized] = $header;
$new->headers[$header] = $value;
}

return $new;
}

public function withoutHeader($header)
{
$normalized = strtolower($header);

if (!isset($this->headerNames[$normalized])) {
return $this;
}

$header = $this->headerNames[$normalized];

$new = clone $this;
unset($new->headers[$header], $new->headerNames[$normalized]);

return $new;
}

public function getBody()
{
if (!$this->stream) {
$this->stream = Utils::streamFor('');
}

return $this->stream;
}

public function withBody(StreamInterface $body)
{
if ($body === $this->stream) {
return $this;
}

$new = clone $this;
$new->stream = $body;
return $new;
}

private function setHeaders(array $headers)
{
$this->headerNames = $this->headers = [];
foreach ($headers as $header => $value) {
if (is_int($header)) {

 
 $header = (string) $header;
}
$this->assertHeader($header);
$value = $this->normalizeHeaderValue($value);
$normalized = strtolower($header);
if (isset($this->headerNames[$normalized])) {
$header = $this->headerNames[$normalized];
$this->headers[$header] = array_merge($this->headers[$header], $value);
} else {
$this->headerNames[$normalized] = $header;
$this->headers[$header] = $value;
}
}
}

private function normalizeHeaderValue($value)
{
if (!is_array($value)) {
return $this->trimHeaderValues([$value]);
}

if (count($value) === 0) {
throw new \InvalidArgumentException('Header value can not be an empty array.');
}

return $this->trimHeaderValues($value);
}















private function trimHeaderValues(array $values)
{
return array_map(function ($value) {
if (!is_scalar($value) && null !== $value) {
throw new \InvalidArgumentException(sprintf(
'Header value must be scalar or null but %s provided.',
is_object($value) ? get_class($value) : gettype($value)
));
}

return trim((string) $value, " \t");
}, array_values($values));
}

private function assertHeader($header)
{
if (!is_string($header)) {
throw new \InvalidArgumentException(sprintf(
'Header name must be a string but %s provided.',
is_object($header) ? get_class($header) : gettype($header)
));
}

if ($header === '') {
throw new \InvalidArgumentException('Header name can not be empty.');
}
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;






class LimitStream implements StreamInterface
{
use StreamDecoratorTrait;


private $offset;


private $limit;








public function __construct(
StreamInterface $stream,
$limit = -1,
$offset = 0
) {
$this->stream = $stream;
$this->setLimit($limit);
$this->setOffset($offset);
}

public function eof()
{

 if ($this->stream->eof()) {
return true;
}


 if ($this->limit == -1) {
return false;
}

return $this->stream->tell() >= $this->offset + $this->limit;
}





public function getSize()
{
if (null === ($length = $this->stream->getSize())) {
return null;
} elseif ($this->limit == -1) {
return $length - $this->offset;
} else {
return min($this->limit, $length - $this->offset);
}
}





public function seek($offset, $whence = SEEK_SET)
{
if ($whence !== SEEK_SET || $offset < 0) {
throw new \RuntimeException(sprintf(
'Cannot seek to offset %s with whence %s',
$offset,
$whence
));
}

$offset += $this->offset;

if ($this->limit !== -1) {
if ($offset > $this->offset + $this->limit) {
$offset = $this->offset + $this->limit;
}
}

$this->stream->seek($offset);
}





public function tell()
{
return $this->stream->tell() - $this->offset;
}








public function setOffset($offset)
{
$current = $this->stream->tell();

if ($current !== $offset) {

 if ($this->stream->isSeekable()) {
$this->stream->seek($offset);
} elseif ($current > $offset) {
throw new \RuntimeException("Could not seek to stream offset $offset");
} else {
$this->stream->read($offset - $current);
}
}

$this->offset = $offset;
}








public function setLimit($limit)
{
$this->limit = $limit;
}

public function read($length)
{
if ($this->limit == -1) {
return $this->stream->read($length);
}


 
 $remaining = ($this->offset + $this->limit) - $this->stream->tell();
if ($remaining > 0) {

 
 return $this->stream->read(min($remaining, $length));
}

return '';
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;

final class Utils
{







public static function caselessRemove($keys, array $data)
{
$result = [];

foreach ($keys as &$key) {
$key = strtolower($key);
}

foreach ($data as $k => $v) {
if (!in_array(strtolower($k), $keys)) {
$result[$k] = $v;
}
}

return $result;
}












public static function copyToStream(StreamInterface $source, StreamInterface $dest, $maxLen = -1)
{
$bufferSize = 8192;

if ($maxLen === -1) {
while (!$source->eof()) {
if (!$dest->write($source->read($bufferSize))) {
break;
}
}
} else {
$remaining = $maxLen;
while ($remaining > 0 && !$source->eof()) {
$buf = $source->read(min($bufferSize, $remaining));
$len = strlen($buf);
if (!$len) {
break;
}
$remaining -= $len;
$dest->write($buf);
}
}
}













public static function copyToString(StreamInterface $stream, $maxLen = -1)
{
$buffer = '';

if ($maxLen === -1) {
while (!$stream->eof()) {
$buf = $stream->read(1048576);

 if ($buf == null) {
break;
}
$buffer .= $buf;
}
return $buffer;
}

$len = 0;
while (!$stream->eof() && $len < $maxLen) {
$buf = $stream->read($maxLen - $len);

 if ($buf == null) {
break;
}
$buffer .= $buf;
$len = strlen($buffer);
}

return $buffer;
}















public static function hash(StreamInterface $stream, $algo, $rawOutput = false)
{
$pos = $stream->tell();

if ($pos > 0) {
$stream->rewind();
}

$ctx = hash_init($algo);
while (!$stream->eof()) {
hash_update($ctx, $stream->read(1048576));
}

$out = hash_final($ctx, (bool) $rawOutput);
$stream->seek($pos);

return $out;
}





















public static function modifyRequest(RequestInterface $request, array $changes)
{
if (!$changes) {
return $request;
}

$headers = $request->getHeaders();

if (!isset($changes['uri'])) {
$uri = $request->getUri();
} else {

 if ($host = $changes['uri']->getHost()) {
$changes['set_headers']['Host'] = $host;

if ($port = $changes['uri']->getPort()) {
$standardPorts = ['http' => 80, 'https' => 443];
$scheme = $changes['uri']->getScheme();
if (isset($standardPorts[$scheme]) && $port != $standardPorts[$scheme]) {
$changes['set_headers']['Host'] .= ':' . $port;
}
}
}
$uri = $changes['uri'];
}

if (!empty($changes['remove_headers'])) {
$headers = self::caselessRemove($changes['remove_headers'], $headers);
}

if (!empty($changes['set_headers'])) {
$headers = self::caselessRemove(array_keys($changes['set_headers']), $headers);
$headers = $changes['set_headers'] + $headers;
}

if (isset($changes['query'])) {
$uri = $uri->withQuery($changes['query']);
}

if ($request instanceof ServerRequestInterface) {
$new = (new ServerRequest(
isset($changes['method']) ? $changes['method'] : $request->getMethod(),
$uri,
$headers,
isset($changes['body']) ? $changes['body'] : $request->getBody(),
isset($changes['version'])
? $changes['version']
: $request->getProtocolVersion(),
$request->getServerParams()
))
->withParsedBody($request->getParsedBody())
->withQueryParams($request->getQueryParams())
->withCookieParams($request->getCookieParams())
->withUploadedFiles($request->getUploadedFiles());

foreach ($request->getAttributes() as $key => $value) {
$new = $new->withAttribute($key, $value);
}

return $new;
}

return new Request(
isset($changes['method']) ? $changes['method'] : $request->getMethod(),
$uri,
$headers,
isset($changes['body']) ? $changes['body'] : $request->getBody(),
isset($changes['version'])
? $changes['version']
: $request->getProtocolVersion()
);
}









public static function readLine(StreamInterface $stream, $maxLength = null)
{
$buffer = '';
$size = 0;

while (!$stream->eof()) {

 if (null == ($byte = $stream->read(1))) {
return $buffer;
}
$buffer .= $byte;

 if ($byte === "\n" || ++$size === $maxLength - 1) {
break;
}
}

return $buffer;
}





































public static function streamFor($resource = '', array $options = [])
{
if (is_scalar($resource)) {
$stream = self::tryFopen('php://temp', 'r+');
if ($resource !== '') {
fwrite($stream, $resource);
fseek($stream, 0);
}
return new Stream($stream, $options);
}

switch (gettype($resource)) {
case 'resource':




$metaData = \stream_get_meta_data($resource);
if (isset($metaData['uri']) && $metaData['uri'] === 'php://input') {
$stream = self::tryFopen('php://temp', 'w+');
fwrite($stream, stream_get_contents($resource));
fseek($stream, 0);
$resource = $stream;
}
return new Stream($resource, $options);
case 'object':
if ($resource instanceof StreamInterface) {
return $resource;
} elseif ($resource instanceof \Iterator) {
return new PumpStream(function () use ($resource) {
if (!$resource->valid()) {
return false;
}
$result = $resource->current();
$resource->next();
return $result;
}, $options);
} elseif (method_exists($resource, '__toString')) {
return Utils::streamFor((string) $resource, $options);
}
break;
case 'NULL':
return new Stream(self::tryFopen('php://temp', 'r+'), $options);
}

if (is_callable($resource)) {
return new PumpStream($resource, $options);
}

throw new \InvalidArgumentException('Invalid resource type: ' . gettype($resource));
}














public static function tryFopen($filename, $mode)
{
$ex = null;
set_error_handler(function () use ($filename, $mode, &$ex) {
$ex = new \RuntimeException(sprintf(
'Unable to open "%s" using mode "%s": %s',
$filename,
$mode,
func_get_args()[1]
));

return true;
});

try {
$handle = fopen($filename, $mode);
} catch (\Throwable $e) {
$ex = new \RuntimeException(sprintf(
'Unable to open "%s" using mode "%s": %s',
$filename,
$mode,
$e->getMessage()
), 0, $e);
}

restore_error_handler();

if ($ex) {

throw $ex;
}

return $handle;
}














public static function uriFor($uri)
{
if ($uri instanceof UriInterface) {
return $uri;
}

if (is_string($uri)) {
return new Uri($uri);
}

throw new \InvalidArgumentException('URI must be a string or UriInterface');
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;








class AppendStream implements StreamInterface
{

private $streams = [];

private $seekable = true;
private $current = 0;
private $pos = 0;





public function __construct(array $streams = [])
{
foreach ($streams as $stream) {
$this->addStream($stream);
}
}

public function __toString()
{
try {
$this->rewind();
return $this->getContents();
} catch (\Exception $e) {
return '';
}
}








public function addStream(StreamInterface $stream)
{
if (!$stream->isReadable()) {
throw new \InvalidArgumentException('Each stream must be readable');
}


 if (!$stream->isSeekable()) {
$this->seekable = false;
}

$this->streams[] = $stream;
}

public function getContents()
{
return Utils::copyToString($this);
}






public function close()
{
$this->pos = $this->current = 0;
$this->seekable = true;

foreach ($this->streams as $stream) {
$stream->close();
}

$this->streams = [];
}








public function detach()
{
$this->pos = $this->current = 0;
$this->seekable = true;

foreach ($this->streams as $stream) {
$stream->detach();
}

$this->streams = [];

return null;
}

public function tell()
{
return $this->pos;
}









public function getSize()
{
$size = 0;

foreach ($this->streams as $stream) {
$s = $stream->getSize();
if ($s === null) {
return null;
}
$size += $s;
}

return $size;
}

public function eof()
{
return !$this->streams ||
($this->current >= count($this->streams) - 1 &&
$this->streams[$this->current]->eof());
}

public function rewind()
{
$this->seek(0);
}






public function seek($offset, $whence = SEEK_SET)
{
if (!$this->seekable) {
throw new \RuntimeException('This AppendStream is not seekable');
} elseif ($whence !== SEEK_SET) {
throw new \RuntimeException('The AppendStream can only seek with SEEK_SET');
}

$this->pos = $this->current = 0;


 foreach ($this->streams as $i => $stream) {
try {
$stream->rewind();
} catch (\Exception $e) {
throw new \RuntimeException('Unable to seek stream '
. $i . ' of the AppendStream', 0, $e);
}
}


 while ($this->pos < $offset && !$this->eof()) {
$result = $this->read(min(8096, $offset - $this->pos));
if ($result === '') {
break;
}
}
}






public function read($length)
{
$buffer = '';
$total = count($this->streams) - 1;
$remaining = $length;
$progressToNext = false;

while ($remaining > 0) {


 if ($progressToNext || $this->streams[$this->current]->eof()) {
$progressToNext = false;
if ($this->current === $total) {
break;
}
$this->current++;
}

$result = $this->streams[$this->current]->read($remaining);


 if ($result == null) {
$progressToNext = true;
continue;
}

$buffer .= $result;
$remaining = $length - strlen($buffer);
}

$this->pos += strlen($buffer);

return $buffer;
}

public function isReadable()
{
return true;
}

public function isWritable()
{
return false;
}

public function isSeekable()
{
return $this->seekable;
}

public function write($string)
{
throw new \RuntimeException('Cannot write to an AppendStream');
}

public function getMetadata($key = null)
{
return $key ? null : [];
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\UriInterface;








final class UriResolver
{









public static function removeDotSegments($path)
{
if ($path === '' || $path === '/') {
return $path;
}

$results = [];
$segments = explode('/', $path);
foreach ($segments as $segment) {
if ($segment === '..') {
array_pop($results);
} elseif ($segment !== '.') {
$results[] = $segment;
}
}

$newPath = implode('/', $results);

if ($path[0] === '/' && (!isset($newPath[0]) || $newPath[0] !== '/')) {

 $newPath = '/' . $newPath;
} elseif ($newPath !== '' && ($segment === '.' || $segment === '..')) {

 
 $newPath .= '/';
}

return $newPath;
}











public static function resolve(UriInterface $base, UriInterface $rel)
{
if ((string) $rel === '') {

 return $base;
}

if ($rel->getScheme() != '') {
return $rel->withPath(self::removeDotSegments($rel->getPath()));
}

if ($rel->getAuthority() != '') {
$targetAuthority = $rel->getAuthority();
$targetPath = self::removeDotSegments($rel->getPath());
$targetQuery = $rel->getQuery();
} else {
$targetAuthority = $base->getAuthority();
if ($rel->getPath() === '') {
$targetPath = $base->getPath();
$targetQuery = $rel->getQuery() != '' ? $rel->getQuery() : $base->getQuery();
} else {
if ($rel->getPath()[0] === '/') {
$targetPath = $rel->getPath();
} else {
if ($targetAuthority != '' && $base->getPath() === '') {
$targetPath = '/' . $rel->getPath();
} else {
$lastSlashPos = strrpos($base->getPath(), '/');
if ($lastSlashPos === false) {
$targetPath = $rel->getPath();
} else {
$targetPath = substr($base->getPath(), 0, $lastSlashPos + 1) . $rel->getPath();
}
}
}
$targetPath = self::removeDotSegments($targetPath);
$targetQuery = $rel->getQuery();
}
}

return new Uri(Uri::composeComponents(
$base->getScheme(),
$targetAuthority,
$targetPath,
$targetQuery,
$rel->getFragment()
));
}



























public static function relativize(UriInterface $base, UriInterface $target)
{
if ($target->getScheme() !== '' &&
($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')
) {
return $target;
}

if (Uri::isRelativePathReference($target)) {

 
 
 return $target;
}

if ($target->getAuthority() !== '' && $base->getAuthority() !== $target->getAuthority()) {
return $target->withScheme('');
}


 
 
 $emptyPathUri = $target->withScheme('')->withPath('')->withUserInfo('')->withPort(null)->withHost('');

if ($base->getPath() !== $target->getPath()) {
return $emptyPathUri->withPath(self::getRelativePath($base, $target));
}

if ($base->getQuery() === $target->getQuery()) {

 return $emptyPathUri->withQuery('');
}


 
 if ($target->getQuery() === '') {
$segments = explode('/', $target->getPath());
$lastSegment = end($segments);

return $emptyPathUri->withPath($lastSegment === '' ? './' : $lastSegment);
}

return $emptyPathUri;
}

private static function getRelativePath(UriInterface $base, UriInterface $target)
{
$sourceSegments = explode('/', $base->getPath());
$targetSegments = explode('/', $target->getPath());
array_pop($sourceSegments);
$targetLastSegment = array_pop($targetSegments);
foreach ($sourceSegments as $i => $segment) {
if (isset($targetSegments[$i]) && $segment === $targetSegments[$i]) {
unset($sourceSegments[$i], $targetSegments[$i]);
} else {
break;
}
}
$targetSegments[] = $targetLastSegment;
$relativePath = str_repeat('../', count($sourceSegments)) . implode('/', $targetSegments);


 
 
 if ('' === $relativePath || false !== strpos(explode('/', $relativePath, 2)[0], ':')) {
$relativePath = "./$relativePath";
} elseif ('/' === $relativePath[0]) {
if ($base->getAuthority() != '' && $base->getPath() === '') {

 $relativePath = ".$relativePath";
} else {
$relativePath = "./$relativePath";
}
}

return $relativePath;
}

private function __construct()
{

 }
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\UriInterface;








class Uri implements UriInterface
{






const HTTP_DEFAULT_HOST = 'localhost';

private static $defaultPorts = [
'http' => 80,
'https' => 443,
'ftp' => 21,
'gopher' => 70,
'nntp' => 119,
'news' => 119,
'telnet' => 23,
'tn3270' => 23,
'imap' => 143,
'pop' => 110,
'ldap' => 389,
];

private static $charUnreserved = 'a-zA-Z0-9_\-\.~';
private static $charSubDelims = '!\$&\'\(\)\*\+,;=';
private static $replaceQuery = ['=' => '%3D', '&' => '%26'];


private $scheme = '';


private $userInfo = '';


private $host = '';


private $port;


private $path = '';


private $query = '';


private $fragment = '';




public function __construct($uri = '')
{

 if ($uri != '') {
$parts = self::parse($uri);
if ($parts === false) {
throw new \InvalidArgumentException("Unable to parse URI: $uri");
}
$this->applyParts($parts);
}
}


















private static function parse($url)
{

 $prefix = '';
if (preg_match('%^(.*://\[[0-9:a-f]+\])(.*?)$%', $url, $matches)) {
$prefix = $matches[1];
$url = $matches[2];
}

$encodedUrl = preg_replace_callback(
'%[^:/@?&=#]+%usD',
static function ($matches) {
return urlencode($matches[0]);
},
$url
);

$result = parse_url($prefix . $encodedUrl);

if ($result === false) {
return false;
}

return array_map('urldecode', $result);
}

public function __toString()
{
return self::composeComponents(
$this->scheme,
$this->getAuthority(),
$this->path,
$this->query,
$this->fragment
);
}



























public static function composeComponents($scheme, $authority, $path, $query, $fragment)
{
$uri = '';


 if ($scheme != '') {
$uri .= $scheme . ':';
}

if ($authority != ''|| $scheme === 'file') {
$uri .= '//' . $authority;
}

$uri .= $path;

if ($query != '') {
$uri .= '?' . $query;
}

if ($fragment != '') {
$uri .= '#' . $fragment;
}

return $uri;
}











public static function isDefaultPort(UriInterface $uri)
{
return $uri->getPort() === null
|| (isset(self::$defaultPorts[$uri->getScheme()]) && $uri->getPort() === self::$defaultPorts[$uri->getScheme()]);
}




















public static function isAbsolute(UriInterface $uri)
{
return $uri->getScheme() !== '';
}












public static function isNetworkPathReference(UriInterface $uri)
{
return $uri->getScheme() === '' && $uri->getAuthority() !== '';
}












public static function isAbsolutePathReference(UriInterface $uri)
{
return $uri->getScheme() === ''
&& $uri->getAuthority() === ''
&& isset($uri->getPath()[0])
&& $uri->getPath()[0] === '/';
}












public static function isRelativePathReference(UriInterface $uri)
{
return $uri->getScheme() === ''
&& $uri->getAuthority() === ''
&& (!isset($uri->getPath()[0]) || $uri->getPath()[0] !== '/');
}















public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null)
{
if ($base !== null) {
$uri = UriResolver::resolve($base, $uri);

return ($uri->getScheme() === $base->getScheme())
&& ($uri->getAuthority() === $base->getAuthority())
&& ($uri->getPath() === $base->getPath())
&& ($uri->getQuery() === $base->getQuery());
}

return $uri->getScheme() === '' && $uri->getAuthority() === '' && $uri->getPath() === '' && $uri->getQuery() === '';
}











public static function removeDotSegments($path)
{
return UriResolver::removeDotSegments($path);
}












public static function resolve(UriInterface $base, $rel)
{
if (!($rel instanceof UriInterface)) {
$rel = new self($rel);
}

return UriResolver::resolve($base, $rel);
}












public static function withoutQueryValue(UriInterface $uri, $key)
{
$result = self::getFilteredQueryString($uri, [$key]);

return $uri->withQuery(implode('&', $result));
}
















public static function withQueryValue(UriInterface $uri, $key, $value)
{
$result = self::getFilteredQueryString($uri, [$key]);

$result[] = self::generateQueryString($key, $value);

return $uri->withQuery(implode('&', $result));
}











public static function withQueryValues(UriInterface $uri, array $keyValueArray)
{
$result = self::getFilteredQueryString($uri, array_keys($keyValueArray));

foreach ($keyValueArray as $key => $value) {
$result[] = self::generateQueryString($key, $value);
}

return $uri->withQuery(implode('&', $result));
}












public static function fromParts(array $parts)
{
$uri = new self();
$uri->applyParts($parts);
$uri->validateState();

return $uri;
}

public function getScheme()
{
return $this->scheme;
}

public function getAuthority()
{
$authority = $this->host;
if ($this->userInfo !== '') {
$authority = $this->userInfo . '@' . $authority;
}

if ($this->port !== null) {
$authority .= ':' . $this->port;
}

return $authority;
}

public function getUserInfo()
{
return $this->userInfo;
}

public function getHost()
{
return $this->host;
}

public function getPort()
{
return $this->port;
}

public function getPath()
{
return $this->path;
}

public function getQuery()
{
return $this->query;
}

public function getFragment()
{
return $this->fragment;
}

public function withScheme($scheme)
{
$scheme = $this->filterScheme($scheme);

if ($this->scheme === $scheme) {
return $this;
}

$new = clone $this;
$new->scheme = $scheme;
$new->removeDefaultPort();
$new->validateState();

return $new;
}

public function withUserInfo($user, $password = null)
{
$info = $this->filterUserInfoComponent($user);
if ($password !== null) {
$info .= ':' . $this->filterUserInfoComponent($password);
}

if ($this->userInfo === $info) {
return $this;
}

$new = clone $this;
$new->userInfo = $info;
$new->validateState();

return $new;
}

public function withHost($host)
{
$host = $this->filterHost($host);

if ($this->host === $host) {
return $this;
}

$new = clone $this;
$new->host = $host;
$new->validateState();

return $new;
}

public function withPort($port)
{
$port = $this->filterPort($port);

if ($this->port === $port) {
return $this;
}

$new = clone $this;
$new->port = $port;
$new->removeDefaultPort();
$new->validateState();

return $new;
}

public function withPath($path)
{
$path = $this->filterPath($path);

if ($this->path === $path) {
return $this;
}

$new = clone $this;
$new->path = $path;
$new->validateState();

return $new;
}

public function withQuery($query)
{
$query = $this->filterQueryAndFragment($query);

if ($this->query === $query) {
return $this;
}

$new = clone $this;
$new->query = $query;

return $new;
}

public function withFragment($fragment)
{
$fragment = $this->filterQueryAndFragment($fragment);

if ($this->fragment === $fragment) {
return $this;
}

$new = clone $this;
$new->fragment = $fragment;

return $new;
}






private function applyParts(array $parts)
{
$this->scheme = isset($parts['scheme'])
? $this->filterScheme($parts['scheme'])
: '';
$this->userInfo = isset($parts['user'])
? $this->filterUserInfoComponent($parts['user'])
: '';
$this->host = isset($parts['host'])
? $this->filterHost($parts['host'])
: '';
$this->port = isset($parts['port'])
? $this->filterPort($parts['port'])
: null;
$this->path = isset($parts['path'])
? $this->filterPath($parts['path'])
: '';
$this->query = isset($parts['query'])
? $this->filterQueryAndFragment($parts['query'])
: '';
$this->fragment = isset($parts['fragment'])
? $this->filterQueryAndFragment($parts['fragment'])
: '';
if (isset($parts['pass'])) {
$this->userInfo .= ':' . $this->filterUserInfoComponent($parts['pass']);
}

$this->removeDefaultPort();
}








private function filterScheme($scheme)
{
if (!is_string($scheme)) {
throw new \InvalidArgumentException('Scheme must be a string');
}

return \strtr($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
}








private function filterUserInfoComponent($component)
{
if (!is_string($component)) {
throw new \InvalidArgumentException('User info must be a string');
}

return preg_replace_callback(
'/(?:[^%' . self::$charUnreserved . self::$charSubDelims . ']+|%(?![A-Fa-f0-9]{2}))/',
[$this, 'rawurlencodeMatchZero'],
$component
);
}








private function filterHost($host)
{
if (!is_string($host)) {
throw new \InvalidArgumentException('Host must be a string');
}

return \strtr($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
}








private function filterPort($port)
{
if ($port === null) {
return null;
}

$port = (int) $port;
if (0 > $port || 0xffff < $port) {
throw new \InvalidArgumentException(
sprintf('Invalid port: %d. Must be between 0 and 65535', $port)
);
}

return $port;
}







private static function getFilteredQueryString(UriInterface $uri, array $keys)
{
$current = $uri->getQuery();

if ($current === '') {
return [];
}

$decodedKeys = array_map('rawurldecode', $keys);

return array_filter(explode('&', $current), function ($part) use ($decodedKeys) {
return !in_array(rawurldecode(explode('=', $part)[0]), $decodedKeys, true);
});
}







private static function generateQueryString($key, $value)
{

 
 
 $queryString = strtr($key, self::$replaceQuery);

if ($value !== null) {
$queryString .= '=' . strtr($value, self::$replaceQuery);
}

return $queryString;
}

private function removeDefaultPort()
{
if ($this->port !== null && self::isDefaultPort($this)) {
$this->port = null;
}
}










private function filterPath($path)
{
if (!is_string($path)) {
throw new \InvalidArgumentException('Path must be a string');
}

return preg_replace_callback(
'/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/]++|%(?![A-Fa-f0-9]{2}))/',
[$this, 'rawurlencodeMatchZero'],
$path
);
}










private function filterQueryAndFragment($str)
{
if (!is_string($str)) {
throw new \InvalidArgumentException('Query and fragment must be a string');
}

return preg_replace_callback(
'/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/',
[$this, 'rawurlencodeMatchZero'],
$str
);
}

private function rawurlencodeMatchZero(array $match)
{
return rawurlencode($match[0]);
}

private function validateState()
{
if ($this->host === '' && ($this->scheme === 'http' || $this->scheme === 'https')) {
$this->host = self::HTTP_DEFAULT_HOST;
}

if ($this->getAuthority() === '') {
if (0 === strpos($this->path, '//')) {
throw new \InvalidArgumentException('The path of a URI without an authority must not start with two slashes "//"');
}
if ($this->scheme === '' && false !== strpos(explode('/', $this->path, 2)[0], ':')) {
throw new \InvalidArgumentException('A relative URI must not have a path beginning with a segment containing a colon');
}
} elseif (isset($this->path[0]) && $this->path[0] !== '/') {
@trigger_error(
'The path of a URI with an authority must start with a slash "/" or be empty. Automagically fixing the URI ' .
'by adding a leading slash to the path is deprecated since version 1.4 and will throw an exception instead.',
E_USER_DEPRECATED
);
$this->path = '/' . $this->path;

 }
}
}
<?php

namespace GuzzleHttp\Psr7;

use InvalidArgumentException;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;




class Request implements RequestInterface
{
use MessageTrait;


private $method;


private $requestTarget;


private $uri;








public function __construct(
$method,
$uri,
array $headers = [],
$body = null,
$version = '1.1'
) {
$this->assertMethod($method);
if (!($uri instanceof UriInterface)) {
$uri = new Uri($uri);
}

$this->method = strtoupper($method);
$this->uri = $uri;
$this->setHeaders($headers);
$this->protocol = $version;

if (!isset($this->headerNames['host'])) {
$this->updateHostFromUri();
}

if ($body !== '' && $body !== null) {
$this->stream = Utils::streamFor($body);
}
}

public function getRequestTarget()
{
if ($this->requestTarget !== null) {
return $this->requestTarget;
}

$target = $this->uri->getPath();
if ($target == '') {
$target = '/';
}
if ($this->uri->getQuery() != '') {
$target .= '?' . $this->uri->getQuery();
}

return $target;
}

public function withRequestTarget($requestTarget)
{
if (preg_match('#\s#', $requestTarget)) {
throw new InvalidArgumentException(
'Invalid request target provided; cannot contain whitespace'
);
}

$new = clone $this;
$new->requestTarget = $requestTarget;
return $new;
}

public function getMethod()
{
return $this->method;
}

public function withMethod($method)
{
$this->assertMethod($method);
$new = clone $this;
$new->method = strtoupper($method);
return $new;
}

public function getUri()
{
return $this->uri;
}

public function withUri(UriInterface $uri, $preserveHost = false)
{
if ($uri === $this->uri) {
return $this;
}

$new = clone $this;
$new->uri = $uri;

if (!$preserveHost || !isset($this->headerNames['host'])) {
$new->updateHostFromUri();
}

return $new;
}

private function updateHostFromUri()
{
$host = $this->uri->getHost();

if ($host == '') {
return;
}

if (($port = $this->uri->getPort()) !== null) {
$host .= ':' . $port;
}

if (isset($this->headerNames['host'])) {
$header = $this->headerNames['host'];
} else {
$header = 'Host';
$this->headerNames['host'] = 'Host';
}

 
 $this->headers = [$header => [$host]] + $this->headers;
}

private function assertMethod($method)
{
if (!is_string($method) || $method === '') {
throw new \InvalidArgumentException('Method must be a non-empty string.');
}
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;






trait StreamDecoratorTrait
{



public function __construct(StreamInterface $stream)
{
$this->stream = $stream;
}









public function __get($name)
{
if ($name == 'stream') {
$this->stream = $this->createStream();
return $this->stream;
}

throw new \UnexpectedValueException("$name not found on class");
}

public function __toString()
{
try {
if ($this->isSeekable()) {
$this->seek(0);
}
return $this->getContents();
} catch (\Exception $e) {

 trigger_error('StreamDecorator::__toString exception: '
. (string) $e, E_USER_ERROR);
return '';
}
}

public function getContents()
{
return Utils::copyToString($this);
}









public function __call($method, array $args)
{
$result = call_user_func_array([$this->stream, $method], $args);


 return $result === $this->stream ? $this : $result;
}

public function close()
{
$this->stream->close();
}

public function getMetadata($key = null)
{
return $this->stream->getMetadata($key);
}

public function detach()
{
return $this->stream->detach();
}

public function getSize()
{
return $this->stream->getSize();
}

public function eof()
{
return $this->stream->eof();
}

public function tell()
{
return $this->stream->tell();
}

public function isReadable()
{
return $this->stream->isReadable();
}

public function isWritable()
{
return $this->stream->isWritable();
}

public function isSeekable()
{
return $this->stream->isSeekable();
}

public function rewind()
{
$this->seek(0);
}

public function seek($offset, $whence = SEEK_SET)
{
$this->stream->seek($offset, $whence);
}

public function read($length)
{
return $this->stream->read($length);
}

public function write($string)
{
return $this->stream->write($string);
}








protected function createStream()
{
throw new \BadMethodCallException('Not implemented');
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;







class CachingStream implements StreamInterface
{
use StreamDecoratorTrait;


private $remoteStream;


private $skipReadBytes = 0;







public function __construct(
StreamInterface $stream,
StreamInterface $target = null
) {
$this->remoteStream = $stream;
$this->stream = $target ?: new Stream(Utils::tryFopen('php://temp', 'r+'));
}

public function getSize()
{
$remoteSize = $this->remoteStream->getSize();

if (null === $remoteSize) {
return null;
}

return max($this->stream->getSize(), $remoteSize);
}

public function rewind()
{
$this->seek(0);
}

public function seek($offset, $whence = SEEK_SET)
{
if ($whence == SEEK_SET) {
$byte = $offset;
} elseif ($whence == SEEK_CUR) {
$byte = $offset + $this->tell();
} elseif ($whence == SEEK_END) {
$size = $this->remoteStream->getSize();
if ($size === null) {
$size = $this->cacheEntireStream();
}
$byte = $size + $offset;
} else {
throw new \InvalidArgumentException('Invalid whence');
}

$diff = $byte - $this->stream->getSize();

if ($diff > 0) {

 
 while ($diff > 0 && !$this->remoteStream->eof()) {
$this->read($diff);
$diff = $byte - $this->stream->getSize();
}
} else {

 $this->stream->seek($byte);
}
}

public function read($length)
{

 $data = $this->stream->read($length);
$remaining = $length - strlen($data);


 if ($remaining) {

 
 
 
 $remoteData = $this->remoteStream->read(
$remaining + $this->skipReadBytes
);

if ($this->skipReadBytes) {
$len = strlen($remoteData);
$remoteData = substr($remoteData, $this->skipReadBytes);
$this->skipReadBytes = max(0, $this->skipReadBytes - $len);
}

$data .= $remoteData;
$this->stream->write($remoteData);
}

return $data;
}

public function write($string)
{

 
 
 
 $overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell();
if ($overflow > 0) {
$this->skipReadBytes += $overflow;
}

return $this->stream->write($string);
}

public function eof()
{
return $this->stream->eof() && $this->remoteStream->eof();
}




public function close()
{
$this->remoteStream->close() && $this->stream->close();
}

private function cacheEntireStream()
{
$target = new FnStream(['write' => 'strlen']);
Utils::copyToStream($this, $target);

return $this->tell();
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;














class InflateStream implements StreamInterface
{
use StreamDecoratorTrait;

public function __construct(StreamInterface $stream)
{

 $header = $stream->read(10);
$filenameHeaderLength = $this->getLengthOfPossibleFilenameHeader($stream, $header);

 $stream = new LimitStream($stream, -1, 10 + $filenameHeaderLength);
$resource = StreamWrapper::getResource($stream);
stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ);
$this->stream = $stream->isSeekable() ? new Stream($resource) : new NoSeekStream(new Stream($resource));
}







private function getLengthOfPossibleFilenameHeader(StreamInterface $stream, $header)
{
$filename_header_length = 0;

if (substr(bin2hex($header), 6, 2) === '08') {

 $filename_header_length = 1;
while ($stream->read(1) !== chr(0)) {
$filename_header_length++;
}
}

return $filename_header_length;
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;











class BufferStream implements StreamInterface
{
private $hwm;
private $buffer = '';








public function __construct($hwm = 16384)
{
$this->hwm = $hwm;
}

public function __toString()
{
return $this->getContents();
}

public function getContents()
{
$buffer = $this->buffer;
$this->buffer = '';

return $buffer;
}

public function close()
{
$this->buffer = '';
}

public function detach()
{
$this->close();

return null;
}

public function getSize()
{
return strlen($this->buffer);
}

public function isReadable()
{
return true;
}

public function isWritable()
{
return true;
}

public function isSeekable()
{
return false;
}

public function rewind()
{
$this->seek(0);
}

public function seek($offset, $whence = SEEK_SET)
{
throw new \RuntimeException('Cannot seek a BufferStream');
}

public function eof()
{
return strlen($this->buffer) === 0;
}

public function tell()
{
throw new \RuntimeException('Cannot determine the position of a BufferStream');
}




public function read($length)
{
$currentLength = strlen($this->buffer);

if ($length >= $currentLength) {

 $result = $this->buffer;
$this->buffer = '';
} else {

 $result = substr($this->buffer, 0, $length);
$this->buffer = substr($this->buffer, $length);
}

return $result;
}




public function write($string)
{
$this->buffer .= $string;


 if (strlen($this->buffer) >= $this->hwm) {
return false;
}

return strlen($string);
}

public function getMetadata($key = null)
{
if ($key == 'hwm') {
return $this->hwm;
}

return $key ? null : [];
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;













class PumpStream implements StreamInterface
{

private $source;


private $size;


private $tellPos = 0;


private $metadata;


private $buffer;











public function __construct(callable $source, array $options = [])
{
$this->source = $source;
$this->size = isset($options['size']) ? $options['size'] : null;
$this->metadata = isset($options['metadata']) ? $options['metadata'] : [];
$this->buffer = new BufferStream();
}

public function __toString()
{
try {
return Utils::copyToString($this);
} catch (\Exception $e) {
return '';
}
}

public function close()
{
$this->detach();
}

public function detach()
{
$this->tellPos = false;
$this->source = null;

return null;
}

public function getSize()
{
return $this->size;
}

public function tell()
{
return $this->tellPos;
}

public function eof()
{
return !$this->source;
}

public function isSeekable()
{
return false;
}

public function rewind()
{
$this->seek(0);
}

public function seek($offset, $whence = SEEK_SET)
{
throw new \RuntimeException('Cannot seek a PumpStream');
}

public function isWritable()
{
return false;
}

public function write($string)
{
throw new \RuntimeException('Cannot write to a PumpStream');
}

public function isReadable()
{
return true;
}

public function read($length)
{
$data = $this->buffer->read($length);
$readLen = strlen($data);
$this->tellPos += $readLen;
$remaining = $length - $readLen;

if ($remaining) {
$this->pump($remaining);
$data .= $this->buffer->read($remaining);
$this->tellPos += strlen($data) - $readLen;
}

return $data;
}

public function getContents()
{
$result = '';
while (!$this->eof()) {
$result .= $this->read(1000000);
}

return $result;
}

public function getMetadata($key = null)
{
if (!$key) {
return $this->metadata;
}

return isset($this->metadata[$key]) ? $this->metadata[$key] : null;
}

private function pump($length)
{
if ($this->source) {
do {
$data = call_user_func($this->source, $length);
if ($data === false || $data === null) {
$this->source = null;
return;
}
$this->buffer->write($data);
$length -= strlen($data);
} while ($length > 0);
}
}
}
<?php


if (!function_exists('GuzzleHttp\Psr7\str')) {
require __DIR__ . '/functions.php';
}
<?php

namespace GuzzleHttp\Psr7;

final class Header
{










public static function parse($header)
{
static $trimmed = "\"'  \n\t\r";
$params = $matches = [];

foreach (self::normalize($header) as $val) {
$part = [];
foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
$m = $matches[0];
if (isset($m[1])) {
$part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);
} else {
$part[] = trim($m[0], $trimmed);
}
}
}
if ($part) {
$params[] = $part;
}
}

return $params;
}









public static function normalize($header)
{
if (!is_array($header)) {
return array_map('trim', explode(',', $header));
}

$result = [];
foreach ($header as $value) {
foreach ((array) $value as $v) {
if (strpos($v, ',') === false) {
$result[] = $v;
continue;
}
foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $v) as $vv) {
$result[] = trim($vv);
}
}
}

return $result;
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;







class MultipartStream implements StreamInterface
{
use StreamDecoratorTrait;

private $boundary;













public function __construct(array $elements = [], $boundary = null)
{
$this->boundary = $boundary ?: sha1(uniqid('', true));
$this->stream = $this->createStream($elements);
}






public function getBoundary()
{
return $this->boundary;
}

public function isWritable()
{
return false;
}




private function getHeaders(array $headers)
{
$str = '';
foreach ($headers as $key => $value) {
$str .= "{$key}: {$value}\r\n";
}

return "--{$this->boundary}\r\n" . trim($str) . "\r\n\r\n";
}




protected function createStream(array $elements)
{
$stream = new AppendStream();

foreach ($elements as $element) {
$this->addElement($stream, $element);
}


 $stream->addStream(Utils::streamFor("--{$this->boundary}--\r\n"));

return $stream;
}

private function addElement(AppendStream $stream, array $element)
{
foreach (['contents', 'name'] as $key) {
if (!array_key_exists($key, $element)) {
throw new \InvalidArgumentException("A '{$key}' key is required");
}
}

$element['contents'] = Utils::streamFor($element['contents']);

if (empty($element['filename'])) {
$uri = $element['contents']->getMetadata('uri');
if (substr($uri, 0, 6) !== 'php://') {
$element['filename'] = $uri;
}
}

list($body, $headers) = $this->createElement(
$element['name'],
$element['contents'],
isset($element['filename']) ? $element['filename'] : null,
isset($element['headers']) ? $element['headers'] : []
);

$stream->addStream(Utils::streamFor($this->getHeaders($headers)));
$stream->addStream($body);
$stream->addStream(Utils::streamFor("\r\n"));
}




private function createElement($name, StreamInterface $stream, $filename, array $headers)
{

 $disposition = $this->getHeader($headers, 'content-disposition');
if (!$disposition) {
$headers['Content-Disposition'] = ($filename === '0' || $filename)
? sprintf(
'form-data; name="%s"; filename="%s"',
$name,
basename($filename)
)
: "form-data; name=\"{$name}\"";
}


 $length = $this->getHeader($headers, 'content-length');
if (!$length) {
if ($length = $stream->getSize()) {
$headers['Content-Length'] = (string) $length;
}
}


 $type = $this->getHeader($headers, 'content-type');
if (!$type && ($filename === '0' || $filename)) {
if ($type = MimeType::fromFilename($filename)) {
$headers['Content-Type'] = $type;
}
}

return [$stream, $headers];
}

private function getHeader(array $headers, $key)
{
$lowercaseHeader = strtolower($key);
foreach ($headers as $k => $v) {
if (strtolower($k) === $lowercaseHeader) {
return $v;
}
}

return null;
}
}
<?php

namespace GuzzleHttp\Psr7;

final class Query
{













public static function parse($str, $urlEncoding = true)
{
$result = [];

if ($str === '') {
return $result;
}

if ($urlEncoding === true) {
$decoder = function ($value) {
return rawurldecode(str_replace('+', ' ', $value));
};
} elseif ($urlEncoding === PHP_QUERY_RFC3986) {
$decoder = 'rawurldecode';
} elseif ($urlEncoding === PHP_QUERY_RFC1738) {
$decoder = 'urldecode';
} else {
$decoder = function ($str) {
return $str;
};
}

foreach (explode('&', $str) as $kvp) {
$parts = explode('=', $kvp, 2);
$key = $decoder($parts[0]);
$value = isset($parts[1]) ? $decoder($parts[1]) : null;
if (!isset($result[$key])) {
$result[$key] = $value;
} else {
if (!is_array($result[$key])) {
$result[$key] = [$result[$key]];
}
$result[$key][] = $value;
}
}

return $result;
}















public static function build(array $params, $encoding = PHP_QUERY_RFC3986)
{
if (!$params) {
return '';
}

if ($encoding === false) {
$encoder = function ($str) {
return $str;
};
} elseif ($encoding === PHP_QUERY_RFC3986) {
$encoder = 'rawurlencode';
} elseif ($encoding === PHP_QUERY_RFC1738) {
$encoder = 'urlencode';
} else {
throw new \InvalidArgumentException('Invalid type');
}

$qs = '';
foreach ($params as $k => $v) {
$k = $encoder($k);
if (!is_array($v)) {
$qs .= $k;
if ($v !== null) {
$qs .= '=' . $encoder($v);
}
$qs .= '&';
} else {
foreach ($v as $vv) {
$qs .= $k;
if ($vv !== null) {
$qs .= '=' . $encoder($vv);
}
$qs .= '&';
}
}
}

return $qs ? (string) substr($qs, 0, -1) : '';
}
}
<?php

namespace GuzzleHttp\Psr7;

use InvalidArgumentException;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;
use Psr\Http\Message\UriInterface;















class ServerRequest extends Request implements ServerRequestInterface
{



private $attributes = [];




private $cookieParams = [];




private $parsedBody;




private $queryParams = [];




private $serverParams;




private $uploadedFiles = [];









public function __construct(
$method,
$uri,
array $headers = [],
$body = null,
$version = '1.1',
array $serverParams = []
) {
$this->serverParams = $serverParams;

parent::__construct($method, $uri, $headers, $body, $version);
}










public static function normalizeFiles(array $files)
{
$normalized = [];

foreach ($files as $key => $value) {
if ($value instanceof UploadedFileInterface) {
$normalized[$key] = $value;
} elseif (is_array($value) && isset($value['tmp_name'])) {
$normalized[$key] = self::createUploadedFileFromSpec($value);
} elseif (is_array($value)) {
$normalized[$key] = self::normalizeFiles($value);
continue;
} else {
throw new InvalidArgumentException('Invalid value in files specification');
}
}

return $normalized;
}











private static function createUploadedFileFromSpec(array $value)
{
if (is_array($value['tmp_name'])) {
return self::normalizeNestedFileSpec($value);
}

return new UploadedFile(
$value['tmp_name'],
(int) $value['size'],
(int) $value['error'],
$value['name'],
$value['type']
);
}











private static function normalizeNestedFileSpec(array $files = [])
{
$normalizedFiles = [];

foreach (array_keys($files['tmp_name']) as $key) {
$spec = [
'tmp_name' => $files['tmp_name'][$key],
'size' => $files['size'][$key],
'error' => $files['error'][$key],
'name' => $files['name'][$key],
'type' => $files['type'][$key],
];
$normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
}

return $normalizedFiles;
}











public static function fromGlobals()
{
$method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
$headers = getallheaders();
$uri = self::getUriFromGlobals();
$body = new CachingStream(new LazyOpenStream('php://input', 'r+'));
$protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1';

$serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER);

return $serverRequest
->withCookieParams($_COOKIE)
->withQueryParams($_GET)
->withParsedBody($_POST)
->withUploadedFiles(self::normalizeFiles($_FILES));
}

private static function extractHostAndPortFromAuthority($authority)
{
$uri = 'http://' . $authority;
$parts = parse_url($uri);
if (false === $parts) {
return [null, null];
}

$host = isset($parts['host']) ? $parts['host'] : null;
$port = isset($parts['port']) ? $parts['port'] : null;

return [$host, $port];
}






public static function getUriFromGlobals()
{
$uri = new Uri('');

$uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');

$hasPort = false;
if (isset($_SERVER['HTTP_HOST'])) {
list($host, $port) = self::extractHostAndPortFromAuthority($_SERVER['HTTP_HOST']);
if ($host !== null) {
$uri = $uri->withHost($host);
}

if ($port !== null) {
$hasPort = true;
$uri = $uri->withPort($port);
}
} elseif (isset($_SERVER['SERVER_NAME'])) {
$uri = $uri->withHost($_SERVER['SERVER_NAME']);
} elseif (isset($_SERVER['SERVER_ADDR'])) {
$uri = $uri->withHost($_SERVER['SERVER_ADDR']);
}

if (!$hasPort && isset($_SERVER['SERVER_PORT'])) {
$uri = $uri->withPort($_SERVER['SERVER_PORT']);
}

$hasQuery = false;
if (isset($_SERVER['REQUEST_URI'])) {
$requestUriParts = explode('?', $_SERVER['REQUEST_URI'], 2);
$uri = $uri->withPath($requestUriParts[0]);
if (isset($requestUriParts[1])) {
$hasQuery = true;
$uri = $uri->withQuery($requestUriParts[1]);
}
}

if (!$hasQuery && isset($_SERVER['QUERY_STRING'])) {
$uri = $uri->withQuery($_SERVER['QUERY_STRING']);
}

return $uri;
}




public function getServerParams()
{
return $this->serverParams;
}




public function getUploadedFiles()
{
return $this->uploadedFiles;
}




public function withUploadedFiles(array $uploadedFiles)
{
$new = clone $this;
$new->uploadedFiles = $uploadedFiles;

return $new;
}




public function getCookieParams()
{
return $this->cookieParams;
}




public function withCookieParams(array $cookies)
{
$new = clone $this;
$new->cookieParams = $cookies;

return $new;
}




public function getQueryParams()
{
return $this->queryParams;
}




public function withQueryParams(array $query)
{
$new = clone $this;
$new->queryParams = $query;

return $new;
}




public function getParsedBody()
{
return $this->parsedBody;
}




public function withParsedBody($data)
{
$new = clone $this;
$new->parsedBody = $data;

return $new;
}




public function getAttributes()
{
return $this->attributes;
}




public function getAttribute($attribute, $default = null)
{
if (false === array_key_exists($attribute, $this->attributes)) {
return $default;
}

return $this->attributes[$attribute];
}




public function withAttribute($attribute, $value)
{
$new = clone $this;
$new->attributes[$attribute] = $value;

return $new;
}




public function withoutAttribute($attribute)
{
if (false === array_key_exists($attribute, $this->attributes)) {
return $this;
}

$new = clone $this;
unset($new->attributes[$attribute]);

return $new;
}
}
<?php

namespace GuzzleHttp\Psr7;

final class Rfc7230
{










const HEADER_REGEX = "(^([^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]++):[ \t]*+((?:[ \t]*+[\x21-\x7E\x80-\xFF]++)*+)[ \t]*+\r?\n)m";
const HEADER_FOLD_REGEX = "(\r?\n[ \t]++)";
}
<?php

namespace GuzzleHttp\Psr7;

use InvalidArgumentException;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;
use RuntimeException;

class UploadedFile implements UploadedFileInterface
{



private static $errors = [
UPLOAD_ERR_OK,
UPLOAD_ERR_INI_SIZE,
UPLOAD_ERR_FORM_SIZE,
UPLOAD_ERR_PARTIAL,
UPLOAD_ERR_NO_FILE,
UPLOAD_ERR_NO_TMP_DIR,
UPLOAD_ERR_CANT_WRITE,
UPLOAD_ERR_EXTENSION,
];




private $clientFilename;




private $clientMediaType;




private $error;




private $file;




private $moved = false;




private $size;




private $stream;








public function __construct(
$streamOrFile,
$size,
$errorStatus,
$clientFilename = null,
$clientMediaType = null
) {
$this->setError($errorStatus);
$this->setSize($size);
$this->setClientFilename($clientFilename);
$this->setClientMediaType($clientMediaType);

if ($this->isOk()) {
$this->setStreamOrFile($streamOrFile);
}
}








private function setStreamOrFile($streamOrFile)
{
if (is_string($streamOrFile)) {
$this->file = $streamOrFile;
} elseif (is_resource($streamOrFile)) {
$this->stream = new Stream($streamOrFile);
} elseif ($streamOrFile instanceof StreamInterface) {
$this->stream = $streamOrFile;
} else {
throw new InvalidArgumentException(
'Invalid stream or file provided for UploadedFile'
);
}
}






private function setError($error)
{
if (false === is_int($error)) {
throw new InvalidArgumentException(
'Upload file error status must be an integer'
);
}

if (false === in_array($error, UploadedFile::$errors)) {
throw new InvalidArgumentException(
'Invalid error status for UploadedFile'
);
}

$this->error = $error;
}






private function setSize($size)
{
if (false === is_int($size)) {
throw new InvalidArgumentException(
'Upload file size must be an integer'
);
}

$this->size = $size;
}






private function isStringOrNull($param)
{
return in_array(gettype($param), ['string', 'NULL']);
}






private function isStringNotEmpty($param)
{
return is_string($param) && false === empty($param);
}






private function setClientFilename($clientFilename)
{
if (false === $this->isStringOrNull($clientFilename)) {
throw new InvalidArgumentException(
'Upload file client filename must be a string or null'
);
}

$this->clientFilename = $clientFilename;
}






private function setClientMediaType($clientMediaType)
{
if (false === $this->isStringOrNull($clientMediaType)) {
throw new InvalidArgumentException(
'Upload file client media type must be a string or null'
);
}

$this->clientMediaType = $clientMediaType;
}






private function isOk()
{
return $this->error === UPLOAD_ERR_OK;
}




public function isMoved()
{
return $this->moved;
}




private function validateActive()
{
if (false === $this->isOk()) {
throw new RuntimeException('Cannot retrieve stream due to upload error');
}

if ($this->isMoved()) {
throw new RuntimeException('Cannot retrieve stream after it has already been moved');
}
}






public function getStream()
{
$this->validateActive();

if ($this->stream instanceof StreamInterface) {
return $this->stream;
}

return new LazyOpenStream($this->file, 'r+');
}














public function moveTo($targetPath)
{
$this->validateActive();

if (false === $this->isStringNotEmpty($targetPath)) {
throw new InvalidArgumentException(
'Invalid path provided for move operation; must be a non-empty string'
);
}

if ($this->file) {
$this->moved = php_sapi_name() == 'cli'
? rename($this->file, $targetPath)
: move_uploaded_file($this->file, $targetPath);
} else {
Utils::copyToStream(
$this->getStream(),
new LazyOpenStream($targetPath, 'w')
);

$this->moved = true;
}

if (false === $this->moved) {
throw new RuntimeException(
sprintf('Uploaded file could not be moved to %s', $targetPath)
);
}
}






public function getSize()
{
return $this->size;
}








public function getError()
{
return $this->error;
}







public function getClientFilename()
{
return $this->clientFilename;
}




public function getClientMediaType()
{
return $this->clientMediaType;
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;






class NoSeekStream implements StreamInterface
{
use StreamDecoratorTrait;

public function seek($offset, $whence = SEEK_SET)
{
throw new \RuntimeException('Cannot seek a NoSeekStream');
}

public function isSeekable()
{
return false;
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\UriInterface;








final class UriNormalizer
{






const PRESERVING_NORMALIZATIONS = 63;






const CAPITALIZE_PERCENT_ENCODING = 1;










const DECODE_UNRESERVED_CHARACTERS = 2;






const CONVERT_EMPTY_PATH = 4;












const REMOVE_DEFAULT_HOST = 8;






const REMOVE_DEFAULT_PORT = 16;









const REMOVE_DOT_SEGMENTS = 32;










const REMOVE_DUPLICATE_SLASHES = 64;












const SORT_QUERY_PARAMETERS = 128;



















public static function normalize(UriInterface $uri, $flags = self::PRESERVING_NORMALIZATIONS)
{
if ($flags & self::CAPITALIZE_PERCENT_ENCODING) {
$uri = self::capitalizePercentEncoding($uri);
}

if ($flags & self::DECODE_UNRESERVED_CHARACTERS) {
$uri = self::decodeUnreservedCharacters($uri);
}

if ($flags & self::CONVERT_EMPTY_PATH && $uri->getPath() === '' &&
($uri->getScheme() === 'http' || $uri->getScheme() === 'https')
) {
$uri = $uri->withPath('/');
}

if ($flags & self::REMOVE_DEFAULT_HOST && $uri->getScheme() === 'file' && $uri->getHost() === 'localhost') {
$uri = $uri->withHost('');
}

if ($flags & self::REMOVE_DEFAULT_PORT && $uri->getPort() !== null && Uri::isDefaultPort($uri)) {
$uri = $uri->withPort(null);
}

if ($flags & self::REMOVE_DOT_SEGMENTS && !Uri::isRelativePathReference($uri)) {
$uri = $uri->withPath(UriResolver::removeDotSegments($uri->getPath()));
}

if ($flags & self::REMOVE_DUPLICATE_SLASHES) {
$uri = $uri->withPath(preg_replace('#//++#', '/', $uri->getPath()));
}

if ($flags & self::SORT_QUERY_PARAMETERS && $uri->getQuery() !== '') {
$queryKeyValues = explode('&', $uri->getQuery());
sort($queryKeyValues);
$uri = $uri->withQuery(implode('&', $queryKeyValues));
}

return $uri;
}

















public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, $normalizations = self::PRESERVING_NORMALIZATIONS)
{
return (string) self::normalize($uri1, $normalizations) === (string) self::normalize($uri2, $normalizations);
}

private static function capitalizePercentEncoding(UriInterface $uri)
{
$regex = '/(?:%[A-Fa-f0-9]{2})++/';

$callback = function (array $match) {
return strtoupper($match[0]);
};

return
$uri->withPath(
preg_replace_callback($regex, $callback, $uri->getPath())
)->withQuery(
preg_replace_callback($regex, $callback, $uri->getQuery())
);
}

private static function decodeUnreservedCharacters(UriInterface $uri)
{
$regex = '/%(?:2D|2E|5F|7E|3[0-9]|[46][1-9A-F]|[57][0-9A])/i';

$callback = function (array $match) {
return rawurldecode($match[0]);
};

return
$uri->withPath(
preg_replace_callback($regex, $callback, $uri->getPath())
)->withQuery(
preg_replace_callback($regex, $callback, $uri->getQuery())
);
}

private function __construct()
{

 }
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

final class Message
{







public static function toString(MessageInterface $message)
{
if ($message instanceof RequestInterface) {
$msg = trim($message->getMethod() . ' '
. $message->getRequestTarget())
. ' HTTP/' . $message->getProtocolVersion();
if (!$message->hasHeader('host')) {
$msg .= "\r\nHost: " . $message->getUri()->getHost();
}
} elseif ($message instanceof ResponseInterface) {
$msg = 'HTTP/' . $message->getProtocolVersion() . ' '
. $message->getStatusCode() . ' '
. $message->getReasonPhrase();
} else {
throw new \InvalidArgumentException('Unknown message type');
}

foreach ($message->getHeaders() as $name => $values) {
if (strtolower($name) === 'set-cookie') {
foreach ($values as $value) {
$msg .= "\r\n{$name}: " . $value;
}
} else {
$msg .= "\r\n{$name}: " . implode(', ', $values);
}
}

return "{$msg}\r\n\r\n" . $message->getBody();
}











public static function bodySummary(MessageInterface $message, $truncateAt = 120)
{
$body = $message->getBody();

if (!$body->isSeekable() || !$body->isReadable()) {
return null;
}

$size = $body->getSize();

if ($size === 0) {
return null;
}

$summary = $body->read($truncateAt);
$body->rewind();

if ($size > $truncateAt) {
$summary .= ' (truncated...)';
}


 
 if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/u', $summary)) {
return null;
}

return $summary;
}











public static function rewindBody(MessageInterface $message)
{
$body = $message->getBody();

if ($body->tell()) {
$body->rewind();
}
}












public static function parseMessage($message)
{
if (!$message) {
throw new \InvalidArgumentException('Invalid message');
}

$message = ltrim($message, "\r\n");

$messageParts = preg_split("/\r?\n\r?\n/", $message, 2);

if ($messageParts === false || count($messageParts) !== 2) {
throw new \InvalidArgumentException('Invalid message: Missing header delimiter');
}

list($rawHeaders, $body) = $messageParts;
$rawHeaders .= "\r\n"; 
 $headerParts = preg_split("/\r?\n/", $rawHeaders, 2);

if ($headerParts === false || count($headerParts) !== 2) {
throw new \InvalidArgumentException('Invalid message: Missing status line');
}

list($startLine, $rawHeaders) = $headerParts;

if (preg_match("/(?:^HTTP\/|^[A-Z]+ \S+ HTTP\/)(\d+(?:\.\d+)?)/i", $startLine, $matches) && $matches[1] === '1.0') {

 $rawHeaders = preg_replace(Rfc7230::HEADER_FOLD_REGEX, ' ', $rawHeaders);
}


$count = preg_match_all(Rfc7230::HEADER_REGEX, $rawHeaders, $headerLines, PREG_SET_ORDER);


 if ($count !== substr_count($rawHeaders, "\n")) {

 if (preg_match(Rfc7230::HEADER_FOLD_REGEX, $rawHeaders)) {
throw new \InvalidArgumentException('Invalid header syntax: Obsolete line folding');
}

throw new \InvalidArgumentException('Invalid header syntax');
}

$headers = [];

foreach ($headerLines as $headerLine) {
$headers[$headerLine[1]][] = $headerLine[2];
}

return [
'start-line' => $startLine,
'headers' => $headers,
'body' => $body,
];
}









public static function parseRequestUri($path, array $headers)
{
$hostKey = array_filter(array_keys($headers), function ($k) {
return strtolower($k) === 'host';
});


 if (!$hostKey) {
return $path;
}

$host = $headers[reset($hostKey)][0];
$scheme = substr($host, -4) === ':443' ? 'https' : 'http';

return $scheme . '://' . $host . '/' . ltrim($path, '/');
}








public static function parseRequest($message)
{
$data = self::parseMessage($message);
$matches = [];
if (!preg_match('/^[\S]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) {
throw new \InvalidArgumentException('Invalid request string');
}
$parts = explode(' ', $data['start-line'], 3);
$version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1';

$request = new Request(
$parts[0],
$matches[1] === '/' ? self::parseRequestUri($parts[1], $data['headers']) : $parts[1],
$data['headers'],
$data['body'],
$version
);

return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]);
}








public static function parseResponse($message)
{
$data = self::parseMessage($message);

 
 
 if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) {
throw new \InvalidArgumentException('Invalid response string: ' . $data['start-line']);
}
$parts = explode(' ', $data['start-line'], 3);

return new Response(
(int) $parts[1],
$data['headers'],
$data['body'],
explode('/', $parts[0])[1],
isset($parts[2]) ? $parts[2] : null
);
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;






class StreamWrapper
{

public $context;


private $stream;


private $mode;










public static function getResource(StreamInterface $stream)
{
self::register();

if ($stream->isReadable()) {
$mode = $stream->isWritable() ? 'r+' : 'r';
} elseif ($stream->isWritable()) {
$mode = 'w';
} else {
throw new \InvalidArgumentException('The stream must be readable, '
. 'writable, or both.');
}

return fopen('guzzle://stream', $mode, null, self::createStreamContext($stream));
}








public static function createStreamContext(StreamInterface $stream)
{
return stream_context_create([
'guzzle' => ['stream' => $stream]
]);
}




public static function register()
{
if (!in_array('guzzle', stream_get_wrappers())) {
stream_wrapper_register('guzzle', __CLASS__);
}
}

public function stream_open($path, $mode, $options, &$opened_path)
{
$options = stream_context_get_options($this->context);

if (!isset($options['guzzle']['stream'])) {
return false;
}

$this->mode = $mode;
$this->stream = $options['guzzle']['stream'];

return true;
}

public function stream_read($count)
{
return $this->stream->read($count);
}

public function stream_write($data)
{
return (int) $this->stream->write($data);
}

public function stream_tell()
{
return $this->stream->tell();
}

public function stream_eof()
{
return $this->stream->eof();
}

public function stream_seek($offset, $whence)
{
$this->stream->seek($offset, $whence);

return true;
}

public function stream_cast($cast_as)
{
$stream = clone($this->stream);

return $stream->detach();
}

public function stream_stat()
{
static $modeMap = [
'r' => 33060,
'rb' => 33060,
'r+' => 33206,
'w' => 33188,
'wb' => 33188
];

return [
'dev' => 0,
'ino' => 0,
'mode' => $modeMap[$this->mode],
'nlink' => 0,
'uid' => 0,
'gid' => 0,
'rdev' => 0,
'size' => $this->stream->getSize() ?: 0,
'atime' => 0,
'mtime' => 0,
'ctime' => 0,
'blksize' => 0,
'blocks' => 0
];
}

public function url_stat($path, $flags)
{
return [
'dev' => 0,
'ino' => 0,
'mode' => 0,
'nlink' => 0,
'uid' => 0,
'gid' => 0,
'rdev' => 0,
'size' => 0,
'atime' => 0,
'mtime' => 0,
'ctime' => 0,
'blksize' => 0,
'blocks' => 0
];
}
}
<?php

namespace GuzzleHttp\Psr7;

final class MimeType
{







public static function fromFilename($filename)
{
return self::fromExtension(pathinfo($filename, PATHINFO_EXTENSION));
}










public static function fromExtension($extension)
{
static $mimetypes = [
'3gp' => 'video/3gpp',
'7z' => 'application/x-7z-compressed',
'aac' => 'audio/x-aac',
'ai' => 'application/postscript',
'aif' => 'audio/x-aiff',
'asc' => 'text/plain',
'asf' => 'video/x-ms-asf',
'atom' => 'application/atom+xml',
'avi' => 'video/x-msvideo',
'bmp' => 'image/bmp',
'bz2' => 'application/x-bzip2',
'cer' => 'application/pkix-cert',
'crl' => 'application/pkix-crl',
'crt' => 'application/x-x509-ca-cert',
'css' => 'text/css',
'csv' => 'text/csv',
'cu' => 'application/cu-seeme',
'deb' => 'application/x-debian-package',
'doc' => 'application/msword',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'dvi' => 'application/x-dvi',
'eot' => 'application/vnd.ms-fontobject',
'eps' => 'application/postscript',
'epub' => 'application/epub+zip',
'etx' => 'text/x-setext',
'flac' => 'audio/flac',
'flv' => 'video/x-flv',
'gif' => 'image/gif',
'gz' => 'application/gzip',
'htm' => 'text/html',
'html' => 'text/html',
'ico' => 'image/x-icon',
'ics' => 'text/calendar',
'ini' => 'text/plain',
'iso' => 'application/x-iso9660-image',
'jar' => 'application/java-archive',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'js' => 'text/javascript',
'json' => 'application/json',
'latex' => 'application/x-latex',
'log' => 'text/plain',
'm4a' => 'audio/mp4',
'm4v' => 'video/mp4',
'mid' => 'audio/midi',
'midi' => 'audio/midi',
'mov' => 'video/quicktime',
'mkv' => 'video/x-matroska',
'mp3' => 'audio/mpeg',
'mp4' => 'video/mp4',
'mp4a' => 'audio/mp4',
'mp4v' => 'video/mp4',
'mpe' => 'video/mpeg',
'mpeg' => 'video/mpeg',
'mpg' => 'video/mpeg',
'mpg4' => 'video/mp4',
'oga' => 'audio/ogg',
'ogg' => 'audio/ogg',
'ogv' => 'video/ogg',
'ogx' => 'application/ogg',
'pbm' => 'image/x-portable-bitmap',
'pdf' => 'application/pdf',
'pgm' => 'image/x-portable-graymap',
'png' => 'image/png',
'pnm' => 'image/x-portable-anymap',
'ppm' => 'image/x-portable-pixmap',
'ppt' => 'application/vnd.ms-powerpoint',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'ps' => 'application/postscript',
'qt' => 'video/quicktime',
'rar' => 'application/x-rar-compressed',
'ras' => 'image/x-cmu-raster',
'rss' => 'application/rss+xml',
'rtf' => 'application/rtf',
'sgm' => 'text/sgml',
'sgml' => 'text/sgml',
'svg' => 'image/svg+xml',
'swf' => 'application/x-shockwave-flash',
'tar' => 'application/x-tar',
'tif' => 'image/tiff',
'tiff' => 'image/tiff',
'torrent' => 'application/x-bittorrent',
'ttf' => 'application/x-font-ttf',
'txt' => 'text/plain',
'wav' => 'audio/x-wav',
'webm' => 'video/webm',
'webp' => 'image/webp',
'wma' => 'audio/x-ms-wma',
'wmv' => 'video/x-ms-wmv',
'woff' => 'application/x-font-woff',
'wsdl' => 'application/wsdl+xml',
'xbm' => 'image/x-xbitmap',
'xls' => 'application/vnd.ms-excel',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'xml' => 'application/xml',
'xpm' => 'image/x-xpixmap',
'xwd' => 'image/x-xwindowdump',
'yaml' => 'text/yaml',
'yml' => 'text/yaml',
'zip' => 'application/zip',
];

$extension = strtolower($extension);

return isset($mimetypes[$extension])
? $mimetypes[$extension]
: null;
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;






class Stream implements StreamInterface
{








const READABLE_MODES = '/r|a\+|ab\+|w\+|wb\+|x\+|xb\+|c\+|cb\+/';
const WRITABLE_MODES = '/a|w|r\+|rb\+|rw|x|c/';

private $stream;
private $size;
private $seekable;
private $readable;
private $writable;
private $uri;
private $customMetadata;















public function __construct($stream, $options = [])
{
if (!is_resource($stream)) {
throw new \InvalidArgumentException('Stream must be a resource');
}

if (isset($options['size'])) {
$this->size = $options['size'];
}

$this->customMetadata = isset($options['metadata'])
? $options['metadata']
: [];

$this->stream = $stream;
$meta = stream_get_meta_data($this->stream);
$this->seekable = $meta['seekable'];
$this->readable = (bool)preg_match(self::READABLE_MODES, $meta['mode']);
$this->writable = (bool)preg_match(self::WRITABLE_MODES, $meta['mode']);
$this->uri = $this->getMetadata('uri');
}




public function __destruct()
{
$this->close();
}

public function __toString()
{
try {
if ($this->isSeekable()) {
$this->seek(0);
}
return $this->getContents();
} catch (\Exception $e) {
return '';
}
}

public function getContents()
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}

$contents = stream_get_contents($this->stream);

if ($contents === false) {
throw new \RuntimeException('Unable to read stream contents');
}

return $contents;
}

public function close()
{
if (isset($this->stream)) {
if (is_resource($this->stream)) {
fclose($this->stream);
}
$this->detach();
}
}

public function detach()
{
if (!isset($this->stream)) {
return null;
}

$result = $this->stream;
unset($this->stream);
$this->size = $this->uri = null;
$this->readable = $this->writable = $this->seekable = false;

return $result;
}

public function getSize()
{
if ($this->size !== null) {
return $this->size;
}

if (!isset($this->stream)) {
return null;
}


 if ($this->uri) {
clearstatcache(true, $this->uri);
}

$stats = fstat($this->stream);
if (isset($stats['size'])) {
$this->size = $stats['size'];
return $this->size;
}

return null;
}

public function isReadable()
{
return $this->readable;
}

public function isWritable()
{
return $this->writable;
}

public function isSeekable()
{
return $this->seekable;
}

public function eof()
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}

return feof($this->stream);
}

public function tell()
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}

$result = ftell($this->stream);

if ($result === false) {
throw new \RuntimeException('Unable to determine stream position');
}

return $result;
}

public function rewind()
{
$this->seek(0);
}

public function seek($offset, $whence = SEEK_SET)
{
$whence = (int) $whence;

if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
if (!$this->seekable) {
throw new \RuntimeException('Stream is not seekable');
}
if (fseek($this->stream, $offset, $whence) === -1) {
throw new \RuntimeException('Unable to seek to stream position '
. $offset . ' with whence ' . var_export($whence, true));
}
}

public function read($length)
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
if (!$this->readable) {
throw new \RuntimeException('Cannot read from non-readable stream');
}
if ($length < 0) {
throw new \RuntimeException('Length parameter cannot be negative');
}

if (0 === $length) {
return '';
}

$string = fread($this->stream, $length);
if (false === $string) {
throw new \RuntimeException('Unable to read from stream');
}

return $string;
}

public function write($string)
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
if (!$this->writable) {
throw new \RuntimeException('Cannot write to a non-writable stream');
}


 $this->size = null;
$result = fwrite($this->stream, $string);

if ($result === false) {
throw new \RuntimeException('Unable to write to stream');
}

return $result;
}

public function getMetadata($key = null)
{
if (!isset($this->stream)) {
return $key ? null : [];
} elseif (!$key) {
return $this->customMetadata + stream_get_meta_data($this->stream);
} elseif (isset($this->customMetadata[$key])) {
return $this->customMetadata[$key];
}

$meta = stream_get_meta_data($this->stream);

return isset($meta[$key]) ? $meta[$key] : null;
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;







class DroppingStream implements StreamInterface
{
use StreamDecoratorTrait;

private $maxLength;





public function __construct(StreamInterface $stream, $maxLength)
{
$this->stream = $stream;
$this->maxLength = $maxLength;
}

public function write($string)
{
$diff = $this->maxLength - $this->stream->getSize();


 if ($diff <= 0) {
return 0;
}


 if (strlen($string) < $diff) {
return $this->stream->write($string);
}

return $this->stream->write(substr($string, 0, $diff));
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;









class FnStream implements StreamInterface
{

private $methods;


private static $slots = ['__toString', 'close', 'detach', 'rewind',
'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write',
'isReadable', 'read', 'getContents', 'getMetadata'];




public function __construct(array $methods)
{
$this->methods = $methods;


 foreach ($methods as $name => $fn) {
$this->{'_fn_' . $name} = $fn;
}
}






public function __get($name)
{
throw new \BadMethodCallException(str_replace('_fn_', '', $name)
. '() is not implemented in the FnStream');
}




public function __destruct()
{
if (isset($this->_fn_close)) {
call_user_func($this->_fn_close);
}
}






public function __wakeup()
{
throw new \LogicException('FnStream should never be unserialized');
}










public static function decorate(StreamInterface $stream, array $methods)
{

 
 foreach (array_diff(self::$slots, array_keys($methods)) as $diff) {
$methods[$diff] = [$stream, $diff];
}

return new self($methods);
}

public function __toString()
{
return call_user_func($this->_fn___toString);
}

public function close()
{
return call_user_func($this->_fn_close);
}

public function detach()
{
return call_user_func($this->_fn_detach);
}

public function getSize()
{
return call_user_func($this->_fn_getSize);
}

public function tell()
{
return call_user_func($this->_fn_tell);
}

public function eof()
{
return call_user_func($this->_fn_eof);
}

public function isSeekable()
{
return call_user_func($this->_fn_isSeekable);
}

public function rewind()
{
call_user_func($this->_fn_rewind);
}

public function seek($offset, $whence = SEEK_SET)
{
call_user_func($this->_fn_seek, $offset, $whence);
}

public function isWritable()
{
return call_user_func($this->_fn_isWritable);
}

public function write($string)
{
return call_user_func($this->_fn_write, $string);
}

public function isReadable()
{
return call_user_func($this->_fn_isReadable);
}

public function read($length)
{
return call_user_func($this->_fn_read, $length);
}

public function getContents()
{
return call_user_func($this->_fn_getContents);
}

public function getMetadata($key = null)
{
return call_user_func($this->_fn_getMetadata, $key);
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;










function str(MessageInterface $message)
{
return Message::toString($message);
}
















function uri_for($uri)
{
return Utils::uriFor($uri);
}







































function stream_for($resource = '', array $options = [])
{
return Utils::streamFor($resource, $options);
}













function parse_header($header)
{
return Header::parse($header);
}











function normalize_header($header)
{
return Header::normalize($header);
}























function modify_request(RequestInterface $request, array $changes)
{
return Utils::modifyRequest($request, $changes);
}













function rewind_body(MessageInterface $message)
{
Message::rewindBody($message);
}
















function try_fopen($filename, $mode)
{
return Utils::tryFopen($filename, $mode);
}















function copy_to_string(StreamInterface $stream, $maxLen = -1)
{
return Utils::copyToString($stream, $maxLen);
}














function copy_to_stream(StreamInterface $source, StreamInterface $dest, $maxLen = -1)
{
return Utils::copyToStream($source, $dest, $maxLen);
}

















function hash(StreamInterface $stream, $algo, $rawOutput = false)
{
return Utils::hash($stream, $algo, $rawOutput);
}











function readline(StreamInterface $stream, $maxLength = null)
{
return Utils::readLine($stream, $maxLength);
}










function parse_request($message)
{
return Message::parseRequest($message);
}










function parse_response($message)
{
return Message::parseResponse($message);
}
















function parse_query($str, $urlEncoding = true)
{
return Query::parse($str, $urlEncoding);
}

















function build_query(array $params, $encoding = PHP_QUERY_RFC3986)
{
return Query::build($params, $encoding);
}










function mimetype_from_filename($filename)
{
return MimeType::fromFilename($filename);
}











function mimetype_from_extension($extension)
{
return MimeType::fromExtension($extension);
}
















function _parse_message($message)
{
return Message::parseMessage($message);
}













function _parse_request_uri($path, array $headers)
{
return Message::parseRequestUri($path, $headers);
}













function get_message_body_summary(MessageInterface $message, $truncateAt = 120)
{
return Message::bodySummary($message, $truncateAt);
}












function _caseless_remove($keys, array $data)
{
return Utils::caselessRemove($keys, $data);
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;




class Response implements ResponseInterface
{
use MessageTrait;


private static $phrases = [
100 => 'Continue',
101 => 'Switching Protocols',
102 => 'Processing',
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative Information',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
207 => 'Multi-status',
208 => 'Already Reported',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
306 => 'Switch Proxy',
307 => 'Temporary Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Time-out',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Large',
415 => 'Unsupported Media Type',
416 => 'Requested range not satisfiable',
417 => 'Expectation Failed',
418 => 'I\'m a teapot',
422 => 'Unprocessable Entity',
423 => 'Locked',
424 => 'Failed Dependency',
425 => 'Unordered Collection',
426 => 'Upgrade Required',
428 => 'Precondition Required',
429 => 'Too Many Requests',
431 => 'Request Header Fields Too Large',
451 => 'Unavailable For Legal Reasons',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Time-out',
505 => 'HTTP Version not supported',
506 => 'Variant Also Negotiates',
507 => 'Insufficient Storage',
508 => 'Loop Detected',
511 => 'Network Authentication Required',
];


private $reasonPhrase = '';


private $statusCode = 200;








public function __construct(
$status = 200,
array $headers = [],
$body = null,
$version = '1.1',
$reason = null
) {
$this->assertStatusCodeIsInteger($status);
$status = (int) $status;
$this->assertStatusCodeRange($status);

$this->statusCode = $status;

if ($body !== '' && $body !== null) {
$this->stream = Utils::streamFor($body);
}

$this->setHeaders($headers);
if ($reason == '' && isset(self::$phrases[$this->statusCode])) {
$this->reasonPhrase = self::$phrases[$this->statusCode];
} else {
$this->reasonPhrase = (string) $reason;
}

$this->protocol = $version;
}

public function getStatusCode()
{
return $this->statusCode;
}

public function getReasonPhrase()
{
return $this->reasonPhrase;
}

public function withStatus($code, $reasonPhrase = '')
{
$this->assertStatusCodeIsInteger($code);
$code = (int) $code;
$this->assertStatusCodeRange($code);

$new = clone $this;
$new->statusCode = $code;
if ($reasonPhrase == '' && isset(self::$phrases[$new->statusCode])) {
$reasonPhrase = self::$phrases[$new->statusCode];
}
$new->reasonPhrase = (string) $reasonPhrase;
return $new;
}

private function assertStatusCodeIsInteger($statusCode)
{
if (filter_var($statusCode, FILTER_VALIDATE_INT) === false) {
throw new \InvalidArgumentException('Status code must be an integer value.');
}
}

private function assertStatusCodeRange($statusCode)
{
if ($statusCode < 100 || $statusCode >= 600) {
throw new \InvalidArgumentException('Status code must be an integer value between 1xx and 5xx.');
}
}
}
<?php

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;







class LazyOpenStream implements StreamInterface
{
use StreamDecoratorTrait;


private $filename;


private $mode;





public function __construct($filename, $mode)
{
$this->filename = $filename;
$this->mode = $mode;
}






protected function createStream()
{
return Utils::streamFor(Utils::tryFopen($this->filename, $this->mode));
}
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Promise;
use GuzzleHttp\Psr7;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;















class Client implements ClientInterface
{

private $config;
































public function __construct(array $config = [])
{
if (!isset($config['handler'])) {
$config['handler'] = HandlerStack::create();
} elseif (!is_callable($config['handler'])) {
throw new \InvalidArgumentException('handler must be a callable');
}


 if (isset($config['base_uri'])) {
$config['base_uri'] = Psr7\uri_for($config['base_uri']);
}

$this->configureDefaults($config);
}







public function __call($method, $args)
{
if (count($args) < 1) {
throw new \InvalidArgumentException('Magic request methods require a URI and optional options array');
}

$uri = $args[0];
$opts = isset($args[1]) ? $args[1] : [];

return substr($method, -5) === 'Async'
? $this->requestAsync(substr($method, 0, -5), $uri, $opts)
: $this->request($method, $uri, $opts);
}









public function sendAsync(RequestInterface $request, array $options = [])
{

 $options = $this->prepareDefaults($options);

return $this->transfer(
$request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')),
$options
);
}










public function send(RequestInterface $request, array $options = [])
{
$options[RequestOptions::SYNCHRONOUS] = true;
return $this->sendAsync($request, $options)->wait();
}















public function requestAsync($method, $uri = '', array $options = [])
{
$options = $this->prepareDefaults($options);

 $headers = isset($options['headers']) ? $options['headers'] : [];
$body = isset($options['body']) ? $options['body'] : null;
$version = isset($options['version']) ? $options['version'] : '1.1';

 $uri = $this->buildUri($uri, $options);
if (is_array($body)) {
$this->invalidBody();
}
$request = new Psr7\Request($method, $uri, $headers, $body, $version);

 unset($options['headers'], $options['body'], $options['version']);

return $this->transfer($request, $options);
}















public function request($method, $uri = '', array $options = [])
{
$options[RequestOptions::SYNCHRONOUS] = true;
return $this->requestAsync($method, $uri, $options)->wait();
}












public function getConfig($option = null)
{
return $option === null
? $this->config
: (isset($this->config[$option]) ? $this->config[$option] : null);
}






private function buildUri($uri, array $config)
{

 $uri = Psr7\uri_for($uri === null ? '' : $uri);

if (isset($config['base_uri'])) {
$uri = Psr7\UriResolver::resolve(Psr7\uri_for($config['base_uri']), $uri);
}

if (isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) {
$idnOptions = ($config['idn_conversion'] === true) ? IDNA_DEFAULT : $config['idn_conversion'];
$uri = Utils::idnUriConvert($uri, $idnOptions);
}

return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
}







private function configureDefaults(array $config)
{
$defaults = [
'allow_redirects' => RedirectMiddleware::$defaultSettings,
'http_errors' => true,
'decode_content' => true,
'verify' => true,
'cookies' => false,
'idn_conversion' => true,
];




 
 
 if (php_sapi_name() === 'cli' && getenv('HTTP_PROXY')) {
$defaults['proxy']['http'] = getenv('HTTP_PROXY');
}

if ($proxy = getenv('HTTPS_PROXY')) {
$defaults['proxy']['https'] = $proxy;
}

if ($noProxy = getenv('NO_PROXY')) {
$cleanedNoProxy = str_replace(' ', '', $noProxy);
$defaults['proxy']['no'] = explode(',', $cleanedNoProxy);
}

$this->config = $config + $defaults;

if (!empty($config['cookies']) && $config['cookies'] === true) {
$this->config['cookies'] = new CookieJar();
}


 if (!isset($this->config['headers'])) {
$this->config['headers'] = ['User-Agent' => default_user_agent()];
} else {

 foreach (array_keys($this->config['headers']) as $name) {
if (strtolower($name) === 'user-agent') {
return;
}
}
$this->config['headers']['User-Agent'] = default_user_agent();
}
}








private function prepareDefaults(array $options)
{
$defaults = $this->config;

if (!empty($defaults['headers'])) {

 $defaults['_conditional'] = $defaults['headers'];
unset($defaults['headers']);
}


 
 if (array_key_exists('headers', $options)) {

 if ($options['headers'] === null) {
$defaults['_conditional'] = [];
unset($options['headers']);
} elseif (!is_array($options['headers'])) {
throw new \InvalidArgumentException('headers must be an array');
}
}


 $result = $options + $defaults;


 foreach ($result as $k => $v) {
if ($v === null) {
unset($result[$k]);
}
}

return $result;
}











private function transfer(RequestInterface $request, array $options)
{

 if (isset($options['save_to'])) {
$options['sink'] = $options['save_to'];
unset($options['save_to']);
}


 if (isset($options['exceptions'])) {
$options['http_errors'] = $options['exceptions'];
unset($options['exceptions']);
}

$request = $this->applyOptions($request, $options);

$handler = $options['handler'];

try {
return Promise\promise_for($handler($request, $options));
} catch (\Exception $e) {
return Promise\rejection_for($e);
}
}









private function applyOptions(RequestInterface $request, array &$options)
{
$modify = [
'set_headers' => [],
];

if (isset($options['headers'])) {
$modify['set_headers'] = $options['headers'];
unset($options['headers']);
}

if (isset($options['form_params'])) {
if (isset($options['multipart'])) {
throw new \InvalidArgumentException('You cannot use '
. 'form_params and multipart at the same time. Use the '
. 'form_params option if you want to send application/'
. 'x-www-form-urlencoded requests, and the multipart '
. 'option to send multipart/form-data requests.');
}
$options['body'] = http_build_query($options['form_params'], '', '&');
unset($options['form_params']);

 $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
$options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
}

if (isset($options['multipart'])) {
$options['body'] = new Psr7\MultipartStream($options['multipart']);
unset($options['multipart']);
}

if (isset($options['json'])) {
$options['body'] = \GuzzleHttp\json_encode($options['json']);
unset($options['json']);

 $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
$options['_conditional']['Content-Type'] = 'application/json';
}

if (!empty($options['decode_content'])
&& $options['decode_content'] !== true
) {

 $options['_conditional'] = Psr7\_caseless_remove(['Accept-Encoding'], $options['_conditional']);
$modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
}

if (isset($options['body'])) {
if (is_array($options['body'])) {
$this->invalidBody();
}
$modify['body'] = Psr7\stream_for($options['body']);
unset($options['body']);
}

if (!empty($options['auth']) && is_array($options['auth'])) {
$value = $options['auth'];
$type = isset($value[2]) ? strtolower($value[2]) : 'basic';
switch ($type) {
case 'basic':

 $modify['set_headers'] = Psr7\_caseless_remove(['Authorization'], $modify['set_headers']);
$modify['set_headers']['Authorization'] = 'Basic '
. base64_encode("$value[0]:$value[1]");
break;
case 'digest':

 $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_DIGEST;
$options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
break;
case 'ntlm':
$options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_NTLM;
$options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
break;
}
}

if (isset($options['query'])) {
$value = $options['query'];
if (is_array($value)) {
$value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);
}
if (!is_string($value)) {
throw new \InvalidArgumentException('query must be a string or array');
}
$modify['query'] = $value;
unset($options['query']);
}


 if (isset($options['sink'])) {

 if (is_bool($options['sink'])) {
throw new \InvalidArgumentException('sink must not be a boolean');
}
}

$request = Psr7\modify_request($request, $modify);
if ($request->getBody() instanceof Psr7\MultipartStream) {

 
 $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
$options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
. $request->getBody()->getBoundary();
}


 if (isset($options['_conditional'])) {

 $modify = [];
foreach ($options['_conditional'] as $k => $v) {
if (!$request->hasHeader($k)) {
$modify['set_headers'][$k] = $v;
}
}
$request = Psr7\modify_request($request, $modify);

 unset($options['_conditional']);
}

return $request;
}






private function invalidBody()
{
throw new \InvalidArgumentException('Passing in the "body" request '
. 'option as an array to send a POST request has been deprecated. '
. 'Please use the "form_params" request option to send a '
. 'application/x-www-form-urlencoded request, or the "multipart" '
. 'request option to send a multipart/form-data request.');
}
}
<?php
namespace GuzzleHttp;

use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;




























class MessageFormatter
{





const CLF = "{hostname} {req_header_User-Agent} - [{date_common_log}] \"{method} {target} HTTP/{version}\" {code} {res_header_Content-Length}";
const DEBUG = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';


private $template;




public function __construct($template = self::CLF)
{
$this->template = $template ?: self::CLF;
}










public function format(
RequestInterface $request,
ResponseInterface $response = null,
\Exception $error = null
) {
$cache = [];

return preg_replace_callback(
'/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
function (array $matches) use ($request, $response, $error, &$cache) {
if (isset($cache[$matches[1]])) {
return $cache[$matches[1]];
}

$result = '';
switch ($matches[1]) {
case 'request':
$result = Psr7\str($request);
break;
case 'response':
$result = $response ? Psr7\str($response) : '';
break;
case 'req_headers':
$result = trim($request->getMethod()
. ' ' . $request->getRequestTarget())
. ' HTTP/' . $request->getProtocolVersion() . "\r\n"
. $this->headers($request);
break;
case 'res_headers':
$result = $response ?
sprintf(
'HTTP/%s %d %s',
$response->getProtocolVersion(),
$response->getStatusCode(),
$response->getReasonPhrase()
) . "\r\n" . $this->headers($response)
: 'NULL';
break;
case 'req_body':
$result = $request->getBody();
break;
case 'res_body':
$result = $response ? $response->getBody() : 'NULL';
break;
case 'ts':
case 'date_iso_8601':
$result = gmdate('c');
break;
case 'date_common_log':
$result = date('d/M/Y:H:i:s O');
break;
case 'method':
$result = $request->getMethod();
break;
case 'version':
$result = $request->getProtocolVersion();
break;
case 'uri':
case 'url':
$result = $request->getUri();
break;
case 'target':
$result = $request->getRequestTarget();
break;
case 'req_version':
$result = $request->getProtocolVersion();
break;
case 'res_version':
$result = $response
? $response->getProtocolVersion()
: 'NULL';
break;
case 'host':
$result = $request->getHeaderLine('Host');
break;
case 'hostname':
$result = gethostname();
break;
case 'code':
$result = $response ? $response->getStatusCode() : 'NULL';
break;
case 'phrase':
$result = $response ? $response->getReasonPhrase() : 'NULL';
break;
case 'error':
$result = $error ? $error->getMessage() : 'NULL';
break;
default:

 if (strpos($matches[1], 'req_header_') === 0) {
$result = $request->getHeaderLine(substr($matches[1], 11));
} elseif (strpos($matches[1], 'res_header_') === 0) {
$result = $response
? $response->getHeaderLine(substr($matches[1], 11))
: 'NULL';
}
}

$cache[$matches[1]] = $result;
return $result;
},
$this->template
);
}






private function headers(MessageInterface $message)
{
$result = '';
foreach ($message->getHeaders() as $name => $values) {
$result .= $name . ': ' . implode(', ', $values) . "\r\n";
}

return trim($result);
}
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;




interface ClientInterface
{



const VERSION = '6.5.5';











public function send(RequestInterface $request, array $options = []);










public function sendAsync(RequestInterface $request, array $options = []);















public function request($method, $uri, array $options = []);















public function requestAsync($method, $uri, array $options = []);












public function getConfig($option = null);
}
<?php
namespace GuzzleHttp;






class UriTemplate
{

private $template;


private $variables;


private static $operatorHash = [
'' => ['prefix' => '', 'joiner' => ',', 'query' => false],
'+' => ['prefix' => '', 'joiner' => ',', 'query' => false],
'#' => ['prefix' => '#', 'joiner' => ',', 'query' => false],
'.' => ['prefix' => '.', 'joiner' => '.', 'query' => false],
'/' => ['prefix' => '/', 'joiner' => '/', 'query' => false],
';' => ['prefix' => ';', 'joiner' => ';', 'query' => true],
'?' => ['prefix' => '?', 'joiner' => '&', 'query' => true],
'&' => ['prefix' => '&', 'joiner' => '&', 'query' => true]
];


private static $delims = [':', '/', '?', '#', '[', ']', '@', '!', '$',
'&', '\'', '(', ')', '*', '+', ',', ';', '='];


private static $delimsPct = ['%3A', '%2F', '%3F', '%23', '%5B', '%5D',
'%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C',
'%3B', '%3D'];

public function expand($template, array $variables)
{
if (false === strpos($template, '{')) {
return $template;
}

$this->template = $template;
$this->variables = $variables;

return preg_replace_callback(
'/\{([^\}]+)\}/',
[$this, 'expandMatch'],
$this->template
);
}








private function parseExpression($expression)
{
$result = [];

if (isset(self::$operatorHash[$expression[0]])) {
$result['operator'] = $expression[0];
$expression = substr($expression, 1);
} else {
$result['operator'] = '';
}

foreach (explode(',', $expression) as $value) {
$value = trim($value);
$varspec = [];
if ($colonPos = strpos($value, ':')) {
$varspec['value'] = substr($value, 0, $colonPos);
$varspec['modifier'] = ':';
$varspec['position'] = (int) substr($value, $colonPos + 1);
} elseif (substr($value, -1) === '*') {
$varspec['modifier'] = '*';
$varspec['value'] = substr($value, 0, -1);
} else {
$varspec['value'] = (string) $value;
$varspec['modifier'] = '';
}
$result['values'][] = $varspec;
}

return $result;
}








private function expandMatch(array $matches)
{
static $rfc1738to3986 = ['+' => '%20', '%7e' => '~'];

$replacements = [];
$parsed = self::parseExpression($matches[1]);
$prefix = self::$operatorHash[$parsed['operator']]['prefix'];
$joiner = self::$operatorHash[$parsed['operator']]['joiner'];
$useQuery = self::$operatorHash[$parsed['operator']]['query'];

foreach ($parsed['values'] as $value) {
if (!isset($this->variables[$value['value']])) {
continue;
}

$variable = $this->variables[$value['value']];
$actuallyUseQuery = $useQuery;
$expanded = '';

if (is_array($variable)) {
$isAssoc = $this->isAssoc($variable);
$kvp = [];
foreach ($variable as $key => $var) {
if ($isAssoc) {
$key = rawurlencode($key);
$isNestedArray = is_array($var);
} else {
$isNestedArray = false;
}

if (!$isNestedArray) {
$var = rawurlencode($var);
if ($parsed['operator'] === '+' ||
$parsed['operator'] === '#'
) {
$var = $this->decodeReserved($var);
}
}

if ($value['modifier'] === '*') {
if ($isAssoc) {
if ($isNestedArray) {

 
 $var = strtr(
http_build_query([$key => $var]),
$rfc1738to3986
);
} else {
$var = $key . '=' . $var;
}
} elseif ($key > 0 && $actuallyUseQuery) {
$var = $value['value'] . '=' . $var;
}
}

$kvp[$key] = $var;
}

if (empty($variable)) {
$actuallyUseQuery = false;
} elseif ($value['modifier'] === '*') {
$expanded = implode($joiner, $kvp);
if ($isAssoc) {

 
 $actuallyUseQuery = false;
}
} else {
if ($isAssoc) {

 
 
 
 foreach ($kvp as $k => &$v) {
$v = $k . ',' . $v;
}
}
$expanded = implode(',', $kvp);
}
} else {
if ($value['modifier'] === ':') {
$variable = substr($variable, 0, $value['position']);
}
$expanded = rawurlencode($variable);
if ($parsed['operator'] === '+' || $parsed['operator'] === '#') {
$expanded = $this->decodeReserved($expanded);
}
}

if ($actuallyUseQuery) {
if (!$expanded && $joiner !== '&') {
$expanded = $value['value'];
} else {
$expanded = $value['value'] . '=' . $expanded;
}
}

$replacements[] = $expanded;
}

$ret = implode($joiner, $replacements);
if ($ret && $prefix) {
return $prefix . $ret;
}

return $ret;
}













private function isAssoc(array $array)
{
return $array && array_keys($array)[0] !== 0;
}









private function decodeReserved($string)
{
return str_replace(self::$delimsPct, self::$delims, $string);
}
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Exception\InvalidArgumentException;
use Psr\Http\Message\UriInterface;
use Symfony\Polyfill\Intl\Idn\Idn;

final class Utils
{








public static function currentTime()
{
return function_exists('hrtime') ? hrtime(true) / 1e9 : microtime(true);
}









public static function idnUriConvert(UriInterface $uri, $options = 0)
{
if ($uri->getHost()) {
$asciiHost = self::idnToAsci($uri->getHost(), $options, $info);
if ($asciiHost === false) {
$errorBitSet = isset($info['errors']) ? $info['errors'] : 0;

$errorConstants = array_filter(array_keys(get_defined_constants()), function ($name) {
return substr($name, 0, 11) === 'IDNA_ERROR_';
});

$errors = [];
foreach ($errorConstants as $errorConstant) {
if ($errorBitSet & constant($errorConstant)) {
$errors[] = $errorConstant;
}
}

$errorMessage = 'IDN conversion failed';
if ($errors) {
$errorMessage .= ' (errors: ' . implode(', ', $errors) . ')';
}

throw new InvalidArgumentException($errorMessage);
} else {
if ($uri->getHost() !== $asciiHost) {

 $uri = $uri->withHost($asciiHost);
}
}
}

return $uri;
}








private static function idnToAsci($domain, $options, &$info = [])
{
if (\preg_match('%^[ -~]+$%', $domain) === 1) {
return $domain;
}

if (\extension_loaded('intl') && defined('INTL_IDNA_VARIANT_UTS46')) {
return \idn_to_ascii($domain, $options, INTL_IDNA_VARIANT_UTS46, $info);
}




if (method_exists(Idn::class, 'idn_to_ascii')) {
return Idn::idn_to_ascii($domain, $options, Idn::INTL_IDNA_VARIANT_UTS46, $info);
}

throw new \RuntimeException('ext-intl or symfony/polyfill-intl-idn not loaded or too old');
}
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;





class HandlerStack
{

private $handler;


private $stack = [];


private $cached;


















public static function create(callable $handler = null)
{
$stack = new self($handler ?: choose_handler());
$stack->push(Middleware::httpErrors(), 'http_errors');
$stack->push(Middleware::redirect(), 'allow_redirects');
$stack->push(Middleware::cookies(), 'cookies');
$stack->push(Middleware::prepareBody(), 'prepare_body');

return $stack;
}




public function __construct(callable $handler = null)
{
$this->handler = $handler;
}









public function __invoke(RequestInterface $request, array $options)
{
$handler = $this->resolve();

return $handler($request, $options);
}






public function __toString()
{
$depth = 0;
$stack = [];
if ($this->handler) {
$stack[] = "0) Handler: " . $this->debugCallable($this->handler);
}

$result = '';
foreach (array_reverse($this->stack) as $tuple) {
$depth++;
$str = "{$depth}) Name: '{$tuple[1]}', ";
$str .= "Function: " . $this->debugCallable($tuple[0]);
$result = "> {$str}\n{$result}";
$stack[] = $str;
}

foreach (array_keys($stack) as $k) {
$result .= "< {$stack[$k]}\n";
}

return $result;
}







public function setHandler(callable $handler)
{
$this->handler = $handler;
$this->cached = null;
}






public function hasHandler()
{
return (bool) $this->handler;
}







public function unshift(callable $middleware, $name = null)
{
array_unshift($this->stack, [$middleware, $name]);
$this->cached = null;
}







public function push(callable $middleware, $name = '')
{
$this->stack[] = [$middleware, $name];
$this->cached = null;
}








public function before($findName, callable $middleware, $withName = '')
{
$this->splice($findName, $withName, $middleware, true);
}








public function after($findName, callable $middleware, $withName = '')
{
$this->splice($findName, $withName, $middleware, false);
}






public function remove($remove)
{
$this->cached = null;
$idx = is_callable($remove) ? 0 : 1;
$this->stack = array_values(array_filter(
$this->stack,
function ($tuple) use ($idx, $remove) {
return $tuple[$idx] !== $remove;
}
));
}






public function resolve()
{
if (!$this->cached) {
if (!($prev = $this->handler)) {
throw new \LogicException('No handler has been specified');
}

foreach (array_reverse($this->stack) as $fn) {
$prev = $fn[0]($prev);
}

$this->cached = $prev;
}

return $this->cached;
}





private function findByName($name)
{
foreach ($this->stack as $k => $v) {
if ($v[1] === $name) {
return $k;
}
}

throw new \InvalidArgumentException("Middleware not found: $name");
}









private function splice($findName, $withName, callable $middleware, $before)
{
$this->cached = null;
$idx = $this->findByName($findName);
$tuple = [$middleware, $withName];

if ($before) {
if ($idx === 0) {
array_unshift($this->stack, $tuple);
} else {
$replacement = [$tuple, $this->stack[$idx]];
array_splice($this->stack, $idx, 1, $replacement);
}
} elseif ($idx === count($this->stack) - 1) {
$this->stack[] = $tuple;
} else {
$replacement = [$this->stack[$idx], $tuple];
array_splice($this->stack, $idx, 1, $replacement);
}
}








private function debugCallable($fn)
{
if (is_string($fn)) {
return "callable({$fn})";
}

if (is_array($fn)) {
return is_string($fn[0])
? "callable({$fn[0]}::{$fn[1]})"
: "callable(['" . get_class($fn[0]) . "', '{$fn[1]}'])";
}

return 'callable(' . spl_object_hash($fn) . ')';
}
}
<?php
namespace GuzzleHttp\Cookie;




class SetCookie
{

private static $defaults = [
'Name' => null,
'Value' => null,
'Domain' => null,
'Path' => '/',
'Max-Age' => null,
'Expires' => null,
'Secure' => false,
'Discard' => false,
'HttpOnly' => false
];


private $data;








public static function fromString($cookie)
{

 $data = self::$defaults;

 $pieces = array_filter(array_map('trim', explode(';', $cookie)));

 if (empty($pieces[0]) || !strpos($pieces[0], '=')) {
return new self($data);
}


 foreach ($pieces as $part) {
$cookieParts = explode('=', $part, 2);
$key = trim($cookieParts[0]);
$value = isset($cookieParts[1])
? trim($cookieParts[1], " \n\r\t\0\x0B")
: true;


 if (empty($data['Name'])) {
$data['Name'] = $key;
$data['Value'] = $value;
} else {
foreach (array_keys(self::$defaults) as $search) {
if (!strcasecmp($search, $key)) {
$data[$search] = $value;
continue 2;
}
}
$data[$key] = $value;
}
}

return new self($data);
}




public function __construct(array $data = [])
{
$this->data = array_replace(self::$defaults, $data);

 if (!$this->getExpires() && $this->getMaxAge()) {

 $this->setExpires(time() + $this->getMaxAge());
} elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
$this->setExpires($this->getExpires());
}
}

public function __toString()
{
$str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';
foreach ($this->data as $k => $v) {
if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) {
if ($k === 'Expires') {
$str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
} else {
$str .= ($v === true ? $k : "{$k}={$v}") . '; ';
}
}
}

return rtrim($str, '; ');
}

public function toArray()
{
return $this->data;
}






public function getName()
{
return $this->data['Name'];
}






public function setName($name)
{
$this->data['Name'] = $name;
}






public function getValue()
{
return $this->data['Value'];
}






public function setValue($value)
{
$this->data['Value'] = $value;
}






public function getDomain()
{
return $this->data['Domain'];
}






public function setDomain($domain)
{
$this->data['Domain'] = $domain;
}






public function getPath()
{
return $this->data['Path'];
}






public function setPath($path)
{
$this->data['Path'] = $path;
}






public function getMaxAge()
{
return $this->data['Max-Age'];
}






public function setMaxAge($maxAge)
{
$this->data['Max-Age'] = $maxAge;
}






public function getExpires()
{
return $this->data['Expires'];
}






public function setExpires($timestamp)
{
$this->data['Expires'] = is_numeric($timestamp)
? (int) $timestamp
: strtotime($timestamp);
}






public function getSecure()
{
return $this->data['Secure'];
}






public function setSecure($secure)
{
$this->data['Secure'] = $secure;
}






public function getDiscard()
{
return $this->data['Discard'];
}






public function setDiscard($discard)
{
$this->data['Discard'] = $discard;
}






public function getHttpOnly()
{
return $this->data['HttpOnly'];
}






public function setHttpOnly($httpOnly)
{
$this->data['HttpOnly'] = $httpOnly;
}


















public function matchesPath($requestPath)
{
$cookiePath = $this->getPath();


 if ($cookiePath === '/' || $cookiePath == $requestPath) {
return true;
}


 if (0 !== strpos($requestPath, $cookiePath)) {
return false;
}


 if (substr($cookiePath, -1, 1) === '/') {
return true;
}


 return substr($requestPath, strlen($cookiePath), 1) === '/';
}








public function matchesDomain($domain)
{

 
 $cookieDomain = ltrim($this->getDomain(), '.');


 if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) {
return true;
}


 
 if (filter_var($domain, FILTER_VALIDATE_IP)) {
return false;
}

return (bool) preg_match('/\.' . preg_quote($cookieDomain, '/') . '$/', $domain);
}






public function isExpired()
{
return $this->getExpires() !== null && time() > $this->getExpires();
}






public function validate()
{

 $name = $this->getName();
if (empty($name) && !is_numeric($name)) {
return 'The cookie name must not be empty';
}


 if (preg_match(
'/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5c\x7b\x7d\x7f]/',
$name
)) {
return 'Cookie name must not contain invalid characters: ASCII '
. 'Control characters (0-31;127), space, tab and the '
. 'following characters: ()<>@,;:\"/?={}';
}


 $value = $this->getValue();
if (empty($value) && !is_numeric($value)) {
return 'The cookie value must not be empty';
}


 
 
 $domain = $this->getDomain();
if (empty($domain) && !is_numeric($domain)) {
return 'The cookie domain must not be empty';
}

return true;
}
}
<?php
namespace GuzzleHttp\Cookie;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;




class CookieJar implements CookieJarInterface
{

private $cookies = [];


private $strictMode;








public function __construct($strictMode = false, $cookieArray = [])
{
$this->strictMode = $strictMode;

foreach ($cookieArray as $cookie) {
if (!($cookie instanceof SetCookie)) {
$cookie = new SetCookie($cookie);
}
$this->setCookie($cookie);
}
}









public static function fromArray(array $cookies, $domain)
{
$cookieJar = new self();
foreach ($cookies as $name => $value) {
$cookieJar->setCookie(new SetCookie([
'Domain' => $domain,
'Name' => $name,
'Value' => $value,
'Discard' => true
]));
}

return $cookieJar;
}




public static function getCookieValue($value)
{
return $value;
}









public static function shouldPersist(
SetCookie $cookie,
$allowSessionCookies = false
) {
if ($cookie->getExpires() || $allowSessionCookies) {
if (!$cookie->getDiscard()) {
return true;
}
}

return false;
}







public function getCookieByName($name)
{

 if ($name === null || !is_scalar($name)) {
return null;
}
foreach ($this->cookies as $cookie) {
if ($cookie->getName() !== null && strcasecmp($cookie->getName(), $name) === 0) {
return $cookie;
}
}

return null;
}

public function toArray()
{
return array_map(function (SetCookie $cookie) {
return $cookie->toArray();
}, $this->getIterator()->getArrayCopy());
}

public function clear($domain = null, $path = null, $name = null)
{
if (!$domain) {
$this->cookies = [];
return;
} elseif (!$path) {
$this->cookies = array_filter(
$this->cookies,
function (SetCookie $cookie) use ($domain) {
return !$cookie->matchesDomain($domain);
}
);
} elseif (!$name) {
$this->cookies = array_filter(
$this->cookies,
function (SetCookie $cookie) use ($path, $domain) {
return !($cookie->matchesPath($path) &&
$cookie->matchesDomain($domain));
}
);
} else {
$this->cookies = array_filter(
$this->cookies,
function (SetCookie $cookie) use ($path, $domain, $name) {
return !($cookie->getName() == $name &&
$cookie->matchesPath($path) &&
$cookie->matchesDomain($domain));
}
);
}
}

public function clearSessionCookies()
{
$this->cookies = array_filter(
$this->cookies,
function (SetCookie $cookie) {
return !$cookie->getDiscard() && $cookie->getExpires();
}
);
}

public function setCookie(SetCookie $cookie)
{

 
 $name = $cookie->getName();
if (!$name && $name !== '0') {
return false;
}


 $result = $cookie->validate();
if ($result !== true) {
if ($this->strictMode) {
throw new \RuntimeException('Invalid cookie: ' . $result);
} else {
$this->removeCookieIfEmpty($cookie);
return false;
}
}


 foreach ($this->cookies as $i => $c) {


 
 if ($c->getPath() != $cookie->getPath() ||
$c->getDomain() != $cookie->getDomain() ||
$c->getName() != $cookie->getName()
) {
continue;
}


 
 if (!$cookie->getDiscard() && $c->getDiscard()) {
unset($this->cookies[$i]);
continue;
}


 
 if ($cookie->getExpires() > $c->getExpires()) {
unset($this->cookies[$i]);
continue;
}


 if ($cookie->getValue() !== $c->getValue()) {
unset($this->cookies[$i]);
continue;
}


 return false;
}

$this->cookies[] = $cookie;

return true;
}

public function count()
{
return count($this->cookies);
}

public function getIterator()
{
return new \ArrayIterator(array_values($this->cookies));
}

public function extractCookies(
RequestInterface $request,
ResponseInterface $response
) {
if ($cookieHeader = $response->getHeader('Set-Cookie')) {
foreach ($cookieHeader as $cookie) {
$sc = SetCookie::fromString($cookie);
if (!$sc->getDomain()) {
$sc->setDomain($request->getUri()->getHost());
}
if (0 !== strpos($sc->getPath(), '/')) {
$sc->setPath($this->getCookiePathFromRequest($request));
}
$this->setCookie($sc);
}
}
}









private function getCookiePathFromRequest(RequestInterface $request)
{
$uriPath = $request->getUri()->getPath();
if ('' === $uriPath) {
return '/';
}
if (0 !== strpos($uriPath, '/')) {
return '/';
}
if ('/' === $uriPath) {
return '/';
}
if (0 === $lastSlashPos = strrpos($uriPath, '/')) {
return '/';
}

return substr($uriPath, 0, $lastSlashPos);
}

public function withCookieHeader(RequestInterface $request)
{
$values = [];
$uri = $request->getUri();
$scheme = $uri->getScheme();
$host = $uri->getHost();
$path = $uri->getPath() ?: '/';

foreach ($this->cookies as $cookie) {
if ($cookie->matchesPath($path) &&
$cookie->matchesDomain($host) &&
!$cookie->isExpired() &&
(!$cookie->getSecure() || $scheme === 'https')
) {
$values[] = $cookie->getName() . '='
. $cookie->getValue();
}
}

return $values
? $request->withHeader('Cookie', implode('; ', $values))
: $request;
}







private function removeCookieIfEmpty(SetCookie $cookie)
{
$cookieValue = $cookie->getValue();
if ($cookieValue === null || $cookieValue === '') {
$this->clear(
$cookie->getDomain(),
$cookie->getPath(),
$cookie->getName()
);
}
}
}
<?php
namespace GuzzleHttp\Cookie;




class SessionCookieJar extends CookieJar
{

private $sessionKey;


private $storeSessionCookies;









public function __construct($sessionKey, $storeSessionCookies = false)
{
parent::__construct();
$this->sessionKey = $sessionKey;
$this->storeSessionCookies = $storeSessionCookies;
$this->load();
}




public function __destruct()
{
$this->save();
}




public function save()
{
$json = [];
foreach ($this as $cookie) {

if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
$json[] = $cookie->toArray();
}
}

$_SESSION[$this->sessionKey] = json_encode($json);
}




protected function load()
{
if (!isset($_SESSION[$this->sessionKey])) {
return;
}
$data = json_decode($_SESSION[$this->sessionKey], true);
if (is_array($data)) {
foreach ($data as $cookie) {
$this->setCookie(new SetCookie($cookie));
}
} elseif (strlen($data)) {
throw new \RuntimeException("Invalid cookie data");
}
}
}
<?php
namespace GuzzleHttp\Cookie;




class FileCookieJar extends CookieJar
{

private $filename;


private $storeSessionCookies;










public function __construct($cookieFile, $storeSessionCookies = false)
{
parent::__construct();
$this->filename = $cookieFile;
$this->storeSessionCookies = $storeSessionCookies;

if (file_exists($cookieFile)) {
$this->load($cookieFile);
}
}




public function __destruct()
{
$this->save($this->filename);
}







public function save($filename)
{
$json = [];
foreach ($this as $cookie) {

if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
$json[] = $cookie->toArray();
}
}

$jsonStr = \GuzzleHttp\json_encode($json);
if (false === file_put_contents($filename, $jsonStr, LOCK_EX)) {
throw new \RuntimeException("Unable to save file {$filename}");
}
}









public function load($filename)
{
$json = file_get_contents($filename);
if (false === $json) {
throw new \RuntimeException("Unable to load file {$filename}");
} elseif ($json === '') {
return;
}

$data = \GuzzleHttp\json_decode($json, true);
if (is_array($data)) {
foreach (json_decode($json, true) as $cookie) {
$this->setCookie(new SetCookie($cookie));
}
} elseif (strlen($data)) {
throw new \RuntimeException("Invalid cookie file: {$filename}");
}
}
}
<?php
namespace GuzzleHttp\Cookie;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;











interface CookieJarInterface extends \Countable, \IteratorAggregate
{










public function withCookieHeader(RequestInterface $request);







public function extractCookies(
RequestInterface $request,
ResponseInterface $response
);








public function setCookie(SetCookie $cookie);

















public function clear($domain = null, $path = null, $name = null);








public function clearSessionCookies();






public function toArray();
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Cookie\CookieJarInterface;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise\RejectedPromise;
use GuzzleHttp\Psr7;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;




final class Middleware
{








public static function cookies()
{
return function (callable $handler) {
return function ($request, array $options) use ($handler) {
if (empty($options['cookies'])) {
return $handler($request, $options);
} elseif (!($options['cookies'] instanceof CookieJarInterface)) {
throw new \InvalidArgumentException('cookies must be an instance of GuzzleHttp\Cookie\CookieJarInterface');
}
$cookieJar = $options['cookies'];
$request = $cookieJar->withCookieHeader($request);
return $handler($request, $options)
->then(
function ($response) use ($cookieJar, $request) {
$cookieJar->extractCookies($request, $response);
return $response;
}
);
};
};
}







public static function httpErrors()
{
return function (callable $handler) {
return function ($request, array $options) use ($handler) {
if (empty($options['http_errors'])) {
return $handler($request, $options);
}
return $handler($request, $options)->then(
function (ResponseInterface $response) use ($request) {
$code = $response->getStatusCode();
if ($code < 400) {
return $response;
}
throw RequestException::create($request, $response);
}
);
};
};
}









public static function history(&$container)
{
if (!is_array($container) && !$container instanceof \ArrayAccess) {
throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess');
}

return function (callable $handler) use (&$container) {
return function ($request, array $options) use ($handler, &$container) {
return $handler($request, $options)->then(
function ($value) use ($request, &$container, $options) {
$container[] = [
'request' => $request,
'response' => $value,
'error' => null,
'options' => $options
];
return $value;
},
function ($reason) use ($request, &$container, $options) {
$container[] = [
'request' => $request,
'response' => null,
'error' => $reason,
'options' => $options
];
return \GuzzleHttp\Promise\rejection_for($reason);
}
);
};
};
}














public static function tap(callable $before = null, callable $after = null)
{
return function (callable $handler) use ($before, $after) {
return function ($request, array $options) use ($handler, $before, $after) {
if ($before) {
$before($request, $options);
}
$response = $handler($request, $options);
if ($after) {
$after($request, $options, $response);
}
return $response;
};
};
}






public static function redirect()
{
return function (callable $handler) {
return new RedirectMiddleware($handler);
};
}
















public static function retry(callable $decider, callable $delay = null)
{
return function (callable $handler) use ($decider, $delay) {
return new RetryMiddleware($decider, $handler, $delay);
};
}











public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = 'info' )
{
return function (callable $handler) use ($logger, $formatter, $logLevel) {
return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {
return $handler($request, $options)->then(
function ($response) use ($logger, $request, $formatter, $logLevel) {
$message = $formatter->format($request, $response);
$logger->log($logLevel, $message);
return $response;
},
function ($reason) use ($logger, $request, $formatter) {
$response = $reason instanceof RequestException
? $reason->getResponse()
: null;
$message = $formatter->format($request, $response, $reason);
$logger->notice($message);
return \GuzzleHttp\Promise\rejection_for($reason);
}
);
};
};
}







public static function prepareBody()
{
return function (callable $handler) {
return new PrepareBodyMiddleware($handler);
};
}









public static function mapRequest(callable $fn)
{
return function (callable $handler) use ($fn) {
return function ($request, array $options) use ($handler, $fn) {
return $handler($fn($request), $options);
};
};
}









public static function mapResponse(callable $fn)
{
return function (callable $handler) use ($fn) {
return function ($request, array $options) use ($handler, $fn) {
return $handler($request, $options)->then($fn);
};
};
}
}
<?php
namespace GuzzleHttp;








final class RequestOptions
{





















const ALLOW_REDIRECTS = 'allow_redirects';








const AUTH = 'auth';





const BODY = 'body';








const CERT = 'cert';








const COOKIES = 'cookies';






const CONNECT_TIMEOUT = 'connect_timeout';






const DEBUG = 'debug';






const DECODE_CONTENT = 'decode_content';




const DELAY = 'delay';

















const EXPECT = 'expect';







const FORM_PARAMS = 'form_params';





const HEADERS = 'headers';







const HTTP_ERRORS = 'http_errors';







const IDN_CONVERSION = 'idn_conversion';






const JSON = 'json';










const MULTIPART = 'multipart';






const ON_HEADERS = 'on_headers';










const ON_STATS = 'on_stats';








const PROGRESS = 'progress';






const PROXY = 'proxy';







const QUERY = 'query';






const SINK = 'sink';







const SYNCHRONOUS = 'synchronous';







const SSL_KEY = 'ssl_key';





const STREAM = 'stream';









const VERIFY = 'verify';





const TIMEOUT = 'timeout';





const READ_TIMEOUT = 'read_timeout';




const VERSION = 'version';




const FORCE_IP_RESOLVE = 'force_ip_resolve';
}
<?php


if (!function_exists('GuzzleHttp\uri_template')) {
require __DIR__ . '/functions.php';
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Promise\EachPromise;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Promise\PromisorInterface;
use Psr\Http\Message\RequestInterface;












class Pool implements PromisorInterface
{

private $each;











public function __construct(
ClientInterface $client,
$requests,
array $config = []
) {

 if (isset($config['pool_size'])) {
$config['concurrency'] = $config['pool_size'];
} elseif (!isset($config['concurrency'])) {
$config['concurrency'] = 25;
}

if (isset($config['options'])) {
$opts = $config['options'];
unset($config['options']);
} else {
$opts = [];
}

$iterable = \GuzzleHttp\Promise\iter_for($requests);
$requests = function () use ($iterable, $client, $opts) {
foreach ($iterable as $key => $rfn) {
if ($rfn instanceof RequestInterface) {
yield $key => $client->sendAsync($rfn, $opts);
} elseif (is_callable($rfn)) {
yield $key => $rfn($opts);
} else {
throw new \InvalidArgumentException('Each value yielded by '
. 'the iterator must be a Psr7\Http\Message\RequestInterface '
. 'or a callable that returns a promise that fulfills '
. 'with a Psr7\Message\Http\ResponseInterface object.');
}
}
};

$this->each = new EachPromise($requests(), $config);
}






public function promise()
{
return $this->each->promise();
}


















public static function batch(
ClientInterface $client,
$requests,
array $options = []
) {
$res = [];
self::cmpCallback($options, 'fulfilled', $res);
self::cmpCallback($options, 'rejected', $res);
$pool = new static($client, $requests, $options);
$pool->promise()->wait();
ksort($res);

return $res;
}






private static function cmpCallback(array &$options, $name, array &$results)
{
if (!isset($options[$name])) {
$options[$name] = function ($v, $k) use (&$results) {
$results[$k] = $v;
};
} else {
$currentFn = $options[$name];
$options[$name] = function ($v, $k) use (&$results, $currentFn) {
$currentFn($v, $k);
$results[$k] = $v;
};
}
}
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Promise\RejectedPromise;
use GuzzleHttp\Psr7;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;





class RetryMiddleware
{

private $nextHandler;


private $decider;


private $delay;











public function __construct(
callable $decider,
callable $nextHandler,
callable $delay = null
) {
$this->decider = $decider;
$this->nextHandler = $nextHandler;
$this->delay = $delay ?: __CLASS__ . '::exponentialDelay';
}








public static function exponentialDelay($retries)
{
return (int) pow(2, $retries - 1) * 1000;
}







public function __invoke(RequestInterface $request, array $options)
{
if (!isset($options['retries'])) {
$options['retries'] = 0;
}

$fn = $this->nextHandler;
return $fn($request, $options)
->then(
$this->onFulfilled($request, $options),
$this->onRejected($request, $options)
);
}






private function onFulfilled(RequestInterface $req, array $options)
{
return function ($value) use ($req, $options) {
if (!call_user_func(
$this->decider,
$options['retries'],
$req,
$value,
null
)) {
return $value;
}
return $this->doRetry($req, $options, $value);
};
}






private function onRejected(RequestInterface $req, array $options)
{
return function ($reason) use ($req, $options) {
if (!call_user_func(
$this->decider,
$options['retries'],
$req,
null,
$reason
)) {
return \GuzzleHttp\Promise\rejection_for($reason);
}
return $this->doRetry($req, $options);
};
}




private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null)
{
$options['delay'] = call_user_func($this->delay, ++$options['retries'], $response);

return $this($request, $options);
}
}
<?php
namespace GuzzleHttp;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;





final class TransferStats
{
private $request;
private $response;
private $transferTime;
private $handlerStats;
private $handlerErrorData;








public function __construct(
RequestInterface $request,
ResponseInterface $response = null,
$transferTime = null,
$handlerErrorData = null,
$handlerStats = []
) {
$this->request = $request;
$this->response = $response;
$this->transferTime = $transferTime;
$this->handlerErrorData = $handlerErrorData;
$this->handlerStats = $handlerStats;
}




public function getRequest()
{
return $this->request;
}






public function getResponse()
{
return $this->response;
}






public function hasResponse()
{
return $this->response !== null;
}










public function getHandlerErrorData()
{
return $this->handlerErrorData;
}






public function getEffectiveUri()
{
return $this->request->getUri();
}






public function getTransferTime()
{
return $this->transferTime;
}






public function getHandlerStats()
{
return $this->handlerStats;
}








public function getHandlerStat($stat)
{
return isset($this->handlerStats[$stat])
? $this->handlerStats[$stat]
: null;
}
}
<?php
namespace GuzzleHttp\Handler;

use Psr\Http\Message\RequestInterface;

interface CurlFactoryInterface
{









public function create(RequestInterface $request, array $options);








public function release(EasyHandle $easy);
}
<?php
namespace GuzzleHttp\Handler;

use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;






final class EasyHandle
{

public $handle;


public $sink;


public $headers = [];


public $response;


public $request;


public $options = [];


public $errno = 0;


public $onHeadersException;






public function createResponse()
{
if (empty($this->headers)) {
throw new \RuntimeException('No headers have been received');
}


 $startLine = explode(' ', array_shift($this->headers), 3);
$headers = \GuzzleHttp\headers_from_lines($this->headers);
$normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);

if (!empty($this->options['decode_content'])
&& isset($normalizedKeys['content-encoding'])
) {
$headers['x-encoded-content-encoding']
= $headers[$normalizedKeys['content-encoding']];
unset($headers[$normalizedKeys['content-encoding']]);
if (isset($normalizedKeys['content-length'])) {
$headers['x-encoded-content-length']
= $headers[$normalizedKeys['content-length']];

$bodyLength = (int) $this->sink->getSize();
if ($bodyLength) {
$headers[$normalizedKeys['content-length']] = $bodyLength;
} else {
unset($headers[$normalizedKeys['content-length']]);
}
}
}


 $this->response = new Response(
$startLine[1],
$headers,
$this->sink,
substr($startLine[0], 5),
isset($startLine[2]) ? (string) $startLine[2] : null
);
}

public function __get($name)
{
$msg = $name === 'handle'
? 'The EasyHandle has been released'
: 'Invalid property: ' . $name;
throw new \BadMethodCallException($msg);
}
}
<?php
namespace GuzzleHttp\Handler;

use GuzzleHttp\Psr7;
use Psr\Http\Message\RequestInterface;








class CurlHandler
{

private $factory;








public function __construct(array $options = [])
{
$this->factory = isset($options['handle_factory'])
? $options['handle_factory']
: new CurlFactory(3);
}

public function __invoke(RequestInterface $request, array $options)
{
if (isset($options['delay'])) {
usleep($options['delay'] * 1000);
}

$easy = $this->factory->create($request, $options);
curl_exec($easy->handle);
$easy->errno = curl_errno($easy->handle);

return CurlFactory::finish($this, $easy, $this->factory);
}
}
<?php
namespace GuzzleHttp\Handler;

use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise\FulfilledPromise;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\LazyOpenStream;
use GuzzleHttp\TransferStats;
use Psr\Http\Message\RequestInterface;




class CurlFactory implements CurlFactoryInterface
{
const CURL_VERSION_STR = 'curl_version';
const LOW_CURL_VERSION_NUMBER = '7.21.2';


private $handles = [];


private $maxHandles;




public function __construct($maxHandles)
{
$this->maxHandles = $maxHandles;
}

public function create(RequestInterface $request, array $options)
{
if (isset($options['curl']['body_as_string'])) {
$options['_body_as_string'] = $options['curl']['body_as_string'];
unset($options['curl']['body_as_string']);
}

$easy = new EasyHandle;
$easy->request = $request;
$easy->options = $options;
$conf = $this->getDefaultConf($easy);
$this->applyMethod($easy, $conf);
$this->applyHandlerOptions($easy, $conf);
$this->applyHeaders($easy, $conf);
unset($conf['_headers']);


 if (isset($options['curl'])) {
$conf = array_replace($conf, $options['curl']);
}

$conf[CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy);
$easy->handle = $this->handles
? array_pop($this->handles)
: curl_init();
curl_setopt_array($easy->handle, $conf);

return $easy;
}

public function release(EasyHandle $easy)
{
$resource = $easy->handle;
unset($easy->handle);

if (count($this->handles) >= $this->maxHandles) {
curl_close($resource);
} else {

 
 
 
 curl_setopt($resource, CURLOPT_HEADERFUNCTION, null);
curl_setopt($resource, CURLOPT_READFUNCTION, null);
curl_setopt($resource, CURLOPT_WRITEFUNCTION, null);
curl_setopt($resource, CURLOPT_PROGRESSFUNCTION, null);
curl_reset($resource);
$this->handles[] = $resource;
}
}











public static function finish(
callable $handler,
EasyHandle $easy,
CurlFactoryInterface $factory
) {
if (isset($easy->options['on_stats'])) {
self::invokeStats($easy);
}

if (!$easy->response || $easy->errno) {
return self::finishError($handler, $easy, $factory);
}


 $factory->release($easy);


 $body = $easy->response->getBody();
if ($body->isSeekable()) {
$body->rewind();
}

return new FulfilledPromise($easy->response);
}

private static function invokeStats(EasyHandle $easy)
{
$curlStats = curl_getinfo($easy->handle);
$curlStats['appconnect_time'] = curl_getinfo($easy->handle, CURLINFO_APPCONNECT_TIME);
$stats = new TransferStats(
$easy->request,
$easy->response,
$curlStats['total_time'],
$easy->errno,
$curlStats
);
call_user_func($easy->options['on_stats'], $stats);
}

private static function finishError(
callable $handler,
EasyHandle $easy,
CurlFactoryInterface $factory
) {

 $ctx = [
'errno' => $easy->errno,
'error' => curl_error($easy->handle),
'appconnect_time' => curl_getinfo($easy->handle, CURLINFO_APPCONNECT_TIME),
] + curl_getinfo($easy->handle);
$ctx[self::CURL_VERSION_STR] = curl_version()['version'];
$factory->release($easy);


 if (empty($easy->options['_err_message'])
&& (!$easy->errno || $easy->errno == 65)
) {
return self::retryFailedRewind($handler, $easy, $ctx);
}

return self::createRejection($easy, $ctx);
}

private static function createRejection(EasyHandle $easy, array $ctx)
{
static $connectionErrors = [
CURLE_OPERATION_TIMEOUTED => true,
CURLE_COULDNT_RESOLVE_HOST => true,
CURLE_COULDNT_CONNECT => true,
CURLE_SSL_CONNECT_ERROR => true,
CURLE_GOT_NOTHING => true,
];


 
 if ($easy->onHeadersException) {
return \GuzzleHttp\Promise\rejection_for(
new RequestException(
'An error was encountered during the on_headers event',
$easy->request,
$easy->response,
$easy->onHeadersException,
$ctx
)
);
}
if (version_compare($ctx[self::CURL_VERSION_STR], self::LOW_CURL_VERSION_NUMBER)) {
$message = sprintf(
'cURL error %s: %s (%s)',
$ctx['errno'],
$ctx['error'],
'see https://curl.haxx.se/libcurl/c/libcurl-errors.html'
);
} else {
$message = sprintf(
'cURL error %s: %s (%s) for %s',
$ctx['errno'],
$ctx['error'],
'see https://curl.haxx.se/libcurl/c/libcurl-errors.html',
$easy->request->getUri()
);
}


 $error = isset($connectionErrors[$easy->errno])
? new ConnectException($message, $easy->request, null, $ctx)
: new RequestException($message, $easy->request, $easy->response, null, $ctx);

return \GuzzleHttp\Promise\rejection_for($error);
}

private function getDefaultConf(EasyHandle $easy)
{
$conf = [
'_headers' => $easy->request->getHeaders(),
CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(),
CURLOPT_URL => (string) $easy->request->getUri()->withFragment(''),
CURLOPT_RETURNTRANSFER => false,
CURLOPT_HEADER => false,
CURLOPT_CONNECTTIMEOUT => 150,
];

if (defined('CURLOPT_PROTOCOLS')) {
$conf[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
}

$version = $easy->request->getProtocolVersion();
if ($version == 1.1) {
$conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
} elseif ($version == 2.0) {
$conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0;
} else {
$conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
}

return $conf;
}

private function applyMethod(EasyHandle $easy, array &$conf)
{
$body = $easy->request->getBody();
$size = $body->getSize();

if ($size === null || $size > 0) {
$this->applyBody($easy->request, $easy->options, $conf);
return;
}

$method = $easy->request->getMethod();
if ($method === 'PUT' || $method === 'POST') {

 if (!$easy->request->hasHeader('Content-Length')) {
$conf[CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
}
} elseif ($method === 'HEAD') {
$conf[CURLOPT_NOBODY] = true;
unset(
$conf[CURLOPT_WRITEFUNCTION],
$conf[CURLOPT_READFUNCTION],
$conf[CURLOPT_FILE],
$conf[CURLOPT_INFILE]
);
}
}

private function applyBody(RequestInterface $request, array $options, array &$conf)
{
$size = $request->hasHeader('Content-Length')
? (int) $request->getHeaderLine('Content-Length')
: null;


 
 if (($size !== null && $size < 1000000) ||
!empty($options['_body_as_string'])
) {
$conf[CURLOPT_POSTFIELDS] = (string) $request->getBody();

 $this->removeHeader('Content-Length', $conf);
$this->removeHeader('Transfer-Encoding', $conf);
} else {
$conf[CURLOPT_UPLOAD] = true;
if ($size !== null) {
$conf[CURLOPT_INFILESIZE] = $size;
$this->removeHeader('Content-Length', $conf);
}
$body = $request->getBody();
if ($body->isSeekable()) {
$body->rewind();
}
$conf[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
return $body->read($length);
};
}


 if (!$request->hasHeader('Expect')) {
$conf[CURLOPT_HTTPHEADER][] = 'Expect:';
}


 if (!$request->hasHeader('Content-Type')) {
$conf[CURLOPT_HTTPHEADER][] = 'Content-Type:';
}
}

private function applyHeaders(EasyHandle $easy, array &$conf)
{
foreach ($conf['_headers'] as $name => $values) {
foreach ($values as $value) {
$value = (string) $value;
if ($value === '') {

 
 $conf[CURLOPT_HTTPHEADER][] = "$name;";
} else {
$conf[CURLOPT_HTTPHEADER][] = "$name: $value";
}
}
}


 if (!$easy->request->hasHeader('Accept')) {
$conf[CURLOPT_HTTPHEADER][] = 'Accept:';
}
}







private function removeHeader($name, array &$options)
{
foreach (array_keys($options['_headers']) as $key) {
if (!strcasecmp($key, $name)) {
unset($options['_headers'][$key]);
return;
}
}
}

private function applyHandlerOptions(EasyHandle $easy, array &$conf)
{
$options = $easy->options;
if (isset($options['verify'])) {
if ($options['verify'] === false) {
unset($conf[CURLOPT_CAINFO]);
$conf[CURLOPT_SSL_VERIFYHOST] = 0;
$conf[CURLOPT_SSL_VERIFYPEER] = false;
} else {
$conf[CURLOPT_SSL_VERIFYHOST] = 2;
$conf[CURLOPT_SSL_VERIFYPEER] = true;
if (is_string($options['verify'])) {

 if (!file_exists($options['verify'])) {
throw new \InvalidArgumentException(
"SSL CA bundle not found: {$options['verify']}"
);
}

 
 if (is_dir($options['verify']) ||
(is_link($options['verify']) && is_dir(readlink($options['verify'])))) {
$conf[CURLOPT_CAPATH] = $options['verify'];
} else {
$conf[CURLOPT_CAINFO] = $options['verify'];
}
}
}
}

if (!empty($options['decode_content'])) {
$accept = $easy->request->getHeaderLine('Accept-Encoding');
if ($accept) {
$conf[CURLOPT_ENCODING] = $accept;
} else {
$conf[CURLOPT_ENCODING] = '';

 $conf[CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
}
}

if (isset($options['sink'])) {
$sink = $options['sink'];
if (!is_string($sink)) {
$sink = \GuzzleHttp\Psr7\stream_for($sink);
} elseif (!is_dir(dirname($sink))) {

 throw new \RuntimeException(sprintf(
'Directory %s does not exist for sink value of %s',
dirname($sink),
$sink
));
} else {
$sink = new LazyOpenStream($sink, 'w+');
}
$easy->sink = $sink;
$conf[CURLOPT_WRITEFUNCTION] = function ($ch, $write) use ($sink) {
return $sink->write($write);
};
} else {

 $conf[CURLOPT_FILE] = fopen('php://temp', 'w+');
$easy->sink = Psr7\stream_for($conf[CURLOPT_FILE]);
}
$timeoutRequiresNoSignal = false;
if (isset($options['timeout'])) {
$timeoutRequiresNoSignal |= $options['timeout'] < 1;
$conf[CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000;
}


 if (isset($options['force_ip_resolve'])) {
if ('v4' === $options['force_ip_resolve']) {
$conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
} elseif ('v6' === $options['force_ip_resolve']) {
$conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V6;
}
}

if (isset($options['connect_timeout'])) {
$timeoutRequiresNoSignal |= $options['connect_timeout'] < 1;
$conf[CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;
}

if ($timeoutRequiresNoSignal && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
$conf[CURLOPT_NOSIGNAL] = true;
}

if (isset($options['proxy'])) {
if (!is_array($options['proxy'])) {
$conf[CURLOPT_PROXY] = $options['proxy'];
} else {
$scheme = $easy->request->getUri()->getScheme();
if (isset($options['proxy'][$scheme])) {
$host = $easy->request->getUri()->getHost();
if (!isset($options['proxy']['no']) ||
!\GuzzleHttp\is_host_in_noproxy($host, $options['proxy']['no'])
) {
$conf[CURLOPT_PROXY] = $options['proxy'][$scheme];
}
}
}
}

if (isset($options['cert'])) {
$cert = $options['cert'];
if (is_array($cert)) {
$conf[CURLOPT_SSLCERTPASSWD] = $cert[1];
$cert = $cert[0];
}
if (!file_exists($cert)) {
throw new \InvalidArgumentException(
"SSL certificate not found: {$cert}"
);
}
$conf[CURLOPT_SSLCERT] = $cert;
}

if (isset($options['ssl_key'])) {
if (is_array($options['ssl_key'])) {
if (count($options['ssl_key']) === 2) {
list($sslKey, $conf[CURLOPT_SSLKEYPASSWD]) = $options['ssl_key'];
} else {
list($sslKey) = $options['ssl_key'];
}
}

$sslKey = isset($sslKey) ? $sslKey: $options['ssl_key'];

if (!file_exists($sslKey)) {
throw new \InvalidArgumentException(
"SSL private key not found: {$sslKey}"
);
}
$conf[CURLOPT_SSLKEY] = $sslKey;
}

if (isset($options['progress'])) {
$progress = $options['progress'];
if (!is_callable($progress)) {
throw new \InvalidArgumentException(
'progress client option must be callable'
);
}
$conf[CURLOPT_NOPROGRESS] = false;
$conf[CURLOPT_PROGRESSFUNCTION] = function () use ($progress) {
$args = func_get_args();

 if (is_resource($args[0])) {
array_shift($args);
}
call_user_func_array($progress, $args);
};
}

if (!empty($options['debug'])) {
$conf[CURLOPT_STDERR] = \GuzzleHttp\debug_resource($options['debug']);
$conf[CURLOPT_VERBOSE] = true;
}
}










private static function retryFailedRewind(
callable $handler,
EasyHandle $easy,
array $ctx
) {
try {

 $body = $easy->request->getBody();
if ($body->tell() > 0) {
$body->rewind();
}
} catch (\RuntimeException $e) {
$ctx['error'] = 'The connection unexpectedly failed without '
. 'providing an error. The request would have been retried, '
. 'but attempting to rewind the request body failed. '
. 'Exception: ' . $e;
return self::createRejection($easy, $ctx);
}


 if (!isset($easy->options['_curl_retries'])) {
$easy->options['_curl_retries'] = 1;
} elseif ($easy->options['_curl_retries'] == 2) {
$ctx['error'] = 'The cURL request was retried 3 times '
. 'and did not succeed. The most likely reason for the failure '
. 'is that cURL was unable to rewind the body of the request '
. 'and subsequent retries resulted in the same error. Turn on '
. 'the debug option to see what went wrong. See '
. 'https://bugs.php.net/bug.php?id=47204 for more information.';
return self::createRejection($easy, $ctx);
} else {
$easy->options['_curl_retries']++;
}

return $handler($easy->request, $easy->options);
}

private function createHeaderFn(EasyHandle $easy)
{
if (isset($easy->options['on_headers'])) {
$onHeaders = $easy->options['on_headers'];

if (!is_callable($onHeaders)) {
throw new \InvalidArgumentException('on_headers must be callable');
}
} else {
$onHeaders = null;
}

return function ($ch, $h) use (
$onHeaders,
$easy,
&$startingResponse
) {
$value = trim($h);
if ($value === '') {
$startingResponse = true;
$easy->createResponse();
if ($onHeaders !== null) {
try {
$onHeaders($easy->response);
} catch (\Exception $e) {

 
 $easy->onHeadersException = $e;
return -1;
}
}
} elseif ($startingResponse) {
$startingResponse = false;
$easy->headers = [$value];
} else {
$easy->headers[] = $value;
}
return strlen($h);
};
}
}
<?php
namespace GuzzleHttp\Handler;

use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise\FulfilledPromise;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Psr7;
use GuzzleHttp\TransferStats;
use GuzzleHttp\Utils;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;




class StreamHandler
{
private $lastHeaders = [];









public function __invoke(RequestInterface $request, array $options)
{

 if (isset($options['delay'])) {
usleep($options['delay'] * 1000);
}

$startTime = isset($options['on_stats']) ? Utils::currentTime() : null;

try {

 $request = $request->withoutHeader('Expect');


 
 if (0 === $request->getBody()->getSize()) {
$request = $request->withHeader('Content-Length', '0');
}

return $this->createResponse(
$request,
$options,
$this->createStream($request, $options),
$startTime
);
} catch (\InvalidArgumentException $e) {
throw $e;
} catch (\Exception $e) {

 $message = $e->getMessage();

 if (strpos($message, 'getaddrinfo') 
 || strpos($message, 'Connection refused')
|| strpos($message, "couldn't connect to host") 
 || strpos($message, "connection attempt failed")
) {
$e = new ConnectException($e->getMessage(), $request, $e);
}
$e = RequestException::wrapException($request, $e);
$this->invokeStats($options, $request, $startTime, null, $e);

return \GuzzleHttp\Promise\rejection_for($e);
}
}

private function invokeStats(
array $options,
RequestInterface $request,
$startTime,
ResponseInterface $response = null,
$error = null
) {
if (isset($options['on_stats'])) {
$stats = new TransferStats(
$request,
$response,
Utils::currentTime() - $startTime,
$error,
[]
);
call_user_func($options['on_stats'], $stats);
}
}

private function createResponse(
RequestInterface $request,
array $options,
$stream,
$startTime
) {
$hdrs = $this->lastHeaders;
$this->lastHeaders = [];
$parts = explode(' ', array_shift($hdrs), 3);
$ver = explode('/', $parts[0])[1];
$status = $parts[1];
$reason = isset($parts[2]) ? $parts[2] : null;
$headers = \GuzzleHttp\headers_from_lines($hdrs);
list($stream, $headers) = $this->checkDecode($options, $headers, $stream);
$stream = Psr7\stream_for($stream);
$sink = $stream;

if (strcasecmp('HEAD', $request->getMethod())) {
$sink = $this->createSink($stream, $options);
}

$response = new Psr7\Response($status, $headers, $sink, $ver, $reason);

if (isset($options['on_headers'])) {
try {
$options['on_headers']($response);
} catch (\Exception $e) {
$msg = 'An error was encountered during the on_headers event';
$ex = new RequestException($msg, $request, $response, $e);
return \GuzzleHttp\Promise\rejection_for($ex);
}
}


 
 if ($sink !== $stream) {
$this->drain(
$stream,
$sink,
$response->getHeaderLine('Content-Length')
);
}

$this->invokeStats($options, $request, $startTime, $response, null);

return new FulfilledPromise($response);
}

private function createSink(StreamInterface $stream, array $options)
{
if (!empty($options['stream'])) {
return $stream;
}

$sink = isset($options['sink'])
? $options['sink']
: fopen('php://temp', 'r+');

return is_string($sink)
? new Psr7\LazyOpenStream($sink, 'w+')
: Psr7\stream_for($sink);
}

private function checkDecode(array $options, array $headers, $stream)
{

 if (!empty($options['decode_content'])) {
$normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
if (isset($normalizedKeys['content-encoding'])) {
$encoding = $headers[$normalizedKeys['content-encoding']];
if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') {
$stream = new Psr7\InflateStream(
Psr7\stream_for($stream)
);
$headers['x-encoded-content-encoding']
= $headers[$normalizedKeys['content-encoding']];

 unset($headers[$normalizedKeys['content-encoding']]);

 if (isset($normalizedKeys['content-length'])) {
$headers['x-encoded-content-length']
= $headers[$normalizedKeys['content-length']];

$length = (int) $stream->getSize();
if ($length === 0) {
unset($headers[$normalizedKeys['content-length']]);
} else {
$headers[$normalizedKeys['content-length']] = [$length];
}
}
}
}
}

return [$stream, $headers];
}












private function drain(
StreamInterface $source,
StreamInterface $sink,
$contentLength
) {

 
 
 
 Psr7\copy_to_stream(
$source,
$sink,
(strlen($contentLength) > 0 && (int) $contentLength > 0) ? (int) $contentLength : -1
);

$sink->seek(0);
$source->close();

return $sink;
}









private function createResource(callable $callback)
{
$errors = null;
set_error_handler(function ($_, $msg, $file, $line) use (&$errors) {
$errors[] = [
'message' => $msg,
'file' => $file,
'line' => $line
];
return true;
});

$resource = $callback();
restore_error_handler();

if (!$resource) {
$message = 'Error creating resource: ';
foreach ($errors as $err) {
foreach ($err as $key => $value) {
$message .= "[$key] $value" . PHP_EOL;
}
}
throw new \RuntimeException(trim($message));
}

return $resource;
}

private function createStream(RequestInterface $request, array $options)
{
static $methods;
if (!$methods) {
$methods = array_flip(get_class_methods(__CLASS__));
}


 
 if ($request->getProtocolVersion() == '1.1'
&& !$request->hasHeader('Connection')
) {
$request = $request->withHeader('Connection', 'close');
}


 if (!isset($options['verify'])) {
$options['verify'] = true;
}

$params = [];
$context = $this->getDefaultContext($request);

if (isset($options['on_headers']) && !is_callable($options['on_headers'])) {
throw new \InvalidArgumentException('on_headers must be callable');
}

if (!empty($options)) {
foreach ($options as $key => $value) {
$method = "add_{$key}";
if (isset($methods[$method])) {
$this->{$method}($request, $context, $value, $params);
}
}
}

if (isset($options['stream_context'])) {
if (!is_array($options['stream_context'])) {
throw new \InvalidArgumentException('stream_context must be an array');
}
$context = array_replace_recursive(
$context,
$options['stream_context']
);
}


 if (isset($options['auth'])
&& is_array($options['auth'])
&& isset($options['auth'][2])
&& 'ntlm' == $options['auth'][2]
) {
throw new \InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler');
}

$uri = $this->resolveHost($request, $options);

$context = $this->createResource(
function () use ($context, $params) {
return stream_context_create($context, $params);
}
);

return $this->createResource(
function () use ($uri, &$http_response_header, $context, $options) {
$resource = fopen((string) $uri, 'r', null, $context);
$this->lastHeaders = $http_response_header;

if (isset($options['read_timeout'])) {
$readTimeout = $options['read_timeout'];
$sec = (int) $readTimeout;
$usec = ($readTimeout - $sec) * 100000;
stream_set_timeout($resource, $sec, $usec);
}

return $resource;
}
);
}

private function resolveHost(RequestInterface $request, array $options)
{
$uri = $request->getUri();

if (isset($options['force_ip_resolve']) && !filter_var($uri->getHost(), FILTER_VALIDATE_IP)) {
if ('v4' === $options['force_ip_resolve']) {
$records = dns_get_record($uri->getHost(), DNS_A);
if (!isset($records[0]['ip'])) {
throw new ConnectException(
sprintf(
"Could not resolve IPv4 address for host '%s'",
$uri->getHost()
),
$request
);
}
$uri = $uri->withHost($records[0]['ip']);
} elseif ('v6' === $options['force_ip_resolve']) {
$records = dns_get_record($uri->getHost(), DNS_AAAA);
if (!isset($records[0]['ipv6'])) {
throw new ConnectException(
sprintf(
"Could not resolve IPv6 address for host '%s'",
$uri->getHost()
),
$request
);
}
$uri = $uri->withHost('[' . $records[0]['ipv6'] . ']');
}
}

return $uri;
}

private function getDefaultContext(RequestInterface $request)
{
$headers = '';
foreach ($request->getHeaders() as $name => $value) {
foreach ($value as $val) {
$headers .= "$name: $val\r\n";
}
}

$context = [
'http' => [
'method' => $request->getMethod(),
'header' => $headers,
'protocol_version' => $request->getProtocolVersion(),
'ignore_errors' => true,
'follow_location' => 0,
],
];

$body = (string) $request->getBody();

if (!empty($body)) {
$context['http']['content'] = $body;

 if (!$request->hasHeader('Content-Type')) {
$context['http']['header'] .= "Content-Type:\r\n";
}
}

$context['http']['header'] = rtrim($context['http']['header']);

return $context;
}

private function add_proxy(RequestInterface $request, &$options, $value, &$params)
{
if (!is_array($value)) {
$options['http']['proxy'] = $value;
} else {
$scheme = $request->getUri()->getScheme();
if (isset($value[$scheme])) {
if (!isset($value['no'])
|| !\GuzzleHttp\is_host_in_noproxy(
$request->getUri()->getHost(),
$value['no']
)
) {
$options['http']['proxy'] = $value[$scheme];
}
}
}
}

private function add_timeout(RequestInterface $request, &$options, $value, &$params)
{
if ($value > 0) {
$options['http']['timeout'] = $value;
}
}

private function add_verify(RequestInterface $request, &$options, $value, &$params)
{
if ($value === true) {

 
 if (PHP_VERSION_ID < 50600) {
$options['ssl']['cafile'] = \GuzzleHttp\default_ca_bundle();
}
} elseif (is_string($value)) {
$options['ssl']['cafile'] = $value;
if (!file_exists($value)) {
throw new \RuntimeException("SSL CA bundle not found: $value");
}
} elseif ($value === false) {
$options['ssl']['verify_peer'] = false;
$options['ssl']['verify_peer_name'] = false;
return;
} else {
throw new \InvalidArgumentException('Invalid verify request option');
}

$options['ssl']['verify_peer'] = true;
$options['ssl']['verify_peer_name'] = true;
$options['ssl']['allow_self_signed'] = false;
}

private function add_cert(RequestInterface $request, &$options, $value, &$params)
{
if (is_array($value)) {
$options['ssl']['passphrase'] = $value[1];
$value = $value[0];
}

if (!file_exists($value)) {
throw new \RuntimeException("SSL certificate not found: {$value}");
}

$options['ssl']['local_cert'] = $value;
}

private function add_progress(RequestInterface $request, &$options, $value, &$params)
{
$this->addNotification(
$params,
function ($code, $a, $b, $c, $transferred, $total) use ($value) {
if ($code == STREAM_NOTIFY_PROGRESS) {
$value($total, $transferred, null, null);
}
}
);
}

private function add_debug(RequestInterface $request, &$options, $value, &$params)
{
if ($value === false) {
return;
}

static $map = [
STREAM_NOTIFY_CONNECT => 'CONNECT',
STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
STREAM_NOTIFY_PROGRESS => 'PROGRESS',
STREAM_NOTIFY_FAILURE => 'FAILURE',
STREAM_NOTIFY_COMPLETED => 'COMPLETED',
STREAM_NOTIFY_RESOLVE => 'RESOLVE',
];
static $args = ['severity', 'message', 'message_code',
'bytes_transferred', 'bytes_max'];

$value = \GuzzleHttp\debug_resource($value);
$ident = $request->getMethod() . ' ' . $request->getUri()->withFragment('');
$this->addNotification(
$params,
function () use ($ident, $value, $map, $args) {
$passed = func_get_args();
$code = array_shift($passed);
fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
foreach (array_filter($passed) as $i => $v) {
fwrite($value, $args[$i] . ': "' . $v . '" ');
}
fwrite($value, "\n");
}
);
}

private function addNotification(array &$params, callable $notify)
{

 if (!isset($params['notification'])) {
$params['notification'] = $notify;
} else {
$params['notification'] = $this->callArray([
$params['notification'],
$notify
]);
}
}

private function callArray(array $functions)
{
return function () use ($functions) {
$args = func_get_args();
foreach ($functions as $fn) {
call_user_func_array($fn, $args);
}
};
}
}
<?php
namespace GuzzleHttp\Handler;

use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Promise\RejectedPromise;
use GuzzleHttp\TransferStats;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;




class MockHandler implements \Countable
{
private $queue = [];
private $lastRequest;
private $lastOptions;
private $onFulfilled;
private $onRejected;











public static function createWithMiddleware(
array $queue = null,
callable $onFulfilled = null,
callable $onRejected = null
) {
return HandlerStack::create(new self($queue, $onFulfilled, $onRejected));
}










public function __construct(
array $queue = null,
callable $onFulfilled = null,
callable $onRejected = null
) {
$this->onFulfilled = $onFulfilled;
$this->onRejected = $onRejected;

if ($queue) {
call_user_func_array([$this, 'append'], $queue);
}
}

public function __invoke(RequestInterface $request, array $options)
{
if (!$this->queue) {
throw new \OutOfBoundsException('Mock queue is empty');
}

if (isset($options['delay']) && is_numeric($options['delay'])) {
usleep($options['delay'] * 1000);
}

$this->lastRequest = $request;
$this->lastOptions = $options;
$response = array_shift($this->queue);

if (isset($options['on_headers'])) {
if (!is_callable($options['on_headers'])) {
throw new \InvalidArgumentException('on_headers must be callable');
}
try {
$options['on_headers']($response);
} catch (\Exception $e) {
$msg = 'An error was encountered during the on_headers event';
$response = new RequestException($msg, $request, $response, $e);
}
}

if (is_callable($response)) {
$response = call_user_func($response, $request, $options);
}

$response = $response instanceof \Exception
? \GuzzleHttp\Promise\rejection_for($response)
: \GuzzleHttp\Promise\promise_for($response);

return $response->then(
function ($value) use ($request, $options) {
$this->invokeStats($request, $options, $value);
if ($this->onFulfilled) {
call_user_func($this->onFulfilled, $value);
}
if (isset($options['sink'])) {
$contents = (string) $value->getBody();
$sink = $options['sink'];

if (is_resource($sink)) {
fwrite($sink, $contents);
} elseif (is_string($sink)) {
file_put_contents($sink, $contents);
} elseif ($sink instanceof \Psr\Http\Message\StreamInterface) {
$sink->write($contents);
}
}

return $value;
},
function ($reason) use ($request, $options) {
$this->invokeStats($request, $options, null, $reason);
if ($this->onRejected) {
call_user_func($this->onRejected, $reason);
}
return \GuzzleHttp\Promise\rejection_for($reason);
}
);
}





public function append()
{
foreach (func_get_args() as $value) {
if ($value instanceof ResponseInterface
|| $value instanceof \Exception
|| $value instanceof PromiseInterface
|| is_callable($value)
) {
$this->queue[] = $value;
} else {
throw new \InvalidArgumentException('Expected a response or '
. 'exception. Found ' . \GuzzleHttp\describe_type($value));
}
}
}






public function getLastRequest()
{
return $this->lastRequest;
}






public function getLastOptions()
{
return $this->lastOptions;
}






public function count()
{
return count($this->queue);
}

public function reset()
{
$this->queue = [];
}

private function invokeStats(
RequestInterface $request,
array $options,
ResponseInterface $response = null,
$reason = null
) {
if (isset($options['on_stats'])) {
$transferTime = isset($options['transfer_time']) ? $options['transfer_time'] : 0;
$stats = new TransferStats($request, $response, $transferTime, $reason);
call_user_func($options['on_stats'], $stats);
}
}
}
<?php
namespace GuzzleHttp\Handler;

use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Utils;
use Psr\Http\Message\RequestInterface;










class CurlMultiHandler
{

private $factory;
private $selectTimeout;
private $active;
private $handles = [];
private $delays = [];
private $options = [];












public function __construct(array $options = [])
{
$this->factory = isset($options['handle_factory'])
? $options['handle_factory'] : new CurlFactory(50);

if (isset($options['select_timeout'])) {
$this->selectTimeout = $options['select_timeout'];
} elseif ($selectTimeout = getenv('GUZZLE_CURL_SELECT_TIMEOUT')) {
$this->selectTimeout = $selectTimeout;
} else {
$this->selectTimeout = 1;
}

$this->options = isset($options['options']) ? $options['options'] : [];
}

public function __get($name)
{
if ($name === '_mh') {
$this->_mh = curl_multi_init();

foreach ($this->options as $option => $value) {

 curl_multi_setopt($this->_mh, $option, $value);
}


 
 return $this->_mh;
}

throw new \BadMethodCallException();
}

public function __destruct()
{
if (isset($this->_mh)) {
curl_multi_close($this->_mh);
unset($this->_mh);
}
}

public function __invoke(RequestInterface $request, array $options)
{
$easy = $this->factory->create($request, $options);
$id = (int) $easy->handle;

$promise = new Promise(
[$this, 'execute'],
function () use ($id) {
return $this->cancel($id);
}
);

$this->addRequest(['easy' => $easy, 'deferred' => $promise]);

return $promise;
}




public function tick()
{

 if ($this->delays) {
$currentTime = Utils::currentTime();
foreach ($this->delays as $id => $delay) {
if ($currentTime >= $delay) {
unset($this->delays[$id]);
curl_multi_add_handle(
$this->_mh,
$this->handles[$id]['easy']->handle
);
}
}
}


 P\queue()->run();

if ($this->active &&
curl_multi_select($this->_mh, $this->selectTimeout) === -1
) {

 
 usleep(250);
}

while (curl_multi_exec($this->_mh, $this->active) === CURLM_CALL_MULTI_PERFORM);

$this->processMessages();
}




public function execute()
{
$queue = P\queue();

while ($this->handles || !$queue->isEmpty()) {

 if (!$this->active && $this->delays) {
usleep($this->timeToNext());
}
$this->tick();
}
}

private function addRequest(array $entry)
{
$easy = $entry['easy'];
$id = (int) $easy->handle;
$this->handles[$id] = $entry;
if (empty($easy->options['delay'])) {
curl_multi_add_handle($this->_mh, $easy->handle);
} else {
$this->delays[$id] = Utils::currentTime() + ($easy->options['delay'] / 1000);
}
}








private function cancel($id)
{

 if (!isset($this->handles[$id])) {
return false;
}

$handle = $this->handles[$id]['easy']->handle;
unset($this->delays[$id], $this->handles[$id]);
curl_multi_remove_handle($this->_mh, $handle);
curl_close($handle);

return true;
}

private function processMessages()
{
while ($done = curl_multi_info_read($this->_mh)) {
$id = (int) $done['handle'];
curl_multi_remove_handle($this->_mh, $done['handle']);

if (!isset($this->handles[$id])) {

 continue;
}

$entry = $this->handles[$id];
unset($this->handles[$id], $this->delays[$id]);
$entry['easy']->errno = $done['result'];
$entry['deferred']->resolve(
CurlFactory::finish(
$this,
$entry['easy'],
$this->factory
)
);
}
}

private function timeToNext()
{
$currentTime = Utils::currentTime();
$nextTime = PHP_INT_MAX;
foreach ($this->delays as $time) {
if ($time < $nextTime) {
$nextTime = $time;
}
}

return max(0, $nextTime - $currentTime) * 1000000;
}
}
<?php
namespace GuzzleHttp\Handler;

use GuzzleHttp\RequestOptions;
use Psr\Http\Message\RequestInterface;




class Proxy
{









public static function wrapSync(
callable $default,
callable $sync
) {
return function (RequestInterface $request, array $options) use ($default, $sync) {
return empty($options[RequestOptions::SYNCHRONOUS])
? $default($request, $options)
: $sync($request, $options);
};
}














public static function wrapStreaming(
callable $default,
callable $streaming
) {
return function (RequestInterface $request, array $options) use ($default, $streaming) {
return empty($options['stream'])
? $default($request, $options)
: $streaming($request, $options);
};
}
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Psr7;
use Psr\Http\Message\RequestInterface;





class PrepareBodyMiddleware
{

private $nextHandler;




public function __construct(callable $nextHandler)
{
$this->nextHandler = $nextHandler;
}







public function __invoke(RequestInterface $request, array $options)
{
$fn = $this->nextHandler;


 if ($request->getBody()->getSize() === 0) {
return $fn($request, $options);
}

$modify = [];


 if (!$request->hasHeader('Content-Type')) {
if ($uri = $request->getBody()->getMetadata('uri')) {
if ($type = Psr7\mimetype_from_filename($uri)) {
$modify['set_headers']['Content-Type'] = $type;
}
}
}


 if (!$request->hasHeader('Content-Length')
&& !$request->hasHeader('Transfer-Encoding')
) {
$size = $request->getBody()->getSize();
if ($size !== null) {
$modify['set_headers']['Content-Length'] = $size;
} else {
$modify['set_headers']['Transfer-Encoding'] = 'chunked';
}
}


 $this->addExpectHeader($request, $options, $modify);

return $fn(Psr7\modify_request($request, $modify), $options);
}






private function addExpectHeader(
RequestInterface $request,
array $options,
array &$modify
) {

 if ($request->hasHeader('Expect')) {
return;
}

$expect = isset($options['expect']) ? $options['expect'] : null;


 if ($expect === false || $request->getProtocolVersion() < 1.1) {
return;
}


 if ($expect === true) {
$modify['set_headers']['Expect'] = '100-Continue';
return;
}


 if ($expect === null) {
$expect = 1048576;
}


 
 $body = $request->getBody();
$size = $body->getSize();

if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
$modify['set_headers']['Expect'] = '100-Continue';
}
}
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\Exception\TooManyRedirectsException;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Psr7;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;







class RedirectMiddleware
{
const HISTORY_HEADER = 'X-Guzzle-Redirect-History';

const STATUS_HISTORY_HEADER = 'X-Guzzle-Redirect-Status-History';

public static $defaultSettings = [
'max' => 5,
'protocols' => ['http', 'https'],
'strict' => false,
'referer' => false,
'track_redirects' => false,
];


private $nextHandler;




public function __construct(callable $nextHandler)
{
$this->nextHandler = $nextHandler;
}







public function __invoke(RequestInterface $request, array $options)
{
$fn = $this->nextHandler;

if (empty($options['allow_redirects'])) {
return $fn($request, $options);
}

if ($options['allow_redirects'] === true) {
$options['allow_redirects'] = self::$defaultSettings;
} elseif (!is_array($options['allow_redirects'])) {
throw new \InvalidArgumentException('allow_redirects must be true, false, or array');
} else {

 $options['allow_redirects'] += self::$defaultSettings;
}

if (empty($options['allow_redirects']['max'])) {
return $fn($request, $options);
}

return $fn($request, $options)
->then(function (ResponseInterface $response) use ($request, $options) {
return $this->checkRedirect($request, $options, $response);
});
}








public function checkRedirect(
RequestInterface $request,
array $options,
ResponseInterface $response
) {
if (substr($response->getStatusCode(), 0, 1) != '3'
|| !$response->hasHeader('Location')
) {
return $response;
}

$this->guardMax($request, $options);
$nextRequest = $this->modifyRequest($request, $options, $response);

if (isset($options['allow_redirects']['on_redirect'])) {
call_user_func(
$options['allow_redirects']['on_redirect'],
$request,
$response,
$nextRequest->getUri()
);
}


$promise = $this($nextRequest, $options);


 if (!empty($options['allow_redirects']['track_redirects'])) {
return $this->withTracking(
$promise,
(string) $nextRequest->getUri(),
$response->getStatusCode()
);
}

return $promise;
}






private function withTracking(PromiseInterface $promise, $uri, $statusCode)
{
return $promise->then(
function (ResponseInterface $response) use ($uri, $statusCode) {

 
 
 $historyHeader = $response->getHeader(self::HISTORY_HEADER);
$statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER);
array_unshift($historyHeader, $uri);
array_unshift($statusHeader, $statusCode);
return $response->withHeader(self::HISTORY_HEADER, $historyHeader)
->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader);
}
);
}








private function guardMax(RequestInterface $request, array &$options)
{
$current = isset($options['__redirect_count'])
? $options['__redirect_count']
: 0;
$options['__redirect_count'] = $current + 1;
$max = $options['allow_redirects']['max'];

if ($options['__redirect_count'] > $max) {
throw new TooManyRedirectsException(
"Will not follow more than {$max} redirects",
$request
);
}
}








public function modifyRequest(
RequestInterface $request,
array $options,
ResponseInterface $response
) {

 $modify = [];
$protocols = $options['allow_redirects']['protocols'];


 
 
 $statusCode = $response->getStatusCode();
if ($statusCode == 303 ||
($statusCode <= 302 && !$options['allow_redirects']['strict'])
) {
$modify['method'] = 'GET';
$modify['body'] = '';
}

$uri = $this->redirectUri($request, $response, $protocols);
if (isset($options['idn_conversion']) && ($options['idn_conversion'] !== false)) {
$idnOptions = ($options['idn_conversion'] === true) ? IDNA_DEFAULT : $options['idn_conversion'];
$uri = Utils::idnUriConvert($uri, $idnOptions);
}

$modify['uri'] = $uri;
Psr7\rewind_body($request);


 
 if ($options['allow_redirects']['referer']
&& $modify['uri']->getScheme() === $request->getUri()->getScheme()
) {
$uri = $request->getUri()->withUserInfo('');
$modify['set_headers']['Referer'] = (string) $uri;
} else {
$modify['remove_headers'][] = 'Referer';
}


 if ($request->getUri()->getHost() !== $modify['uri']->getHost()) {
$modify['remove_headers'][] = 'Authorization';
}

return Psr7\modify_request($request, $modify);
}










private function redirectUri(
RequestInterface $request,
ResponseInterface $response,
array $protocols
) {
$location = Psr7\UriResolver::resolve(
$request->getUri(),
new Psr7\Uri($response->getHeaderLine('Location'))
);


 if (!in_array($location->getScheme(), $protocols)) {
throw new BadResponseException(
sprintf(
'Redirect URI, %s, does not use one of the allowed redirect protocols: %s',
$location,
implode(', ', $protocols)
),
$request,
$response
);
}

return $location;
}
}
<?php
namespace GuzzleHttp\Exception;

use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;




class RequestException extends TransferException
{

private $request;


private $response;


private $handlerContext;

public function __construct(
$message,
RequestInterface $request,
ResponseInterface $response = null,
\Exception $previous = null,
array $handlerContext = []
) {

 $code = $response && !($response instanceof PromiseInterface)
? $response->getStatusCode()
: 0;
parent::__construct($message, $code, $previous);
$this->request = $request;
$this->response = $response;
$this->handlerContext = $handlerContext;
}









public static function wrapException(RequestInterface $request, \Exception $e)
{
return $e instanceof RequestException
? $e
: new RequestException($e->getMessage(), $request, null, $e);
}











public static function create(
RequestInterface $request,
ResponseInterface $response = null,
\Exception $previous = null,
array $ctx = []
) {
if (!$response) {
return new self(
'Error completing request',
$request,
null,
$previous,
$ctx
);
}

$level = (int) floor($response->getStatusCode() / 100);
if ($level === 4) {
$label = 'Client error';
$className = ClientException::class;
} elseif ($level === 5) {
$label = 'Server error';
$className = ServerException::class;
} else {
$label = 'Unsuccessful request';
$className = __CLASS__;
}

$uri = $request->getUri();
$uri = static::obfuscateUri($uri);


 
 $message = sprintf(
'%s: `%s %s` resulted in a `%s %s` response',
$label,
$request->getMethod(),
$uri,
$response->getStatusCode(),
$response->getReasonPhrase()
);

$summary = static::getResponseBodySummary($response);

if ($summary !== null) {
$message .= ":\n{$summary}\n";
}

return new $className($message, $request, $response, $previous, $ctx);
}










public static function getResponseBodySummary(ResponseInterface $response)
{
return \GuzzleHttp\Psr7\get_message_body_summary($response);
}








private static function obfuscateUri(UriInterface $uri)
{
$userInfo = $uri->getUserInfo();

if (false !== ($pos = strpos($userInfo, ':'))) {
return $uri->withUserInfo(substr($userInfo, 0, $pos), '***');
}

return $uri;
}






public function getRequest()
{
return $this->request;
}






public function getResponse()
{
return $this->response;
}






public function hasResponse()
{
return $this->response !== null;
}











public function getHandlerContext()
{
return $this->handlerContext;
}
}
<?php
namespace GuzzleHttp\Exception;

class TooManyRedirectsException extends RequestException
{
}
<?php
namespace GuzzleHttp\Exception;




class ServerException extends BadResponseException
{
}
<?php
namespace GuzzleHttp\Exception;

use Psr\Http\Message\RequestInterface;






class ConnectException extends RequestException
{
public function __construct(
$message,
RequestInterface $request,
\Exception $previous = null,
array $handlerContext = []
) {
parent::__construct($message, $request, null, $previous, $handlerContext);
}




public function getResponse()
{
return null;
}




public function hasResponse()
{
return false;
}
}
<?php
namespace GuzzleHttp\Exception;

use Throwable;

if (interface_exists(Throwable::class)) {
interface GuzzleException extends Throwable
{
}
} else {









interface GuzzleException
{
}
}
<?php
namespace GuzzleHttp\Exception;

class TransferException extends \RuntimeException implements GuzzleException
{
}
<?php
namespace GuzzleHttp\Exception;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;




class BadResponseException extends RequestException
{
public function __construct(
$message,
RequestInterface $request,
ResponseInterface $response = null,
\Exception $previous = null,
array $handlerContext = []
) {
if (null === $response) {
@trigger_error(
'Instantiating the ' . __CLASS__ . ' class without a Response is deprecated since version 6.3 and will be removed in 7.0.',
E_USER_DEPRECATED
);
}
parent::__construct($message, $request, $response, $previous, $handlerContext);
}
}
<?php

namespace GuzzleHttp\Exception;

final class InvalidArgumentException extends \InvalidArgumentException implements GuzzleException
{
}
<?php
namespace GuzzleHttp\Exception;

use Psr\Http\Message\StreamInterface;




class SeekException extends \RuntimeException implements GuzzleException
{
private $stream;

public function __construct(StreamInterface $stream, $pos = 0, $msg = '')
{
$this->stream = $stream;
$msg = $msg ?: 'Could not seek the stream to position ' . $pos;
parent::__construct($msg);
}




public function getStream()
{
return $this->stream;
}
}
<?php
namespace GuzzleHttp\Exception;




class ClientException extends BadResponseException
{
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\Handler\CurlMultiHandler;
use GuzzleHttp\Handler\Proxy;
use GuzzleHttp\Handler\StreamHandler;









function uri_template($template, array $variables)
{
if (extension_loaded('uri_template')) {

 return \uri_template($template, $variables);

 }

static $uriTemplate;
if (!$uriTemplate) {
$uriTemplate = new UriTemplate();
}

return $uriTemplate->expand($template, $variables);
}









function describe_type($input)
{
switch (gettype($input)) {
case 'object':
return 'object(' . get_class($input) . ')';
case 'array':
return 'array(' . count($input) . ')';
default:
ob_start();
var_dump($input);

 return str_replace('double(', 'float(', rtrim(ob_get_clean()));
}
}








function headers_from_lines($lines)
{
$headers = [];

foreach ($lines as $line) {
$parts = explode(':', $line, 2);
$headers[trim($parts[0])][] = isset($parts[1])
? trim($parts[1])
: null;
}

return $headers;
}








function debug_resource($value = null)
{
if (is_resource($value)) {
return $value;
} elseif (defined('STDOUT')) {
return STDOUT;
}

return fopen('php://output', 'w');
}









function choose_handler()
{
$handler = null;
if (function_exists('curl_multi_exec') && function_exists('curl_exec')) {
$handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
} elseif (function_exists('curl_exec')) {
$handler = new CurlHandler();
} elseif (function_exists('curl_multi_exec')) {
$handler = new CurlMultiHandler();
}

if (ini_get('allow_url_fopen')) {
$handler = $handler
? Proxy::wrapStreaming($handler, new StreamHandler())
: new StreamHandler();
} elseif (!$handler) {
throw new \RuntimeException('GuzzleHttp requires cURL, the '
. 'allow_url_fopen ini setting, or a custom HTTP handler.');
}

return $handler;
}






function default_user_agent()
{
static $defaultAgent = '';

if (!$defaultAgent) {
$defaultAgent = 'GuzzleHttp/' . Client::VERSION;
if (extension_loaded('curl') && function_exists('curl_version')) {
$defaultAgent .= ' curl/' . \curl_version()['version'];
}
$defaultAgent .= ' PHP/' . PHP_VERSION;
}

return $defaultAgent;
}















function default_ca_bundle()
{
static $cached = null;
static $cafiles = [

 '/etc/pki/tls/certs/ca-bundle.crt',

 '/etc/ssl/certs/ca-certificates.crt',

 '/usr/local/share/certs/ca-root-nss.crt',

 '/var/lib/ca-certificates/ca-bundle.pem',

 '/usr/local/etc/openssl/cert.pem',

 '/etc/ca-certificates.crt',

 'C:\\windows\\system32\\curl-ca-bundle.crt',
'C:\\windows\\curl-ca-bundle.crt',
];

if ($cached) {
return $cached;
}

if ($ca = ini_get('openssl.cafile')) {
return $cached = $ca;
}

if ($ca = ini_get('curl.cainfo')) {
return $cached = $ca;
}

foreach ($cafiles as $filename) {
if (file_exists($filename)) {
return $cached = $filename;
}
}

throw new \RuntimeException(
<<< EOT
No system CA bundle could be found in any of the the common system locations.
PHP versions earlier than 5.6 are not properly configured to use the system's
CA bundle by default. In order to verify peer certificates, you will need to
supply the path on disk to a certificate bundle to the 'verify' request
option: http://docs.guzzlephp.org/en/latest/clients.html#verify. If you do not
need a specific certificate bundle, then Mozilla provides a commonly used CA
bundle which can be downloaded here (provided by the maintainer of cURL):
https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt. Once
you have a CA bundle available on disk, you can set the 'openssl.cafile' PHP
ini setting to point to the path to the file, allowing you to omit the 'verify'
request option. See http://curl.haxx.se/docs/sslcerts.html for more
information.
EOT
);
}









function normalize_header_keys(array $headers)
{
$result = [];
foreach (array_keys($headers) as $key) {
$result[strtolower($key)] = $key;
}

return $result;
}




















function is_host_in_noproxy($host, array $noProxyArray)
{
if (strlen($host) === 0) {
throw new \InvalidArgumentException('Empty host provided');
}


 if (strpos($host, ':')) {
$host = explode($host, ':', 2)[0];
}

foreach ($noProxyArray as $area) {

 if ($area === '*') {
return true;
} elseif (empty($area)) {

 continue;
} elseif ($area === $host) {

 return true;
} else {

 
 $area = '.' . ltrim($area, '.');
if (substr($host, -(strlen($area))) === $area) {
return true;
}
}
}

return false;
}














function json_decode($json, $assoc = false, $depth = 512, $options = 0)
{
$data = \json_decode($json, $assoc, $depth, $options);
if (JSON_ERROR_NONE !== json_last_error()) {
throw new Exception\InvalidArgumentException(
'json_decode error: ' . json_last_error_msg()
);
}

return $data;
}












function json_encode($value, $options = 0, $depth = 512)
{
$json = \json_encode($value, $options, $depth);
if (JSON_ERROR_NONE !== json_last_error()) {
throw new Exception\InvalidArgumentException(
'json_encode error: ' . json_last_error_msg()
);
}

return $json;
}
<?php









namespace SebastianBergmann\FileIterator;

class Iterator extends \FilterIterator
{
const PREFIX = 0;
const SUFFIX = 1;




private $basePath;




private $suffixes = [];




private $prefixes = [];




private $exclude = [];








public function __construct(string $basePath, \Iterator $iterator, array $suffixes = [], array $prefixes = [], array $exclude = [])
{
$this->basePath = \realpath($basePath);
$this->prefixes = $prefixes;
$this->suffixes = $suffixes;
$this->exclude = \array_filter(\array_map('realpath', $exclude));

parent::__construct($iterator);
}





 public function accept()
{
$current = $this->getInnerIterator()->current();
$filename = $current->getFilename();
$realPath = $current->getRealPath();

return $this->acceptPath($realPath) &&
$this->acceptPrefix($filename) &&
$this->acceptSuffix($filename);
}

private function acceptPath(string $path): bool
{

 if (\preg_match('=/\.[^/]*/=', \str_replace($this->basePath, '', $path))) {
return false;
}

foreach ($this->exclude as $exclude) {
if (\strpos($path, $exclude) === 0) {
return false;
}
}

return true;
}

private function acceptPrefix(string $filename): bool
{
return $this->acceptSubString($filename, $this->prefixes, self::PREFIX);
}

private function acceptSuffix(string $filename): bool
{
return $this->acceptSubString($filename, $this->suffixes, self::SUFFIX);
}

private function acceptSubString(string $filename, array $subStrings, int $type): bool
{
if (empty($subStrings)) {
return true;
}

$matched = false;

foreach ($subStrings as $string) {
if (($type === self::PREFIX && \strpos($filename, $string) === 0) ||
($type === self::SUFFIX &&
\substr($filename, -1 * \strlen($string)) === $string)) {
$matched = true;

break;
}
}

return $matched;
}
}
<?php









namespace SebastianBergmann\FileIterator;

class Factory
{








public function getFileIterator($paths, $suffixes = '', $prefixes = '', array $exclude = []): \AppendIterator
{
if (\is_string($paths)) {
$paths = [$paths];
}

$paths = $this->getPathsAfterResolvingWildcards($paths);
$exclude = $this->getPathsAfterResolvingWildcards($exclude);

if (\is_string($prefixes)) {
if ($prefixes !== '') {
$prefixes = [$prefixes];
} else {
$prefixes = [];
}
}

if (\is_string($suffixes)) {
if ($suffixes !== '') {
$suffixes = [$suffixes];
} else {
$suffixes = [];
}
}

$iterator = new \AppendIterator;

foreach ($paths as $path) {
if (\is_dir($path)) {
$iterator->append(
new Iterator(
$path,
new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::FOLLOW_SYMLINKS | \RecursiveDirectoryIterator::SKIP_DOTS)
),
$suffixes,
$prefixes,
$exclude
)
);
}
}

return $iterator;
}

protected function getPathsAfterResolvingWildcards(array $paths): array
{
$_paths = [[]];

foreach ($paths as $path) {
if ($locals = \glob($path, GLOB_ONLYDIR)) {
$_paths[] = \array_map('\realpath', $locals);
} else {
$_paths[] = [\realpath($path)];
}
}

return \array_filter(\array_merge(...$_paths));
}
}
<?php









namespace SebastianBergmann\FileIterator;

class Facade
{









public function getFilesAsArray($paths, $suffixes = '', $prefixes = '', array $exclude = [], bool $commonPath = false): array
{
if (\is_string($paths)) {
$paths = [$paths];
}

$factory = new Factory;

$iterator = $factory->getFileIterator($paths, $suffixes, $prefixes, $exclude);

$files = [];

foreach ($iterator as $file) {
$file = $file->getRealPath();

if ($file) {
$files[] = $file;
}
}

foreach ($paths as $path) {
if (\is_file($path)) {
$files[] = \realpath($path);
}
}

$files = \array_unique($files);
\sort($files);

if ($commonPath) {
return [
'commonPath' => $this->getCommonPath($files),
'files' => $files
];
}

return $files;
}

protected function getCommonPath(array $files): string
{
$count = \count($files);

if ($count === 0) {
return '';
}

if ($count === 1) {
return \dirname($files[0]) . DIRECTORY_SEPARATOR;
}

$_files = [];

foreach ($files as $file) {
$_files[] = $_fileParts = \explode(DIRECTORY_SEPARATOR, $file);

if (empty($_fileParts[0])) {
$_fileParts[0] = DIRECTORY_SEPARATOR;
}
}

$common = '';
$done = false;
$j = 0;
$count--;

while (!$done) {
for ($i = 0; $i < $count; $i++) {
if ($_files[$i][$j] != $_files[$i + 1][$j]) {
$done = true;

break;
}
}

if (!$done) {
$common .= $_files[0][$j];

if ($j > 0) {
$common .= DIRECTORY_SEPARATOR;
}
}

$j++;
}

return DIRECTORY_SEPARATOR . $common;
}
}
<?php














class Text_Template
{



protected $template = '';




protected $openDelimiter = '{';




protected $closeDelimiter = '}';




protected $values = array();







public function __construct($file = '', $openDelimiter = '{', $closeDelimiter = '}')
{
$this->setFile($file);
$this->openDelimiter = $openDelimiter;
$this->closeDelimiter = $closeDelimiter;
}







public function setFile($file)
{
$distFile = $file . '.dist';

if (file_exists($file)) {
$this->template = file_get_contents($file);
}

else if (file_exists($distFile)) {
$this->template = file_get_contents($distFile);
}

else {
throw new InvalidArgumentException(
'Template file could not be loaded.'
);
}
}







public function setVar(array $values, $merge = TRUE)
{
if (!$merge || empty($this->values)) {
$this->values = $values;
} else {
$this->values = array_merge($this->values, $values);
}
}






public function render()
{
$keys = array();

foreach ($this->values as $key => $value) {
$keys[] = $this->openDelimiter . $key . $this->closeDelimiter;
}

return str_replace($keys, $this->values, $this->template);
}






public function renderTo($target)
{
$fp = @fopen($target, 'wt');

if ($fp) {
fwrite($fp, $this->render());
fclose($fp);
} else {
$error = error_get_last();

throw new RuntimeException(
sprintf(
'Could not write to %s: %s',
$target,
substr(
$error['message'],
strpos($error['message'], ':') + 2
)
)
);
}
}
}

<?php declare(strict_types=1);








namespace SebastianBergmann\Timer;

interface Exception
{
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Timer;

final class Timer
{



private static $sizes = [
'GB' => 1073741824,
'MB' => 1048576,
'KB' => 1024,
];




private static $times = [
'hour' => 3600000,
'minute' => 60000,
'second' => 1000,
];




private static $startTimes = [];

public static function start(): void
{
self::$startTimes[] = \microtime(true);
}

public static function stop(): float
{
return \microtime(true) - \array_pop(self::$startTimes);
}

public static function bytesToString(float $bytes): string
{
foreach (self::$sizes as $unit => $value) {
if ($bytes >= $value) {
return \sprintf('%.2f %s', $bytes >= 1024 ? $bytes / $value : $bytes, $unit);
}
}

return $bytes . ' byte' . ((int) $bytes !== 1 ? 's' : '');
}

public static function secondsToTimeString(float $time): string
{
$ms = \round($time * 1000);

foreach (self::$times as $unit => $value) {
if ($ms >= $value) {
$time = \floor($ms / $value * 100.0) / 100.0;

return $time . ' ' . ($time == 1 ? $unit : $unit . 's');
}
}

return $ms . ' ms';
}




public static function timeSinceStartOfRequest(): string
{
if (isset($_SERVER['REQUEST_TIME_FLOAT'])) {
$startOfRequest = $_SERVER['REQUEST_TIME_FLOAT'];
} elseif (isset($_SERVER['REQUEST_TIME'])) {
$startOfRequest = $_SERVER['REQUEST_TIME'];
} else {
throw new RuntimeException('Cannot determine time at which the request started');
}

return self::secondsToTimeString(\microtime(true) - $startOfRequest);
}




public static function resourceUsage(): string
{
return \sprintf(
'Time: %s, Memory: %s',
self::timeSinceStartOfRequest(),
self::bytesToString(\memory_get_peak_usage(true))
);
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Timer;

final class RuntimeException extends \RuntimeException implements Exception
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;




final class NullTestResultCache implements TestResultCache
{
public function setState(string $testName, int $state): void
{
}

public function getState(string $testName): int
{
return BaseTestRunner::STATUS_UNKNOWN;
}

public function setTime(string $testName, float $time): void
{
}

public function getTime(string $testName): float
{
return 0;
}

public function load(): void
{
}

public function persist(): void
{
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

use const DIRECTORY_SEPARATOR;
use const LOCK_EX;
use function assert;
use function dirname;
use function file_get_contents;
use function file_put_contents;
use function in_array;
use function is_array;
use function is_dir;
use function is_file;
use function json_decode;
use function json_encode;
use PHPUnit\Util\Filesystem;




final class DefaultTestResultCache implements TestResultCache
{



private const VERSION = 1;




private const ALLOWED_TEST_STATUSES = [
BaseTestRunner::STATUS_SKIPPED,
BaseTestRunner::STATUS_INCOMPLETE,
BaseTestRunner::STATUS_FAILURE,
BaseTestRunner::STATUS_ERROR,
BaseTestRunner::STATUS_RISKY,
BaseTestRunner::STATUS_WARNING,
];




private const DEFAULT_RESULT_CACHE_FILENAME = '.phpunit.result.cache';




private $cacheFilename;




private $defects = [];




private $times = [];

public function __construct(?string $filepath = null)
{
if ($filepath !== null && is_dir($filepath)) {
$filepath .= DIRECTORY_SEPARATOR . self::DEFAULT_RESULT_CACHE_FILENAME;
}

$this->cacheFilename = $filepath ?? $_ENV['PHPUNIT_RESULT_CACHE'] ?? self::DEFAULT_RESULT_CACHE_FILENAME;
}

public function setState(string $testName, int $state): void
{
if (!in_array($state, self::ALLOWED_TEST_STATUSES, true)) {
return;
}

$this->defects[$testName] = $state;
}

public function getState(string $testName): int
{
return $this->defects[$testName] ?? BaseTestRunner::STATUS_UNKNOWN;
}

public function setTime(string $testName, float $time): void
{
$this->times[$testName] = $time;
}

public function getTime(string $testName): float
{
return $this->times[$testName] ?? 0.0;
}

public function load(): void
{
if (!is_file($this->cacheFilename)) {
return;
}

$data = json_decode(
file_get_contents($this->cacheFilename),
true
);

if ($data === null) {
return;
}

if (!isset($data['version'])) {
return;
}

if ($data['version'] !== self::VERSION) {
return;
}

assert(isset($data['defects']) && is_array($data['defects']));
assert(isset($data['times']) && is_array($data['times']));

$this->defects = $data['defects'];
$this->times = $data['times'];
}




public function persist(): void
{
if (!Filesystem::createDirectory(dirname($this->cacheFilename))) {
throw new Exception(
sprintf(
'Cannot create directory "%s" for result cache file',
$this->cacheFilename
)
);
}

file_put_contents(
$this->cacheFilename,
json_encode(
[
'version' => self::VERSION,
'defects' => $this->defects,
'times' => $this->times,
]
),
LOCK_EX
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

use function array_intersect;
use function array_map;
use function array_merge;
use function array_reduce;
use function array_reverse;
use function array_splice;
use function count;
use function get_class;
use function in_array;
use function max;
use function shuffle;
use function strpos;
use function substr;
use function usort;
use PHPUnit\Framework\DataProviderTestSuite;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Util\Test as TestUtil;




final class TestSuiteSorter
{



public const ORDER_DEFAULT = 0;




public const ORDER_RANDOMIZED = 1;




public const ORDER_REVERSED = 2;




public const ORDER_DEFECTS_FIRST = 3;




public const ORDER_DURATION = 4;






public const ORDER_SIZE = 5;




private const DEFECT_SORT_WEIGHT = [
BaseTestRunner::STATUS_ERROR => 6,
BaseTestRunner::STATUS_FAILURE => 5,
BaseTestRunner::STATUS_WARNING => 4,
BaseTestRunner::STATUS_INCOMPLETE => 3,
BaseTestRunner::STATUS_RISKY => 2,
BaseTestRunner::STATUS_SKIPPED => 1,
BaseTestRunner::STATUS_UNKNOWN => 0,
];

private const SIZE_SORT_WEIGHT = [
TestUtil::SMALL => 1,
TestUtil::MEDIUM => 2,
TestUtil::LARGE => 3,
TestUtil::UNKNOWN => 4,
];




private $defectSortOrder = [];




private $cache;




private $originalExecutionOrder = [];




private $executionOrder = [];




public static function getTestSorterUID(Test $test): string
{
if ($test instanceof PhptTestCase) {
return $test->getName();
}

if ($test instanceof TestCase) {
$testName = $test->getName(true);

if (strpos($testName, '::') === false) {
$testName = get_class($test) . '::' . $testName;
}

return $testName;
}

return $test->getName();
}

public function __construct(?TestResultCache $cache = null)
{
$this->cache = $cache ?? new NullTestResultCache;
}





public function reorderTestsInSuite(Test $suite, int $order, bool $resolveDependencies, int $orderDefects, bool $isRootTestSuite = true): void
{
$allowedOrders = [
self::ORDER_DEFAULT,
self::ORDER_REVERSED,
self::ORDER_RANDOMIZED,
self::ORDER_DURATION,
self::ORDER_SIZE,
];

if (!in_array($order, $allowedOrders, true)) {
throw new Exception(
'$order must be one of TestSuiteSorter::ORDER_[DEFAULT|REVERSED|RANDOMIZED|DURATION|SIZE]'
);
}

$allowedOrderDefects = [
self::ORDER_DEFAULT,
self::ORDER_DEFECTS_FIRST,
];

if (!in_array($orderDefects, $allowedOrderDefects, true)) {
throw new Exception(
'$orderDefects must be one of TestSuiteSorter::ORDER_DEFAULT, TestSuiteSorter::ORDER_DEFECTS_FIRST'
);
}

if ($isRootTestSuite) {
$this->originalExecutionOrder = $this->calculateTestExecutionOrder($suite);
}

if ($suite instanceof TestSuite) {
foreach ($suite as $_suite) {
$this->reorderTestsInSuite($_suite, $order, $resolveDependencies, $orderDefects, false);
}

if ($orderDefects === self::ORDER_DEFECTS_FIRST) {
$this->addSuiteToDefectSortOrder($suite);
}

$this->sort($suite, $order, $resolveDependencies, $orderDefects);
}

if ($isRootTestSuite) {
$this->executionOrder = $this->calculateTestExecutionOrder($suite);
}
}

public function getOriginalExecutionOrder(): array
{
return $this->originalExecutionOrder;
}

public function getExecutionOrder(): array
{
return $this->executionOrder;
}

private function sort(TestSuite $suite, int $order, bool $resolveDependencies, int $orderDefects): void
{
if (empty($suite->tests())) {
return;
}

if ($order === self::ORDER_REVERSED) {
$suite->setTests($this->reverse($suite->tests()));
} elseif ($order === self::ORDER_RANDOMIZED) {
$suite->setTests($this->randomize($suite->tests()));
} elseif ($order === self::ORDER_DURATION && $this->cache !== null) {
$suite->setTests($this->sortByDuration($suite->tests()));
} elseif ($order === self::ORDER_SIZE) {
$suite->setTests($this->sortBySize($suite->tests()));
}

if ($orderDefects === self::ORDER_DEFECTS_FIRST && $this->cache !== null) {
$suite->setTests($this->sortDefectsFirst($suite->tests()));
}

if ($resolveDependencies && !($suite instanceof DataProviderTestSuite) && $this->suiteOnlyContainsTests($suite)) {

$tests = $suite->tests();

$suite->setTests($this->resolveDependencies($tests));
}
}




private function addSuiteToDefectSortOrder(TestSuite $suite): void
{
$max = 0;

foreach ($suite->tests() as $test) {
$testname = self::getTestSorterUID($test);

if (!isset($this->defectSortOrder[$testname])) {
$this->defectSortOrder[$testname] = self::DEFECT_SORT_WEIGHT[$this->cache->getState($testname)];
$max = max($max, $this->defectSortOrder[$testname]);
}
}

$this->defectSortOrder[$suite->getName()] = $max;
}

private function suiteOnlyContainsTests(TestSuite $suite): bool
{
return array_reduce(
$suite->tests(),
static function ($carry, $test)
{
return $carry && ($test instanceof TestCase || $test instanceof DataProviderTestSuite);
},
true
);
}

private function reverse(array $tests): array
{
return array_reverse($tests);
}

private function randomize(array $tests): array
{
shuffle($tests);

return $tests;
}

private function sortDefectsFirst(array $tests): array
{
usort(
$tests,



function ($left, $right)
{
return $this->cmpDefectPriorityAndTime($left, $right);
}
);

return $tests;
}

private function sortByDuration(array $tests): array
{
usort(
$tests,



function ($left, $right)
{
return $this->cmpDuration($left, $right);
}
);

return $tests;
}

private function sortBySize(array $tests): array
{
usort(
$tests,



function ($left, $right)
{
return $this->cmpSize($left, $right);
}
);

return $tests;
}









private function cmpDefectPriorityAndTime(Test $a, Test $b): int
{
$priorityA = $this->defectSortOrder[self::getTestSorterUID($a)] ?? 0;
$priorityB = $this->defectSortOrder[self::getTestSorterUID($b)] ?? 0;

if ($priorityB <=> $priorityA) {

 return $priorityB <=> $priorityA;
}

if ($priorityA || $priorityB) {
return $this->cmpDuration($a, $b);
}


 return 0;
}






private function cmpDuration(Test $a, Test $b): int
{
return $this->cache->getTime(self::getTestSorterUID($a)) <=> $this->cache->getTime(self::getTestSorterUID($b));
}




private function cmpSize(Test $a, Test $b): int
{
$sizeA = ($a instanceof TestCase || $a instanceof DataProviderTestSuite)
? $a->getSize()
: TestUtil::UNKNOWN;
$sizeB = ($b instanceof TestCase || $b instanceof DataProviderTestSuite)
? $b->getSize()
: TestUtil::UNKNOWN;

return self::SIZE_SORT_WEIGHT[$sizeA] <=> self::SIZE_SORT_WEIGHT[$sizeB];
}
















private function resolveDependencies(array $tests): array
{
$newTestOrder = [];
$i = 0;

do {
$todoNames = array_map(



static function ($test)
{
return self::getTestSorterUID($test);
},
$tests
);

if (!$tests[$i]->hasDependencies() || empty(array_intersect($this->getNormalizedDependencyNames($tests[$i]), $todoNames))) {
$newTestOrder = array_merge($newTestOrder, array_splice($tests, $i, 1));
$i = 0;
} else {
$i++;
}
} while (!empty($tests) && ($i < count($tests)));

return array_merge($newTestOrder, $tests);
}






private function getNormalizedDependencyNames($test): array
{
if ($test instanceof DataProviderTestSuite) {
$testClass = substr($test->getName(), 0, strpos($test->getName(), '::'));
} else {
$testClass = get_class($test);
}

$names = array_map(
static function ($name) use ($testClass)
{
return strpos($name, '::') === false ? $testClass . '::' . $name : $name;
},
$test->getDependencies()
);

return $names;
}




private function calculateTestExecutionOrder(Test $suite): array
{
$tests = [];

if ($suite instanceof TestSuite) {
foreach ($suite->tests() as $test) {
if (!($test instanceof TestSuite)) {
$tests[] = self::getTestSorterUID($test);
} else {
$tests = array_merge($tests, $this->calculateTestExecutionOrder($test));
}
}
}

return $tests;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

use RuntimeException;




final class Exception extends RuntimeException implements \PHPUnit\Exception
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

use const DEBUG_BACKTRACE_IGNORE_ARGS;
use const DIRECTORY_SEPARATOR;
use function array_merge;
use function basename;
use function debug_backtrace;
use function defined;
use function dirname;
use function explode;
use function extension_loaded;
use function file;
use function file_exists;
use function file_get_contents;
use function file_put_contents;
use function is_array;
use function is_file;
use function is_readable;
use function is_string;
use function ltrim;
use function phpversion;
use function preg_match;
use function preg_replace;
use function preg_split;
use function realpath;
use function rtrim;
use function sprintf;
use function str_replace;
use function strncasecmp;
use function strpos;
use function substr;
use function trim;
use function unlink;
use function unserialize;
use function var_export;
use function version_compare;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\IncompleteTestError;
use PHPUnit\Framework\PHPTAssertionFailedError;
use PHPUnit\Framework\SelfDescribing;
use PHPUnit\Framework\SkippedTestError;
use PHPUnit\Framework\SyntheticSkippedError;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestResult;
use PHPUnit\Util\PHP\AbstractPhpProcess;
use SebastianBergmann\Timer\Timer;
use Text_Template;
use Throwable;




final class PhptTestCase implements SelfDescribing, Test
{



private $filename;




private $phpUtil;




private $output = '';






public function __construct(string $filename, AbstractPhpProcess $phpUtil = null)
{
if (!is_file($filename)) {
throw new Exception(
sprintf(
'File "%s" does not exist.',
$filename
)
);
}

$this->filename = $filename;
$this->phpUtil = $phpUtil ?: AbstractPhpProcess::factory();
}




public function count(): int
{
return 1;
}












public function run(TestResult $result = null): TestResult
{
if ($result === null) {
$result = new TestResult;
}

try {
$sections = $this->parse();
} catch (Exception $e) {
$result->startTest($this);
$result->addFailure($this, new SkippedTestError($e->getMessage()), 0);
$result->endTest($this, 0);

return $result;
}

$code = $this->render($sections['FILE']);
$xfail = false;
$settings = $this->parseIniSection($this->settings($result->getCollectCodeCoverageInformation()));

$result->startTest($this);

if (isset($sections['INI'])) {
$settings = $this->parseIniSection($sections['INI'], $settings);
}

if (isset($sections['ENV'])) {
$env = $this->parseEnvSection($sections['ENV']);
$this->phpUtil->setEnv($env);
}

$this->phpUtil->setUseStderrRedirection(true);

if ($result->enforcesTimeLimit()) {
$this->phpUtil->setTimeout($result->getTimeoutForLargeTests());
}

$skip = $this->runSkip($sections, $result, $settings);

if ($skip) {
return $result;
}

if (isset($sections['XFAIL'])) {
$xfail = trim($sections['XFAIL']);
}

if (isset($sections['STDIN'])) {
$this->phpUtil->setStdin($sections['STDIN']);
}

if (isset($sections['ARGS'])) {
$this->phpUtil->setArgs($sections['ARGS']);
}

if ($result->getCollectCodeCoverageInformation()) {
$this->renderForCoverage($code);
}

Timer::start();

$jobResult = $this->phpUtil->runJob($code, $this->stringifyIni($settings));
$time = Timer::stop();
$this->output = $jobResult['stdout'] ?? '';

if ($result->getCollectCodeCoverageInformation() && ($coverage = $this->cleanupForCoverage())) {
$result->getCodeCoverage()->append($coverage, $this, true, [], [], true);
}

try {
$this->assertPhptExpectation($sections, $this->output);
} catch (AssertionFailedError $e) {
$failure = $e;

if ($xfail !== false) {
$failure = new IncompleteTestError($xfail, 0, $e);
} elseif ($e instanceof ExpectationFailedException) {
$comparisonFailure = $e->getComparisonFailure();

if ($comparisonFailure) {
$diff = $comparisonFailure->getDiff();
} else {
$diff = $e->getMessage();
}

$hint = $this->getLocationHintFromDiff($diff, $sections);
$trace = array_merge($hint, debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));
$failure = new PHPTAssertionFailedError(
$e->getMessage(),
0,
$trace[0]['file'],
$trace[0]['line'],
$trace,
$comparisonFailure ? $diff : ''
);
}

$result->addFailure($this, $failure, $time);
} catch (Throwable $t) {
$result->addError($this, $t, $time);
}

if ($xfail !== false && $result->allCompletelyImplemented()) {
$result->addFailure($this, new IncompleteTestError('XFAIL section but test passes'), $time);
}

$this->runClean($sections, $result->getCollectCodeCoverageInformation());

$result->endTest($this, $time);

return $result;
}




public function getName(): string
{
return $this->toString();
}




public function toString(): string
{
return $this->filename;
}

public function usesDataProvider(): bool
{
return false;
}

public function getNumAssertions(): int
{
return 1;
}

public function getActualOutput(): string
{
return $this->output;
}

public function hasOutput(): bool
{
return !empty($this->output);
}






private function parseIniSection($content, $ini = []): array
{
if (is_string($content)) {
$content = explode("\n", trim($content));
}

foreach ($content as $setting) {
if (strpos($setting, '=') === false) {
continue;
}

$setting = explode('=', $setting, 2);
$name = trim($setting[0]);
$value = trim($setting[1]);

if ($name === 'extension' || $name === 'zend_extension') {
if (!isset($ini[$name])) {
$ini[$name] = [];
}

$ini[$name][] = $value;

continue;
}

$ini[$name] = $value;
}

return $ini;
}

private function parseEnvSection(string $content): array
{
$env = [];

foreach (explode("\n", trim($content)) as $e) {
$e = explode('=', trim($e), 2);

if (!empty($e[0]) && isset($e[1])) {
$env[$e[0]] = $e[1];
}
}

return $env;
}






private function assertPhptExpectation(array $sections, string $output): void
{
$assertions = [
'EXPECT' => 'assertEquals',
'EXPECTF' => 'assertStringMatchesFormat',
'EXPECTREGEX' => 'assertRegExp',
];

$actual = preg_replace('/\r\n/', "\n", trim($output));

foreach ($assertions as $sectionName => $sectionAssertion) {
if (isset($sections[$sectionName])) {
$sectionContent = preg_replace('/\r\n/', "\n", trim($sections[$sectionName]));
$expected = $sectionName === 'EXPECTREGEX' ? "/{$sectionContent}/" : $sectionContent;

if ($expected === null) {
throw new Exception('No PHPT expectation found');
}

Assert::$sectionAssertion($expected, $actual);

return;
}
}

throw new Exception('No PHPT assertion found');
}




private function runSkip(array &$sections, TestResult $result, array $settings): bool
{
if (!isset($sections['SKIPIF'])) {
return false;
}

$skipif = $this->render($sections['SKIPIF']);
$jobResult = $this->phpUtil->runJob($skipif, $this->stringifyIni($settings));

if (!strncasecmp('skip', ltrim($jobResult['stdout']), 4)) {
$message = '';

if (preg_match('/^\s*skip\s*(.+)\s*/i', $jobResult['stdout'], $skipMatch)) {
$message = substr($skipMatch[1], 2);
}

$hint = $this->getLocationHint($message, $sections, 'SKIPIF');
$trace = array_merge($hint, debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));
$result->addFailure(
$this,
new SyntheticSkippedError($message, 0, $trace[0]['file'], $trace[0]['line'], $trace),
0
);
$result->endTest($this, 0);

return true;
}

return false;
}

private function runClean(array &$sections, bool $collectCoverage): void
{
$this->phpUtil->setStdin('');
$this->phpUtil->setArgs('');

if (isset($sections['CLEAN'])) {
$cleanCode = $this->render($sections['CLEAN']);

$this->phpUtil->runJob($cleanCode, $this->settings($collectCoverage));
}
}




private function parse(): array
{
$sections = [];
$section = '';

$unsupportedSections = [
'CGI',
'COOKIE',
'DEFLATE_POST',
'EXPECTHEADERS',
'EXTENSIONS',
'GET',
'GZIP_POST',
'HEADERS',
'PHPDBG',
'POST',
'POST_RAW',
'PUT',
'REDIRECTTEST',
'REQUEST',
];

$lineNr = 0;

foreach (file($this->filename) as $line) {
$lineNr++;

if (preg_match('/^--([_A-Z]+)--/', $line, $result)) {
$section = $result[1];
$sections[$section] = '';
$sections[$section . '_offset'] = $lineNr;

continue;
}

if (empty($section)) {
throw new Exception('Invalid PHPT file: empty section header');
}

$sections[$section] .= $line;
}

if (isset($sections['FILEEOF'])) {
$sections['FILE'] = rtrim($sections['FILEEOF'], "\r\n");
unset($sections['FILEEOF']);
}

$this->parseExternal($sections);

if (!$this->validate($sections)) {
throw new Exception('Invalid PHPT file');
}

foreach ($unsupportedSections as $section) {
if (isset($sections[$section])) {
throw new Exception(
"PHPUnit does not support PHPT {$section} sections"
);
}
}

return $sections;
}




private function parseExternal(array &$sections): void
{
$allowSections = [
'FILE',
'EXPECT',
'EXPECTF',
'EXPECTREGEX',
];
$testDirectory = dirname($this->filename) . DIRECTORY_SEPARATOR;

foreach ($allowSections as $section) {
if (isset($sections[$section . '_EXTERNAL'])) {
$externalFilename = trim($sections[$section . '_EXTERNAL']);

if (!is_file($testDirectory . $externalFilename) ||
!is_readable($testDirectory . $externalFilename)) {
throw new Exception(
sprintf(
'Could not load --%s-- %s for PHPT file',
$section . '_EXTERNAL',
$testDirectory . $externalFilename
)
);
}

$sections[$section] = file_get_contents($testDirectory . $externalFilename);
}
}
}

private function validate(array &$sections): bool
{
$requiredSections = [
'FILE',
[
'EXPECT',
'EXPECTF',
'EXPECTREGEX',
],
];

foreach ($requiredSections as $section) {
if (is_array($section)) {
$foundSection = false;

foreach ($section as $anySection) {
if (isset($sections[$anySection])) {
$foundSection = true;

break;
}
}

if (!$foundSection) {
return false;
}

continue;
}

if (!isset($sections[$section])) {
return false;
}
}

return true;
}

private function render(string $code): string
{
return str_replace(
[
'__DIR__',
'__FILE__',
],
[
"'" . dirname($this->filename) . "'",
"'" . $this->filename . "'",
],
$code
);
}

private function getCoverageFiles(): array
{
$baseDir = dirname(realpath($this->filename)) . DIRECTORY_SEPARATOR;
$basename = basename($this->filename, 'phpt');

return [
'coverage' => $baseDir . $basename . 'coverage',
'job' => $baseDir . $basename . 'php',
];
}

private function renderForCoverage(string &$job): void
{
$files = $this->getCoverageFiles();

$template = new Text_Template(
__DIR__ . '/../Util/PHP/Template/PhptTestCase.tpl'
);

$composerAutoload = '\'\'';

if (defined('PHPUNIT_COMPOSER_INSTALL')) {
$composerAutoload = var_export(PHPUNIT_COMPOSER_INSTALL, true);
}

$phar = '\'\'';

if (defined('__PHPUNIT_PHAR__')) {
$phar = var_export(__PHPUNIT_PHAR__, true);
}

$globals = '';

if (!empty($GLOBALS['__PHPUNIT_BOOTSTRAP'])) {
$globals = '$GLOBALS[\'__PHPUNIT_BOOTSTRAP\'] = ' . var_export(
$GLOBALS['__PHPUNIT_BOOTSTRAP'],
true
) . ";\n";
}

$template->setVar(
[
'composerAutoload' => $composerAutoload,
'phar' => $phar,
'globals' => $globals,
'job' => $files['job'],
'coverageFile' => $files['coverage'],
]
);

file_put_contents($files['job'], $job);
$job = $template->render();
}

private function cleanupForCoverage(): array
{
$coverage = [];
$files = $this->getCoverageFiles();

if (file_exists($files['coverage'])) {
$buffer = @file_get_contents($files['coverage']);

if ($buffer !== false) {
$coverage = @unserialize($buffer);

if ($coverage === false) {
$coverage = [];
}
}
}

foreach ($files as $file) {
@unlink($file);
}

return $coverage;
}

private function stringifyIni(array $ini): array
{
$settings = [];

foreach ($ini as $key => $value) {
if (is_array($value)) {
foreach ($value as $val) {
$settings[] = $key . '=' . $val;
}

continue;
}

$settings[] = $key . '=' . $value;
}

return $settings;
}

private function getLocationHintFromDiff(string $message, array $sections): array
{
$needle = '';
$previousLine = '';
$block = 'message';

foreach (preg_split('/\r\n|\r|\n/', $message) as $line) {
$line = trim($line);

if ($block === 'message' && $line === '--- Expected') {
$block = 'expected';
}

if ($block === 'expected' && $line === '@@ @@') {
$block = 'diff';
}

if ($block === 'diff') {
if (strpos($line, '+') === 0) {
$needle = $this->getCleanDiffLine($previousLine);

break;
}

if (strpos($line, '-') === 0) {
$needle = $this->getCleanDiffLine($line);

break;
}
}

if (!empty($line)) {
$previousLine = $line;
}
}

return $this->getLocationHint($needle, $sections);
}

private function getCleanDiffLine(string $line): string
{
if (preg_match('/^[\-+]([\'\"]?)(.*)\1$/', $line, $matches)) {
$line = $matches[2];
}

return $line;
}

private function getLocationHint(string $needle, array $sections, ?string $sectionName = null): array
{
$needle = trim($needle);

if (empty($needle)) {
return [[
'file' => realpath($this->filename),
'line' => 1,
]];
}

if ($sectionName) {
$search = [$sectionName];
} else {
$search = [

 'EXPECT',
'EXPECTF',
'EXPECTREGEX',
];
}

foreach ($search as $section) {
if (!isset($sections[$section])) {
continue;
}

if (isset($sections[$section . '_EXTERNAL'])) {
$externalFile = trim($sections[$section . '_EXTERNAL']);

return [
[
'file' => realpath(dirname($this->filename) . DIRECTORY_SEPARATOR . $externalFile),
'line' => 1,
],
[
'file' => realpath($this->filename),
'line' => ($sections[$section . '_EXTERNAL_offset'] ?? 0) + 1,
],
];
}

$sectionOffset = $sections[$section . '_offset'] ?? 0;
$offset = $sectionOffset + 1;

foreach (preg_split('/\r\n|\r|\n/', $sections[$section]) as $line) {
if (strpos($line, $needle) !== false) {
return [[
'file' => realpath($this->filename),
'line' => $offset,
]];
}
$offset++;
}
}

if ($sectionName) {

 return [[
'file' => realpath($this->filename),
'line' => $sectionOffset,
]];
}


 return [[
'file' => realpath($this->filename),
'line' => 1,
]];
}




private function settings(bool $collectCoverage): array
{
$settings = [
'allow_url_fopen=1',
'auto_append_file=',
'auto_prepend_file=',
'disable_functions=',
'display_errors=1',
'docref_ext=.html',
'docref_root=',
'error_append_string=',
'error_prepend_string=',
'error_reporting=-1',
'html_errors=0',
'log_errors=0',
'open_basedir=',
'output_buffering=Off',
'output_handler=',
'report_memleaks=0',
'report_zend_debug=0',
];

if (extension_loaded('pcov')) {
if ($collectCoverage) {
$settings[] = 'pcov.enabled=1';
} else {
$settings[] = 'pcov.enabled=0';
}
}

if (extension_loaded('xdebug')) {
if (version_compare(phpversion('xdebug'), '3', '>=')) {
if ($collectCoverage) {
$settings[] = 'xdebug.mode=coverage';
} else {
$settings[] = 'xdebug.mode=off';
}
} else {
$settings[] = 'xdebug.default_enable=0';

if ($collectCoverage) {
$settings[] = 'xdebug.coverage_enable=1';
}
}
}

return $settings;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

use ReflectionClass;




interface TestSuiteLoader
{
public function load(string $suiteClassName, string $suiteClassFile = ''): ReflectionClass;

public function reload(ReflectionClass $aClass): ReflectionClass;
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

use function is_dir;
use function is_file;
use PHPUnit\Framework\Exception;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestSuite;
use ReflectionClass;
use ReflectionException;
use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;




abstract class BaseTestRunner
{



public const STATUS_UNKNOWN = -1;




public const STATUS_PASSED = 0;




public const STATUS_SKIPPED = 1;




public const STATUS_INCOMPLETE = 2;




public const STATUS_FAILURE = 3;




public const STATUS_ERROR = 4;




public const STATUS_RISKY = 5;




public const STATUS_WARNING = 6;




public const SUITE_METHODNAME = 'suite';




public function getLoader(): TestSuiteLoader
{
return new StandardTestSuiteLoader;
}










public function getTest(string $suiteClassName, string $suiteClassFile = '', $suffixes = ''): ?Test
{
if (empty($suiteClassFile) && is_dir($suiteClassName) && !is_file($suiteClassName . '.php')) {

$files = (new FileIteratorFacade)->getFilesAsArray(
$suiteClassName,
$suffixes
);

$suite = new TestSuite($suiteClassName);
$suite->addTestFiles($files);

return $suite;
}

try {
$testClass = $this->loadSuiteClass(
$suiteClassName,
$suiteClassFile
);
} catch (Exception $e) {
$this->runFailed($e->getMessage());

return null;
}

try {
$suiteMethod = $testClass->getMethod(self::SUITE_METHODNAME);

if (!$suiteMethod->isStatic()) {
$this->runFailed(
'suite() method must be static.'
);

return null;
}

$test = $suiteMethod->invoke(null, $testClass->getName());
} catch (ReflectionException $e) {
try {
$test = new TestSuite($testClass);
} catch (Exception $e) {
$test = new TestSuite;
$test->setName($suiteClassName);
}
}

$this->clearStatus();

return $test;
}




protected function loadSuiteClass(string $suiteClassName, string $suiteClassFile = ''): ReflectionClass
{
return $this->getLoader()->load($suiteClassName, $suiteClassFile);
}




protected function clearStatus(): void
{
}





abstract protected function runFailed(string $message): void;
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

use function array_slice;
use function dirname;
use function explode;
use function implode;
use function strpos;
use SebastianBergmann\Version as VersionId;

final class Version
{



private static $pharVersion = '';




private static $version = '';




public static function id(): string
{
if (self::$pharVersion !== '') {
return self::$pharVersion;
}

if (self::$version === '') {
self::$version = (new VersionId('8.5.21', dirname(__DIR__, 2)))->getVersion();
}

return self::$version;
}

public static function series(): string
{
if (strpos(self::id(), '-')) {
$version = explode('-', self::id())[0];
} else {
$version = self::id();
}

return implode('.', array_slice(explode('.', $version), 0, 2));
}

public static function getVersionString(): string
{
return 'PHPUnit ' . self::id() . ' by Sebastian Bergmann and contributors.';
}

public static function getReleaseChannel(): string
{
if (strpos(self::$pharVersion, '-') !== false) {
return '-snapshot';
}

return '';
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;




interface TestResultCache
{
public function setState(string $testName, int $state): void;

public function getState(string $testName): int;

public function setTime(string $testName, float $time): void;

public function getTime(string $testName): float;

public function load(): void;

public function persist(): void;
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

use function array_diff;
use function array_values;
use function class_exists;
use function get_declared_classes;
use function realpath;
use function sprintf;
use function str_replace;
use function strlen;
use function substr;
use PHPUnit\Framework\TestCase;
use PHPUnit\Util\FileLoader;
use PHPUnit\Util\Filesystem;
use ReflectionClass;
use ReflectionException;




final class StandardTestSuiteLoader implements TestSuiteLoader
{




public function load(string $suiteClassName, string $suiteClassFile = ''): ReflectionClass
{
$suiteClassName = str_replace('.php', '', $suiteClassName);
$filename = null;

if (empty($suiteClassFile)) {
$suiteClassFile = Filesystem::classNameToFilename(
$suiteClassName
);
}

if (!class_exists($suiteClassName, false)) {
$loadedClasses = get_declared_classes();

$filename = FileLoader::checkAndLoad($suiteClassFile);

$loadedClasses = array_values(
array_diff(get_declared_classes(), $loadedClasses)
);
}

if (!empty($loadedClasses) && !class_exists($suiteClassName, false)) {
$offset = 0 - strlen($suiteClassName);

foreach ($loadedClasses as $loadedClass) {
try {
$class = new ReflectionClass($loadedClass);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if (substr($loadedClass, $offset) === $suiteClassName &&
$class->getFileName() == $filename) {
$suiteClassName = $loadedClass;

break;
}
}
}

if (!empty($loadedClasses) && !class_exists($suiteClassName, false)) {
$testCaseClass = TestCase::class;

foreach ($loadedClasses as $loadedClass) {
try {
$class = new ReflectionClass($loadedClass);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


$classFile = $class->getFileName();

if ($class->isSubclassOf($testCaseClass) && !$class->isAbstract()) {
$suiteClassName = $loadedClass;
$testCaseClass = $loadedClass;

if ($classFile == realpath($suiteClassFile)) {
break;
}
}

if ($class->hasMethod('suite')) {
try {
$method = $class->getMethod('suite');

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if (!$method->isAbstract() && $method->isPublic() && $method->isStatic()) {
$suiteClassName = $loadedClass;

if ($classFile == realpath($suiteClassFile)) {
break;
}
}
}
}
}

if (class_exists($suiteClassName, false)) {
try {
$class = new ReflectionClass($suiteClassName);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if ($class->getFileName() == realpath($suiteClassFile)) {
return $class;
}
}

throw new Exception(
sprintf(
"Class '%s' could not be found in '%s'.",
$suiteClassName,
$suiteClassFile
)
);
}

public function reload(ReflectionClass $aClass): ReflectionClass
{
return $aClass;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner\Filter;

use function in_array;




final class ExcludeGroupFilterIterator extends GroupFilterIterator
{
protected function doAccept(string $hash): bool
{
return !in_array($hash, $this->groupTests, true);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner\Filter;

use function end;
use function implode;
use function preg_match;
use function sprintf;
use function str_replace;
use Exception;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Framework\WarningTestCase;
use PHPUnit\Util\RegularExpression;
use RecursiveFilterIterator;
use RecursiveIterator;




final class NameFilterIterator extends RecursiveFilterIterator
{



private $filter;




private $filterMin;




private $filterMax;




public function __construct(RecursiveIterator $iterator, string $filter)
{
parent::__construct($iterator);

$this->setFilter($filter);
}




public function accept(): bool
{
$test = $this->getInnerIterator()->current();

if ($test instanceof TestSuite) {
return true;
}

$tmp = \PHPUnit\Util\Test::describe($test);

if ($test instanceof WarningTestCase) {
$name = $test->getMessage();
} elseif ($tmp[0] !== '') {
$name = implode('::', $tmp);
} else {
$name = $tmp[1];
}

$accepted = @preg_match($this->filter, $name, $matches);

if ($accepted && isset($this->filterMax)) {
$set = end($matches);
$accepted = $set >= $this->filterMin && $set <= $this->filterMax;
}

return (bool) $accepted;
}




private function setFilter(string $filter): void
{
if (RegularExpression::safeMatch($filter, '') === false) {

 
 
 if (preg_match('/^(.*?)#(\d+)(?:-(\d+))?$/', $filter, $matches)) {
if (isset($matches[3]) && $matches[2] < $matches[3]) {
$filter = sprintf(
'%s.*with data set #(\d+)$',
$matches[1]
);

$this->filterMin = (int) $matches[2];
$this->filterMax = (int) $matches[3];
} else {
$filter = sprintf(
'%s.*with data set #%s$',
$matches[1],
$matches[2]
);
}
} 
 
 
 elseif (preg_match('/^(.*?)@(.+)$/', $filter, $matches)) {
$filter = sprintf(
'%s.*with data set "%s"$',
$matches[1],
$matches[2]
);
}


 
 $filter = sprintf(
'/%s/i',
str_replace(
'/',
'\\/',
$filter
)
);
}

$this->filter = $filter;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner\Filter;

use function sprintf;
use FilterIterator;
use InvalidArgumentException;
use Iterator;
use PHPUnit\Framework\TestSuite;
use RecursiveFilterIterator;
use ReflectionClass;




final class Factory
{



private $filters = [];




public function addFilter(ReflectionClass $filter, $args): void
{
if (!$filter->isSubclassOf(RecursiveFilterIterator::class)) {
throw new InvalidArgumentException(
sprintf(
'Class "%s" does not extend RecursiveFilterIterator',
$filter->name
)
);
}

$this->filters[] = [$filter, $args];
}

public function factory(Iterator $iterator, TestSuite $suite): FilterIterator
{
foreach ($this->filters as $filter) {
[$class, $args] = $filter;
$iterator = $class->newInstance($iterator, $args, $suite);
}

return $iterator;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner\Filter;

use function array_map;
use function array_merge;
use function in_array;
use function spl_object_hash;
use PHPUnit\Framework\TestSuite;
use RecursiveFilterIterator;
use RecursiveIterator;




abstract class GroupFilterIterator extends RecursiveFilterIterator
{



protected $groupTests = [];

public function __construct(RecursiveIterator $iterator, array $groups, TestSuite $suite)
{
parent::__construct($iterator);

foreach ($suite->getGroupDetails() as $group => $tests) {
if (in_array((string) $group, $groups, true)) {
$testHashes = array_map(
'spl_object_hash',
$tests
);

$this->groupTests = array_merge($this->groupTests, $testHashes);
}
}
}

public function accept(): bool
{
$test = $this->getInnerIterator()->current();

if ($test instanceof TestSuite) {
return true;
}

return $this->doAccept(spl_object_hash($test));
}

abstract protected function doAccept(string $hash);
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner\Filter;

use function in_array;




final class IncludeGroupFilterIterator extends GroupFilterIterator
{
protected function doAccept(string $hash): bool
{
return in_array($hash, $this->groupTests, true);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

interface AfterTestHook extends TestHook
{






public function executeAfterTest(string $test, float $time): void;
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

interface AfterSuccessfulTestHook extends TestHook
{
public function executeAfterSuccessfulTest(string $test, float $time): void;
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

interface BeforeFirstTestHook extends Hook
{
public function executeBeforeFirstTest(): void;
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

interface AfterTestFailureHook extends TestHook
{
public function executeAfterTestFailure(string $test, string $message, float $time): void;
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Framework\Warning;
use PHPUnit\Util\Test as TestUtil;
use Throwable;




final class TestListenerAdapter implements TestListener
{



private $hooks = [];




private $lastTestWasNotSuccessful;

public function add(TestHook $hook): void
{
$this->hooks[] = $hook;
}

public function startTest(Test $test): void
{
foreach ($this->hooks as $hook) {
if ($hook instanceof BeforeTestHook) {
$hook->executeBeforeTest(TestUtil::describeAsString($test));
}
}

$this->lastTestWasNotSuccessful = false;
}

public function addError(Test $test, Throwable $t, float $time): void
{
foreach ($this->hooks as $hook) {
if ($hook instanceof AfterTestErrorHook) {
$hook->executeAfterTestError(TestUtil::describeAsString($test), $t->getMessage(), $time);
}
}

$this->lastTestWasNotSuccessful = true;
}

public function addWarning(Test $test, Warning $e, float $time): void
{
foreach ($this->hooks as $hook) {
if ($hook instanceof AfterTestWarningHook) {
$hook->executeAfterTestWarning(TestUtil::describeAsString($test), $e->getMessage(), $time);
}
}

$this->lastTestWasNotSuccessful = true;
}

public function addFailure(Test $test, AssertionFailedError $e, float $time): void
{
foreach ($this->hooks as $hook) {
if ($hook instanceof AfterTestFailureHook) {
$hook->executeAfterTestFailure(TestUtil::describeAsString($test), $e->getMessage(), $time);
}
}

$this->lastTestWasNotSuccessful = true;
}

public function addIncompleteTest(Test $test, Throwable $t, float $time): void
{
foreach ($this->hooks as $hook) {
if ($hook instanceof AfterIncompleteTestHook) {
$hook->executeAfterIncompleteTest(TestUtil::describeAsString($test), $t->getMessage(), $time);
}
}

$this->lastTestWasNotSuccessful = true;
}

public function addRiskyTest(Test $test, Throwable $t, float $time): void
{
foreach ($this->hooks as $hook) {
if ($hook instanceof AfterRiskyTestHook) {
$hook->executeAfterRiskyTest(TestUtil::describeAsString($test), $t->getMessage(), $time);
}
}

$this->lastTestWasNotSuccessful = true;
}

public function addSkippedTest(Test $test, Throwable $t, float $time): void
{
foreach ($this->hooks as $hook) {
if ($hook instanceof AfterSkippedTestHook) {
$hook->executeAfterSkippedTest(TestUtil::describeAsString($test), $t->getMessage(), $time);
}
}

$this->lastTestWasNotSuccessful = true;
}

public function endTest(Test $test, float $time): void
{
if (!$this->lastTestWasNotSuccessful) {
foreach ($this->hooks as $hook) {
if ($hook instanceof AfterSuccessfulTestHook) {
$hook->executeAfterSuccessfulTest(TestUtil::describeAsString($test), $time);
}
}
}

foreach ($this->hooks as $hook) {
if ($hook instanceof AfterTestHook) {
$hook->executeAfterTest(TestUtil::describeAsString($test), $time);
}
}
}

public function startTestSuite(TestSuite $suite): void
{
}

public function endTestSuite(TestSuite $suite): void
{
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

interface AfterLastTestHook extends Hook
{
public function executeAfterLastTest(): void;
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

interface AfterSkippedTestHook extends TestHook
{
public function executeAfterSkippedTest(string $test, string $message, float $time): void;
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

interface AfterRiskyTestHook extends TestHook
{
public function executeAfterRiskyTest(string $test, string $message, float $time): void;
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

interface BeforeTestHook extends TestHook
{
public function executeBeforeTest(string $test): void;
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

interface TestHook extends Hook
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

interface AfterIncompleteTestHook extends TestHook
{
public function executeAfterIncompleteTest(string $test, string $message, float $time): void;
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

interface AfterTestWarningHook extends TestHook
{
public function executeAfterTestWarning(string $test, string $message, float $time): void;
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

interface Hook
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

interface AfterTestErrorHook extends TestHook
{
public function executeAfterTestError(string $test, string $message, float $time): void;
}
<?php declare(strict_types=1);








namespace PHPUnit\Runner;

use function preg_match;
use function round;




final class ResultCacheExtension implements AfterIncompleteTestHook, AfterLastTestHook, AfterRiskyTestHook, AfterSkippedTestHook, AfterSuccessfulTestHook, AfterTestErrorHook, AfterTestFailureHook, AfterTestWarningHook
{



private $cache;

public function __construct(TestResultCache $cache)
{
$this->cache = $cache;
}

public function flush(): void
{
$this->cache->persist();
}

public function executeAfterSuccessfulTest(string $test, float $time): void
{
$testName = $this->getTestName($test);

$this->cache->setTime($testName, round($time, 3));
}

public function executeAfterIncompleteTest(string $test, string $message, float $time): void
{
$testName = $this->getTestName($test);

$this->cache->setTime($testName, round($time, 3));
$this->cache->setState($testName, BaseTestRunner::STATUS_INCOMPLETE);
}

public function executeAfterRiskyTest(string $test, string $message, float $time): void
{
$testName = $this->getTestName($test);

$this->cache->setTime($testName, round($time, 3));
$this->cache->setState($testName, BaseTestRunner::STATUS_RISKY);
}

public function executeAfterSkippedTest(string $test, string $message, float $time): void
{
$testName = $this->getTestName($test);

$this->cache->setTime($testName, round($time, 3));
$this->cache->setState($testName, BaseTestRunner::STATUS_SKIPPED);
}

public function executeAfterTestError(string $test, string $message, float $time): void
{
$testName = $this->getTestName($test);

$this->cache->setTime($testName, round($time, 3));
$this->cache->setState($testName, BaseTestRunner::STATUS_ERROR);
}

public function executeAfterTestFailure(string $test, string $message, float $time): void
{
$testName = $this->getTestName($test);

$this->cache->setTime($testName, round($time, 3));
$this->cache->setState($testName, BaseTestRunner::STATUS_FAILURE);
}

public function executeAfterTestWarning(string $test, string $message, float $time): void
{
$testName = $this->getTestName($test);

$this->cache->setTime($testName, round($time, 3));
$this->cache->setState($testName, BaseTestRunner::STATUS_WARNING);
}

public function executeAfterLastTest(): void
{
$this->flush();
}






private function getTestName(string $test): string
{
$matches = [];

if (preg_match('/^(?<name>\S+::\S+)(?:(?<dataname> with data set (?:#\d+|"[^"]+"))\s\()?/', $test, $matches)) {
$test = $matches['name'] . ($matches['dataname'] ?? '');
}

return $test;
}
}
<?php declare(strict_types=1);








namespace PHPUnit;

use Throwable;




interface Exception extends Throwable
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;

use const PHP_EOL;
use function class_exists;
use function count;
use function extension_loaded;
use function function_exists;
use function get_class;
use function sprintf;
use function xdebug_get_monitored_functions;
use function xdebug_start_function_monitor;
use function xdebug_stop_function_monitor;
use AssertionError;
use Countable;
use Error;
use PHPUnit\Framework\MockObject\Exception as MockObjectException;
use PHPUnit\Util\Blacklist;
use PHPUnit\Util\ErrorHandler;
use PHPUnit\Util\Printer;
use PHPUnit\Util\Test as TestUtil;
use ReflectionClass;
use ReflectionException;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\CoveredCodeNotExecutedException as OriginalCoveredCodeNotExecutedException;
use SebastianBergmann\CodeCoverage\Exception as OriginalCodeCoverageException;
use SebastianBergmann\CodeCoverage\MissingCoversAnnotationException as OriginalMissingCoversAnnotationException;
use SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException;
use SebastianBergmann\Invoker\Invoker;
use SebastianBergmann\Invoker\TimeoutException;
use SebastianBergmann\ResourceOperations\ResourceOperations;
use SebastianBergmann\Timer\Timer;
use Throwable;




final class TestResult implements Countable
{



private $passed = [];




private $errors = [];




private $failures = [];




private $warnings = [];




private $notImplemented = [];




private $risky = [];




private $skipped = [];






private $listeners = [];




private $runTests = 0;




private $time = 0;




private $topTestSuite;






private $codeCoverage;




private $convertDeprecationsToExceptions = false;




private $convertErrorsToExceptions = true;




private $convertNoticesToExceptions = true;




private $convertWarningsToExceptions = true;




private $stop = false;




private $stopOnError = false;




private $stopOnFailure = false;




private $stopOnWarning = false;




private $beStrictAboutTestsThatDoNotTestAnything = true;




private $beStrictAboutOutputDuringTests = false;




private $beStrictAboutTodoAnnotatedTests = false;




private $beStrictAboutResourceUsageDuringSmallTests = false;




private $enforceTimeLimit = false;




private $timeoutForSmallTests = 1;




private $timeoutForMediumTests = 10;




private $timeoutForLargeTests = 60;




private $stopOnRisky = false;




private $stopOnIncomplete = false;




private $stopOnSkipped = false;




private $lastTestFailed = false;




private $defaultTimeLimit = 0;




private $stopOnDefect = false;




private $registerMockObjectsFromTestArgumentsRecursively = false;








public function addListener(TestListener $listener): void
{
$this->listeners[] = $listener;
}








public function removeListener(TestListener $listener): void
{
foreach ($this->listeners as $key => $_listener) {
if ($listener === $_listener) {
unset($this->listeners[$key]);
}
}
}








public function flushListeners(): void
{
foreach ($this->listeners as $listener) {
if ($listener instanceof Printer) {
$listener->flush();
}
}
}




public function addError(Test $test, Throwable $t, float $time): void
{
if ($t instanceof RiskyTestError) {
$this->risky[] = new TestFailure($test, $t);
$notifyMethod = 'addRiskyTest';

if ($test instanceof TestCase) {
$test->markAsRisky();
}

if ($this->stopOnRisky || $this->stopOnDefect) {
$this->stop();
}
} elseif ($t instanceof IncompleteTest) {
$this->notImplemented[] = new TestFailure($test, $t);
$notifyMethod = 'addIncompleteTest';

if ($this->stopOnIncomplete) {
$this->stop();
}
} elseif ($t instanceof SkippedTest) {
$this->skipped[] = new TestFailure($test, $t);
$notifyMethod = 'addSkippedTest';

if ($this->stopOnSkipped) {
$this->stop();
}
} else {
$this->errors[] = new TestFailure($test, $t);
$notifyMethod = 'addError';

if ($this->stopOnError || $this->stopOnFailure) {
$this->stop();
}
}


 if ($t instanceof Error) {
$t = new ExceptionWrapper($t);
}

foreach ($this->listeners as $listener) {
$listener->{$notifyMethod}($test, $t, $time);
}

$this->lastTestFailed = true;
$this->time += $time;
}





public function addWarning(Test $test, Warning $e, float $time): void
{
if ($this->stopOnWarning || $this->stopOnDefect) {
$this->stop();
}

$this->warnings[] = new TestFailure($test, $e);

foreach ($this->listeners as $listener) {
$listener->addWarning($test, $e, $time);
}

$this->time += $time;
}





public function addFailure(Test $test, AssertionFailedError $e, float $time): void
{
if ($e instanceof RiskyTestError || $e instanceof OutputError) {
$this->risky[] = new TestFailure($test, $e);
$notifyMethod = 'addRiskyTest';

if ($test instanceof TestCase) {
$test->markAsRisky();
}

if ($this->stopOnRisky || $this->stopOnDefect) {
$this->stop();
}
} elseif ($e instanceof IncompleteTest) {
$this->notImplemented[] = new TestFailure($test, $e);
$notifyMethod = 'addIncompleteTest';

if ($this->stopOnIncomplete) {
$this->stop();
}
} elseif ($e instanceof SkippedTest) {
$this->skipped[] = new TestFailure($test, $e);
$notifyMethod = 'addSkippedTest';

if ($this->stopOnSkipped) {
$this->stop();
}
} else {
$this->failures[] = new TestFailure($test, $e);
$notifyMethod = 'addFailure';

if ($this->stopOnFailure || $this->stopOnDefect) {
$this->stop();
}
}

foreach ($this->listeners as $listener) {
$listener->{$notifyMethod}($test, $e, $time);
}

$this->lastTestFailed = true;
$this->time += $time;
}




public function startTestSuite(TestSuite $suite): void
{
if ($this->topTestSuite === null) {
$this->topTestSuite = $suite;
}

foreach ($this->listeners as $listener) {
$listener->startTestSuite($suite);
}
}




public function endTestSuite(TestSuite $suite): void
{
foreach ($this->listeners as $listener) {
$listener->endTestSuite($suite);
}
}




public function startTest(Test $test): void
{
$this->lastTestFailed = false;
$this->runTests += count($test);

foreach ($this->listeners as $listener) {
$listener->startTest($test);
}
}






public function endTest(Test $test, float $time): void
{
foreach ($this->listeners as $listener) {
$listener->endTest($test, $time);
}

if (!$this->lastTestFailed && $test instanceof TestCase) {
$class = get_class($test);
$key = $class . '::' . $test->getName();

$this->passed[$key] = [
'result' => $test->getResult(),
'size' => \PHPUnit\Util\Test::getSize(
$class,
$test->getName(false)
),
];

$this->time += $time;
}
}




public function allHarmless(): bool
{
return $this->riskyCount() == 0;
}




public function riskyCount(): int
{
return count($this->risky);
}




public function allCompletelyImplemented(): bool
{
return $this->notImplementedCount() == 0;
}




public function notImplementedCount(): int
{
return count($this->notImplemented);
}






public function risky(): array
{
return $this->risky;
}






public function notImplemented(): array
{
return $this->notImplemented;
}




public function noneSkipped(): bool
{
return $this->skippedCount() == 0;
}




public function skippedCount(): int
{
return count($this->skipped);
}






public function skipped(): array
{
return $this->skipped;
}




public function errorCount(): int
{
return count($this->errors);
}






public function errors(): array
{
return $this->errors;
}




public function failureCount(): int
{
return count($this->failures);
}






public function failures(): array
{
return $this->failures;
}




public function warningCount(): int
{
return count($this->warnings);
}






public function warnings(): array
{
return $this->warnings;
}




public function passed(): array
{
return $this->passed;
}




public function topTestSuite(): TestSuite
{
return $this->topTestSuite;
}




public function getCollectCodeCoverageInformation(): bool
{
return $this->codeCoverage !== null;
}












public function run(Test $test): void
{
Assert::resetCount();

if ($test instanceof TestCase) {
$test->setRegisterMockObjectsFromTestArgumentsRecursively(
$this->registerMockObjectsFromTestArgumentsRecursively
);

$isAnyCoverageRequired = TestUtil::requiresCodeCoverageDataCollection($test);
}

$error = false;
$failure = false;
$warning = false;
$incomplete = false;
$risky = false;
$skipped = false;

$this->startTest($test);

if ($this->convertDeprecationsToExceptions || $this->convertErrorsToExceptions || $this->convertNoticesToExceptions || $this->convertWarningsToExceptions) {
$errorHandler = new ErrorHandler(
$this->convertDeprecationsToExceptions,
$this->convertErrorsToExceptions,
$this->convertNoticesToExceptions,
$this->convertWarningsToExceptions
);

$errorHandler->register();
}

$collectCodeCoverage = $this->codeCoverage !== null &&
!$test instanceof WarningTestCase &&
$isAnyCoverageRequired;

if ($collectCodeCoverage) {
$this->codeCoverage->start($test);
}

$monitorFunctions = $this->beStrictAboutResourceUsageDuringSmallTests &&
!$test instanceof WarningTestCase &&
$test->getSize() == \PHPUnit\Util\Test::SMALL &&
function_exists('xdebug_start_function_monitor');

if ($monitorFunctions) {

xdebug_start_function_monitor(ResourceOperations::getFunctions());
}

Timer::start();

try {
if (!$test instanceof WarningTestCase &&
$this->enforceTimeLimit &&
($this->defaultTimeLimit || $test->getSize() != \PHPUnit\Util\Test::UNKNOWN) &&
extension_loaded('pcntl') && class_exists(Invoker::class)) {
switch ($test->getSize()) {
case \PHPUnit\Util\Test::SMALL:
$_timeout = $this->timeoutForSmallTests;

break;

case \PHPUnit\Util\Test::MEDIUM:
$_timeout = $this->timeoutForMediumTests;

break;

case \PHPUnit\Util\Test::LARGE:
$_timeout = $this->timeoutForLargeTests;

break;

case \PHPUnit\Util\Test::UNKNOWN:
$_timeout = $this->defaultTimeLimit;

break;
}

$invoker = new Invoker;
$invoker->invoke([$test, 'runBare'], [], $_timeout);
} else {
$test->runBare();
}
} catch (TimeoutException $e) {
$this->addFailure(
$test,
new RiskyTestError(
$e->getMessage()
),
$_timeout
);

$risky = true;
} catch (MockObjectException $e) {
$e = new Warning(
$e->getMessage()
);

$warning = true;
} catch (AssertionFailedError $e) {
$failure = true;

if ($e instanceof RiskyTestError) {
$risky = true;
} elseif ($e instanceof IncompleteTestError) {
$incomplete = true;
} elseif ($e instanceof SkippedTestError) {
$skipped = true;
}
} catch (AssertionError $e) {
$test->addToAssertionCount(1);

$failure = true;
$frame = $e->getTrace()[0];

$e = new AssertionFailedError(
sprintf(
'%s in %s:%s',
$e->getMessage(),
$frame['file'],
$frame['line']
)
);
} catch (Warning $e) {
$warning = true;
} catch (Exception $e) {
$error = true;
} catch (Throwable $e) {
$e = new ExceptionWrapper($e);
$error = true;
}

$time = Timer::stop();
$test->addToAssertionCount(Assert::getCount());

if ($monitorFunctions) {
$blacklist = new Blacklist;


$functions = xdebug_get_monitored_functions();


xdebug_stop_function_monitor();

foreach ($functions as $function) {
if (!$blacklist->isBlacklisted($function['filename'])) {
$this->addFailure(
$test,
new RiskyTestError(
sprintf(
'%s() used in %s:%s',
$function['function'],
$function['filename'],
$function['lineno']
)
),
$time
);
}
}
}

if ($this->beStrictAboutTestsThatDoNotTestAnything &&
$test->getNumAssertions() == 0) {
$risky = true;
}

if ($collectCodeCoverage) {
$append = !$risky && !$incomplete && !$skipped;
$linesToBeCovered = [];
$linesToBeUsed = [];

if ($append && $test instanceof TestCase) {
try {
$linesToBeCovered = \PHPUnit\Util\Test::getLinesToBeCovered(
get_class($test),
$test->getName(false)
);

$linesToBeUsed = \PHPUnit\Util\Test::getLinesToBeUsed(
get_class($test),
$test->getName(false)
);
} catch (InvalidCoversTargetException $cce) {
$this->addWarning(
$test,
new Warning(
$cce->getMessage()
),
$time
);
}
}

try {
$this->codeCoverage->stop(
$append,
$linesToBeCovered,
$linesToBeUsed
);
} catch (UnintentionallyCoveredCodeException $cce) {
$this->addFailure(
$test,
new UnintentionallyCoveredCodeError(
'This test executed code that is not listed as code to be covered or used:' .
PHP_EOL . $cce->getMessage()
),
$time
);
} catch (OriginalCoveredCodeNotExecutedException $cce) {
$this->addFailure(
$test,
new CoveredCodeNotExecutedException(
'This test did not execute all the code that is listed as code to be covered:' .
PHP_EOL . $cce->getMessage()
),
$time
);
} catch (OriginalMissingCoversAnnotationException $cce) {
if ($linesToBeCovered !== false) {
$this->addFailure(
$test,
new MissingCoversAnnotationException(
'This test does not have a @covers annotation but is expected to have one'
),
$time
);
}
} catch (OriginalCodeCoverageException $cce) {
$error = true;

$e = $e ?? $cce;
}
}

if (isset($errorHandler)) {
$errorHandler->unregister();

unset($errorHandler);
}

if ($error) {
$this->addError($test, $e, $time);
} elseif ($failure) {
$this->addFailure($test, $e, $time);
} elseif ($warning) {
$this->addWarning($test, $e, $time);
} elseif ($this->beStrictAboutTestsThatDoNotTestAnything &&
!$test->doesNotPerformAssertions() &&
$test->getNumAssertions() == 0) {
try {
$reflected = new ReflectionClass($test);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


$name = $test->getName(false);

if ($name && $reflected->hasMethod($name)) {
try {
$reflected = $reflected->getMethod($name);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}

 }

$this->addFailure(
$test,
new RiskyTestError(
sprintf(
"This test did not perform any assertions\n\n%s:%d",
$reflected->getFileName(),
$reflected->getStartLine()
)
),
$time
);
} elseif ($this->beStrictAboutTestsThatDoNotTestAnything &&
$test->doesNotPerformAssertions() &&
$test->getNumAssertions() > 0) {
$this->addFailure(
$test,
new RiskyTestError(
sprintf(
'This test is annotated with "@doesNotPerformAssertions" but performed %d assertions',
$test->getNumAssertions()
)
),
$time
);
} elseif ($this->beStrictAboutOutputDuringTests && $test->hasOutput()) {
$this->addFailure(
$test,
new OutputError(
sprintf(
'This test printed output: %s',
$test->getActualOutput()
)
),
$time
);
} elseif ($this->beStrictAboutTodoAnnotatedTests && $test instanceof TestCase) {
$annotations = $test->getAnnotations();

if (isset($annotations['method']['todo'])) {
$this->addFailure(
$test,
new RiskyTestError(
'Test method is annotated with @todo'
),
$time
);
}
}

$this->endTest($test, $time);
}




public function count(): int
{
return $this->runTests;
}




public function shouldStop(): bool
{
return $this->stop;
}




public function stop(): void
{
$this->stop = true;
}




public function getCodeCoverage(): ?CodeCoverage
{
return $this->codeCoverage;
}




public function setCodeCoverage(CodeCoverage $codeCoverage): void
{
$this->codeCoverage = $codeCoverage;
}




public function convertDeprecationsToExceptions(bool $flag): void
{
$this->convertDeprecationsToExceptions = $flag;
}




public function getConvertDeprecationsToExceptions(): bool
{
return $this->convertDeprecationsToExceptions;
}




public function convertErrorsToExceptions(bool $flag): void
{
$this->convertErrorsToExceptions = $flag;
}




public function getConvertErrorsToExceptions(): bool
{
return $this->convertErrorsToExceptions;
}




public function convertNoticesToExceptions(bool $flag): void
{
$this->convertNoticesToExceptions = $flag;
}




public function getConvertNoticesToExceptions(): bool
{
return $this->convertNoticesToExceptions;
}




public function convertWarningsToExceptions(bool $flag): void
{
$this->convertWarningsToExceptions = $flag;
}




public function getConvertWarningsToExceptions(): bool
{
return $this->convertWarningsToExceptions;
}




public function stopOnError(bool $flag): void
{
$this->stopOnError = $flag;
}




public function stopOnFailure(bool $flag): void
{
$this->stopOnFailure = $flag;
}




public function stopOnWarning(bool $flag): void
{
$this->stopOnWarning = $flag;
}

public function beStrictAboutTestsThatDoNotTestAnything(bool $flag): void
{
$this->beStrictAboutTestsThatDoNotTestAnything = $flag;
}

public function isStrictAboutTestsThatDoNotTestAnything(): bool
{
return $this->beStrictAboutTestsThatDoNotTestAnything;
}

public function beStrictAboutOutputDuringTests(bool $flag): void
{
$this->beStrictAboutOutputDuringTests = $flag;
}

public function isStrictAboutOutputDuringTests(): bool
{
return $this->beStrictAboutOutputDuringTests;
}

public function beStrictAboutResourceUsageDuringSmallTests(bool $flag): void
{
$this->beStrictAboutResourceUsageDuringSmallTests = $flag;
}

public function isStrictAboutResourceUsageDuringSmallTests(): bool
{
return $this->beStrictAboutResourceUsageDuringSmallTests;
}

public function enforceTimeLimit(bool $flag): void
{
$this->enforceTimeLimit = $flag;
}

public function enforcesTimeLimit(): bool
{
return $this->enforceTimeLimit;
}

public function beStrictAboutTodoAnnotatedTests(bool $flag): void
{
$this->beStrictAboutTodoAnnotatedTests = $flag;
}

public function isStrictAboutTodoAnnotatedTests(): bool
{
return $this->beStrictAboutTodoAnnotatedTests;
}




public function stopOnRisky(bool $flag): void
{
$this->stopOnRisky = $flag;
}




public function stopOnIncomplete(bool $flag): void
{
$this->stopOnIncomplete = $flag;
}




public function stopOnSkipped(bool $flag): void
{
$this->stopOnSkipped = $flag;
}




public function stopOnDefect(bool $flag): void
{
$this->stopOnDefect = $flag;
}




public function time(): float
{
return $this->time;
}




public function wasSuccessful(): bool
{
return $this->wasSuccessfulIgnoringWarnings() && empty($this->warnings);
}

public function wasSuccessfulIgnoringWarnings(): bool
{
return empty($this->errors) && empty($this->failures);
}

public function wasSuccessfulAndNoTestIsRiskyOrSkippedOrIncomplete(): bool
{
return $this->wasSuccessful() && $this->allHarmless() && $this->allCompletelyImplemented() && $this->noneSkipped();
}




public function setDefaultTimeLimit(int $timeout): void
{
$this->defaultTimeLimit = $timeout;
}




public function setTimeoutForSmallTests(int $timeout): void
{
$this->timeoutForSmallTests = $timeout;
}




public function setTimeoutForMediumTests(int $timeout): void
{
$this->timeoutForMediumTests = $timeout;
}




public function setTimeoutForLargeTests(int $timeout): void
{
$this->timeoutForLargeTests = $timeout;
}




public function getTimeoutForLargeTests(): int
{
return $this->timeoutForLargeTests;
}

public function setRegisterMockObjectsFromTestArgumentsRecursively(bool $flag): void
{
$this->registerMockObjectsFromTestArgumentsRecursively = $flag;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class IncompleteTestCase extends TestCase
{



protected $backupGlobals = false;




protected $backupStaticAttributes = false;




protected $runTestInSeparateProcess = false;




private $message;

public function __construct(string $className, string $methodName, string $message = '')
{
parent::__construct($className . '::' . $methodName);

$this->message = $message;
}

public function getMessage(): string
{
return $this->message;
}






public function toString(): string
{
return $this->getName();
}




protected function runTest(): void
{
$this->markTestIncomplete($this->message);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;

use function array_keys;
use function get_class;
use function spl_object_hash;
use PHPUnit\Util\Filter;
use Throwable;












final class ExceptionWrapper extends Exception
{



protected $className;




protected $previous;

public function __construct(Throwable $t)
{

 
 parent::__construct($t->getMessage(), (int) $t->getCode());
$this->setOriginalException($t);
}

public function __toString(): string
{
$string = TestFailure::exceptionToString($this);

if ($trace = Filter::getFilteredStacktrace($this)) {
$string .= "\n" . $trace;
}

if ($this->previous) {
$string .= "\nCaused by\n" . $this->previous;
}

return $string;
}

public function getClassName(): string
{
return $this->className;
}

public function getPreviousWrapped(): ?self
{
return $this->previous;
}

public function setClassName(string $className): void
{
$this->className = $className;
}

public function setOriginalException(Throwable $t): void
{
$this->originalException($t);

$this->className = get_class($t);
$this->file = $t->getFile();
$this->line = $t->getLine();

$this->serializableTrace = $t->getTrace();

foreach (array_keys($this->serializableTrace) as $key) {
unset($this->serializableTrace[$key]['args']);
}

if ($t->getPrevious()) {
$this->previous = new self($t->getPrevious());
}
}

public function getOriginalException(): ?Throwable
{
return $this->originalException();
}






private function originalException(Throwable $exceptionToStore = null): ?Throwable
{
static $originalExceptions;

$instanceId = spl_object_hash($this);

if ($exceptionToStore) {
$originalExceptions[$instanceId] = $exceptionToStore;
}

return $originalExceptions[$instanceId] ?? null;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Error;

final class Notice extends Error
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Error;

final class Warning extends Error
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Error;

final class Deprecated extends Error
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Error;

use PHPUnit\Framework\Exception;

class Error extends Exception
{
public function __construct(string $message, int $code, string $file, int $line, \Exception $previous = null)
{
parent::__construct($message, $code, $previous);

$this->file = $file;
$this->line = $line;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class InvalidParameterGroupException extends Exception
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use PHPUnit\Framework\Assert;
use PHPUnit\Framework\ExpectationFailedException;





final class Attribute extends Composite
{



private $attributeName;

public function __construct(Constraint $constraint, string $attributeName)
{
parent::__construct($constraint);

$this->attributeName = $attributeName;
}















public function evaluate($other, string $description = '', bool $returnResult = false)
{
return parent::evaluate(
Assert::readAttribute(
$other,
$this->attributeName
),
$description,
$returnResult
);
}




public function toString(): string
{
return 'attribute "' . $this->attributeName . '" ' . $this->innerConstraint()->toString();
}









protected function failureDescription($other): string
{
return $this->toString();
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;




final class IsFalse extends Constraint
{



public function toString(): string
{
return 'is false';
}







protected function matches($other): bool
{
return $other === false;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function mb_stripos;
use function mb_strpos;
use function mb_strtolower;
use function sprintf;










final class StringContains extends Constraint
{



private $string;




private $ignoreCase;

public function __construct(string $string, bool $ignoreCase = false)
{
$this->string = $string;
$this->ignoreCase = $ignoreCase;
}




public function toString(): string
{
if ($this->ignoreCase) {
$string = mb_strtolower($this->string);
} else {
$string = $this->string;
}

return sprintf(
'contains "%s"',
$string
);
}







protected function matches($other): bool
{
if ('' === $this->string) {
return true;
}

if ($this->ignoreCase) {
return mb_stripos($other, $this->string) !== false;
}

return mb_strpos($other, $this->string) !== false;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function file_exists;
use function sprintf;






final class FileExists extends Constraint
{



public function toString(): string
{
return 'file exists';
}







protected function matches($other): bool
{
return file_exists($other);
}









protected function failureDescription($other): string
{
return sprintf(
'file "%s" exists',
$other
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function sprintf;
use function strpos;
use Throwable;

final class ExceptionMessage extends Constraint
{



private $expectedMessage;

public function __construct(string $expected)
{
$this->expectedMessage = $expected;
}

public function toString(): string
{
if ($this->expectedMessage === '') {
return 'exception message is empty';
}

return 'exception message contains ';
}







protected function matches($other): bool
{
if ($this->expectedMessage === '') {
return $other->getMessage() === '';
}

return strpos((string) $other->getMessage(), $this->expectedMessage) !== false;
}









protected function failureDescription($other): string
{
if ($this->expectedMessage === '') {
return sprintf(
"exception message is empty but is '%s'",
$other->getMessage()
);
}

return sprintf(
"exception message '%s' contains '%s'",
$other->getMessage(),
$this->expectedMessage
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use PHPUnit\Framework\ExpectationFailedException;





final class TraversableContainsOnly extends Constraint
{



private $constraint;




private $type;




public function __construct(string $type, bool $isNativeType = true)
{
if ($isNativeType) {
$this->constraint = new IsType($type);
} else {
$this->constraint = new IsInstanceOf(
$type
);
}

$this->type = $type;
}














public function evaluate($other, string $description = '', bool $returnResult = false)
{
$success = true;

foreach ($other as $item) {
if (!$this->constraint->evaluate($item, '', true)) {
$success = false;

break;
}
}

if ($returnResult) {
return $success;
}

if (!$success) {
$this->fail($other, $description);
}
}




public function toString(): string
{
return 'contains only values of type "' . $this->type . '"';
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;






final class Callback extends Constraint
{





private $callback;


public function __construct(callable $callback)
{
$this->callback = $callback;
}




public function toString(): string
{
return 'is accepted by specified callback';
}









protected function matches($other): bool
{
return ($this->callback)($other);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function is_readable;
use function sprintf;






final class IsReadable extends Constraint
{



public function toString(): string
{
return 'is readable';
}







protected function matches($other): bool
{
return is_readable($other);
}









protected function failureDescription($other): string
{
return sprintf(
'"%s" is readable',
$other
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function get_class;
use function sprintf;
use PHPUnit\Util\Filter;
use Throwable;

final class Exception extends Constraint
{



private $className;

public function __construct(string $className)
{
$this->className = $className;
}




public function toString(): string
{
return sprintf(
'exception of type "%s"',
$this->className
);
}







protected function matches($other): bool
{
return $other instanceof $this->className;
}









protected function failureDescription($other): string
{
if ($other !== null) {
$message = '';

if ($other instanceof Throwable) {
$message = '. Message was: "' . $other->getMessage() . '" at'
. "\n" . Filter::getFilteredStacktrace($other);
}

return sprintf(
'exception of type "%s" matches expected exception "%s"%s',
get_class($other),
$this->className,
$message
);
}

return sprintf(
'exception of type "%s" is thrown',
$this->className
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function array_key_exists;
use function is_array;
use ArrayAccess;









final class ArrayHasKey extends Constraint
{



private $key;




public function __construct($key)
{
$this->key = $key;
}






public function toString(): string
{
return 'has the key ' . $this->exporter()->export($this->key);
}







protected function matches($other): bool
{
if (is_array($other)) {
return array_key_exists($this->key, $other);
}

if ($other instanceof ArrayAccess) {
return $other->offsetExists($this->key);
}

return false;
}











protected function failureDescription($other): string
{
return 'an array ' . $this->toString();
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function strlen;
use function substr;





final class StringEndsWith extends Constraint
{



private $suffix;

public function __construct(string $suffix)
{
$this->suffix = $suffix;
}




public function toString(): string
{
return 'ends with "' . $this->suffix . '"';
}







protected function matches($other): bool
{
return substr($other, 0 - strlen($this->suffix)) === $this->suffix;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function is_writable;
use function sprintf;






final class IsWritable extends Constraint
{



public function toString(): string
{
return 'is writable';
}







protected function matches($other): bool
{
return is_writable($other);
}









protected function failureDescription($other): string
{
return sprintf(
'"%s" is writable',
$other
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function count;
use function gettype;
use function sprintf;
use function strpos;
use Countable;
use EmptyIterator;




final class IsEmpty extends Constraint
{



public function toString(): string
{
return 'is empty';
}







protected function matches($other): bool
{
if ($other instanceof EmptyIterator) {
return true;
}

if ($other instanceof Countable) {
return count($other) === 0;
}

return empty($other);
}









protected function failureDescription($other): string
{
$type = gettype($other);

return sprintf(
'%s %s %s',
strpos($type, 'a') === 0 || strpos($type, 'o') === 0 ? 'an' : 'a',
$type,
$this->toString()
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;




final class IsTrue extends Constraint
{



public function toString(): string
{
return 'is true';
}







protected function matches($other): bool
{
return $other === true;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;





final class GreaterThan extends Constraint
{



private $value;




public function __construct($value)
{
$this->value = $value;
}






public function toString(): string
{
return 'is greater than ' . $this->exporter()->export($this->value);
}







protected function matches($other): bool
{
return $this->value < $other;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function count;
use function is_array;
use function iterator_count;
use function sprintf;
use Countable;
use EmptyIterator;
use Generator;
use Iterator;
use IteratorAggregate;
use Traversable;

class Count extends Constraint
{



private $expectedCount;

public function __construct(int $expected)
{
$this->expectedCount = $expected;
}

public function toString(): string
{
return sprintf(
'count matches %d',
$this->expectedCount
);
}





protected function matches($other): bool
{
return $this->expectedCount === $this->getCountOf($other);
}




protected function getCountOf($other): ?int
{
if ($other instanceof Countable || is_array($other)) {
return count($other);
}

if ($other instanceof EmptyIterator) {
return 0;
}

if ($other instanceof Traversable) {
while ($other instanceof IteratorAggregate) {
$other = $other->getIterator();
}

$iterator = $other;

if ($iterator instanceof Generator) {
return $this->getCountOfGenerator($iterator);
}

if (!$iterator instanceof Iterator) {
return iterator_count($iterator);
}

$key = $iterator->key();
$count = iterator_count($iterator);


 
 if ($key !== null) {
$iterator->rewind();

while ($iterator->valid() && $key !== $iterator->key()) {
$iterator->next();
}
}

return $count;
}

return null;
}





protected function getCountOfGenerator(Generator $generator): int
{
for ($count = 0; $generator->valid(); $generator->next()) {
$count++;
}

return $count;
}









protected function failureDescription($other): string
{
return sprintf(
'actual size %d matches expected size %d',
$this->getCountOf($other),
$this->expectedCount
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use PHPUnit\Framework\ExpectationFailedException;




final class IsAnything extends Constraint
{












public function evaluate($other, string $description = '', bool $returnResult = false)
{
return $returnResult ? true : null;
}




public function toString(): string
{
return 'is anything';
}




public function count(): int
{
return 0;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function array_values;
use function count;
use PHPUnit\Framework\ExpectationFailedException;




final class LogicalAnd extends Constraint
{



private $constraints = [];

public static function fromConstraints(Constraint ...$constraints): self
{
$constraint = new self;

$constraint->constraints = array_values($constraints);

return $constraint;
}






public function setConstraints(array $constraints): void
{
$this->constraints = [];

foreach ($constraints as $constraint) {
if (!($constraint instanceof Constraint)) {
throw new \PHPUnit\Framework\Exception(
'All parameters to ' . __CLASS__ .
' must be a constraint object.'
);
}

$this->constraints[] = $constraint;
}
}














public function evaluate($other, string $description = '', bool $returnResult = false)
{
$success = true;

foreach ($this->constraints as $constraint) {
if (!$constraint->evaluate($other, $description, true)) {
$success = false;

break;
}
}

if ($returnResult) {
return $success;
}

if (!$success) {
$this->fail($other, $description);
}
}




public function toString(): string
{
$text = '';

foreach ($this->constraints as $key => $constraint) {
if ($key > 0) {
$text .= ' and ';
}

$text .= $constraint->toString();
}

return $text;
}




public function count(): int
{
$count = 0;

foreach ($this->constraints as $constraint) {
$count += count($constraint);
}

return $count;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function abs;
use function get_class;
use function is_array;
use function is_float;
use function is_infinite;
use function is_nan;
use function is_object;
use function is_string;
use function sprintf;
use PHPUnit\Framework\ExpectationFailedException;
use SebastianBergmann\Comparator\ComparisonFailure;












final class IsIdentical extends Constraint
{



private const EPSILON = 0.0000000001;




private $value;

public function __construct($value)
{
$this->value = $value;
}














public function evaluate($other, string $description = '', bool $returnResult = false)
{
if (is_float($this->value) && is_float($other) &&
!is_infinite($this->value) && !is_infinite($other) &&
!is_nan($this->value) && !is_nan($other)) {
$success = abs($this->value - $other) < self::EPSILON;
} else {
$success = $this->value === $other;
}

if ($returnResult) {
return $success;
}

if (!$success) {
$f = null;


 if (is_string($this->value) && is_string($other)) {
$f = new ComparisonFailure(
$this->value,
$other,
sprintf("'%s'", $this->value),
sprintf("'%s'", $other)
);
}


 if (is_array($this->value) && is_array($other)) {
$f = new ComparisonFailure(
$this->value,
$other,
$this->exporter()->export($this->value),
$this->exporter()->export($other)
);
}

$this->fail($other, $description, $f);
}
}






public function toString(): string
{
if (is_object($this->value)) {
return 'is identical to an object of class "' .
get_class($this->value) . '"';
}

return 'is identical to ' . $this->exporter()->export($this->value);
}











protected function failureDescription($other): string
{
if (is_object($this->value) && is_object($other)) {
return 'two variables reference the same object';
}

if (is_string($this->value) && is_string($other)) {
return 'two strings are identical';
}

if (is_array($this->value) && is_array($other)) {
return 'two arrays are identical';
}

return parent::failureDescription($other);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function is_array;
use function is_string;
use function sprintf;
use function strpos;
use SplObjectStorage;





final class TraversableContainsEqual extends Constraint
{



private $value;

public function __construct($value)
{
$this->value = $value;
}






public function toString(): string
{
if (is_string($this->value) && strpos($this->value, "\n") !== false) {
return 'contains "' . $this->value . '"';
}

return 'contains ' . $this->exporter()->export($this->value);
}







protected function matches($other): bool
{
if ($other instanceof SplObjectStorage) {
return $other->contains($this->value);
}

foreach ($other as $element) {

if ($this->value == $element) {
return true;
}
}

return false;
}











protected function failureDescription($other): string
{
return sprintf(
'%s %s',
is_array($other) ? 'an array' : 'a traversable',
$this->toString()
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function array_values;
use function count;
use PHPUnit\Framework\ExpectationFailedException;




final class LogicalXor extends Constraint
{



private $constraints = [];

public static function fromConstraints(Constraint ...$constraints): self
{
$constraint = new self;

$constraint->constraints = array_values($constraints);

return $constraint;
}




public function setConstraints(array $constraints): void
{
$this->constraints = [];

foreach ($constraints as $constraint) {
if (!($constraint instanceof Constraint)) {
$constraint = new IsEqual(
$constraint
);
}

$this->constraints[] = $constraint;
}
}














public function evaluate($other, string $description = '', bool $returnResult = false)
{
$success = true;
$lastResult = null;

foreach ($this->constraints as $constraint) {
$result = $constraint->evaluate($other, $description, true);

if ($result === $lastResult) {
$success = false;

break;
}

$lastResult = $result;
}

if ($returnResult) {
return $success;
}

if (!$success) {
$this->fail($other, $description);
}
}




public function toString(): string
{
$text = '';

foreach ($this->constraints as $key => $constraint) {
if ($key > 0) {
$text .= ' xor ';
}

$text .= $constraint->toString();
}

return $text;
}




public function count(): int
{
$count = 0;

foreach ($this->constraints as $constraint) {
$count += count($constraint);
}

return $count;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function json_decode;
use function json_last_error;
use function sprintf;




final class IsJson extends Constraint
{



public function toString(): string
{
return 'is valid JSON';
}







protected function matches($other): bool
{
if ($other === '') {
return false;
}

json_decode($other);

if (json_last_error()) {
return false;
}

return true;
}











protected function failureDescription($other): string
{
if ($other === '') {
return 'an empty string is valid JSON';
}

json_decode($other);
$error = JsonMatchesErrorMessageProvider::determineJsonError(
(string) json_last_error()
);

return sprintf(
'%s is valid JSON (%s)',
$this->exporter()->shortenedExport($other),
$error
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function sprintf;
use Throwable;

final class ExceptionCode extends Constraint
{



private $expectedCode;




public function __construct($expected)
{
$this->expectedCode = $expected;
}

public function toString(): string
{
return 'exception code is ';
}







protected function matches($other): bool
{
return (string) $other->getCode() === (string) $this->expectedCode;
}











protected function failureDescription($other): string
{
return sprintf(
'%s is equal to expected exception code %s',
$this->exporter()->export($other->getCode()),
$this->exporter()->export($this->expectedCode)
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function sprintf;
use ReflectionClass;
use ReflectionException;







final class IsInstanceOf extends Constraint
{



private $className;

public function __construct(string $className)
{
$this->className = $className;
}




public function toString(): string
{
return sprintf(
'is instance of %s "%s"',
$this->getType(),
$this->className
);
}







protected function matches($other): bool
{
return $other instanceof $this->className;
}











protected function failureDescription($other): string
{
return sprintf(
'%s is an instance of %s "%s"',
$this->exporter()->shortenedExport($other),
$this->getType(),
$this->className
);
}

private function getType(): string
{
try {
$reflection = new ReflectionClass($this->className);

if ($reflection->isInterface()) {
return 'interface';
}
} catch (ReflectionException $e) {
}

return 'class';
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function sprintf;
use PHPUnit\Framework\Exception;
use ReflectionClass;
use ReflectionException;







final class ClassHasStaticAttribute extends ClassHasAttribute
{



public function toString(): string
{
return sprintf(
'has static attribute "%s"',
$this->attributeName()
);
}







protected function matches($other): bool
{
try {
$class = new ReflectionClass($other);

if ($class->hasProperty($this->attributeName())) {
return $class->getProperty($this->attributeName())->isStatic();
}

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


return false;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function is_array;
use function is_string;
use function sprintf;
use function strpos;
use SplObjectStorage;





final class TraversableContainsIdentical extends Constraint
{



private $value;

public function __construct($value)
{
$this->value = $value;
}






public function toString(): string
{
if (is_string($this->value) && strpos($this->value, "\n") !== false) {
return 'contains "' . $this->value . '"';
}

return 'contains ' . $this->exporter()->export($this->value);
}







protected function matches($other): bool
{
if ($other instanceof SplObjectStorage) {
return $other->contains($this->value);
}

foreach ($other as $element) {
if ($this->value === $element) {
return true;
}
}

return false;
}











protected function failureDescription($other): string
{
return sprintf(
'%s %s',
is_array($other) ? 'an array' : 'a traversable',
$this->toString()
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use const JSON_ERROR_CTRL_CHAR;
use const JSON_ERROR_DEPTH;
use const JSON_ERROR_NONE;
use const JSON_ERROR_STATE_MISMATCH;
use const JSON_ERROR_SYNTAX;
use const JSON_ERROR_UTF8;
use function strtolower;




final class JsonMatchesErrorMessageProvider
{



public static function determineJsonError(string $error, string $prefix = ''): ?string
{
switch ($error) {
case JSON_ERROR_NONE:
return null;
case JSON_ERROR_DEPTH:
return $prefix . 'Maximum stack depth exceeded';
case JSON_ERROR_STATE_MISMATCH:
return $prefix . 'Underflow or the modes mismatch';
case JSON_ERROR_CTRL_CHAR:
return $prefix . 'Unexpected control character found';
case JSON_ERROR_SYNTAX:
return $prefix . 'Syntax error, malformed JSON';
case JSON_ERROR_UTF8:
return $prefix . 'Malformed UTF-8 characters, possibly incorrectly encoded';

default:
return $prefix . 'Unknown error';
}
}




public static function translateTypeToPrefix(string $type): string
{
switch (strtolower($type)) {
case 'expected':
$prefix = 'Expected value JSON decode error - ';

break;
case 'actual':
$prefix = 'Actual value JSON decode error - ';

break;

default:
$prefix = '';

break;
}

return $prefix;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function get_resource_type;
use function is_array;
use function is_bool;
use function is_callable;
use function is_float;
use function is_int;
use function is_iterable;
use function is_numeric;
use function is_object;
use function is_resource;
use function is_scalar;
use function is_string;
use function sprintf;
use TypeError;







final class IsType extends Constraint
{



public const TYPE_ARRAY = 'array';




public const TYPE_BOOL = 'bool';




public const TYPE_FLOAT = 'float';




public const TYPE_INT = 'int';




public const TYPE_NULL = 'null';




public const TYPE_NUMERIC = 'numeric';




public const TYPE_OBJECT = 'object';




public const TYPE_RESOURCE = 'resource';




public const TYPE_STRING = 'string';




public const TYPE_SCALAR = 'scalar';




public const TYPE_CALLABLE = 'callable';




public const TYPE_ITERABLE = 'iterable';




private const KNOWN_TYPES = [
'array' => true,
'boolean' => true,
'bool' => true,
'double' => true,
'float' => true,
'integer' => true,
'int' => true,
'null' => true,
'numeric' => true,
'object' => true,
'real' => true,
'resource' => true,
'string' => true,
'scalar' => true,
'callable' => true,
'iterable' => true,
];




private $type;




public function __construct(string $type)
{
if (!isset(self::KNOWN_TYPES[$type])) {
throw new \PHPUnit\Framework\Exception(
sprintf(
'Type specified for PHPUnit\Framework\Constraint\IsType <%s> ' .
'is not a valid type.',
$type
)
);
}

$this->type = $type;
}




public function toString(): string
{
return sprintf(
'is of type "%s"',
$this->type
);
}







protected function matches($other): bool
{
switch ($this->type) {
case 'numeric':
return is_numeric($other);

case 'integer':
case 'int':
return is_int($other);

case 'double':
case 'float':
case 'real':
return is_float($other);

case 'string':
return is_string($other);

case 'boolean':
case 'bool':
return is_bool($other);

case 'null':
return null === $other;

case 'array':
return is_array($other);

case 'object':
return is_object($other);

case 'resource':
if (is_resource($other)) {
return true;
}

try {
$resource = @get_resource_type($other);

if (is_string($resource)) {
return true;
}
} catch (TypeError $e) {
}

return false;

case 'scalar':
return is_scalar($other);

case 'callable':
return is_callable($other);

case 'iterable':
return is_iterable($other);
}
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function count;
use function get_class;
use function preg_match;
use function str_replace;
use PHPUnit\Framework\ExpectationFailedException;




final class LogicalNot extends Constraint
{



private $constraint;

public static function negate(string $string): string
{
$positives = [
'contains ',
'exists',
'has ',
'is ',
'are ',
'matches ',
'starts with ',
'ends with ',
'reference ',
'not not ',
];

$negatives = [
'does not contain ',
'does not exist',
'does not have ',
'is not ',
'are not ',
'does not match ',
'starts not with ',
'ends not with ',
'don\'t reference ',
'not ',
];

preg_match('/(\'[\w\W]*\')([\w\W]*)("[\w\W]*")/i', $string, $matches);

if (count($matches) > 0) {
$nonInput = $matches[2];

$negatedString = str_replace(
$nonInput,
str_replace(
$positives,
$negatives,
$nonInput
),
$string
);
} else {
$negatedString = str_replace(
$positives,
$negatives,
$string
);
}

return $negatedString;
}




public function __construct($constraint)
{
if (!($constraint instanceof Constraint)) {
$constraint = new IsEqual($constraint);
}

$this->constraint = $constraint;
}














public function evaluate($other, string $description = '', bool $returnResult = false)
{
$success = !$this->constraint->evaluate($other, $description, true);

if ($returnResult) {
return $success;
}

if (!$success) {
$this->fail($other, $description);
}
}




public function toString(): string
{
switch (get_class($this->constraint)) {
case LogicalAnd::class:
case self::class:
case LogicalOr::class:
return 'not( ' . $this->constraint->toString() . ' )';

default:
return self::negate(
$this->constraint->toString()
);
}
}




public function count(): int
{
return count($this->constraint);
}











protected function failureDescription($other): string
{
switch (get_class($this->constraint)) {
case LogicalAnd::class:
case self::class:
case LogicalOr::class:
return 'not( ' . $this->constraint->failureDescription($other) . ' )';

default:
return self::negate(
$this->constraint->failureDescription($other)
);
}
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;




final class IsNull extends Constraint
{



public function toString(): string
{
return 'is null';
}







protected function matches($other): bool
{
return $other === null;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function is_dir;
use function sprintf;






final class DirectoryExists extends Constraint
{



public function toString(): string
{
return 'directory exists';
}







protected function matches($other): bool
{
return is_dir($other);
}









protected function failureDescription($other): string
{
return sprintf(
'directory "%s" exists',
$other
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function preg_match;
use function sprintf;










class RegularExpression extends Constraint
{



private $pattern;

public function __construct(string $pattern)
{
$this->pattern = $pattern;
}




public function toString(): string
{
return sprintf(
'matches PCRE pattern "%s"',
$this->pattern
);
}







protected function matches($other): bool
{
return preg_match($this->pattern, $other) > 0;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function sprintf;
use Exception;
use PHPUnit\Util\RegularExpression as RegularExpressionUtil;

final class ExceptionMessageRegularExpression extends Constraint
{



private $expectedMessageRegExp;

public function __construct(string $expected)
{
$this->expectedMessageRegExp = $expected;
}

public function toString(): string
{
return 'exception message matches ';
}










protected function matches($other): bool
{
$match = RegularExpressionUtil::safeMatch($this->expectedMessageRegExp, $other->getMessage());

if ($match === false) {
throw new \PHPUnit\Framework\Exception(
"Invalid expected exception message regex given: '{$this->expectedMessageRegExp}'"
);
}

return $match === 1;
}









protected function failureDescription($other): string
{
return sprintf(
"exception message '%s' matches '%s'",
$other->getMessage(),
$this->expectedMessageRegExp
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

final class SameSize extends Count
{
public function __construct(iterable $expected)
{
parent::__construct($this->getCountOf($expected));
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use ReflectionObject;







final class ObjectHasAttribute extends ClassHasAttribute
{






protected function matches($other): bool
{
return (new ReflectionObject($other))->hasProperty($this->attributeName());
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function json_decode;
use function sprintf;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Util\Json;
use SebastianBergmann\Comparator\ComparisonFailure;




final class JsonMatches extends Constraint
{



private $value;

public function __construct(string $value)
{
$this->value = $value;
}




public function toString(): string
{
return sprintf(
'matches JSON string "%s"',
$this->value
);
}









protected function matches($other): bool
{
[$error, $recodedOther] = Json::canonicalize($other);

if ($error) {
return false;
}

[$error, $recodedValue] = Json::canonicalize($this->value);

if ($error) {
return false;
}

return $recodedOther == $recodedValue;
}














protected function fail($other, $description, ComparisonFailure $comparisonFailure = null): void
{
if ($comparisonFailure === null) {
[$error, $recodedOther] = Json::canonicalize($other);

if ($error) {
parent::fail($other, $description);
}

[$error, $recodedValue] = Json::canonicalize($this->value);

if ($error) {
parent::fail($other, $description);
}

$comparisonFailure = new ComparisonFailure(
json_decode($this->value),
json_decode($other),
Json::prettify($recodedValue),
Json::prettify($recodedOther),
false,
'Failed asserting that two json values are equal.'
);
}

parent::fail($other, $description, $comparisonFailure);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function is_infinite;




final class IsInfinite extends Constraint
{



public function toString(): string
{
return 'is infinite';
}







protected function matches($other): bool
{
return is_infinite($other);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function is_nan;




final class IsNan extends Constraint
{



public function toString(): string
{
return 'is nan';
}







protected function matches($other): bool
{
return is_nan($other);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function get_class;
use function is_object;
use function sprintf;
use PHPUnit\Framework\Exception;
use ReflectionClass;
use ReflectionException;







class ClassHasAttribute extends Constraint
{



private $attributeName;

public function __construct(string $attributeName)
{
$this->attributeName = $attributeName;
}




public function toString(): string
{
return sprintf(
'has attribute "%s"',
$this->attributeName
);
}







protected function matches($other): bool
{
try {
return (new ReflectionClass($other))->hasProperty($this->attributeName);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}

 }









protected function failureDescription($other): string
{
return sprintf(
'%sclass "%s" %s',
is_object($other) ? 'object of ' : '',
is_object($other) ? get_class($other) : $other,
$this->toString()
);
}

protected function attributeName(): string
{
return $this->attributeName;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function is_array;
use function is_object;
use function is_string;
use function sprintf;
use function strpos;
use SplObjectStorage;







final class TraversableContains extends Constraint
{



private $checkForObjectIdentity;




private $checkForNonObjectIdentity;




private $value;

public function __construct($value, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false)
{
$this->checkForObjectIdentity = $checkForObjectIdentity;
$this->checkForNonObjectIdentity = $checkForNonObjectIdentity;
$this->value = $value;
}






public function toString(): string
{
if (is_string($this->value) && strpos($this->value, "\n") !== false) {
return 'contains "' . $this->value . '"';
}

return 'contains ' . $this->exporter()->export($this->value);
}







protected function matches($other): bool
{
if ($other instanceof SplObjectStorage) {
return $other->contains($this->value);
}

if (is_object($this->value)) {
foreach ($other as $element) {
if ($this->checkForObjectIdentity && $element === $this->value) {
return true;
}


if (!$this->checkForObjectIdentity && $element == $this->value) {
return true;
}
}
} else {
foreach ($other as $element) {
if ($this->checkForNonObjectIdentity && $element === $this->value) {
return true;
}


if (!$this->checkForNonObjectIdentity && $element == $this->value) {
return true;
}
}
}

return false;
}











protected function failureDescription($other): string
{
return sprintf(
'%s %s',
is_array($other) ? 'an array' : 'a traversable',
$this->toString()
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function sprintf;
use Countable;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\SelfDescribing;
use SebastianBergmann\Comparator\ComparisonFailure;
use SebastianBergmann\Exporter\Exporter;




abstract class Constraint implements Countable, SelfDescribing
{



private $exporter;














public function evaluate($other, string $description = '', bool $returnResult = false)
{
$success = false;

if ($this->matches($other)) {
$success = true;
}

if ($returnResult) {
return $success;
}

if (!$success) {
$this->fail($other, $description);
}
}




public function count(): int
{
return 1;
}

protected function exporter(): Exporter
{
if ($this->exporter === null) {
$this->exporter = new Exporter;
}

return $this->exporter;
}










protected function matches($other): bool
{
return false;
}













protected function fail($other, $description, ComparisonFailure $comparisonFailure = null): void
{
$failureDescription = sprintf(
'Failed asserting that %s.',
$this->failureDescription($other)
);

$additionalFailureDescription = $this->additionalFailureDescription($other);

if ($additionalFailureDescription) {
$failureDescription .= "\n" . $additionalFailureDescription;
}

if (!empty($description)) {
$failureDescription = $description . "\n" . $failureDescription;
}

throw new ExpectationFailedException(
$failureDescription,
$comparisonFailure
);
}









protected function additionalFailureDescription($other): string
{
return '';
}














protected function failureDescription($other): string
{
return $this->exporter()->export($other) . ' ' . $this->toString();
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function count;
use PHPUnit\Framework\ExpectationFailedException;





abstract class Composite extends Constraint
{



private $innerConstraint;

public function __construct(Constraint $innerConstraint)
{
$this->innerConstraint = $innerConstraint;
}














public function evaluate($other, string $description = '', bool $returnResult = false)
{
try {
return $this->innerConstraint->evaluate(
$other,
$description,
$returnResult
);
} catch (ExpectationFailedException $e) {
$this->fail($other, $description, $e->getComparisonFailure());
}
}




public function count(): int
{
return count($this->innerConstraint);
}

protected function innerConstraint(): Constraint
{
return $this->innerConstraint;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;





final class LessThan extends Constraint
{



private $value;




public function __construct($value)
{
$this->value = $value;
}






public function toString(): string
{
return 'is less than ' . $this->exporter()->export($this->value);
}







protected function matches($other): bool
{
return $this->value > $other;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function strlen;
use function strpos;
use PHPUnit\Framework\InvalidArgumentException;





final class StringStartsWith extends Constraint
{



private $prefix;

public function __construct(string $prefix)
{
if (strlen($prefix) === 0) {
throw InvalidArgumentException::create(1, 'non-empty string');
}

$this->prefix = $prefix;
}




public function toString(): string
{
return 'starts with "' . $this->prefix . '"';
}







protected function matches($other): bool
{
return strpos((string) $other, $this->prefix) === 0;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function is_string;
use function sprintf;
use function strpos;
use function trim;
use PHPUnit\Framework\ExpectationFailedException;
use SebastianBergmann\Comparator\ComparisonFailure;
use SebastianBergmann\Comparator\Factory as ComparatorFactory;










final class IsEqual extends Constraint
{



private $value;




private $delta;




private $canonicalize;




private $ignoreCase;

public function __construct($value, float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false)
{
$this->value = $value;
$this->delta = $delta;
$this->canonicalize = $canonicalize;
$this->ignoreCase = $ignoreCase;
}













public function evaluate($other, string $description = '', bool $returnResult = false)
{

 
 
 if ($this->value === $other) {
return true;
}

$comparatorFactory = ComparatorFactory::getInstance();

try {
$comparator = $comparatorFactory->getComparatorFor(
$this->value,
$other
);

$comparator->assertEquals(
$this->value,
$other,
$this->delta,
$this->canonicalize,
$this->ignoreCase
);
} catch (ComparisonFailure $f) {
if ($returnResult) {
return false;
}

throw new ExpectationFailedException(
trim($description . "\n" . $f->getMessage()),
$f
);
}

return true;
}






public function toString(): string
{
$delta = '';

if (is_string($this->value)) {
if (strpos($this->value, "\n") !== false) {
return 'is equal to <text>';
}

return sprintf(
"is equal to '%s'",
$this->value
);
}

if ($this->delta != 0) {
$delta = sprintf(
' with delta <%F>',
$this->delta
);
}

return sprintf(
'is equal to %s%s',
$this->exporter()->export($this->value),
$delta
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function array_replace_recursive;
use function is_array;
use function iterator_to_array;
use function var_export;
use ArrayObject;
use PHPUnit\Framework\ExpectationFailedException;
use SebastianBergmann\Comparator\ComparisonFailure;
use Traversable;











final class ArraySubset extends Constraint
{



private $subset;




private $strict;

public function __construct(iterable $subset, bool $strict = false)
{
$this->strict = $strict;
$this->subset = $subset;
}














public function evaluate($other, string $description = '', bool $returnResult = false)
{

 
 $other = $this->toArray($other);
$this->subset = $this->toArray($this->subset);

$patched = array_replace_recursive($other, $this->subset);

if ($this->strict) {
$result = $other === $patched;
} else {
$result = $other == $patched;
}

if ($returnResult) {
return $result;
}

if (!$result) {
$f = new ComparisonFailure(
$patched,
$other,
var_export($patched, true),
var_export($other, true)
);

$this->fail($other, $description, $f);
}
}






public function toString(): string
{
return 'has the subset ' . $this->exporter()->export($this->subset);
}











protected function failureDescription($other): string
{
return 'an array ' . $this->toString();
}

private function toArray(iterable $other): array
{
if (is_array($other)) {
return $other;
}

if ($other instanceof ArrayObject) {
return $other->getArrayCopy();
}

if ($other instanceof Traversable) {
return iterator_to_array($other);
}


 return (array) $other;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use const DIRECTORY_SEPARATOR;
use function explode;
use function implode;
use function preg_match;
use function preg_quote;
use function preg_replace;
use function strtr;
use SebastianBergmann\Diff\Differ;




final class StringMatchesFormatDescription extends RegularExpression
{



private $string;

public function __construct(string $string)
{
parent::__construct(
$this->createPatternFromFormat(
$this->convertNewlines($string)
)
);

$this->string = $string;
}







protected function matches($other): bool
{
return parent::matches(
$this->convertNewlines($other)
);
}

protected function failureDescription($other): string
{
return 'string matches format description';
}

protected function additionalFailureDescription($other): string
{
$from = explode("\n", $this->string);
$to = explode("\n", $this->convertNewlines($other));

foreach ($from as $index => $line) {
if (isset($to[$index]) && $line !== $to[$index]) {
$line = $this->createPatternFromFormat($line);

if (preg_match($line, $to[$index]) > 0) {
$from[$index] = $to[$index];
}
}
}

$this->string = implode("\n", $from);
$other = implode("\n", $to);

return (new Differ("--- Expected\n+++ Actual\n"))->diff($this->string, $other);
}

private function createPatternFromFormat(string $string): string
{
$string = strtr(
preg_quote($string, '/'),
[
'%%' => '%',
'%e' => '\\' . DIRECTORY_SEPARATOR,
'%s' => '[^\r\n]+',
'%S' => '[^\r\n]*',
'%a' => '.+',
'%A' => '.*',
'%w' => '\s*',
'%i' => '[+-]?\d+',
'%d' => '\d+',
'%x' => '[0-9a-fA-F]+',
'%f' => '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?',
'%c' => '.',
]
);

return '/^' . $string . '$/s';
}

private function convertNewlines($text): string
{
return preg_replace('/\r\n/', "\n", $text);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function is_finite;




final class IsFinite extends Constraint
{



public function toString(): string
{
return 'is finite';
}







protected function matches($other): bool
{
return is_finite($other);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\Constraint;

use function array_values;
use function count;
use PHPUnit\Framework\ExpectationFailedException;




final class LogicalOr extends Constraint
{



private $constraints = [];

public static function fromConstraints(Constraint ...$constraints): self
{
$constraint = new self;

$constraint->constraints = array_values($constraints);

return $constraint;
}




public function setConstraints(array $constraints): void
{
$this->constraints = [];

foreach ($constraints as $constraint) {
if (!($constraint instanceof Constraint)) {
$constraint = new IsEqual(
$constraint
);
}

$this->constraints[] = $constraint;
}
}














public function evaluate($other, string $description = '', bool $returnResult = false)
{
$success = false;

foreach ($this->constraints as $constraint) {
if ($constraint->evaluate($other, $description, true)) {
$success = true;

break;
}
}

if ($returnResult) {
return $success;
}

if (!$success) {
$this->fail($other, $description);
}
}




public function toString(): string
{
$text = '';

foreach ($this->constraints as $key => $constraint) {
if ($key > 0) {
$text .= ' or ';
}

$text .= $constraint->toString();
}

return $text;
}




public function count(): int
{
$count = 0;

foreach ($this->constraints as $constraint) {
$count += count($constraint);
}

return $count;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;

use function assert;
use function count;
use function get_class;
use function sprintf;
use function trim;
use PHPUnit\Util\Filter;
use PHPUnit\Util\InvalidDataSetException;
use PHPUnit\Util\Test as TestUtil;
use ReflectionClass;
use Throwable;




final class TestBuilder
{
public function build(ReflectionClass $theClass, string $methodName): Test
{
$className = $theClass->getName();

if (!$theClass->isInstantiable()) {
return new WarningTestCase(
sprintf('Cannot instantiate class "%s".', $className)
);
}

$backupSettings = TestUtil::getBackupSettings(
$className,
$methodName
);

$preserveGlobalState = TestUtil::getPreserveGlobalStateSettings(
$className,
$methodName
);

$runTestInSeparateProcess = TestUtil::getProcessIsolationSettings(
$className,
$methodName
);

$runClassInSeparateProcess = TestUtil::getClassProcessIsolationSettings(
$className,
$methodName
);

$constructor = $theClass->getConstructor();

if ($constructor === null) {
throw new Exception('No valid test provided.');
}

$parameters = $constructor->getParameters();


 if (count($parameters) < 2) {
$test = $this->buildTestWithoutData($className);
} 
 else {
try {
$data = TestUtil::getProvidedData(
$className,
$methodName
);
} catch (IncompleteTestError $e) {
$message = sprintf(
"Test for %s::%s marked incomplete by data provider\n%s",
$className,
$methodName,
$this->throwableToString($e)
);

$data = new IncompleteTestCase($className, $methodName, $message);
} catch (SkippedTestError $e) {
$message = sprintf(
"Test for %s::%s skipped by data provider\n%s",
$className,
$methodName,
$this->throwableToString($e)
);

$data = new SkippedTestCase($className, $methodName, $message);
} catch (Throwable $t) {
$message = sprintf(
"The data provider specified for %s::%s is invalid.\n%s",
$className,
$methodName,
$this->throwableToString($t)
);

$data = new WarningTestCase($message);
}


 if (isset($data)) {
$test = $this->buildDataProviderTestSuite(
$methodName,
$className,
$data,
$runTestInSeparateProcess,
$preserveGlobalState,
$runClassInSeparateProcess,
$backupSettings
);
} else {
$test = $this->buildTestWithoutData($className);
}
}

if ($test instanceof TestCase) {
$test->setName($methodName);
$this->configureTestCase(
$test,
$runTestInSeparateProcess,
$preserveGlobalState,
$runClassInSeparateProcess,
$backupSettings
);
}

return $test;
}


private function buildTestWithoutData(string $className)
{
return new $className;
}


private function buildDataProviderTestSuite(
string $methodName,
string $className,
$data,
bool $runTestInSeparateProcess,
?bool $preserveGlobalState,
bool $runClassInSeparateProcess,
array $backupSettings
): DataProviderTestSuite {
$dataProviderTestSuite = new DataProviderTestSuite(
$className . '::' . $methodName
);

$groups = TestUtil::getGroups($className, $methodName);

if ($data instanceof WarningTestCase ||
$data instanceof SkippedTestCase ||
$data instanceof IncompleteTestCase) {
$dataProviderTestSuite->addTest($data, $groups);
} else {
foreach ($data as $_dataName => $_data) {
$_test = new $className($methodName, $_data, $_dataName);

assert($_test instanceof TestCase);

$this->configureTestCase(
$_test,
$runTestInSeparateProcess,
$preserveGlobalState,
$runClassInSeparateProcess,
$backupSettings
);

$dataProviderTestSuite->addTest($_test, $groups);
}
}

return $dataProviderTestSuite;
}

private function configureTestCase(
TestCase $test,
bool $runTestInSeparateProcess,
?bool $preserveGlobalState,
bool $runClassInSeparateProcess,
array $backupSettings
): void {
if ($runTestInSeparateProcess) {
$test->setRunTestInSeparateProcess(true);

if ($preserveGlobalState !== null) {
$test->setPreserveGlobalState($preserveGlobalState);
}
}

if ($runClassInSeparateProcess) {
$test->setRunClassInSeparateProcess(true);

if ($preserveGlobalState !== null) {
$test->setPreserveGlobalState($preserveGlobalState);
}
}

if ($backupSettings['backupGlobals'] !== null) {
$test->setBackupGlobals($backupSettings['backupGlobals']);
}

if ($backupSettings['backupStaticAttributes'] !== null) {
$test->setBackupStaticAttributes(
$backupSettings['backupStaticAttributes']
);
}
}

private function throwableToString(Throwable $t): string
{
$message = $t->getMessage();

if (empty(trim($message))) {
$message = '<no message>';
}

if ($t instanceof InvalidDataSetException) {
return sprintf(
"%s\n%s",
$message,
Filter::getFilteredStacktrace($t)
);
}

return sprintf(
"%s: %s\n%s",
get_class($t),
$message,
Filter::getFilteredStacktrace($t)
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use function call_user_func;
use function class_exists;




final class MockClass implements MockType
{



private $classCode;




private $mockName;




private $configurableMethods;

public function __construct(string $classCode, string $mockName, array $configurableMethods)
{
$this->classCode = $classCode;
$this->mockName = $mockName;
$this->configurableMethods = $configurableMethods;
}

public function generate(): string
{
if (!class_exists($this->mockName, false)) {
eval($this->classCode);

call_user_func(
[
$this->mockName,
'__phpunit_initConfigurableMethods',
],
...$this->configurableMethods
);
}

return $this->mockName;
}

public function getClassCode(): string
{
return $this->classCode;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use function array_key_exists;
use function array_values;
use function strtolower;




final class MockMethodSet
{



private $methods = [];

public function addMethods(MockMethod ...$methods): void
{
foreach ($methods as $method) {
$this->methods[strtolower($method->getName())] = $method;
}
}




public function asArray(): array
{
return array_values($this->methods);
}

public function hasMethod(string $methodName): bool
{
return array_key_exists(strtolower($methodName), $this->methods);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Rule;

use function count;
use function gettype;
use function is_iterable;
use function sprintf;
use PHPUnit\Framework\Constraint\Constraint;
use PHPUnit\Framework\Constraint\IsEqual;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\InvalidParameterGroupException;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;




final class ConsecutiveParameters implements ParametersRule
{



private $parameterGroups = [];




private $invocations = [];




public function __construct(array $parameterGroups)
{
foreach ($parameterGroups as $index => $parameters) {
if (!is_iterable($parameters)) {
throw new InvalidParameterGroupException(
sprintf(
'Parameter group #%d must be an array or Traversable, got %s',
$index,
gettype($parameters)
)
);
}

foreach ($parameters as $parameter) {
if (!$parameter instanceof Constraint) {
$parameter = new IsEqual($parameter);
}

$this->parameterGroups[$index][] = $parameter;
}
}
}

public function toString(): string
{
return 'with consecutive parameters';
}





public function apply(BaseInvocation $invocation): void
{
$this->invocations[] = $invocation;
$callIndex = count($this->invocations) - 1;

$this->verifyInvocation($invocation, $callIndex);
}





public function verify(): void
{
foreach ($this->invocations as $callIndex => $invocation) {
$this->verifyInvocation($invocation, $callIndex);
}
}









private function verifyInvocation(BaseInvocation $invocation, $callIndex): void
{
if (!isset($this->parameterGroups[$callIndex])) {

 return;
}

if ($invocation === null) {
throw new ExpectationFailedException(
'Mocked method does not exist.'
);
}

$parameters = $this->parameterGroups[$callIndex];

if (count($invocation->getParameters()) < count($parameters)) {
throw new ExpectationFailedException(
sprintf(
'Parameter count for invocation %s is too low.',
$invocation->toString()
)
);
}

foreach ($parameters as $i => $parameter) {
$parameter->evaluate(
$invocation->getParameters()[$i],
sprintf(
'Parameter %s for invocation #%d %s does not match expected ' .
'value.',
$i,
$callIndex,
$invocation->toString()
)
);
}
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Rule;

use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;




final class InvokedAtLeastOnce extends InvocationOrder
{
public function toString(): string
{
return 'invoked at least once';
}







public function verify(): void
{
$count = $this->getInvocationCount();

if ($count < 1) {
throw new ExpectationFailedException(
'Expected invocation at least once but it never occurred.'
);
}
}

public function matches(BaseInvocation $invocation): bool
{
return true;
}

protected function invokedDo(BaseInvocation $invocation): void
{
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Rule;

use function sprintf;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;




final class InvokedCount extends InvocationOrder
{



private $expectedCount;




public function __construct($expectedCount)
{
$this->expectedCount = $expectedCount;
}

public function isNever(): bool
{
return $this->expectedCount === 0;
}

public function toString(): string
{
return 'invoked ' . $this->expectedCount . ' time(s)';
}

public function matches(BaseInvocation $invocation): bool
{
return true;
}







public function verify(): void
{
$count = $this->getInvocationCount();

if ($count !== $this->expectedCount) {
throw new ExpectationFailedException(
sprintf(
'Method was expected to be called %d times, ' .
'actually called %d times.',
$this->expectedCount,
$count
)
);
}
}




protected function invokedDo(BaseInvocation $invocation): void
{
$count = $this->getInvocationCount();

if ($count > $this->expectedCount) {
$message = $invocation->toString() . ' ';

switch ($this->expectedCount) {
case 0:
$message .= 'was not expected to be called.';

break;

case 1:
$message .= 'was not expected to be called more than once.';

break;

default:
$message .= sprintf(
'was not expected to be called more than %d times.',
$this->expectedCount
);
}

throw new ExpectationFailedException($message);
}
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Rule;

use function count;
use function get_class;
use function sprintf;
use Exception;
use PHPUnit\Framework\Constraint\Constraint;
use PHPUnit\Framework\Constraint\IsAnything;
use PHPUnit\Framework\Constraint\IsEqual;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;




final class Parameters implements ParametersRule
{



private $parameters = [];




private $invocation;




private $parameterVerificationResult;




public function __construct(array $parameters)
{
foreach ($parameters as $parameter) {
if (!($parameter instanceof Constraint)) {
$parameter = new IsEqual(
$parameter
);
}

$this->parameters[] = $parameter;
}
}

public function toString(): string
{
$text = 'with parameter';

foreach ($this->parameters as $index => $parameter) {
if ($index > 0) {
$text .= ' and';
}

$text .= ' ' . $index . ' ' . $parameter->toString();
}

return $text;
}




public function apply(BaseInvocation $invocation): void
{
$this->invocation = $invocation;
$this->parameterVerificationResult = null;

try {
$this->parameterVerificationResult = $this->doVerify();
} catch (ExpectationFailedException $e) {
$this->parameterVerificationResult = $e;

throw $this->parameterVerificationResult;
}
}









public function verify(): void
{
$this->doVerify();
}





private function doVerify(): bool
{
if (isset($this->parameterVerificationResult)) {
return $this->guardAgainstDuplicateEvaluationOfParameterConstraints();
}

if ($this->invocation === null) {
throw new ExpectationFailedException('Mocked method does not exist.');
}

if (count($this->invocation->getParameters()) < count($this->parameters)) {
$message = 'Parameter count for invocation %s is too low.';


 
 
 
 if (count($this->parameters) === 1 &&
get_class($this->parameters[0]) === IsAnything::class) {
$message .= "\nTo allow 0 or more parameters with any value, omit ->with() or use ->withAnyParameters() instead.";
}

throw new ExpectationFailedException(
sprintf($message, $this->invocation->toString())
);
}

foreach ($this->parameters as $i => $parameter) {
$parameter->evaluate(
$this->invocation->getParameters()[$i],
sprintf(
'Parameter %s for invocation %s does not match expected ' .
'value.',
$i,
$this->invocation->toString()
)
);
}

return true;
}




private function guardAgainstDuplicateEvaluationOfParameterConstraints(): bool
{
if ($this->parameterVerificationResult instanceof ExpectationFailedException) {
throw $this->parameterVerificationResult;
}

return (bool) $this->parameterVerificationResult;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Rule;

use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;




final class InvokedAtLeastCount extends InvocationOrder
{



private $requiredInvocations;




public function __construct($requiredInvocations)
{
$this->requiredInvocations = $requiredInvocations;
}

public function toString(): string
{
return 'invoked at least ' . $this->requiredInvocations . ' times';
}







public function verify(): void
{
$count = $this->getInvocationCount();

if ($count < $this->requiredInvocations) {
throw new ExpectationFailedException(
'Expected invocation at least ' . $this->requiredInvocations .
' times but it occurred ' . $count . ' time(s).'
);
}
}

public function matches(BaseInvocation $invocation): bool
{
return true;
}

protected function invokedDo(BaseInvocation $invocation): void
{
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Rule;

use function count;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
use PHPUnit\Framework\MockObject\Verifiable;
use PHPUnit\Framework\SelfDescribing;




abstract class InvocationOrder implements SelfDescribing, Verifiable
{



private $invocations = [];

public function getInvocationCount(): int
{
return count($this->invocations);
}

public function hasBeenInvoked(): bool
{
return count($this->invocations) > 0;
}

final public function invoked(BaseInvocation $invocation)
{
$this->invocations[] = $invocation;

return $this->invokedDo($invocation);
}

abstract public function matches(BaseInvocation $invocation): bool;

abstract protected function invokedDo(BaseInvocation $invocation);
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Rule;

use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;




final class AnyParameters implements ParametersRule
{
public function toString(): string
{
return 'with any parameters';
}

public function apply(BaseInvocation $invocation): void
{
}

public function verify(): void
{
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Rule;

use function sprintf;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;




class InvokedAtIndex extends InvocationOrder
{



private $sequenceIndex;




private $currentIndex = -1;




public function __construct($sequenceIndex)
{
$this->sequenceIndex = $sequenceIndex;
}

public function toString(): string
{
return 'invoked at sequence index ' . $this->sequenceIndex;
}

public function matches(BaseInvocation $invocation): bool
{
$this->currentIndex++;

return $this->currentIndex == $this->sequenceIndex;
}







public function verify(): void
{
if ($this->currentIndex < $this->sequenceIndex) {
throw new ExpectationFailedException(
sprintf(
'The expected invocation at index %s was never reached.',
$this->sequenceIndex
)
);
}
}

protected function invokedDo(BaseInvocation $invocation): void
{
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Rule;

use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;




final class InvokedAtMostCount extends InvocationOrder
{



private $allowedInvocations;




public function __construct($allowedInvocations)
{
$this->allowedInvocations = $allowedInvocations;
}

public function toString(): string
{
return 'invoked at most ' . $this->allowedInvocations . ' times';
}







public function verify(): void
{
$count = $this->getInvocationCount();

if ($count > $this->allowedInvocations) {
throw new ExpectationFailedException(
'Expected invocation at most ' . $this->allowedInvocations .
' times but it occurred ' . $count . ' time(s).'
);
}
}

public function matches(BaseInvocation $invocation): bool
{
return true;
}

protected function invokedDo(BaseInvocation $invocation): void
{
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Rule;

use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;




final class AnyInvokedCount extends InvocationOrder
{
public function toString(): string
{
return 'invoked zero or more times';
}

public function verify(): void
{
}

public function matches(BaseInvocation $invocation): bool
{
return true;
}

protected function invokedDo(BaseInvocation $invocation): void
{
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Rule;

use function is_string;
use PHPUnit\Framework\Constraint\Constraint;
use PHPUnit\Framework\InvalidArgumentException;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
use PHPUnit\Framework\MockObject\MethodNameConstraint;




final class MethodName
{



private $constraint;






public function __construct($constraint)
{
if (is_string($constraint)) {
$constraint = new MethodNameConstraint($constraint);
}

if (!$constraint instanceof Constraint) {
throw InvalidArgumentException::create(1, 'PHPUnit\Framework\Constraint\Constraint object or string');
}

$this->constraint = $constraint;
}

public function toString(): string
{
return 'method name ' . $this->constraint->toString();
}





public function matches(BaseInvocation $invocation): bool
{
return $this->matchesName($invocation->getMethodName());
}

public function matchesName(string $methodName): bool
{
return $this->constraint->evaluate($methodName, '', true);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Rule;

use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
use PHPUnit\Framework\MockObject\Verifiable;
use PHPUnit\Framework\SelfDescribing;

interface ParametersRule extends SelfDescribing, Verifiable
{



public function apply(BaseInvocation $invocation): void;

public function verify(): void;
}

    {modifier} function {reference}{method_name}({arguments_decl}){return_declaration}
    {
        $__phpunit_arguments = [{arguments_call}];
        $__phpunit_count     = func_num_args();

        if ($__phpunit_count > {arguments_count}) {
            $__phpunit_arguments_tmp = func_get_args();

            for ($__phpunit_i = {arguments_count}; $__phpunit_i < $__phpunit_count; $__phpunit_i++) {
                $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i];
            }
        }

        $this->__phpunit_getInvocationHandler()->invoke(
            new \PHPUnit\Framework\MockObject\Invocation(
                '{class_name}', '{method_name}', $__phpunit_arguments, '{return_declaration}', $this, {clone_arguments}, true
            )
        );

        call_user_func_array(array($this->__phpunit_originalObject, "{method_name}"), $__phpunit_arguments);
    }

    {modifier} function {reference}{method_name}({arguments_decl}){return_declaration}
    {{deprecation}
        $__phpunit_arguments = [{arguments_call}];
        $__phpunit_count     = func_num_args();

        if ($__phpunit_count > {arguments_count}) {
            $__phpunit_arguments_tmp = func_get_args();

            for ($__phpunit_i = {arguments_count}; $__phpunit_i < $__phpunit_count; $__phpunit_i++) {
                $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i];
            }
        }

        $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke(
            new \PHPUnit\Framework\MockObject\Invocation(
                '{class_name}', '{method_name}', $__phpunit_arguments, '{return_declaration}', $this, {clone_arguments}
            )
        );

        return $__phpunit_result;
    }

    {modifier} function {reference}{method_name}({arguments_decl}){return_declaration}
    {{deprecation}
        $__phpunit_arguments = [{arguments_call}];
        $__phpunit_count     = func_num_args();

        if ($__phpunit_count > {arguments_count}) {
            $__phpunit_arguments_tmp = func_get_args();

            for ($__phpunit_i = {arguments_count}; $__phpunit_i < $__phpunit_count; $__phpunit_i++) {
                $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i];
            }
        }

        $this->__phpunit_getInvocationHandler()->invoke(
            new \PHPUnit\Framework\MockObject\Invocation(
                '{class_name}', '{method_name}', $__phpunit_arguments, '{return_declaration}', $this, {clone_arguments}
            )
        );
    }
declare(strict_types=1);

{prologue}class {class_name}
{
    use {trait_name};
}

    {modifier} function {reference}{method_name}({arguments_decl}){return_declaration}
    {
        throw new \PHPUnit\Framework\MockObject\BadMethodCallException('Static method "{method_name}" cannot be invoked on mock object');
    }

        @trigger_error({deprecation}, E_USER_DEPRECATED);
declare(strict_types=1);

{namespace}class {class_name} extends \SoapClient
{
    public function __construct($wsdl, array $options)
    {
        parent::__construct('{wsdl}', $options);
    }
{methods}}

    public function {method_name}({arguments})
    {
    }

    {modifier} function {reference}{method_name}({arguments_decl}){return_declaration}
    {
        $__phpunit_arguments = [{arguments_call}];
        $__phpunit_count     = func_num_args();

        if ($__phpunit_count > {arguments_count}) {
            $__phpunit_arguments_tmp = func_get_args();

            for ($__phpunit_i = {arguments_count}; $__phpunit_i < $__phpunit_count; $__phpunit_i++) {
                $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i];
            }
        }

        $this->__phpunit_getInvocationHandler()->invoke(
            new \PHPUnit\Framework\MockObject\Invocation(
                '{class_name}', '{method_name}', $__phpunit_arguments, '{return_declaration}', $this, {clone_arguments}, true
            )
        );

        return call_user_func_array(array($this->__phpunit_originalObject, "{method_name}"), $__phpunit_arguments);
    }
declare(strict_types=1);

{prologue}{class_declaration}
{
    use \PHPUnit\Framework\MockObject\Api;{method}{clone}
{mocked_methods}}{epilogue}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use const DIRECTORY_SEPARATOR;
use function implode;
use function is_string;
use function method_exists;
use function preg_match;
use function preg_replace;
use function sprintf;
use function str_replace;
use function substr_count;
use function trim;
use function var_export;
use ReflectionException;
use ReflectionMethod;
use ReflectionNamedType;
use ReflectionType;
use SebastianBergmann\Type\ObjectType;
use SebastianBergmann\Type\Type;
use SebastianBergmann\Type\UnknownType;
use SebastianBergmann\Type\VoidType;
use Text_Template;




final class MockMethod
{



private static $templates = [];




private $className;




private $methodName;




private $cloneArguments;




private $modifier;




private $argumentsForDeclaration;




private $argumentsForCall;




private $returnType;




private $reference;




private $callOriginalMethod;




private $static;




private $deprecation;




public static function fromReflection(ReflectionMethod $method, bool $callOriginalMethod, bool $cloneArguments): self
{
if ($method->isPrivate()) {
$modifier = 'private';
} elseif ($method->isProtected()) {
$modifier = 'protected';
} else {
$modifier = 'public';
}

if ($method->isStatic()) {
$modifier .= ' static';
}

if ($method->returnsReference()) {
$reference = '&';
} else {
$reference = '';
}

$docComment = $method->getDocComment();

if (is_string($docComment) &&
preg_match('#\*[ \t]*+@deprecated[ \t]*+(.*?)\r?+\n[ \t]*+\*(?:[ \t]*+@|/$)#s', $docComment, $deprecation)) {
$deprecation = trim(preg_replace('#[ \t]*\r?\n[ \t]*+\*[ \t]*+#', ' ', $deprecation[1]));
} else {
$deprecation = null;
}

return new self(
$method->getDeclaringClass()->getName(),
$method->getName(),
$cloneArguments,
$modifier,
self::getMethodParametersForDeclaration($method),
self::getMethodParametersForCall($method),
self::deriveReturnType($method),
$reference,
$callOriginalMethod,
$method->isStatic(),
$deprecation
);
}

public static function fromName(string $fullClassName, string $methodName, bool $cloneArguments): self
{
return new self(
$fullClassName,
$methodName,
$cloneArguments,
'public',
'',
'',
new UnknownType,
'',
false,
false,
null
);
}

public function __construct(string $className, string $methodName, bool $cloneArguments, string $modifier, string $argumentsForDeclaration, string $argumentsForCall, Type $returnType, string $reference, bool $callOriginalMethod, bool $static, ?string $deprecation)
{
$this->className = $className;
$this->methodName = $methodName;
$this->cloneArguments = $cloneArguments;
$this->modifier = $modifier;
$this->argumentsForDeclaration = $argumentsForDeclaration;
$this->argumentsForCall = $argumentsForCall;
$this->returnType = $returnType;
$this->reference = $reference;
$this->callOriginalMethod = $callOriginalMethod;
$this->static = $static;
$this->deprecation = $deprecation;
}

public function getName(): string
{
return $this->methodName;
}




public function generateCode(): string
{
if ($this->static) {
$templateFile = 'mocked_static_method.tpl';
} elseif ($this->returnType instanceof VoidType) {
$templateFile = sprintf(
'%s_method_void.tpl',
$this->callOriginalMethod ? 'proxied' : 'mocked'
);
} else {
$templateFile = sprintf(
'%s_method.tpl',
$this->callOriginalMethod ? 'proxied' : 'mocked'
);
}

$deprecation = $this->deprecation;

if (null !== $this->deprecation) {
$deprecation = "The {$this->className}::{$this->methodName} method is deprecated ({$this->deprecation}).";
$deprecationTemplate = $this->getTemplate('deprecation.tpl');

$deprecationTemplate->setVar([
'deprecation' => var_export($deprecation, true),
]);

$deprecation = $deprecationTemplate->render();
}





$returnTypeDeclaration = str_replace(
'?mixed',
'mixed',
$this->returnType->getReturnTypeDeclaration()
);

$template = $this->getTemplate($templateFile);

$template->setVar(
[
'arguments_decl' => $this->argumentsForDeclaration,
'arguments_call' => $this->argumentsForCall,
'return_declaration' => $returnTypeDeclaration,
'arguments_count' => !empty($this->argumentsForCall) ? substr_count($this->argumentsForCall, ',') + 1 : 0,
'class_name' => $this->className,
'method_name' => $this->methodName,
'modifier' => $this->modifier,
'reference' => $this->reference,
'clone_arguments' => $this->cloneArguments ? 'true' : 'false',
'deprecation' => $deprecation,
]
);

return $template->render();
}

public function getReturnType(): Type
{
return $this->returnType;
}

private function getTemplate(string $template): Text_Template
{
$filename = __DIR__ . DIRECTORY_SEPARATOR . 'Generator' . DIRECTORY_SEPARATOR . $template;

if (!isset(self::$templates[$filename])) {
self::$templates[$filename] = new Text_Template($filename);
}

return self::$templates[$filename];
}






private static function getMethodParametersForDeclaration(ReflectionMethod $method): string
{
$parameters = [];

foreach ($method->getParameters() as $i => $parameter) {
$name = '$' . $parameter->getName();




if ($name === '$' || $name === '$...') {
$name = '$arg' . $i;
}

$nullable = '';
$default = '';
$reference = '';
$typeDeclaration = '';
$type = null;
$typeName = null;

if ($parameter->hasType()) {
$type = $parameter->getType();

if ($type instanceof ReflectionNamedType) {
$typeName = $type->getName();
}
}

if ($parameter->isVariadic()) {
$name = '...' . $name;
} elseif ($parameter->isDefaultValueAvailable()) {
$default = ' = ' . var_export($parameter->getDefaultValue(), true);
} elseif ($parameter->isOptional()) {
$default = ' = null';
}

if ($type !== null) {
if ($typeName !== 'mixed' && $parameter->allowsNull()) {
$nullable = '?';
}

if ($typeName === 'self') {
$typeDeclaration = $method->getDeclaringClass()->getName() . ' ';
} elseif ($typeName !== null) {
$typeDeclaration = $typeName . ' ';
}
}

if ($parameter->isPassedByReference()) {
$reference = '&';
}

$parameters[] = $nullable . $typeDeclaration . $reference . $name . $default;
}

return implode(', ', $parameters);
}






private static function getMethodParametersForCall(ReflectionMethod $method): string
{
$parameters = [];

foreach ($method->getParameters() as $i => $parameter) {
$name = '$' . $parameter->getName();




if ($name === '$' || $name === '$...') {
$name = '$arg' . $i;
}

if ($parameter->isVariadic()) {
continue;
}

if ($parameter->isPassedByReference()) {
$parameters[] = '&' . $name;
} else {
$parameters[] = $name;
}
}

return implode(', ', $parameters);
}

private static function deriveReturnType(ReflectionMethod $method): Type
{
$returnType = self::reflectionMethodGetReturnType($method);

if ($returnType === null) {
return new UnknownType;
}


 if ($returnType instanceof ReflectionNamedType && $returnType->getName() === 'self') {
return ObjectType::fromName($method->getDeclaringClass()->getName(), $returnType->allowsNull());
}


 if ($returnType instanceof ReflectionNamedType && $returnType->getName() === 'parent') {
$parentClass = $method->getDeclaringClass()->getParentClass();

if ($parentClass === false) {
throw new RuntimeException(
sprintf(
'Cannot mock %s::%s because "parent" return type declaration is used but %s does not have a parent class',
$method->getDeclaringClass()->getName(),
$method->getName(),
$method->getDeclaringClass()->getName()
)
);
}

return ObjectType::fromName($parentClass->getName(), $returnType->allowsNull());
}

return Type::fromName($returnType->getName(), $returnType->allowsNull());
}

private static function reflectionMethodGetReturnType(ReflectionMethod $method): ?ReflectionType
{
if ($method->hasReturnType()) {
return $method->getReturnType();
}

if (!method_exists($method, 'getTentativeReturnType')) {
return null;
}

return $method->getTentativeReturnType();
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Builder;




interface Match_ extends Stub
{








public function after($id);
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Builder;

use PHPUnit\Framework\MockObject\Stub\Stub;
use Throwable;

interface InvocationStubber
{
public function will(Stub $stub): Identity;


public function willReturn($value, ...$nextValues);






public function willReturnReference(&$reference);






public function willReturnMap(array $valueMap);






public function willReturnArgument($argumentIndex);






public function willReturnCallback($callback);


public function willReturnSelf();






public function willReturnOnConsecutiveCalls(...$values);


public function willThrowException(Throwable $exception);
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Builder;

use function array_map;
use function array_merge;
use function count;
use function get_class;
use function gettype;
use function in_array;
use function is_object;
use function is_string;
use function sprintf;
use function strtolower;
use PHPUnit\Framework\Constraint\Constraint;
use PHPUnit\Framework\MockObject\ConfigurableMethod;
use PHPUnit\Framework\MockObject\IncompatibleReturnValueException;
use PHPUnit\Framework\MockObject\InvocationHandler;
use PHPUnit\Framework\MockObject\Matcher;
use PHPUnit\Framework\MockObject\Rule;
use PHPUnit\Framework\MockObject\RuntimeException;
use PHPUnit\Framework\MockObject\Stub\ConsecutiveCalls;
use PHPUnit\Framework\MockObject\Stub\Exception;
use PHPUnit\Framework\MockObject\Stub\ReturnArgument;
use PHPUnit\Framework\MockObject\Stub\ReturnCallback;
use PHPUnit\Framework\MockObject\Stub\ReturnReference;
use PHPUnit\Framework\MockObject\Stub\ReturnSelf;
use PHPUnit\Framework\MockObject\Stub\ReturnStub;
use PHPUnit\Framework\MockObject\Stub\ReturnValueMap;
use PHPUnit\Framework\MockObject\Stub\Stub;
use Throwable;

final class InvocationMocker implements InvocationStubber, MethodNameMatch
{



private $invocationHandler;




private $matcher;




private $configurableMethods;

public function __construct(InvocationHandler $handler, Matcher $matcher, ConfigurableMethod ...$configurableMethods)
{
$this->invocationHandler = $handler;
$this->matcher = $matcher;
$this->configurableMethods = $configurableMethods;
}




public function id($id): self
{
$this->invocationHandler->registerMatcher($id, $this->matcher);

return $this;
}




public function will(Stub $stub): Identity
{
$this->matcher->setStub($stub);

return $this;
}

public function willReturn($value, ...$nextValues): self
{
if (count($nextValues) === 0) {
$this->ensureTypeOfReturnValues([$value]);

$stub = $value instanceof Stub ? $value : new ReturnStub($value);
} else {
$values = array_merge([$value], $nextValues);

$this->ensureTypeOfReturnValues($values);

$stub = new ConsecutiveCalls($values);
}

return $this->will($stub);
}

public function willReturnReference(&$reference): self
{
$stub = new ReturnReference($reference);

return $this->will($stub);
}

public function willReturnMap(array $valueMap): self
{
$stub = new ReturnValueMap($valueMap);

return $this->will($stub);
}

public function willReturnArgument($argumentIndex): self
{
$stub = new ReturnArgument($argumentIndex);

return $this->will($stub);
}

public function willReturnCallback($callback): self
{
$stub = new ReturnCallback($callback);

return $this->will($stub);
}

public function willReturnSelf(): self
{
$stub = new ReturnSelf;

return $this->will($stub);
}

public function willReturnOnConsecutiveCalls(...$values): self
{
$stub = new ConsecutiveCalls($values);

return $this->will($stub);
}

public function willThrowException(Throwable $exception): self
{
$stub = new Exception($exception);

return $this->will($stub);
}




public function after($id): self
{
$this->matcher->setAfterMatchBuilderId($id);

return $this;
}






public function with(...$arguments): self
{
$this->canDefineParameters();

$this->matcher->setParametersRule(new Rule\Parameters($arguments));

return $this;
}








public function withConsecutive(...$arguments): self
{
$this->canDefineParameters();

$this->matcher->setParametersRule(new Rule\ConsecutiveParameters($arguments));

return $this;
}






public function withAnyParameters(): self
{
$this->canDefineParameters();

$this->matcher->setParametersRule(new Rule\AnyParameters);

return $this;
}








public function method($constraint): self
{
if ($this->matcher->hasMethodNameRule()) {
throw new RuntimeException(
'Rule for method name is already defined, cannot redefine'
);
}

$configurableMethodNames = array_map(
static function (ConfigurableMethod $configurable)
{
return strtolower($configurable->getName());
},
$this->configurableMethods
);

if (is_string($constraint) && !in_array(strtolower($constraint), $configurableMethodNames, true)) {
throw new RuntimeException(
sprintf(
'Trying to configure method "%s" which cannot be configured because it does not exist, has not been specified, is final, or is static',
$constraint
)
);
}

$this->matcher->setMethodNameRule(new Rule\MethodName($constraint));

return $this;
}






private function canDefineParameters(): void
{
if (!$this->matcher->hasMethodNameRule()) {
throw new RuntimeException(
'Rule for method name is not defined, cannot define rule for parameters ' .
'without one'
);
}

if ($this->matcher->hasParametersRule()) {
throw new RuntimeException(
'Rule for parameters is already defined, cannot redefine'
);
}
}

private function getConfiguredMethod(): ?ConfigurableMethod
{
$configuredMethod = null;

foreach ($this->configurableMethods as $configurableMethod) {
if ($this->matcher->getMethodNameRule()->matchesName($configurableMethod->getName())) {
if ($configuredMethod !== null) {
return null;
}

$configuredMethod = $configurableMethod;
}
}

return $configuredMethod;
}

private function ensureTypeOfReturnValues(array $values): void
{
$configuredMethod = $this->getConfiguredMethod();

if ($configuredMethod === null) {
return;
}

foreach ($values as $value) {
if (!$configuredMethod->mayReturn($value)) {
throw new IncompatibleReturnValueException(
sprintf(
'Method %s may not return value of type %s, its return declaration is "%s"',
$configuredMethod->getName(),
is_object($value) ? get_class($value) : gettype($value),
$configuredMethod->getReturnTypeDeclaration()
)
);
}
}
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Builder;




interface ParametersMatch extends Match_
{

















public function with(...$arguments);












public function withAnyParameters();
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Builder;




interface MethodNameMatch extends ParametersMatch
{








public function method($constraint);
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Builder;

use PHPUnit\Framework\MockObject\Stub\Stub as BaseStub;




interface Stub extends Identity
{




public function will(BaseStub $stub): Identity;
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Builder;




interface Identity
{







public function id($id);
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use PHPUnit\Framework\MockObject\Builder\InvocationStubber;




interface Stub
{
public function __phpunit_getInvocationHandler(): InvocationHandler;

public function __phpunit_hasMatchers(): bool;

public function __phpunit_setReturnValueGeneration(bool $returnValueGeneration): void;
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use PHPUnit\Framework\MockObject\Builder\InvocationMocker as BuilderInvocationMocker;
use PHPUnit\Framework\MockObject\Rule\InvocationOrder;




interface MockObject extends Stub
{
public function __phpunit_setOriginalObject($originalObject): void;

public function __phpunit_verify(bool $unsetInvocationMocker = true): void;

public function expects(InvocationOrder $invocationRule): BuilderInvocationMocker;
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;




trait UnmockedCloneMethod
{
public function __clone()
{
$this->__phpunit_invocationMocker = clone $this->__phpunit_getInvocationHandler();

parent::__clone();
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;




trait MockedCloneMethod
{
public function __clone()
{
$this->__phpunit_invocationMocker = clone $this->__phpunit_getInvocationHandler();
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use PHPUnit\Framework\MockObject\Builder\InvocationMocker as InvocationMockerBuilder;
use PHPUnit\Framework\MockObject\Rule\InvocationOrder;




trait Api
{



private static $__phpunit_configurableMethods;




private $__phpunit_originalObject;




private $__phpunit_returnValueGeneration = true;




private $__phpunit_invocationMocker;


public static function __phpunit_initConfigurableMethods(ConfigurableMethod ...$configurableMethods): void
{
if (isset(static::$__phpunit_configurableMethods)) {
throw new ConfigurableMethodsAlreadyInitializedException(
'Configurable methods is already initialized and can not be reinitialized'
);
}

static::$__phpunit_configurableMethods = $configurableMethods;
}


public function __phpunit_setOriginalObject($originalObject): void
{
$this->__phpunit_originalObject = $originalObject;
}


public function __phpunit_setReturnValueGeneration(bool $returnValueGeneration): void
{
$this->__phpunit_returnValueGeneration = $returnValueGeneration;
}


public function __phpunit_getInvocationHandler(): InvocationHandler
{
if ($this->__phpunit_invocationMocker === null) {
$this->__phpunit_invocationMocker = new InvocationHandler(
static::$__phpunit_configurableMethods,
$this->__phpunit_returnValueGeneration
);
}

return $this->__phpunit_invocationMocker;
}


public function __phpunit_hasMatchers(): bool
{
return $this->__phpunit_getInvocationHandler()->hasMatchers();
}


public function __phpunit_verify(bool $unsetInvocationMocker = true): void
{
$this->__phpunit_getInvocationHandler()->verify();

if ($unsetInvocationMocker) {
$this->__phpunit_invocationMocker = null;
}
}

public function expects(InvocationOrder $matcher): InvocationMockerBuilder
{
return $this->__phpunit_getInvocationHandler()->expects($matcher);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use function call_user_func_array;
use function func_get_args;
use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount;




trait Method
{
public function method()
{
$expects = $this->expects(new AnyInvokedCount);

return call_user_func_array(
[$expects, 'method'],
func_get_args()
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use const DIRECTORY_SEPARATOR;
use const PHP_EOL;
use const PHP_MAJOR_VERSION;
use const PREG_OFFSET_CAPTURE;
use const WSDL_CACHE_NONE;
use function array_diff_assoc;
use function array_map;
use function array_merge;
use function array_pop;
use function array_unique;
use function class_exists;
use function count;
use function explode;
use function extension_loaded;
use function implode;
use function in_array;
use function interface_exists;
use function is_array;
use function is_object;
use function is_string;
use function md5;
use function mt_rand;
use function preg_match;
use function preg_match_all;
use function range;
use function serialize;
use function sort;
use function sprintf;
use function str_replace;
use function strlen;
use function strpos;
use function strtolower;
use function substr;
use function trait_exists;
use Doctrine\Instantiator\Exception\ExceptionInterface as InstantiatorException;
use Doctrine\Instantiator\Instantiator;
use Exception;
use Iterator;
use IteratorAggregate;
use PHPUnit\Framework\InvalidArgumentException;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
use SoapClient;
use SoapFault;
use Text_Template;
use Throwable;
use Traversable;




final class Generator
{



private const BLACKLISTED_METHOD_NAMES = [
'__CLASS__' => true,
'__DIR__' => true,
'__FILE__' => true,
'__FUNCTION__' => true,
'__LINE__' => true,
'__METHOD__' => true,
'__NAMESPACE__' => true,
'__TRAIT__' => true,
'__clone' => true,
'__halt_compiler' => true,
];




private static $cache = [];




private static $templates = [];









public function getMock($type, $methods = [], array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = true, bool $callOriginalClone = true, bool $callAutoload = true, bool $cloneArguments = true, bool $callOriginalMethods = false, object $proxyTarget = null, bool $allowMockingUnknownTypes = true, bool $returnValueGeneration = true): MockObject
{
if (!is_array($type) && !is_string($type)) {
throw InvalidArgumentException::create(1, 'array or string');
}

if (!is_array($methods) && null !== $methods) {
throw InvalidArgumentException::create(2, 'array');
}

if ($type === 'Traversable' || $type === '\\Traversable') {
$type = 'Iterator';
}

if (is_array($type)) {
$type = array_unique(
array_map(
static function ($type)
{
if ($type === 'Traversable' ||
$type === '\\Traversable' ||
$type === '\\Iterator') {
return 'Iterator';
}

return $type;
},
$type
)
);
}

if (!$allowMockingUnknownTypes) {
if (is_array($type)) {
foreach ($type as $_type) {
if (!class_exists($_type, $callAutoload) &&
!interface_exists($_type, $callAutoload)) {
throw new RuntimeException(
sprintf(
'Cannot stub or mock class or interface "%s" which does not exist',
$_type
)
);
}
}
} elseif (!class_exists($type, $callAutoload) && !interface_exists($type, $callAutoload)) {
throw new RuntimeException(
sprintf(
'Cannot stub or mock class or interface "%s" which does not exist',
$type
)
);
}
}

if (null !== $methods) {
foreach ($methods as $method) {
if (!preg_match('~[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*~', (string) $method)) {
throw new RuntimeException(
sprintf(
'Cannot stub or mock method with invalid name "%s"',
$method
)
);
}
}

if ($methods !== array_unique($methods)) {
throw new RuntimeException(
sprintf(
'Cannot stub or mock using a method list that contains duplicates: "%s" (duplicate: "%s")',
implode(', ', $methods),
implode(', ', array_unique(array_diff_assoc($methods, array_unique($methods))))
)
);
}
}

if ($mockClassName !== '' && class_exists($mockClassName, false)) {
try {
$reflector = new ReflectionClass($mockClassName);

 } catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if (!$reflector->implementsInterface(MockObject::class)) {
throw new RuntimeException(
sprintf(
'Class "%s" already exists.',
$mockClassName
)
);
}
}

if (!$callOriginalConstructor && $callOriginalMethods) {
throw new RuntimeException(
'Proxying to original methods requires invoking the original constructor'
);
}

$mock = $this->generate(
$type,
$methods,
$mockClassName,
$callOriginalClone,
$callAutoload,
$cloneArguments,
$callOriginalMethods
);

return $this->getObject(
$mock,
$type,
$callOriginalConstructor,
$callAutoload,
$arguments,
$callOriginalMethods,
$proxyTarget,
$returnValueGeneration
);
}












public function getMockForAbstractClass(string $originalClassName, array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = true, bool $callOriginalClone = true, bool $callAutoload = true, array $mockedMethods = null, bool $cloneArguments = true): MockObject
{
if (class_exists($originalClassName, $callAutoload) ||
interface_exists($originalClassName, $callAutoload)) {
try {
$reflector = new ReflectionClass($originalClassName);

 } catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


$methods = $mockedMethods;

foreach ($reflector->getMethods() as $method) {
if ($method->isAbstract() && !in_array($method->getName(), $methods ?? [], true)) {
$methods[] = $method->getName();
}
}

if (empty($methods)) {
$methods = null;
}

return $this->getMock(
$originalClassName,
$methods,
$arguments,
$mockClassName,
$callOriginalConstructor,
$callOriginalClone,
$callAutoload,
$cloneArguments
);
}

throw new RuntimeException(
sprintf('Class "%s" does not exist.', $originalClassName)
);
}








public function getMockForTrait(string $traitName, array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = true, bool $callOriginalClone = true, bool $callAutoload = true, array $mockedMethods = null, bool $cloneArguments = true): MockObject
{
if (!trait_exists($traitName, $callAutoload)) {
throw new RuntimeException(
sprintf(
'Trait "%s" does not exist.',
$traitName
)
);
}

$className = $this->generateClassName(
$traitName,
'',
'Trait_'
);

$classTemplate = $this->getTemplate('trait_class.tpl');

$classTemplate->setVar(
[
'prologue' => 'abstract ',
'class_name' => $className['className'],
'trait_name' => $traitName,
]
);

$mockTrait = new MockTrait($classTemplate->render(), $className['className']);
$mockTrait->generate();

return $this->getMockForAbstractClass($className['className'], $arguments, $mockClassName, $callOriginalConstructor, $callOriginalClone, $callAutoload, $mockedMethods, $cloneArguments);
}






public function getObjectForTrait(string $traitName, string $traitClassName = '', bool $callAutoload = true, bool $callOriginalConstructor = false, array $arguments = []): object
{
if (!trait_exists($traitName, $callAutoload)) {
throw new RuntimeException(
sprintf(
'Trait "%s" does not exist.',
$traitName
)
);
}

$className = $this->generateClassName(
$traitName,
$traitClassName,
'Trait_'
);

$classTemplate = $this->getTemplate('trait_class.tpl');

$classTemplate->setVar(
[
'prologue' => '',
'class_name' => $className['className'],
'trait_name' => $traitName,
]
);

return $this->getObject(
new MockTrait(
$classTemplate->render(),
$className['className']
),
'',
$callOriginalConstructor,
$callAutoload,
$arguments
);
}

public function generate($type, array $methods = null, string $mockClassName = '', bool $callOriginalClone = true, bool $callAutoload = true, bool $cloneArguments = true, bool $callOriginalMethods = false): MockClass
{
if (is_array($type)) {
sort($type);
}

if ($mockClassName !== '') {
return $this->generateMock(
$type,
$methods,
$mockClassName,
$callOriginalClone,
$callAutoload,
$cloneArguments,
$callOriginalMethods
);
}

$key = md5(
is_array($type) ? implode('_', $type) : $type .
serialize($methods) .
serialize($callOriginalClone) .
serialize($cloneArguments) .
serialize($callOriginalMethods)
);

if (!isset(self::$cache[$key])) {
self::$cache[$key] = $this->generateMock(
$type,
$methods,
$mockClassName,
$callOriginalClone,
$callAutoload,
$cloneArguments,
$callOriginalMethods
);
}

return self::$cache[$key];
}




public function generateClassFromWsdl(string $wsdlFile, string $className, array $methods = [], array $options = []): string
{
if (!extension_loaded('soap')) {
throw new RuntimeException(
'The SOAP extension is required to generate a mock object from WSDL.'
);
}

$options = array_merge($options, ['cache_wsdl' => WSDL_CACHE_NONE]);

try {
$client = new SoapClient($wsdlFile, $options);
$_methods = array_unique($client->__getFunctions());
unset($client);
} catch (SoapFault $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}

sort($_methods);

$methodTemplate = $this->getTemplate('wsdl_method.tpl');
$methodsBuffer = '';

foreach ($_methods as $method) {
preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\(/', $method, $matches, PREG_OFFSET_CAPTURE);
$lastFunction = array_pop($matches[0]);
$nameStart = $lastFunction[1];
$nameEnd = $nameStart + strlen($lastFunction[0]) - 1;
$name = str_replace('(', '', $lastFunction[0]);

if (empty($methods) || in_array($name, $methods, true)) {
$args = explode(
',',
str_replace(')', '', substr($method, $nameEnd + 1))
);

foreach (range(0, count($args) - 1) as $i) {
$parameterStart = strpos($args[$i], '$');

if (!$parameterStart) {
continue;
}

$args[$i] = substr($args[$i], $parameterStart);
}

$methodTemplate->setVar(
[
'method_name' => $name,
'arguments' => implode(', ', $args),
]
);

$methodsBuffer .= $methodTemplate->render();
}
}

$optionsBuffer = '[';

foreach ($options as $key => $value) {
$optionsBuffer .= $key . ' => ' . $value;
}

$optionsBuffer .= ']';

$classTemplate = $this->getTemplate('wsdl_class.tpl');
$namespace = '';

if (strpos($className, '\\') !== false) {
$parts = explode('\\', $className);
$className = array_pop($parts);
$namespace = 'namespace ' . implode('\\', $parts) . ';' . "\n\n";
}

$classTemplate->setVar(
[
'namespace' => $namespace,
'class_name' => $className,
'wsdl' => $wsdlFile,
'options' => $optionsBuffer,
'methods' => $methodsBuffer,
]
);

return $classTemplate->render();
}






public function getClassMethods(string $className): array
{
try {
$class = new ReflectionClass($className);

 } catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


$methods = [];

foreach ($class->getMethods() as $method) {
if ($method->isPublic() || $method->isAbstract()) {
$methods[] = $method->getName();
}
}

return $methods;
}






public function mockClassMethods(string $className, bool $callOriginalMethods, bool $cloneArguments): array
{
try {
$class = new ReflectionClass($className);

 } catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


$methods = [];

foreach ($class->getMethods() as $method) {
if (($method->isPublic() || $method->isAbstract()) && $this->canMockMethod($method)) {
$methods[] = MockMethod::fromReflection($method, $callOriginalMethods, $cloneArguments);
}
}

return $methods;
}






public function mockInterfaceMethods(string $interfaceName, bool $cloneArguments): array
{
try {
$class = new ReflectionClass($interfaceName);

 } catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


$methods = [];

foreach ($class->getMethods() as $method) {
$methods[] = MockMethod::fromReflection($method, false, $cloneArguments);
}

return $methods;
}






private function userDefinedInterfaceMethods(string $interfaceName): array
{
try {

 $interface = new ReflectionClass($interfaceName);
} catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


$methods = [];

foreach ($interface->getMethods() as $method) {
if (!$method->isUserDefined()) {
continue;
}

$methods[] = $method;
}

return $methods;
}

private function getObject(MockType $mockClass, $type = '', bool $callOriginalConstructor = false, bool $callAutoload = false, array $arguments = [], bool $callOriginalMethods = false, object $proxyTarget = null, bool $returnValueGeneration = true)
{
$className = $mockClass->generate();

if ($callOriginalConstructor) {
if (count($arguments) === 0) {
$object = new $className;
} else {
try {
$class = new ReflectionClass($className);

 } catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


$object = $class->newInstanceArgs($arguments);
}
} else {
try {
$object = (new Instantiator)->instantiate($className);
} catch (InstantiatorException $exception) {
throw new RuntimeException($exception->getMessage());
}
}

if ($callOriginalMethods) {
if (!is_object($proxyTarget)) {
if (count($arguments) === 0) {
$proxyTarget = new $type;
} else {
try {
$class = new ReflectionClass($type);

 } catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


$proxyTarget = $class->newInstanceArgs($arguments);
}
}

$object->__phpunit_setOriginalObject($proxyTarget);
}

if ($object instanceof MockObject) {
$object->__phpunit_setReturnValueGeneration($returnValueGeneration);
}

return $object;
}






private function generateMock($type, ?array $explicitMethods, string $mockClassName, bool $callOriginalClone, bool $callAutoload, bool $cloneArguments, bool $callOriginalMethods): MockClass
{
$classTemplate = $this->getTemplate('mocked_class.tpl');
$additionalInterfaces = [];
$mockedCloneMethod = false;
$unmockedCloneMethod = false;
$isClass = false;
$isInterface = false;
$class = null;
$mockMethods = new MockMethodSet;

if (is_array($type)) {
$interfaceMethods = [];

foreach ($type as $_type) {
if (!interface_exists($_type, $callAutoload)) {
throw new RuntimeException(
sprintf(
'Interface "%s" does not exist.',
$_type
)
);
}

$additionalInterfaces[] = $_type;

try {
$typeClass = new ReflectionClass($_type);

 } catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


foreach ($this->getClassMethods($_type) as $method) {
if (in_array($method, $interfaceMethods, true)) {
throw new RuntimeException(
sprintf(
'Duplicate method "%s" not allowed.',
$method
)
);
}

try {
$methodReflection = $typeClass->getMethod($method);

 } catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if ($this->canMockMethod($methodReflection)) {
$mockMethods->addMethods(
MockMethod::fromReflection($methodReflection, $callOriginalMethods, $cloneArguments)
);

$interfaceMethods[] = $method;
}
}
}

unset($interfaceMethods);
}

$mockClassName = $this->generateClassName(
$type,
$mockClassName,
'Mock_'
);

if (class_exists($mockClassName['fullClassName'], $callAutoload)) {
$isClass = true;
} elseif (interface_exists($mockClassName['fullClassName'], $callAutoload)) {
$isInterface = true;
}

if (!$isClass && !$isInterface) {
$prologue = 'class ' . $mockClassName['originalClassName'] . "\n{\n}\n\n";

if (!empty($mockClassName['namespaceName'])) {
$prologue = 'namespace ' . $mockClassName['namespaceName'] .
" {\n\n" . $prologue . "}\n\n" .
"namespace {\n\n";

$epilogue = "\n\n}";
}

$mockedCloneMethod = true;
} else {
try {
$class = new ReflectionClass($mockClassName['fullClassName']);

 } catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if ($class->isFinal()) {
throw new RuntimeException(
sprintf(
'Class "%s" is declared "final" and cannot be mocked.',
$mockClassName['fullClassName']
)
);
}


 if ($isInterface && $class->implementsInterface(Throwable::class)) {
$actualClassName = Exception::class;
$additionalInterfaces[] = $class->getName();
$isInterface = false;

try {
$class = new ReflectionClass($actualClassName);

 } catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


foreach ($this->userDefinedInterfaceMethods($mockClassName['fullClassName']) as $method) {
$methodName = $method->getName();

if ($class->hasMethod($methodName)) {
try {
$classMethod = $class->getMethod($methodName);

 } catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if (!$this->canMockMethod($classMethod)) {
continue;
}
}

$mockMethods->addMethods(
MockMethod::fromReflection($method, $callOriginalMethods, $cloneArguments)
);
}

$mockClassName = $this->generateClassName(
$actualClassName,
$mockClassName['className'],
'Mock_'
);
}


 if ($isInterface && $class->implementsInterface(Traversable::class) &&
!$class->implementsInterface(Iterator::class) &&
!$class->implementsInterface(IteratorAggregate::class)) {
$additionalInterfaces[] = Iterator::class;

$mockMethods->addMethods(
...$this->mockClassMethods(Iterator::class, $callOriginalMethods, $cloneArguments)
);
}

if ($class->hasMethod('__clone')) {
try {
$cloneMethod = $class->getMethod('__clone');

 } catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if (!$cloneMethod->isFinal()) {
if ($callOriginalClone && !$isInterface) {
$unmockedCloneMethod = true;
} else {
$mockedCloneMethod = true;
}
}
} else {
$mockedCloneMethod = true;
}
}

if ($isClass && $explicitMethods === []) {
$mockMethods->addMethods(
...$this->mockClassMethods($mockClassName['fullClassName'], $callOriginalMethods, $cloneArguments)
);
}

if ($isInterface && ($explicitMethods === [] || $explicitMethods === null)) {
$mockMethods->addMethods(
...$this->mockInterfaceMethods($mockClassName['fullClassName'], $cloneArguments)
);
}

if (is_array($explicitMethods)) {
foreach ($explicitMethods as $methodName) {
if ($class !== null && $class->hasMethod($methodName)) {
try {
$method = $class->getMethod($methodName);

 } catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if ($this->canMockMethod($method)) {
$mockMethods->addMethods(
MockMethod::fromReflection($method, $callOriginalMethods, $cloneArguments)
);
}
} else {
$mockMethods->addMethods(
MockMethod::fromName(
$mockClassName['fullClassName'],
$methodName,
$cloneArguments
)
);
}
}
}

$mockedMethods = '';
$configurable = [];

foreach ($mockMethods->asArray() as $mockMethod) {
$mockedMethods .= $mockMethod->generateCode();
$configurable[] = new ConfigurableMethod($mockMethod->getName(), $mockMethod->getReturnType());
}

$method = '';

if (!$mockMethods->hasMethod('method') && (!isset($class) || !$class->hasMethod('method'))) {
$method = PHP_EOL . '    use \PHPUnit\Framework\MockObject\Method;';
}

$cloneTrait = '';

if ($mockedCloneMethod) {
$cloneTrait = PHP_EOL . '    use \PHPUnit\Framework\MockObject\MockedCloneMethod;';
}

if ($unmockedCloneMethod) {
$cloneTrait = PHP_EOL . '    use \PHPUnit\Framework\MockObject\UnmockedCloneMethod;';
}

$classTemplate->setVar(
[
'prologue' => $prologue ?? '',
'epilogue' => $epilogue ?? '',
'class_declaration' => $this->generateMockClassDeclaration(
$mockClassName,
$isInterface,
$additionalInterfaces
),
'clone' => $cloneTrait,
'mock_class_name' => $mockClassName['className'],
'mocked_methods' => $mockedMethods,
'method' => $method,
]
);

return new MockClass(
$classTemplate->render(),
$mockClassName['className'],
$configurable
);
}




private function generateClassName($type, string $className, string $prefix): array
{
if (is_array($type)) {
$type = implode('_', $type);
}

if ($type[0] === '\\') {
$type = substr($type, 1);
}

$classNameParts = explode('\\', $type);

if (count($classNameParts) > 1) {
$type = array_pop($classNameParts);
$namespaceName = implode('\\', $classNameParts);
$fullClassName = $namespaceName . '\\' . $type;
} else {
$namespaceName = '';
$fullClassName = $type;
}

if ($className === '') {
do {
$className = $prefix . $type . '_' .
substr(md5((string) mt_rand()), 0, 8);
} while (class_exists($className, false));
}

return [
'className' => $className,
'originalClassName' => $type,
'fullClassName' => $fullClassName,
'namespaceName' => $namespaceName,
];
}

private function generateMockClassDeclaration(array $mockClassName, bool $isInterface, array $additionalInterfaces = []): string
{
$buffer = 'class ';

$additionalInterfaces[] = MockObject::class;
$interfaces = implode(', ', $additionalInterfaces);

if ($isInterface) {
$buffer .= sprintf(
'%s implements %s',
$mockClassName['className'],
$interfaces
);

if (!in_array($mockClassName['originalClassName'], $additionalInterfaces, true)) {
$buffer .= ', ';

if (!empty($mockClassName['namespaceName'])) {
$buffer .= $mockClassName['namespaceName'] . '\\';
}

$buffer .= $mockClassName['originalClassName'];
}
} else {
$buffer .= sprintf(
'%s extends %s%s implements %s',
$mockClassName['className'],
!empty($mockClassName['namespaceName']) ? $mockClassName['namespaceName'] . '\\' : '',
$mockClassName['originalClassName'],
$interfaces
);
}

return $buffer;
}

private function canMockMethod(ReflectionMethod $method): bool
{
return !($this->isConstructor($method) || $method->isFinal() || $method->isPrivate() || $this->isMethodNameBlacklisted($method->getName()));
}

private function isMethodNameBlacklisted(string $name): bool
{
return isset(self::BLACKLISTED_METHOD_NAMES[$name]);
}

private function getTemplate(string $template): Text_Template
{
$filename = __DIR__ . DIRECTORY_SEPARATOR . 'Generator' . DIRECTORY_SEPARATOR . $template;

if (!isset(self::$templates[$filename])) {
self::$templates[$filename] = new Text_Template($filename);
}

return self::$templates[$filename];
}




private function isConstructor(ReflectionMethod $method): bool
{
$methodName = strtolower($method->getName());

if ($methodName === '__construct') {
return true;
}

if (PHP_MAJOR_VERSION >= 8) {
return false;
}

$className = strtolower($method->getDeclaringClass()->getName());

return $methodName === $className;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use PHPUnit\Framework\ExpectationFailedException;




interface Verifiable
{






public function verify(): void;
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use function array_diff;
use function array_merge;
use function sprintf;
use PHPUnit\Framework\TestCase;
use ReflectionClass;
use ReflectionException;




final class MockBuilder
{



private $testCase;




private $type;




private $methods = [];




private $emptyMethodsArray = false;




private $mockClassName = '';




private $constructorArgs = [];




private $originalConstructor = true;




private $originalClone = true;




private $autoload = true;




private $cloneArguments = false;




private $callOriginalMethods = false;




private $proxyTarget;




private $allowMockingUnknownTypes = true;




private $returnValueGeneration = true;




private $generator;






public function __construct(TestCase $testCase, $type)
{
$this->testCase = $testCase;
$this->type = $type;
$this->generator = new Generator;
}








public function getMock(): MockObject
{
$object = $this->generator->getMock(
$this->type,
!$this->emptyMethodsArray ? $this->methods : null,
$this->constructorArgs,
$this->mockClassName,
$this->originalConstructor,
$this->originalClone,
$this->autoload,
$this->cloneArguments,
$this->callOriginalMethods,
$this->proxyTarget,
$this->allowMockingUnknownTypes,
$this->returnValueGeneration
);

$this->testCase->registerMockObject($object);

return $object;
}









public function getMockForAbstractClass(): MockObject
{
$object = $this->generator->getMockForAbstractClass(
$this->type,
$this->constructorArgs,
$this->mockClassName,
$this->originalConstructor,
$this->originalClone,
$this->autoload,
$this->methods,
$this->cloneArguments
);

$this->testCase->registerMockObject($object);

return $object;
}









public function getMockForTrait(): MockObject
{
$object = $this->generator->getMockForTrait(
$this->type,
$this->constructorArgs,
$this->mockClassName,
$this->originalConstructor,
$this->originalClone,
$this->autoload,
$this->methods,
$this->cloneArguments
);

$this->testCase->registerMockObject($object);

return $object;
}








public function setMethods(?array $methods = null): self
{
if ($methods === null) {
$this->methods = $methods;
} else {
$this->methods = array_merge($this->methods ?? [], $methods);
}

return $this;
}










public function onlyMethods(array $methods): self
{
if (empty($methods)) {
$this->emptyMethodsArray = true;

return $this;
}

try {
$reflector = new ReflectionClass($this->type);

 } catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


foreach ($methods as $method) {
if (!$reflector->hasMethod($method)) {
throw new RuntimeException(
sprintf(
'Trying to set mock method "%s" with onlyMethods, but it does not exist in class "%s". Use addMethods() for methods that don\'t exist in the class.',
$method,
$this->type
)
);
}
}

$this->methods = array_merge($this->methods ?? [], $methods);

return $this;
}










public function addMethods(array $methods): self
{
if (empty($methods)) {
$this->emptyMethodsArray = true;

return $this;
}

try {
$reflector = new ReflectionClass($this->type);

 } catch (ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


foreach ($methods as $method) {
if ($reflector->hasMethod($method)) {
throw new RuntimeException(
sprintf(
'Trying to set mock method "%s" with addMethods(), but it exists in class "%s". Use onlyMethods() for methods that exist in the class.',
$method,
$this->type
)
);
}
}

$this->methods = array_merge($this->methods ?? [], $methods);

return $this;
}




public function setMethodsExcept(array $methods = []): self
{
return $this->setMethods(
array_diff(
$this->generator->getClassMethods($this->type),
$methods
)
);
}






public function setConstructorArgs(array $args): self
{
$this->constructorArgs = $args;

return $this;
}






public function setMockClassName(string $name): self
{
$this->mockClassName = $name;

return $this;
}






public function disableOriginalConstructor(): self
{
$this->originalConstructor = false;

return $this;
}






public function enableOriginalConstructor(): self
{
$this->originalConstructor = true;

return $this;
}






public function disableOriginalClone(): self
{
$this->originalClone = false;

return $this;
}






public function enableOriginalClone(): self
{
$this->originalClone = true;

return $this;
}






public function disableAutoload(): self
{
$this->autoload = false;

return $this;
}






public function enableAutoload(): self
{
$this->autoload = true;

return $this;
}






public function disableArgumentCloning(): self
{
$this->cloneArguments = false;

return $this;
}






public function enableArgumentCloning(): self
{
$this->cloneArguments = true;

return $this;
}






public function enableProxyingToOriginalMethods(): self
{
$this->callOriginalMethods = true;

return $this;
}






public function disableProxyingToOriginalMethods(): self
{
$this->callOriginalMethods = false;
$this->proxyTarget = null;

return $this;
}






public function setProxyTarget(object $object): self
{
$this->proxyTarget = $object;

return $this;
}




public function allowMockingUnknownTypes(): self
{
$this->allowMockingUnknownTypes = true;

return $this;
}




public function disallowMockingUnknownTypes(): self
{
$this->allowMockingUnknownTypes = false;

return $this;
}




public function enableAutoReturnValueGeneration(): self
{
$this->returnValueGeneration = true;

return $this;
}




public function disableAutoReturnValueGeneration(): self
{
$this->returnValueGeneration = false;

return $this;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use function array_map;
use function implode;
use function is_object;
use function ltrim;
use function sprintf;
use function strpos;
use function strtolower;
use function substr;
use PHPUnit\Framework\SelfDescribing;
use PHPUnit\Util\Type;
use SebastianBergmann\Exporter\Exporter;
use stdClass;




final class Invocation implements SelfDescribing
{



private $className;




private $methodName;




private $parameters;




private $returnType;




private $isReturnTypeNullable = false;




private $proxiedCall;




private $object;

public function __construct(string $className, string $methodName, array $parameters, string $returnType, object $object, bool $cloneObjects = false, bool $proxiedCall = false)
{
$this->className = $className;
$this->methodName = $methodName;
$this->parameters = $parameters;
$this->object = $object;
$this->proxiedCall = $proxiedCall;

$returnType = ltrim($returnType, ': ');

if (strtolower($methodName) === '__tostring') {
$returnType = 'string';
}

if (strpos($returnType, '?') === 0) {
$returnType = substr($returnType, 1);
$this->isReturnTypeNullable = true;
}

$this->returnType = $returnType;

if (!$cloneObjects) {
return;
}

foreach ($this->parameters as $key => $value) {
if (is_object($value)) {
$this->parameters[$key] = $this->cloneObject($value);
}
}
}

public function getClassName(): string
{
return $this->className;
}

public function getMethodName(): string
{
return $this->methodName;
}

public function getParameters(): array
{
return $this->parameters;
}






public function generateReturnValue()
{
if ($this->isReturnTypeNullable || $this->proxiedCall) {
return;
}

switch (strtolower($this->returnType)) {
case '':
case 'void':
return;

case 'string':
return '';

case 'float':
return 0.0;

case 'int':
return 0;

case 'bool':
return false;

case 'array':
return [];

case 'object':
return new stdClass;

case 'callable':
case 'closure':
return static function (): void
{
};

case 'traversable':
case 'generator':
case 'iterable':
$generator = static function ()
{
yield from [];
};

return $generator();

default:
$generator = new Generator;

return $generator->getMock($this->returnType, [], [], '', false);
}
}

public function toString(): string
{
$exporter = new Exporter;

return sprintf(
'%s::%s(%s)%s',
$this->className,
$this->methodName,
implode(
', ',
array_map(
[$exporter, 'shortenedExport'],
$this->parameters
)
),
$this->returnType ? sprintf(': %s', $this->returnType) : ''
);
}

public function getObject(): object
{
return $this->object;
}

private function cloneObject(object $original): object
{
if (Type::isCloneable($original)) {
return clone $original;
}

return $original;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use function is_string;
use function sprintf;
use function strtolower;
use PHPUnit\Framework\Constraint\Constraint;




final class MethodNameConstraint extends Constraint
{



private $methodName;

public function __construct(string $methodName)
{
$this->methodName = $methodName;
}

public function toString(): string
{
return sprintf(
'is "%s"',
$this->methodName
);
}

protected function matches($other): bool
{
if (!is_string($other)) {
return false;
}

return strtolower($this->methodName) === strtolower($other);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Stub;

use function call_user_func_array;
use function get_class;
use function is_array;
use function is_object;
use function sprintf;
use PHPUnit\Framework\MockObject\Invocation;




final class ReturnCallback implements Stub
{
private $callback;

public function __construct($callback)
{
$this->callback = $callback;
}

public function invoke(Invocation $invocation)
{
return call_user_func_array($this->callback, $invocation->getParameters());
}

public function toString(): string
{
if (is_array($this->callback)) {
if (is_object($this->callback[0])) {
$class = get_class($this->callback[0]);
$type = '->';
} else {
$class = $this->callback[0];
$type = '::';
}

return sprintf(
'return result of user defined callback %s%s%s() with the ' .
'passed arguments',
$class,
$type,
$this->callback[1]
);
}

return 'return result of user defined callback ' . $this->callback .
' with the passed arguments';
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Stub;

use function sprintf;
use PHPUnit\Framework\MockObject\Invocation;
use SebastianBergmann\Exporter\Exporter;




final class ReturnStub implements Stub
{



private $value;

public function __construct($value)
{
$this->value = $value;
}

public function invoke(Invocation $invocation)
{
return $this->value;
}

public function toString(): string
{
$exporter = new Exporter;

return sprintf(
'return user-specified value %s',
$exporter->export($this->value)
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Stub;

use function sprintf;
use PHPUnit\Framework\MockObject\Invocation;
use SebastianBergmann\Exporter\Exporter;
use Throwable;




final class Exception implements Stub
{
private $exception;

public function __construct(Throwable $exception)
{
$this->exception = $exception;
}




public function invoke(Invocation $invocation): void
{
throw $this->exception;
}

public function toString(): string
{
$exporter = new Exporter;

return sprintf(
'raise user-specified exception %s',
$exporter->export($this->exception)
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Stub;

use function array_shift;
use function sprintf;
use PHPUnit\Framework\MockObject\Invocation;
use SebastianBergmann\Exporter\Exporter;




final class ConsecutiveCalls implements Stub
{



private $stack;




private $value;

public function __construct(array $stack)
{
$this->stack = $stack;
}

public function invoke(Invocation $invocation)
{
$this->value = array_shift($this->stack);

if ($this->value instanceof Stub) {
$this->value = $this->value->invoke($invocation);
}

return $this->value;
}

public function toString(): string
{
$exporter = new Exporter;

return sprintf(
'return user-specified value %s',
$exporter->export($this->value)
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Stub;

use PHPUnit\Framework\MockObject\Invocation;
use PHPUnit\Framework\SelfDescribing;




interface Stub extends SelfDescribing
{






public function invoke(Invocation $invocation);
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Stub;

use function sprintf;
use PHPUnit\Framework\MockObject\Invocation;




final class ReturnArgument implements Stub
{



private $argumentIndex;

public function __construct($argumentIndex)
{
$this->argumentIndex = $argumentIndex;
}

public function invoke(Invocation $invocation)
{
if (isset($invocation->getParameters()[$this->argumentIndex])) {
return $invocation->getParameters()[$this->argumentIndex];
}
}

public function toString(): string
{
return sprintf('return argument #%d', $this->argumentIndex);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Stub;

use function sprintf;
use PHPUnit\Framework\MockObject\Invocation;
use SebastianBergmann\Exporter\Exporter;




final class ReturnReference implements Stub
{



private $reference;

public function __construct(&$reference)
{
$this->reference = &$reference;
}

public function invoke(Invocation $invocation)
{
return $this->reference;
}

public function toString(): string
{
$exporter = new Exporter;

return sprintf(
'return user-specified reference %s',
$exporter->export($this->reference)
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Stub;

use PHPUnit\Framework\MockObject\Invocation;
use PHPUnit\Framework\MockObject\RuntimeException;




final class ReturnSelf implements Stub
{



public function invoke(Invocation $invocation)
{
return $invocation->getObject();
}

public function toString(): string
{
return 'return the current object';
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject\Stub;

use function array_pop;
use function count;
use function is_array;
use PHPUnit\Framework\MockObject\Invocation;




final class ReturnValueMap implements Stub
{



private $valueMap;

public function __construct(array $valueMap)
{
$this->valueMap = $valueMap;
}

public function invoke(Invocation $invocation)
{
$parameterCount = count($invocation->getParameters());

foreach ($this->valueMap as $map) {
if (!is_array($map) || $parameterCount !== (count($map) - 1)) {
continue;
}

$return = array_pop($map);

if ($invocation->getParameters() === $map) {
return $return;
}
}
}

public function toString(): string
{
return 'return value from a map';
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use function sprintf;
use function strtolower;
use Exception;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\MockObject\Builder\InvocationMocker;
use PHPUnit\Framework\MockObject\Rule\InvocationOrder;
use Throwable;




final class InvocationHandler
{



private $matchers = [];




private $matcherMap = [];




private $configurableMethods;




private $returnValueGeneration;




private $deferredError;

public function __construct(array $configurableMethods, bool $returnValueGeneration)
{
$this->configurableMethods = $configurableMethods;
$this->returnValueGeneration = $returnValueGeneration;
}

public function hasMatchers(): bool
{
foreach ($this->matchers as $matcher) {
if ($matcher->hasMatchers()) {
return true;
}
}

return false;
}






public function lookupMatcher(string $id): ?Matcher
{
if (isset($this->matcherMap[$id])) {
return $this->matcherMap[$id];
}

return null;
}










public function registerMatcher(string $id, Matcher $matcher): void
{
if (isset($this->matcherMap[$id])) {
throw new RuntimeException(
'Matcher with id <' . $id . '> is already registered.'
);
}

$this->matcherMap[$id] = $matcher;
}

public function expects(InvocationOrder $rule): InvocationMocker
{
$matcher = new Matcher($rule);
$this->addMatcher($matcher);

return new InvocationMocker(
$this,
$matcher,
...$this->configurableMethods
);
}






public function invoke(Invocation $invocation)
{
$exception = null;
$hasReturnValue = false;
$returnValue = null;

foreach ($this->matchers as $match) {
try {
if ($match->matches($invocation)) {
$value = $match->invoked($invocation);

if (!$hasReturnValue) {
$returnValue = $value;
$hasReturnValue = true;
}
}
} catch (Exception $e) {
$exception = $e;
}
}

if ($exception !== null) {
throw $exception;
}

if ($hasReturnValue) {
return $returnValue;
}

if (!$this->returnValueGeneration) {
$exception = new ExpectationFailedException(
sprintf(
'Return value inference disabled and no expectation set up for %s::%s()',
$invocation->getClassName(),
$invocation->getMethodName()
)
);

if (strtolower($invocation->getMethodName()) === '__tostring') {
$this->deferredError = $exception;

return '';
}

throw $exception;
}

return $invocation->generateReturnValue();
}

public function matches(Invocation $invocation): bool
{
foreach ($this->matchers as $matcher) {
if (!$matcher->matches($invocation)) {
return false;
}
}

return true;
}




public function verify(): void
{
foreach ($this->matchers as $matcher) {
$matcher->verify();
}

if ($this->deferredError) {
throw $this->deferredError;
}
}

private function addMatcher(Matcher $matcher): void
{
$this->matchers[] = $matcher;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;




interface MockType
{
public function generate(): string;
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use SebastianBergmann\Type\Type;




final class ConfigurableMethod
{



private $name;




private $returnType;

public function __construct(string $name, Type $returnType)
{
$this->name = $name;
$this->returnType = $returnType;
}

public function getName(): string
{
return $this->name;
}

public function mayReturn($value): bool
{
if ($value === null && $this->returnType->allowsNull()) {
return true;
}

return $this->returnType->isAssignable(Type::fromValue($value, false));
}

public function getReturnTypeDeclaration(): string
{
return $this->returnType->getReturnTypeDeclaration();
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use Throwable;




interface Exception extends Throwable
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;




final class BadMethodCallException extends \BadMethodCallException implements Exception
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;




final class ConfigurableMethodsAlreadyInitializedException extends \PHPUnit\Framework\Exception implements Exception
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;




final class RuntimeException extends \RuntimeException implements Exception
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;




final class IncompatibleReturnValueException extends \PHPUnit\Framework\Exception implements Exception
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use function class_exists;




final class MockTrait implements MockType
{



private $classCode;




private $mockName;

public function __construct(string $classCode, string $mockName)
{
$this->classCode = $classCode;
$this->mockName = $mockName;
}

public function generate(): string
{
if (!class_exists($this->mockName, false)) {
eval($this->classCode);
}

return $this->mockName;
}

public function getClassCode(): string
{
return $this->classCode;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework\MockObject;

use function assert;
use function implode;
use function sprintf;
use Exception;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount;
use PHPUnit\Framework\MockObject\Rule\AnyParameters;
use PHPUnit\Framework\MockObject\Rule\InvocationOrder;
use PHPUnit\Framework\MockObject\Rule\InvokedCount;
use PHPUnit\Framework\MockObject\Rule\MethodName;
use PHPUnit\Framework\MockObject\Rule\ParametersRule;
use PHPUnit\Framework\MockObject\Stub\Stub;
use PHPUnit\Framework\TestFailure;




final class Matcher
{



private $invocationRule;




private $afterMatchBuilderId;




private $afterMatchBuilderIsInvoked = false;




private $methodNameRule;




private $parametersRule;




private $stub;

public function __construct(InvocationOrder $rule)
{
$this->invocationRule = $rule;
}

public function hasMatchers(): bool
{
return !$this->invocationRule instanceof AnyInvokedCount;
}

public function hasMethodNameRule(): bool
{
return $this->methodNameRule !== null;
}

public function getMethodNameRule(): MethodName
{
return $this->methodNameRule;
}

public function setMethodNameRule(MethodName $rule): void
{
$this->methodNameRule = $rule;
}

public function hasParametersRule(): bool
{
return $this->parametersRule !== null;
}

public function setParametersRule(ParametersRule $rule): void
{
$this->parametersRule = $rule;
}

public function setStub(Stub $stub): void
{
$this->stub = $stub;
}

public function setAfterMatchBuilderId(string $id): void
{
$this->afterMatchBuilderId = $id;
}






public function invoked(Invocation $invocation)
{
if ($this->methodNameRule === null) {
throw new RuntimeException('No method rule is set');
}

if ($this->afterMatchBuilderId !== null) {
$matcher = $invocation->getObject()
->__phpunit_getInvocationHandler()
->lookupMatcher($this->afterMatchBuilderId);

if (!$matcher) {
throw new RuntimeException(
sprintf(
'No builder found for match builder identification <%s>',
$this->afterMatchBuilderId
)
);
}
assert($matcher instanceof self);

if ($matcher->invocationRule->hasBeenInvoked()) {
$this->afterMatchBuilderIsInvoked = true;
}
}

$this->invocationRule->invoked($invocation);

try {
if ($this->parametersRule !== null) {
$this->parametersRule->apply($invocation);
}
} catch (ExpectationFailedException $e) {
throw new ExpectationFailedException(
sprintf(
"Expectation failed for %s when %s\n%s",
$this->methodNameRule->toString(),
$this->invocationRule->toString(),
$e->getMessage()
),
$e->getComparisonFailure()
);
}

if ($this->stub) {
return $this->stub->invoke($invocation);
}

return $invocation->generateReturnValue();
}






public function matches(Invocation $invocation): bool
{
if ($this->afterMatchBuilderId !== null) {
$matcher = $invocation->getObject()
->__phpunit_getInvocationHandler()
->lookupMatcher($this->afterMatchBuilderId);

if (!$matcher) {
throw new RuntimeException(
sprintf(
'No builder found for match builder identification <%s>',
$this->afterMatchBuilderId
)
);
}
assert($matcher instanceof self);

if (!$matcher->invocationRule->hasBeenInvoked()) {
return false;
}
}

if ($this->methodNameRule === null) {
throw new RuntimeException('No method rule is set');
}

if (!$this->invocationRule->matches($invocation)) {
return false;
}

try {
if (!$this->methodNameRule->matches($invocation)) {
return false;
}
} catch (ExpectationFailedException $e) {
throw new ExpectationFailedException(
sprintf(
"Expectation failed for %s when %s\n%s",
$this->methodNameRule->toString(),
$this->invocationRule->toString(),
$e->getMessage()
),
$e->getComparisonFailure()
);
}

return true;
}






public function verify(): void
{
if ($this->methodNameRule === null) {
throw new RuntimeException('No method rule is set');
}

try {
$this->invocationRule->verify();

if ($this->parametersRule === null) {
$this->parametersRule = new AnyParameters;
}

$invocationIsAny = $this->invocationRule instanceof AnyInvokedCount;
$invocationIsNever = $this->invocationRule instanceof InvokedCount && $this->invocationRule->isNever();

if (!$invocationIsAny && !$invocationIsNever) {
$this->parametersRule->verify();
}
} catch (ExpectationFailedException $e) {
throw new ExpectationFailedException(
sprintf(
"Expectation failed for %s when %s.\n%s",
$this->methodNameRule->toString(),
$this->invocationRule->toString(),
TestFailure::exceptionToString($e)
)
);
}
}

public function toString(): string
{
$list = [];

if ($this->invocationRule !== null) {
$list[] = $this->invocationRule->toString();
}

if ($this->methodNameRule !== null) {
$list[] = 'where ' . $this->methodNameRule->toString();
}

if ($this->parametersRule !== null) {
$list[] = 'and ' . $this->parametersRule->toString();
}

if ($this->afterMatchBuilderId !== null) {
$list[] = 'after ' . $this->afterMatchBuilderId;
}

if ($this->stub !== null) {
$list[] = 'will ' . $this->stub->toString();
}

return implode(' ', $list);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;

use const LC_ALL;
use const LC_COLLATE;
use const LC_CTYPE;
use const LC_MESSAGES;
use const LC_MONETARY;
use const LC_NUMERIC;
use const LC_TIME;
use const PATHINFO_FILENAME;
use const PHP_EOL;
use const PHP_URL_PATH;
use function array_filter;
use function array_flip;
use function array_keys;
use function array_merge;
use function array_unique;
use function array_values;
use function assert;
use function basename;
use function call_user_func;
use function chdir;
use function class_exists;
use function clearstatcache;
use function count;
use function defined;
use function explode;
use function get_class;
use function get_include_path;
use function getcwd;
use function implode;
use function in_array;
use function ini_set;
use function is_array;
use function is_int;
use function is_object;
use function is_string;
use function libxml_clear_errors;
use function method_exists;
use function ob_end_clean;
use function ob_get_contents;
use function ob_get_level;
use function ob_start;
use function parse_url;
use function pathinfo;
use function preg_replace;
use function serialize;
use function setlocale;
use function sprintf;
use function strlen;
use function strpos;
use function substr;
use function trim;
use function var_export;
use DeepCopy\DeepCopy;
use PHPUnit\Framework\Constraint\Exception as ExceptionConstraint;
use PHPUnit\Framework\Constraint\ExceptionCode;
use PHPUnit\Framework\Constraint\ExceptionMessage;
use PHPUnit\Framework\Constraint\ExceptionMessageRegularExpression;
use PHPUnit\Framework\Constraint\LogicalOr;
use PHPUnit\Framework\Error\Deprecated;
use PHPUnit\Framework\Error\Error;
use PHPUnit\Framework\Error\Notice;
use PHPUnit\Framework\Error\Warning as WarningError;
use PHPUnit\Framework\MockObject\Generator as MockGenerator;
use PHPUnit\Framework\MockObject\MockBuilder;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount as AnyInvokedCountMatcher;
use PHPUnit\Framework\MockObject\Rule\InvokedAtIndex as InvokedAtIndexMatcher;
use PHPUnit\Framework\MockObject\Rule\InvokedAtLeastCount as InvokedAtLeastCountMatcher;
use PHPUnit\Framework\MockObject\Rule\InvokedAtLeastOnce as InvokedAtLeastOnceMatcher;
use PHPUnit\Framework\MockObject\Rule\InvokedAtMostCount as InvokedAtMostCountMatcher;
use PHPUnit\Framework\MockObject\Rule\InvokedCount as InvokedCountMatcher;
use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\MockObject\Stub\ConsecutiveCalls as ConsecutiveCallsStub;
use PHPUnit\Framework\MockObject\Stub\Exception as ExceptionStub;
use PHPUnit\Framework\MockObject\Stub\ReturnArgument as ReturnArgumentStub;
use PHPUnit\Framework\MockObject\Stub\ReturnCallback as ReturnCallbackStub;
use PHPUnit\Framework\MockObject\Stub\ReturnSelf as ReturnSelfStub;
use PHPUnit\Framework\MockObject\Stub\ReturnStub;
use PHPUnit\Framework\MockObject\Stub\ReturnValueMap as ReturnValueMapStub;
use PHPUnit\Runner\BaseTestRunner;
use PHPUnit\Runner\PhptTestCase;
use PHPUnit\Util\Exception as UtilException;
use PHPUnit\Util\GlobalState;
use PHPUnit\Util\PHP\AbstractPhpProcess;
use PHPUnit\Util\Test as TestUtil;
use PHPUnit\Util\Type;
use Prophecy\Exception\Prediction\PredictionException;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Prophet;
use ReflectionClass;
use ReflectionException;
use SebastianBergmann\Comparator\Comparator;
use SebastianBergmann\Comparator\Factory as ComparatorFactory;
use SebastianBergmann\Diff\Differ;
use SebastianBergmann\Exporter\Exporter;
use SebastianBergmann\GlobalState\Blacklist;
use SebastianBergmann\GlobalState\Restorer;
use SebastianBergmann\GlobalState\Snapshot;
use SebastianBergmann\ObjectEnumerator\Enumerator;
use Text_Template;
use Throwable;

abstract class TestCase extends Assert implements SelfDescribing, Test
{
private const LOCALE_CATEGORIES = [LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME];




protected $backupGlobals;




protected $backupGlobalsBlacklist = [];




protected $backupStaticAttributes;




protected $backupStaticAttributesBlacklist = [];




protected $runTestInSeparateProcess;




protected $preserveGlobalState = true;




private $runClassInSeparateProcess;




private $inIsolation = false;




private $data;




private $dataName;




private $expectedException;




private $expectedExceptionMessage;




private $expectedExceptionMessageRegExp;




private $expectedExceptionCode;




private $name = '';




private $dependencies = [];




private $dependencyInput = [];




private $iniSettings = [];




private $locale = [];




private $mockObjects = [];




private $mockObjectGenerator;




private $status = BaseTestRunner::STATUS_UNKNOWN;




private $statusMessage = '';




private $numAssertions = 0;




private $result;




private $testResult;




private $output = '';




private $outputExpectedRegex;




private $outputExpectedString;




private $outputCallback = false;




private $outputBufferingActive = false;




private $outputBufferingLevel;




private $outputRetrievedForAssertion = false;




private $snapshot;




private $prophet;




private $beStrictAboutChangesToGlobalState = false;




private $registerMockObjectsFromTestArgumentsRecursively = false;




private $warnings = [];




private $groups = [];




private $doesNotPerformAssertions = false;




private $customComparators = [];




private $doubledTypes = [];




private $deprecatedExpectExceptionMessageRegExpUsed = false;





public static function any(): AnyInvokedCountMatcher
{
return new AnyInvokedCountMatcher;
}




public static function never(): InvokedCountMatcher
{
return new InvokedCountMatcher(0);
}





public static function atLeast(int $requiredInvocations): InvokedAtLeastCountMatcher
{
return new InvokedAtLeastCountMatcher(
$requiredInvocations
);
}




public static function atLeastOnce(): InvokedAtLeastOnceMatcher
{
return new InvokedAtLeastOnceMatcher;
}




public static function once(): InvokedCountMatcher
{
return new InvokedCountMatcher(1);
}





public static function exactly(int $count): InvokedCountMatcher
{
return new InvokedCountMatcher($count);
}





public static function atMost(int $allowedInvocations): InvokedAtMostCountMatcher
{
return new InvokedAtMostCountMatcher($allowedInvocations);
}





public static function at(int $index): InvokedAtIndexMatcher
{
return new InvokedAtIndexMatcher($index);
}

public static function returnValue($value): ReturnStub
{
return new ReturnStub($value);
}

public static function returnValueMap(array $valueMap): ReturnValueMapStub
{
return new ReturnValueMapStub($valueMap);
}

public static function returnArgument(int $argumentIndex): ReturnArgumentStub
{
return new ReturnArgumentStub($argumentIndex);
}

public static function returnCallback($callback): ReturnCallbackStub
{
return new ReturnCallbackStub($callback);
}






public static function returnSelf(): ReturnSelfStub
{
return new ReturnSelfStub;
}

public static function throwException(Throwable $exception): ExceptionStub
{
return new ExceptionStub($exception);
}

public static function onConsecutiveCalls(...$args): ConsecutiveCallsStub
{
return new ConsecutiveCallsStub($args);
}







public function __construct($name = null, array $data = [], $dataName = '')
{
if ($name !== null) {
$this->setName($name);
}

$this->data = $data;
$this->dataName = $dataName;
}




public static function setUpBeforeClass(): void
{
}




public static function tearDownAfterClass(): void
{
}




protected function setUp(): void
{
}




protected function tearDown(): void
{
}







public function toString(): string
{
try {
$class = new ReflectionClass($this);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


$buffer = sprintf(
'%s::%s',
$class->name,
$this->getName(false)
);

return $buffer . $this->getDataSetAsString();
}

public function count(): int
{
return 1;
}

public function getActualOutputForAssertion(): string
{
$this->outputRetrievedForAssertion = true;

return $this->getActualOutput();
}

public function expectOutputRegex(string $expectedRegex): void
{
$this->outputExpectedRegex = $expectedRegex;
}

public function expectOutputString(string $expectedString): void
{
$this->outputExpectedString = $expectedString;
}




public function expectException(string $exception): void
{
$this->expectedException = $exception;
}




public function expectExceptionCode($code): void
{
$this->expectedExceptionCode = $code;
}

public function expectExceptionMessage(string $message): void
{
$this->expectedExceptionMessage = $message;
}

public function expectExceptionMessageMatches(string $regularExpression): void
{
$this->expectedExceptionMessageRegExp = $regularExpression;
}




public function expectExceptionMessageRegExp(string $regularExpression): void
{
$this->deprecatedExpectExceptionMessageRegExpUsed = true;

$this->expectExceptionMessageMatches($regularExpression);
}






public function expectExceptionObject(\Exception $exception): void
{
$this->expectException(get_class($exception));
$this->expectExceptionMessage($exception->getMessage());
$this->expectExceptionCode($exception->getCode());
}

public function expectNotToPerformAssertions(): void
{
$this->doesNotPerformAssertions = true;
}

public function expectDeprecation(): void
{
$this->expectException(Deprecated::class);
}

public function expectDeprecationMessage(string $message): void
{
$this->expectExceptionMessage($message);
}

public function expectDeprecationMessageMatches(string $regularExpression): void
{
$this->expectExceptionMessageMatches($regularExpression);
}

public function expectNotice(): void
{
$this->expectException(Notice::class);
}

public function expectNoticeMessage(string $message): void
{
$this->expectExceptionMessage($message);
}

public function expectNoticeMessageMatches(string $regularExpression): void
{
$this->expectExceptionMessageMatches($regularExpression);
}

public function expectWarning(): void
{
$this->expectException(WarningError::class);
}

public function expectWarningMessage(string $message): void
{
$this->expectExceptionMessage($message);
}

public function expectWarningMessageMatches(string $regularExpression): void
{
$this->expectExceptionMessageMatches($regularExpression);
}

public function expectError(): void
{
$this->expectException(Error::class);
}

public function expectErrorMessage(string $message): void
{
$this->expectExceptionMessage($message);
}

public function expectErrorMessageMatches(string $regularExpression): void
{
$this->expectExceptionMessageMatches($regularExpression);
}

public function getStatus(): int
{
return $this->status;
}

public function markAsRisky(): void
{
$this->status = BaseTestRunner::STATUS_RISKY;
}

public function getStatusMessage(): string
{
return $this->statusMessage;
}

public function hasFailed(): bool
{
$status = $this->getStatus();

return $status === BaseTestRunner::STATUS_FAILURE || $status === BaseTestRunner::STATUS_ERROR;
}














public function run(TestResult $result = null): TestResult
{
if ($result === null) {
$result = $this->createResult();
}

if (!$this instanceof WarningTestCase) {
$this->setTestResultObject($result);
}

if (!$this instanceof WarningTestCase &&
!$this instanceof SkippedTestCase &&
!$this->handleDependencies()) {
return $result;
}

if ($this->runInSeparateProcess()) {
$runEntireClass = $this->runClassInSeparateProcess && !$this->runTestInSeparateProcess;

try {
$class = new ReflectionClass($this);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if ($runEntireClass) {
$template = new Text_Template(
__DIR__ . '/../Util/PHP/Template/TestCaseClass.tpl'
);
} else {
$template = new Text_Template(
__DIR__ . '/../Util/PHP/Template/TestCaseMethod.tpl'
);
}

if ($this->preserveGlobalState) {
$constants = GlobalState::getConstantsAsString();
$globals = GlobalState::getGlobalsAsString();
$includedFiles = GlobalState::getIncludedFilesAsString();
$iniSettings = GlobalState::getIniSettingsAsString();
} else {
$constants = '';

if (!empty($GLOBALS['__PHPUNIT_BOOTSTRAP'])) {
$globals = '$GLOBALS[\'__PHPUNIT_BOOTSTRAP\'] = ' . var_export($GLOBALS['__PHPUNIT_BOOTSTRAP'], true) . ";\n";
} else {
$globals = '';
}

$includedFiles = '';
$iniSettings = '';
}

$coverage = $result->getCollectCodeCoverageInformation() ? 'true' : 'false';
$isStrictAboutTestsThatDoNotTestAnything = $result->isStrictAboutTestsThatDoNotTestAnything() ? 'true' : 'false';
$isStrictAboutOutputDuringTests = $result->isStrictAboutOutputDuringTests() ? 'true' : 'false';
$enforcesTimeLimit = $result->enforcesTimeLimit() ? 'true' : 'false';
$isStrictAboutTodoAnnotatedTests = $result->isStrictAboutTodoAnnotatedTests() ? 'true' : 'false';
$isStrictAboutResourceUsageDuringSmallTests = $result->isStrictAboutResourceUsageDuringSmallTests() ? 'true' : 'false';

if (defined('PHPUNIT_COMPOSER_INSTALL')) {
$composerAutoload = var_export(PHPUNIT_COMPOSER_INSTALL, true);
} else {
$composerAutoload = '\'\'';
}

if (defined('__PHPUNIT_PHAR__')) {
$phar = var_export(__PHPUNIT_PHAR__, true);
} else {
$phar = '\'\'';
}

if ($result->getCodeCoverage()) {
$codeCoverageFilter = $result->getCodeCoverage()->filter();
} else {
$codeCoverageFilter = null;
}

$data = var_export(serialize($this->data), true);
$dataName = var_export($this->dataName, true);
$dependencyInput = var_export(serialize($this->dependencyInput), true);
$includePath = var_export(get_include_path(), true);
$codeCoverageFilter = var_export(serialize($codeCoverageFilter), true);

 
 $data = "'." . $data . ".'";
$dataName = "'.(" . $dataName . ").'";
$dependencyInput = "'." . $dependencyInput . ".'";
$includePath = "'." . $includePath . ".'";
$codeCoverageFilter = "'." . $codeCoverageFilter . ".'";

$configurationFilePath = $GLOBALS['__PHPUNIT_CONFIGURATION_FILE'] ?? '';

$var = [
'composerAutoload' => $composerAutoload,
'phar' => $phar,
'filename' => $class->getFileName(),
'className' => $class->getName(),
'collectCodeCoverageInformation' => $coverage,
'data' => $data,
'dataName' => $dataName,
'dependencyInput' => $dependencyInput,
'constants' => $constants,
'globals' => $globals,
'include_path' => $includePath,
'included_files' => $includedFiles,
'iniSettings' => $iniSettings,
'isStrictAboutTestsThatDoNotTestAnything' => $isStrictAboutTestsThatDoNotTestAnything,
'isStrictAboutOutputDuringTests' => $isStrictAboutOutputDuringTests,
'enforcesTimeLimit' => $enforcesTimeLimit,
'isStrictAboutTodoAnnotatedTests' => $isStrictAboutTodoAnnotatedTests,
'isStrictAboutResourceUsageDuringSmallTests' => $isStrictAboutResourceUsageDuringSmallTests,
'codeCoverageFilter' => $codeCoverageFilter,
'configurationFilePath' => $configurationFilePath,
'name' => $this->getName(false),
];

if (!$runEntireClass) {
$var['methodName'] = $this->name;
}

$template->setVar($var);

$php = AbstractPhpProcess::factory();
$php->runTestJob($template->render(), $this, $result);
} else {
$result->run($this);
}

$this->result = null;

return $result;
}










public function getMockBuilder($className): MockBuilder
{
if (!is_string($className)) {
$this->addWarning('Passing an array of interface names to getMockBuilder() for creating a test double that implements multiple interfaces is deprecated and will no longer be supported in PHPUnit 9.');
}

$this->recordDoubledType($className);

return new MockBuilder($this, $className);
}

public function registerComparator(Comparator $comparator): void
{
ComparatorFactory::getInstance()->register($comparator);

$this->customComparators[] = $comparator;
}






public function setUseErrorHandler(bool $useErrorHandler): void
{
}






public function doubledTypes(): array
{
return array_unique($this->doubledTypes);
}




public function getGroups(): array
{
return $this->groups;
}




public function setGroups(array $groups): void
{
$this->groups = $groups;
}




public function getAnnotations(): array
{
return TestUtil::parseTestMethodAnnotations(
static::class,
$this->name
);
}






public function getName(bool $withDataSet = true): string
{
if ($withDataSet) {
return $this->name . $this->getDataSetAsString(false);
}

return $this->name;
}








public function getSize(): int
{
return TestUtil::getSize(
static::class,
$this->getName(false)
);
}






public function hasSize(): bool
{
return $this->getSize() !== TestUtil::UNKNOWN;
}






public function isSmall(): bool
{
return $this->getSize() === TestUtil::SMALL;
}






public function isMedium(): bool
{
return $this->getSize() === TestUtil::MEDIUM;
}






public function isLarge(): bool
{
return $this->getSize() === TestUtil::LARGE;
}




public function getActualOutput(): string
{
if (!$this->outputBufferingActive) {
return $this->output;
}

return (string) ob_get_contents();
}




public function hasOutput(): bool
{
if ($this->output === '') {
return false;
}

if ($this->hasExpectationOnOutput()) {
return false;
}

return true;
}




public function doesNotPerformAssertions(): bool
{
return $this->doesNotPerformAssertions;
}




public function hasExpectationOnOutput(): bool
{
return is_string($this->outputExpectedString) || is_string($this->outputExpectedRegex) || $this->outputRetrievedForAssertion;
}




public function getExpectedException(): ?string
{
return $this->expectedException;
}






public function getExpectedExceptionCode()
{
return $this->expectedExceptionCode;
}




public function getExpectedExceptionMessage(): ?string
{
return $this->expectedExceptionMessage;
}




public function getExpectedExceptionMessageRegExp(): ?string
{
return $this->expectedExceptionMessageRegExp;
}




public function setRegisterMockObjectsFromTestArgumentsRecursively(bool $flag): void
{
$this->registerMockObjectsFromTestArgumentsRecursively = $flag;
}






public function runBare(): void
{
$this->numAssertions = 0;

$this->snapshotGlobalState();
$this->startOutputBuffering();
clearstatcache();
$currentWorkingDirectory = getcwd();

$hookMethods = TestUtil::getHookMethods(static::class);

$hasMetRequirements = false;

try {
$this->checkRequirements();
$hasMetRequirements = true;

if ($this->inIsolation) {
foreach ($hookMethods['beforeClass'] as $method) {
$this->{$method}();
}
}

$this->setExpectedExceptionFromAnnotation();
$this->setDoesNotPerformAssertionsFromAnnotation();

foreach ($hookMethods['before'] as $method) {
$this->{$method}();
}

$this->assertPreConditions();
$this->testResult = $this->runTest();
$this->verifyMockObjects();
$this->assertPostConditions();

if (!empty($this->warnings)) {
throw new Warning(
implode(
"\n",
array_unique($this->warnings)
)
);
}

$this->status = BaseTestRunner::STATUS_PASSED;
} catch (IncompleteTest $e) {
$this->status = BaseTestRunner::STATUS_INCOMPLETE;
$this->statusMessage = $e->getMessage();
} catch (SkippedTest $e) {
$this->status = BaseTestRunner::STATUS_SKIPPED;
$this->statusMessage = $e->getMessage();
} catch (Warning $e) {
$this->status = BaseTestRunner::STATUS_WARNING;
$this->statusMessage = $e->getMessage();
} catch (AssertionFailedError $e) {
$this->status = BaseTestRunner::STATUS_FAILURE;
$this->statusMessage = $e->getMessage();
} catch (PredictionException $e) {
$this->status = BaseTestRunner::STATUS_FAILURE;
$this->statusMessage = $e->getMessage();
} catch (Throwable $_e) {
$e = $_e;
$this->status = BaseTestRunner::STATUS_ERROR;
$this->statusMessage = $_e->getMessage();
}

$this->mockObjects = [];
$this->prophet = null;


 
 try {
if ($hasMetRequirements) {
foreach ($hookMethods['after'] as $method) {
$this->{$method}();
}

if ($this->inIsolation) {
foreach ($hookMethods['afterClass'] as $method) {
$this->{$method}();
}
}
}
} catch (Throwable $_e) {
$e = $e ?? $_e;
}

try {
$this->stopOutputBuffering();
} catch (RiskyTestError $_e) {
$e = $e ?? $_e;
}

if (isset($_e)) {
$this->status = BaseTestRunner::STATUS_ERROR;
$this->statusMessage = $_e->getMessage();
}

clearstatcache();

if ($currentWorkingDirectory !== getcwd()) {
chdir($currentWorkingDirectory);
}

$this->restoreGlobalState();
$this->unregisterCustomComparators();
$this->cleanupIniSettings();
$this->cleanupLocaleSettings();
libxml_clear_errors();


 if (!isset($e)) {
try {
if ($this->outputExpectedRegex !== null) {
$this->assertRegExp($this->outputExpectedRegex, $this->output);
} elseif ($this->outputExpectedString !== null) {
$this->assertEquals($this->outputExpectedString, $this->output);
}
} catch (Throwable $_e) {
$e = $_e;
}
}


 if (isset($e)) {
if ($e instanceof PredictionException) {
$e = new AssertionFailedError($e->getMessage());
}

$this->onNotSuccessfulTest($e);
}
}




public function setName(string $name): void
{
$this->name = $name;
}






public function setDependencies(array $dependencies): void
{
$this->dependencies = $dependencies;
}




public function getDependencies(): array
{
return $this->dependencies;
}




public function hasDependencies(): bool
{
return count($this->dependencies) > 0;
}




public function setDependencyInput(array $dependencyInput): void
{
$this->dependencyInput = $dependencyInput;
}




public function getDependencyInput(): array
{
return $this->dependencyInput;
}




public function setBeStrictAboutChangesToGlobalState(?bool $beStrictAboutChangesToGlobalState): void
{
$this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState;
}




public function setBackupGlobals(?bool $backupGlobals): void
{
if ($this->backupGlobals === null && $backupGlobals !== null) {
$this->backupGlobals = $backupGlobals;
}
}




public function setBackupStaticAttributes(?bool $backupStaticAttributes): void
{
if ($this->backupStaticAttributes === null && $backupStaticAttributes !== null) {
$this->backupStaticAttributes = $backupStaticAttributes;
}
}




public function setRunTestInSeparateProcess(bool $runTestInSeparateProcess): void
{
if ($this->runTestInSeparateProcess === null) {
$this->runTestInSeparateProcess = $runTestInSeparateProcess;
}
}




public function setRunClassInSeparateProcess(bool $runClassInSeparateProcess): void
{
if ($this->runClassInSeparateProcess === null) {
$this->runClassInSeparateProcess = $runClassInSeparateProcess;
}
}




public function setPreserveGlobalState(bool $preserveGlobalState): void
{
$this->preserveGlobalState = $preserveGlobalState;
}




public function setInIsolation(bool $inIsolation): void
{
$this->inIsolation = $inIsolation;
}




public function isInIsolation(): bool
{
return $this->inIsolation;
}




public function getResult()
{
return $this->testResult;
}




public function setResult($result): void
{
$this->testResult = $result;
}




public function setOutputCallback(callable $callback): void
{
$this->outputCallback = $callback;
}




public function getTestResultObject(): ?TestResult
{
return $this->result;
}




public function setTestResultObject(TestResult $result): void
{
$this->result = $result;
}




public function registerMockObject(MockObject $mockObject): void
{
$this->mockObjects[] = $mockObject;
}




public function addToAssertionCount(int $count): void
{
$this->numAssertions += $count;
}






public function getNumAssertions(): int
{
return $this->numAssertions;
}




public function usesDataProvider(): bool
{
return !empty($this->data);
}




public function dataDescription(): string
{
return is_string($this->dataName) ? $this->dataName : '';
}






public function dataName()
{
return $this->dataName;
}




public function getDataSetAsString(bool $includeData = true): string
{
$buffer = '';

if (!empty($this->data)) {
if (is_int($this->dataName)) {
$buffer .= sprintf(' with data set #%d', $this->dataName);
} else {
$buffer .= sprintf(' with data set "%s"', $this->dataName);
}

if ($includeData) {
$exporter = new Exporter;

$buffer .= sprintf(' (%s)', $exporter->shortenedRecursiveExport($this->data));
}
}

return $buffer;
}






public function getProvidedData(): array
{
return $this->data;
}




public function addWarning(string $warning): void
{
$this->warnings[] = $warning;
}










protected function runTest()
{
if (trim($this->name) === '') {
throw new Exception(
'PHPUnit\Framework\TestCase::$name must be a non-blank string.'
);
}

$testArguments = array_merge($this->data, $this->dependencyInput);

$this->registerMockObjectsFromTestArguments($testArguments);

try {
$testResult = $this->{$this->name}(...array_values($testArguments));
} catch (Throwable $exception) {
if (!$this->checkExceptionExpectations($exception)) {
throw $exception;
}

if ($this->expectedException !== null) {
if ($this->expectedException === Error::class) {
$this->assertThat(
$exception,
LogicalOr::fromConstraints(
new ExceptionConstraint(Error::class),
new ExceptionConstraint(\Error::class)
)
);
} else {
$this->assertThat(
$exception,
new ExceptionConstraint(
$this->expectedException
)
);
}
}

if ($this->expectedExceptionMessage !== null) {
$this->assertThat(
$exception,
new ExceptionMessage(
$this->expectedExceptionMessage
)
);
}

if ($this->expectedExceptionMessageRegExp !== null) {
$this->assertThat(
$exception,
new ExceptionMessageRegularExpression(
$this->expectedExceptionMessageRegExp
)
);
}

if ($this->expectedExceptionCode !== null) {
$this->assertThat(
$exception,
new ExceptionCode(
$this->expectedExceptionCode
)
);
}

if ($this->deprecatedExpectExceptionMessageRegExpUsed) {
$this->addWarning('expectExceptionMessageRegExp() is deprecated in PHPUnit 8 and will be removed in PHPUnit 9. Use expectExceptionMessageMatches() instead.');
}

return;
}

if ($this->expectedException !== null) {
$this->assertThat(
null,
new ExceptionConstraint(
$this->expectedException
)
);
} elseif ($this->expectedExceptionMessage !== null) {
$this->numAssertions++;

throw new AssertionFailedError(
sprintf(
'Failed asserting that exception with message "%s" is thrown',
$this->expectedExceptionMessage
)
);
} elseif ($this->expectedExceptionMessageRegExp !== null) {
$this->numAssertions++;

throw new AssertionFailedError(
sprintf(
'Failed asserting that exception with message matching "%s" is thrown',
$this->expectedExceptionMessageRegExp
)
);
} elseif ($this->expectedExceptionCode !== null) {
$this->numAssertions++;

throw new AssertionFailedError(
sprintf(
'Failed asserting that exception with code "%s" is thrown',
$this->expectedExceptionCode
)
);
}

return $testResult;
}








protected function iniSet(string $varName, string $newValue): void
{
$currentValue = ini_set($varName, $newValue);

if ($currentValue !== false) {
$this->iniSettings[$varName] = $currentValue;
} else {
throw new Exception(
sprintf(
'INI setting "%s" could not be set to "%s".',
$varName,
$newValue
)
);
}
}







protected function setLocale(...$args): void
{
if (count($args) < 2) {
throw new Exception;
}

[$category, $locale] = $args;

if (defined('LC_MESSAGES')) {
$categories[] = LC_MESSAGES;
}

if (!in_array($category, self::LOCALE_CATEGORIES, true)) {
throw new Exception;
}

if (!is_array($locale) && !is_string($locale)) {
throw new Exception;
}

$this->locale[$category] = setlocale($category, 0);

$result = setlocale(...$args);

if ($result === false) {
throw new Exception(
'The locale functionality is not implemented on your platform, ' .
'the specified locale does not exist or the category name is ' .
'invalid.'
);
}
}








protected function createStub(string $originalClassName): Stub
{
return $this->createMock($originalClassName);
}










protected function createMock($originalClassName): MockObject
{
if (!is_string($originalClassName)) {
$this->addWarning('Passing an array of interface names to createMock() for creating a test double that implements multiple interfaces is deprecated and will no longer be supported in PHPUnit 9.');
}

return $this->getMockBuilder($originalClassName)
->disableOriginalConstructor()
->disableOriginalClone()
->disableArgumentCloning()
->disallowMockingUnknownTypes()
->getMock();
}










protected function createConfiguredMock($originalClassName, array $configuration): MockObject
{
$o = $this->createMock($originalClassName);

foreach ($configuration as $method => $return) {
$o->method($method)->willReturn($return);
}

return $o;
}











protected function createPartialMock($originalClassName, array $methods): MockObject
{
if (!is_string($originalClassName)) {
$this->addWarning('Passing an array of interface names to createPartialMock() for creating a test double that implements multiple interfaces is deprecated and will no longer be supported in PHPUnit 9.');
}

$class_names = is_array($originalClassName) ? $originalClassName : [$originalClassName];

foreach ($class_names as $class_name) {
$reflection = new ReflectionClass($class_name);

$mockedMethodsThatDontExist = array_filter(
$methods,
static function (string $method) use ($reflection)
{
return !$reflection->hasMethod($method);
}
);

if ($mockedMethodsThatDontExist) {
$this->addWarning(
sprintf(
'createPartialMock called with method(s) %s that do not exist in %s. This will not be allowed in future versions of PHPUnit.',
implode(', ', $mockedMethodsThatDontExist),
$class_name
)
);
}
}

return $this->getMockBuilder($originalClassName)
->disableOriginalConstructor()
->disableOriginalClone()
->disableArgumentCloning()
->disallowMockingUnknownTypes()
->setMethods(empty($methods) ? null : $methods)
->getMock();
}








protected function createTestProxy(string $originalClassName, array $constructorArguments = []): MockObject
{
return $this->getMockBuilder($originalClassName)
->setConstructorArgs($constructorArguments)
->enableProxyingToOriginalMethods()
->getMock();
}
















protected function getMockClass($originalClassName, $methods = [], array $arguments = [], $mockClassName = '', $callOriginalConstructor = false, $callOriginalClone = true, $callAutoload = true, $cloneArguments = false): string
{
$this->recordDoubledType($originalClassName);

$mock = $this->getMockObjectGenerator()->getMock(
$originalClassName,
$methods,
$arguments,
$mockClassName,
$callOriginalConstructor,
$callOriginalClone,
$callAutoload,
$cloneArguments
);

return get_class($mock);
}


















protected function getMockForAbstractClass($originalClassName, array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = [], $cloneArguments = false): MockObject
{
$this->recordDoubledType($originalClassName);

$mockObject = $this->getMockObjectGenerator()->getMockForAbstractClass(
$originalClassName,
$arguments,
$mockClassName,
$callOriginalConstructor,
$callOriginalClone,
$callAutoload,
$mockedMethods,
$cloneArguments
);

$this->registerMockObject($mockObject);

return $mockObject;
}














protected function getMockFromWsdl($wsdlFile, $originalClassName = '', $mockClassName = '', array $methods = [], $callOriginalConstructor = true, array $options = []): MockObject
{
$this->recordDoubledType('SoapClient');

if ($originalClassName === '') {
$fileName = pathinfo(basename(parse_url($wsdlFile, PHP_URL_PATH)), PATHINFO_FILENAME);
$originalClassName = preg_replace('/\W/', '', $fileName);
}

if (!class_exists($originalClassName)) {
eval(
$this->getMockObjectGenerator()->generateClassFromWsdl(
$wsdlFile,
$originalClassName,
$methods,
$options
)
);
}

$mockObject = $this->getMockObjectGenerator()->getMock(
$originalClassName,
$methods,
['', $options],
$mockClassName,
$callOriginalConstructor,
false,
false
);

$this->registerMockObject($mockObject);

return $mockObject;
}














protected function getMockForTrait($traitName, array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = [], $cloneArguments = false): MockObject
{
$this->recordDoubledType($traitName);

$mockObject = $this->getMockObjectGenerator()->getMockForTrait(
$traitName,
$arguments,
$mockClassName,
$callOriginalConstructor,
$callOriginalClone,
$callAutoload,
$mockedMethods,
$cloneArguments
);

$this->registerMockObject($mockObject);

return $mockObject;
}












protected function getObjectForTrait($traitName, array $arguments = [], $traitClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true)
{
$this->recordDoubledType($traitName);

return $this->getMockObjectGenerator()->getObjectForTrait(
$traitName,
$traitClassName,
$callAutoload,
$callOriginalConstructor,
$arguments
);
}










protected function prophesize($classOrInterface = null): ObjectProphecy
{
if (is_string($classOrInterface)) {
$this->recordDoubledType($classOrInterface);
}

return $this->getProphet()->prophesize($classOrInterface);
}






protected function createResult(): TestResult
{
return new TestResult;
}






protected function assertPreConditions(): void
{
}






protected function assertPostConditions(): void
{
}






protected function onNotSuccessfulTest(Throwable $t): void
{
throw $t;
}

private function setExpectedExceptionFromAnnotation(): void
{
if ($this->name === null) {
return;
}

try {
$expectedException = TestUtil::getExpectedException(
static::class,
$this->name
);

if ($expectedException !== false) {
$this->addWarning('The @expectedException, @expectedExceptionCode, @expectedExceptionMessage, and @expectedExceptionMessageRegExp annotations are deprecated. They will be removed in PHPUnit 9. Refactor your test to use expectException(), expectExceptionCode(), expectExceptionMessage(), or expectExceptionMessageMatches() instead.');

$this->expectException($expectedException['class']);

if ($expectedException['code'] !== null) {
$this->expectExceptionCode($expectedException['code']);
}

if ($expectedException['message'] !== '') {
$this->expectExceptionMessage($expectedException['message']);
} elseif ($expectedException['message_regex'] !== '') {
$this->expectExceptionMessageMatches($expectedException['message_regex']);
}
}
} catch (UtilException $e) {
}
}






private function checkRequirements(): void
{
if (!$this->name || !method_exists($this, $this->name)) {
return;
}

$missingRequirements = TestUtil::getMissingRequirements(
static::class,
$this->name
);

if (!empty($missingRequirements)) {
$this->markTestSkipped(implode(PHP_EOL, $missingRequirements));
}
}




private function verifyMockObjects(): void
{
foreach ($this->mockObjects as $mockObject) {
if ($mockObject->__phpunit_hasMatchers()) {
$this->numAssertions++;
}

$mockObject->__phpunit_verify(
$this->shouldInvocationMockerBeReset($mockObject)
);
}

if ($this->prophet !== null) {
try {
$this->prophet->checkPredictions();
} finally {
foreach ($this->prophet->getProphecies() as $objectProphecy) {
foreach ($objectProphecy->getMethodProphecies() as $methodProphecies) {
foreach ($methodProphecies as $methodProphecy) {
assert($methodProphecy instanceof MethodProphecy);

$this->numAssertions += count($methodProphecy->getCheckedPredictions());
}
}
}
}
}
}

private function handleDependencies(): bool
{
if (!empty($this->dependencies) && !$this->inIsolation) {
$passed = $this->result->passed();
$passedKeys = array_keys($passed);

foreach ($passedKeys as $key => $value) {
$pos = strpos($value, ' with data set');

if ($pos !== false) {
$passedKeys[$key] = substr($value, 0, $pos);
}
}

$passedKeys = array_flip(array_unique($passedKeys));

foreach ($this->dependencies as $dependency) {
$deepClone = false;
$shallowClone = false;

if (empty($dependency)) {
$this->markSkippedForNotSpecifyingDependency();

return false;
}

if (strpos($dependency, 'clone ') === 0) {
$deepClone = true;
$dependency = substr($dependency, strlen('clone '));
} elseif (strpos($dependency, '!clone ') === 0) {
$deepClone = false;
$dependency = substr($dependency, strlen('!clone '));
}

if (strpos($dependency, 'shallowClone ') === 0) {
$shallowClone = true;
$dependency = substr($dependency, strlen('shallowClone '));
} elseif (strpos($dependency, '!shallowClone ') === 0) {
$shallowClone = false;
$dependency = substr($dependency, strlen('!shallowClone '));
}

if (strpos($dependency, '::') === false) {
$dependency = static::class . '::' . $dependency;
}

if (!isset($passedKeys[$dependency])) {
if (!$this->isCallableTestMethod($dependency)) {
$this->warnAboutDependencyThatDoesNotExist($dependency);
} else {
$this->markSkippedForMissingDependency($dependency);
}

return false;
}

if (isset($passed[$dependency])) {
if ($passed[$dependency]['size'] !== TestUtil::UNKNOWN &&
$this->getSize() !== TestUtil::UNKNOWN &&
$passed[$dependency]['size'] > $this->getSize()) {
$this->result->addError(
$this,
new SkippedTestError(
'This test depends on a test that is larger than itself.'
),
0
);

return false;
}

if ($deepClone) {
$deepCopy = new DeepCopy;
$deepCopy->skipUncloneable(false);

$this->dependencyInput[$dependency] = $deepCopy->copy($passed[$dependency]['result']);
} elseif ($shallowClone) {
$this->dependencyInput[$dependency] = clone $passed[$dependency]['result'];
} else {
$this->dependencyInput[$dependency] = $passed[$dependency]['result'];
}
} else {
$this->dependencyInput[$dependency] = null;
}
}
}

return true;
}

private function markSkippedForNotSpecifyingDependency(): void
{
$this->status = BaseTestRunner::STATUS_SKIPPED;

$this->result->startTest($this);

$this->result->addError(
$this,
new SkippedTestError(
'This method has an invalid @depends annotation.'
),
0
);

$this->result->endTest($this, 0);
}

private function markSkippedForMissingDependency(string $dependency): void
{
$this->status = BaseTestRunner::STATUS_SKIPPED;

$this->result->startTest($this);

$this->result->addError(
$this,
new SkippedTestError(
sprintf(
'This test depends on "%s" to pass.',
$dependency
)
),
0
);

$this->result->endTest($this, 0);
}

private function warnAboutDependencyThatDoesNotExist(string $dependency): void
{
$this->status = BaseTestRunner::STATUS_WARNING;

$this->result->startTest($this);

$this->result->addWarning(
$this,
new Warning(
sprintf(
'This test depends on "%s" which does not exist.',
$dependency
)
),
0
);

$this->result->endTest($this, 0);
}




private function getMockObjectGenerator(): MockGenerator
{
if ($this->mockObjectGenerator === null) {
$this->mockObjectGenerator = new MockGenerator;
}

return $this->mockObjectGenerator;
}

private function startOutputBuffering(): void
{
ob_start();

$this->outputBufferingActive = true;
$this->outputBufferingLevel = ob_get_level();
}




private function stopOutputBuffering(): void
{
if (ob_get_level() !== $this->outputBufferingLevel) {
while (ob_get_level() >= $this->outputBufferingLevel) {
ob_end_clean();
}

throw new RiskyTestError(
'Test code or tested code did not (only) close its own output buffers'
);
}

$this->output = ob_get_contents();

if ($this->outputCallback !== false) {
$this->output = (string) call_user_func($this->outputCallback, $this->output);
}

ob_end_clean();

$this->outputBufferingActive = false;
$this->outputBufferingLevel = ob_get_level();
}

private function snapshotGlobalState(): void
{
if ($this->runTestInSeparateProcess || $this->inIsolation ||
(!$this->backupGlobals && !$this->backupStaticAttributes)) {
return;
}

$this->snapshot = $this->createGlobalStateSnapshot($this->backupGlobals === true);
}





private function restoreGlobalState(): void
{
if (!$this->snapshot instanceof Snapshot) {
return;
}

if ($this->beStrictAboutChangesToGlobalState) {
try {
$this->compareGlobalStateSnapshots(
$this->snapshot,
$this->createGlobalStateSnapshot($this->backupGlobals === true)
);
} catch (RiskyTestError $rte) {

 }
}

$restorer = new Restorer;

if ($this->backupGlobals) {
$restorer->restoreGlobalVariables($this->snapshot);
}

if ($this->backupStaticAttributes) {
$restorer->restoreStaticAttributes($this->snapshot);
}

$this->snapshot = null;

if (isset($rte)) {
throw $rte;
}
}

private function createGlobalStateSnapshot(bool $backupGlobals): Snapshot
{
$blacklist = new Blacklist;

foreach ($this->backupGlobalsBlacklist as $globalVariable) {
$blacklist->addGlobalVariable($globalVariable);
}

if (!defined('PHPUNIT_TESTSUITE')) {
$blacklist->addClassNamePrefix('PHPUnit');
$blacklist->addClassNamePrefix('SebastianBergmann\CodeCoverage');
$blacklist->addClassNamePrefix('SebastianBergmann\FileIterator');
$blacklist->addClassNamePrefix('SebastianBergmann\Invoker');
$blacklist->addClassNamePrefix('SebastianBergmann\Timer');
$blacklist->addClassNamePrefix('PHP_Token');
$blacklist->addClassNamePrefix('Symfony');
$blacklist->addClassNamePrefix('Text_Template');
$blacklist->addClassNamePrefix('Doctrine\Instantiator');
$blacklist->addClassNamePrefix('Prophecy');
$blacklist->addStaticAttribute(ComparatorFactory::class, 'instance');

foreach ($this->backupStaticAttributesBlacklist as $class => $attributes) {
foreach ($attributes as $attribute) {
$blacklist->addStaticAttribute($class, $attribute);
}
}
}

return new Snapshot(
$blacklist,
$backupGlobals,
(bool) $this->backupStaticAttributes,
false,
false,
false,
false,
false,
false,
false
);
}





private function compareGlobalStateSnapshots(Snapshot $before, Snapshot $after): void
{
$backupGlobals = $this->backupGlobals === null || $this->backupGlobals;

if ($backupGlobals) {
$this->compareGlobalStateSnapshotPart(
$before->globalVariables(),
$after->globalVariables(),
"--- Global variables before the test\n+++ Global variables after the test\n"
);

$this->compareGlobalStateSnapshotPart(
$before->superGlobalVariables(),
$after->superGlobalVariables(),
"--- Super-global variables before the test\n+++ Super-global variables after the test\n"
);
}

if ($this->backupStaticAttributes) {
$this->compareGlobalStateSnapshotPart(
$before->staticAttributes(),
$after->staticAttributes(),
"--- Static attributes before the test\n+++ Static attributes after the test\n"
);
}
}




private function compareGlobalStateSnapshotPart(array $before, array $after, string $header): void
{
if ($before != $after) {
$differ = new Differ($header);
$exporter = new Exporter;

$diff = $differ->diff(
$exporter->export($before),
$exporter->export($after)
);

throw new RiskyTestError(
$diff
);
}
}

private function getProphet(): Prophet
{
if ($this->prophet === null) {
$this->prophet = new Prophet;
}

return $this->prophet;
}




private function shouldInvocationMockerBeReset(MockObject $mock): bool
{
$enumerator = new Enumerator;

foreach ($enumerator->enumerate($this->dependencyInput) as $object) {
if ($mock === $object) {
return false;
}
}

if (!is_array($this->testResult) && !is_object($this->testResult)) {
return true;
}

return !in_array($mock, $enumerator->enumerate($this->testResult), true);
}






private function registerMockObjectsFromTestArguments(array $testArguments, array &$visited = []): void
{
if ($this->registerMockObjectsFromTestArgumentsRecursively) {
foreach ((new Enumerator)->enumerate($testArguments) as $object) {
if ($object instanceof MockObject) {
$this->registerMockObject($object);
}
}
} else {
foreach ($testArguments as $testArgument) {
if ($testArgument instanceof MockObject) {
if (Type::isCloneable($testArgument)) {
$testArgument = clone $testArgument;
}

$this->registerMockObject($testArgument);
} elseif (is_array($testArgument) && !in_array($testArgument, $visited, true)) {
$visited[] = $testArgument;

$this->registerMockObjectsFromTestArguments(
$testArgument,
$visited
);
}
}
}
}

private function setDoesNotPerformAssertionsFromAnnotation(): void
{
$annotations = $this->getAnnotations();

if (isset($annotations['method']['doesNotPerformAssertions'])) {
$this->doesNotPerformAssertions = true;
}
}

private function unregisterCustomComparators(): void
{
$factory = ComparatorFactory::getInstance();

foreach ($this->customComparators as $comparator) {
$factory->unregister($comparator);
}

$this->customComparators = [];
}

private function cleanupIniSettings(): void
{
foreach ($this->iniSettings as $varName => $oldValue) {
ini_set($varName, $oldValue);
}

$this->iniSettings = [];
}

private function cleanupLocaleSettings(): void
{
foreach ($this->locale as $category => $locale) {
setlocale($category, $locale);
}

$this->locale = [];
}




private function checkExceptionExpectations(Throwable $throwable): bool
{
$result = false;

if ($this->expectedException !== null || $this->expectedExceptionCode !== null || $this->expectedExceptionMessage !== null || $this->expectedExceptionMessageRegExp !== null) {
$result = true;
}

if ($throwable instanceof Exception) {
$result = false;
}

if (is_string($this->expectedException)) {
try {
$reflector = new ReflectionClass($this->expectedException);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if ($this->expectedException === 'PHPUnit\Framework\Exception' ||
$this->expectedException === '\PHPUnit\Framework\Exception' ||
$reflector->isSubclassOf(Exception::class)) {
$result = true;
}
}

return $result;
}

private function runInSeparateProcess(): bool
{
return ($this->runTestInSeparateProcess || $this->runClassInSeparateProcess) &&
!$this->inIsolation && !$this instanceof PhptTestCase;
}




private function recordDoubledType($originalClassName): void
{
if (is_string($originalClassName)) {
$this->doubledTypes[] = $originalClassName;
}

if (is_array($originalClassName)) {
foreach ($originalClassName as $_originalClassName) {
if (is_string($_originalClassName)) {
$this->doubledTypes[] = $_originalClassName;
}
}
}
}

private function isCallableTestMethod(string $dependency): bool
{
[$className, $methodName] = explode('::', $dependency);

if (!class_exists($className)) {
return false;
}

try {
$class = new ReflectionClass($className);
} catch (ReflectionException $e) {
return false;
}

if (!$class->isSubclassOf(__CLASS__)) {
return false;
}

if (!$class->hasMethod($methodName)) {
return false;
}

try {
$method = $class->getMethod($methodName);
} catch (ReflectionException $e) {
return false;
}

return TestUtil::isTestMethod($method);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;

use const PHP_EOL;
use function array_diff;
use function array_keys;
use function array_merge;
use function basename;
use function call_user_func;
use function class_exists;
use function count;
use function dirname;
use function file_exists;
use function get_declared_classes;
use function implode;
use function is_bool;
use function is_object;
use function is_string;
use function method_exists;
use function preg_match;
use function preg_quote;
use function sprintf;
use function substr;
use Iterator;
use IteratorAggregate;
use PHPUnit\Runner\BaseTestRunner;
use PHPUnit\Runner\Filter\Factory;
use PHPUnit\Runner\PhptTestCase;
use PHPUnit\Util\FileLoader;
use PHPUnit\Util\Test as TestUtil;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
use Throwable;




class TestSuite implements IteratorAggregate, SelfDescribing, Test
{





protected $backupGlobals;






protected $backupStaticAttributes;




protected $runTestInSeparateProcess = false;






protected $name = '';






protected $groups = [];






protected $tests = [];






protected $numTests = -1;




protected $testCase = false;




protected $foundClasses = [];






private $cachedNumTests;




private $beStrictAboutChangesToGlobalState;




private $iteratorFilter;




private $declaredClasses;






















public function __construct($theClass = '', string $name = '')
{
if (!is_string($theClass) && !$theClass instanceof ReflectionClass) {
throw InvalidArgumentException::create(
1,
'ReflectionClass object or string'
);
}

$this->declaredClasses = get_declared_classes();

if (!$theClass instanceof ReflectionClass) {
if (class_exists($theClass, true)) {
if ($name === '') {
$name = $theClass;
}

try {
$theClass = new ReflectionClass($theClass);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}

 } else {
$this->setName($theClass);

return;
}
}

if (!$theClass->isSubclassOf(TestCase::class)) {
$this->setName((string) $theClass);

return;
}

if ($name !== '') {
$this->setName($name);
} else {
$this->setName($theClass->getName());
}

$constructor = $theClass->getConstructor();

if ($constructor !== null &&
!$constructor->isPublic()) {
$this->addTest(
new WarningTestCase(
sprintf(
'Class "%s" has no public constructor.',
$theClass->getName()
)
)
);

return;
}

foreach ($theClass->getMethods() as $method) {
if ($method->getDeclaringClass()->getName() === Assert::class) {
continue;
}

if ($method->getDeclaringClass()->getName() === TestCase::class) {
continue;
}

if (!TestUtil::isTestMethod($method)) {
continue;
}

$this->addTestMethod($theClass, $method);
}

if (empty($this->tests)) {
$this->addTest(
new WarningTestCase(
sprintf(
'No tests found in class "%s".',
$theClass->getName()
)
)
);
}

$this->testCase = true;
}




public function toString(): string
{
return $this->getName();
}






public function addTest(Test $test, $groups = []): void
{
try {
$class = new ReflectionClass($test);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if (!$class->isAbstract()) {
$this->tests[] = $test;
$this->numTests = -1;

if ($test instanceof self && empty($groups)) {
$groups = $test->getGroups();
}

if (empty($groups)) {
$groups = ['default'];
}

foreach ($groups as $group) {
if (!isset($this->groups[$group])) {
$this->groups[$group] = [$test];
} else {
$this->groups[$group][] = $test;
}
}

if ($test instanceof TestCase) {
$test->setGroups($groups);
}
}
}








public function addTestSuite($testClass): void
{
if (!(is_object($testClass) || (is_string($testClass) && class_exists($testClass)))) {
throw InvalidArgumentException::create(
1,
'class name or object'
);
}

if (!is_object($testClass)) {
try {
$testClass = new ReflectionClass($testClass);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}

 }

if ($testClass instanceof self) {
$this->addTest($testClass);
} elseif ($testClass instanceof ReflectionClass) {
$suiteMethod = false;

if (!$testClass->isAbstract() && $testClass->hasMethod(BaseTestRunner::SUITE_METHODNAME)) {
try {
$method = $testClass->getMethod(
BaseTestRunner::SUITE_METHODNAME
);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if ($method->isStatic()) {
$this->addTest(
$method->invoke(null, $testClass->getName())
);

$suiteMethod = true;
}
}

if (!$suiteMethod && !$testClass->isAbstract() && $testClass->isSubclassOf(TestCase::class)) {
$this->addTest(new self($testClass));
}
} else {
throw new Exception;
}
}











public function addTestFile(string $filename): void
{
if (file_exists($filename) && substr($filename, -5) === '.phpt') {
$this->addTest(
new PhptTestCase($filename)
);

return;
}


 
 $filename = FileLoader::checkAndLoad($filename);
$newClasses = array_diff(get_declared_classes(), $this->declaredClasses);


 
 
 
 if (!empty($newClasses)) {

 
 
 $this->foundClasses = array_merge($newClasses, $this->foundClasses);
$this->declaredClasses = get_declared_classes();
}


 
 
 
 $shortName = basename($filename, '.php');
$shortNameRegEx = '/(?:^|_|\\\\)' . preg_quote($shortName, '/') . '$/';

foreach ($this->foundClasses as $i => $className) {
if (preg_match($shortNameRegEx, $className)) {
try {
$class = new ReflectionClass($className);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if ($class->getFileName() == $filename) {
$newClasses = [$className];
unset($this->foundClasses[$i]);

break;
}
}
}

foreach ($newClasses as $className) {
try {
$class = new ReflectionClass($className);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if (dirname($class->getFileName()) === __DIR__) {
continue;
}

if (!$class->isAbstract()) {
if ($class->hasMethod(BaseTestRunner::SUITE_METHODNAME)) {
try {
$method = $class->getMethod(
BaseTestRunner::SUITE_METHODNAME
);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if ($method->isStatic()) {
$this->addTest($method->invoke(null, $className));
}
} elseif ($class->implementsInterface(Test::class)) {
$this->addTestSuite($class);
}
}
}

$this->numTests = -1;
}






public function addTestFiles(iterable $fileNames): void
{
foreach ($fileNames as $filename) {
$this->addTestFile((string) $filename);
}
}




public function count(bool $preferCache = false): int
{
if ($preferCache && $this->cachedNumTests !== null) {
return $this->cachedNumTests;
}

$numTests = 0;

foreach ($this as $test) {
$numTests += count($test);
}

$this->cachedNumTests = $numTests;

return $numTests;
}




public function getName(): string
{
return $this->name;
}




public function getGroups(): array
{
return array_keys($this->groups);
}

public function getGroupDetails(): array
{
return $this->groups;
}




public function setGroupDetails(array $groups): void
{
$this->groups = $groups;
}













public function run(TestResult $result = null): TestResult
{
if ($result === null) {
$result = $this->createResult();
}

if (count($this) === 0) {
return $result;
}


$className = $this->name;
$hookMethods = TestUtil::getHookMethods($className);

$result->startTestSuite($this);

try {
foreach ($hookMethods['beforeClass'] as $beforeClassMethod) {
if ($this->testCase &&
class_exists($this->name, false) &&
method_exists($this->name, $beforeClassMethod)) {
if ($missingRequirements = TestUtil::getMissingRequirements($this->name, $beforeClassMethod)) {
$this->markTestSuiteSkipped(implode(PHP_EOL, $missingRequirements));
}

call_user_func([$this->name, $beforeClassMethod]);
}
}
} catch (SkippedTestSuiteError $error) {
foreach ($this->tests() as $test) {
$result->startTest($test);
$result->addFailure($test, $error, 0);
$result->endTest($test, 0);
}

$result->endTestSuite($this);

return $result;
} catch (Throwable $t) {
$errorAdded = false;

foreach ($this->tests() as $test) {
if ($result->shouldStop()) {
break;
}

$result->startTest($test);

if (!$errorAdded) {
$result->addError($test, $t, 0);

$errorAdded = true;
} else {
$result->addFailure(
$test,
new SkippedTestError('Test skipped because of an error in hook method'),
0
);
}

$result->endTest($test, 0);
}

$result->endTestSuite($this);

return $result;
}

foreach ($this as $test) {
if ($result->shouldStop()) {
break;
}

if ($test instanceof TestCase || $test instanceof self) {
$test->setBeStrictAboutChangesToGlobalState($this->beStrictAboutChangesToGlobalState);
$test->setBackupGlobals($this->backupGlobals);
$test->setBackupStaticAttributes($this->backupStaticAttributes);
$test->setRunTestInSeparateProcess($this->runTestInSeparateProcess);
}

$test->run($result);
}

try {
foreach ($hookMethods['afterClass'] as $afterClassMethod) {
if ($this->testCase &&
class_exists($this->name, false) &&
method_exists($this->name, $afterClassMethod)) {
call_user_func([$this->name, $afterClassMethod]);
}
}
} catch (Throwable $t) {
$message = "Exception in {$this->name}::{$afterClassMethod}" . PHP_EOL . $t->getMessage();
$error = new SyntheticError($message, 0, $t->getFile(), $t->getLine(), $t->getTrace());

$placeholderTest = clone $test;
$placeholderTest->setName($afterClassMethod);

$result->startTest($placeholderTest);
$result->addFailure($placeholderTest, $error, 0);
$result->endTest($placeholderTest, 0);
}

$result->endTestSuite($this);

return $result;
}

public function setRunTestInSeparateProcess(bool $runTestInSeparateProcess): void
{
$this->runTestInSeparateProcess = $runTestInSeparateProcess;
}

public function setName(string $name): void
{
$this->name = $name;
}






public function testAt(int $index)
{
return $this->tests[$index] ?? false;
}






public function tests(): array
{
return $this->tests;
}






public function setTests(array $tests): void
{
$this->tests = $tests;
}










public function markTestSuiteSkipped($message = ''): void
{
throw new SkippedTestSuiteError($message);
}




public function setBeStrictAboutChangesToGlobalState($beStrictAboutChangesToGlobalState): void
{
if (null === $this->beStrictAboutChangesToGlobalState && is_bool($beStrictAboutChangesToGlobalState)) {
$this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState;
}
}




public function setBackupGlobals($backupGlobals): void
{
if (null === $this->backupGlobals && is_bool($backupGlobals)) {
$this->backupGlobals = $backupGlobals;
}
}




public function setBackupStaticAttributes($backupStaticAttributes): void
{
if (null === $this->backupStaticAttributes && is_bool($backupStaticAttributes)) {
$this->backupStaticAttributes = $backupStaticAttributes;
}
}




public function getIterator(): Iterator
{
$iterator = new TestSuiteIterator($this);

if ($this->iteratorFilter !== null) {
$iterator = $this->iteratorFilter->factory($iterator, $this);
}

return $iterator;
}

public function injectFilter(Factory $filter): void
{
$this->iteratorFilter = $filter;

foreach ($this as $test) {
if ($test instanceof self) {
$test->injectFilter($filter);
}
}
}




protected function createResult(): TestResult
{
return new TestResult;
}




protected function addTestMethod(ReflectionClass $class, ReflectionMethod $method): void
{
if (!TestUtil::isTestMethod($method)) {
return;
}

$methodName = $method->getName();

$test = (new TestBuilder)->build($class, $methodName);

if ($test instanceof TestCase || $test instanceof DataProviderTestSuite) {
$test->setDependencies(
TestUtil::getDependencies($class->getName(), $methodName)
);
}

$this->addTest(
$test,
TestUtil::getGroups($class->getName(), $methodName)
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




interface SelfDescribing
{



public function toString(): string;
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class WarningTestCase extends TestCase
{



protected $backupGlobals = false;




protected $backupStaticAttributes = false;




protected $runTestInSeparateProcess = false;




private $message;

public function __construct(string $message = '')
{
$this->message = $message;

parent::__construct('Warning');
}

public function getMessage(): string
{
return $this->message;
}




public function toString(): string
{
return 'Warning';
}






protected function runTest(): void
{
throw new Warning($this->message);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;

use function get_class;
use function sprintf;
use function trim;
use PHPUnit\Framework\Error\Error;
use Throwable;




final class TestFailure
{



private $failedTest;




private $thrownException;




private $testName;




public static function exceptionToString(Throwable $e): string
{
if ($e instanceof SelfDescribing) {
$buffer = $e->toString();

if ($e instanceof ExpectationFailedException && $e->getComparisonFailure()) {
$buffer .= $e->getComparisonFailure()->getDiff();
}

if ($e instanceof PHPTAssertionFailedError) {
$buffer .= $e->getDiff();
}

if (!empty($buffer)) {
$buffer = trim($buffer) . "\n";
}

return $buffer;
}

if ($e instanceof Error) {
return $e->getMessage() . "\n";
}

if ($e instanceof ExceptionWrapper) {
return $e->getClassName() . ': ' . $e->getMessage() . "\n";
}

return get_class($e) . ': ' . $e->getMessage() . "\n";
}






public function __construct(Test $failedTest, $t)
{
if ($failedTest instanceof SelfDescribing) {
$this->testName = $failedTest->toString();
} else {
$this->testName = get_class($failedTest);
}

if (!$failedTest instanceof TestCase || !$failedTest->isInIsolation()) {
$this->failedTest = $failedTest;
}

$this->thrownException = $t;
}




public function toString(): string
{
return sprintf(
'%s: %s',
$this->testName,
$this->thrownException->getMessage()
);
}




public function getExceptionAsString(): string
{
return self::exceptionToString($this->thrownException);
}




public function getTestName(): string
{
return $this->testName;
}









public function failedTest(): ?Test
{
return $this->failedTest;
}




public function thrownException(): Throwable
{
return $this->thrownException;
}




public function exceptionMessage(): string
{
return $this->thrownException()->getMessage();
}





public function isFailure(): bool
{
return $this->thrownException() instanceof AssertionFailedError;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;

use Throwable;




trait TestListenerDefaultImplementation
{
public function addError(Test $test, Throwable $t, float $time): void
{
}

public function addWarning(Test $test, Warning $e, float $time): void
{
}

public function addFailure(Test $test, AssertionFailedError $e, float $time): void
{
}

public function addIncompleteTest(Test $test, Throwable $t, float $time): void
{
}

public function addRiskyTest(Test $test, Throwable $t, float $time): void
{
}

public function addSkippedTest(Test $test, Throwable $t, float $time): void
{
}

public function startTestSuite(TestSuite $suite): void
{
}

public function endTestSuite(TestSuite $suite): void
{
}

public function startTest(Test $test): void
{
}

public function endTest(Test $test, float $time): void
{
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class SkippedTestCase extends TestCase
{



protected $backupGlobals = false;




protected $backupStaticAttributes = false;




protected $runTestInSeparateProcess = false;




private $message;

public function __construct(string $className, string $methodName, string $message = '')
{
parent::__construct($className . '::' . $methodName);

$this->message = $message;
}

public function getMessage(): string
{
return $this->message;
}






public function toString(): string
{
return $this->getName();
}




protected function runTest(): void
{
$this->markTestSkipped($this->message);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




interface IncompleteTest
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




interface SkippedTest
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;

use function count;
use function explode;
use PHPUnit\Util\Test as TestUtil;




final class DataProviderTestSuite extends TestSuite
{



private $dependencies = [];




public function setDependencies(array $dependencies): void
{
$this->dependencies = $dependencies;

foreach ($this->tests as $test) {
if (!$test instanceof TestCase) {
continue;
}

$test->setDependencies($dependencies);
}
}

public function getDependencies(): array
{
return $this->dependencies;
}

public function hasDependencies(): bool
{
return count($this->dependencies) > 0;
}






public function getSize(): int
{
[$className, $methodName] = explode('::', $this->getName());

return TestUtil::getSize($className, $methodName);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;

use Throwable;




interface TestListener
{





public function addError(Test $test, Throwable $t, float $time): void;






public function addWarning(Test $test, Warning $e, float $time): void;






public function addFailure(Test $test, AssertionFailedError $e, float $time): void;






public function addIncompleteTest(Test $test, Throwable $t, float $time): void;






public function addRiskyTest(Test $test, Throwable $t, float $time): void;






public function addSkippedTest(Test $test, Throwable $t, float $time): void;




public function startTestSuite(TestSuite $suite): void;




public function endTestSuite(TestSuite $suite): void;






public function startTest(Test $test): void;






public function endTest(Test $test, float $time): void;
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;

use Countable;




interface Test extends Countable
{



public function run(TestResult $result = null): TestResult;
}
<?php declare(strict_types=1);








use PHPUnit\Framework\Assert;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\Constraint\ArrayHasKey;
use PHPUnit\Framework\Constraint\Attribute;
use PHPUnit\Framework\Constraint\Callback;
use PHPUnit\Framework\Constraint\ClassHasAttribute;
use PHPUnit\Framework\Constraint\ClassHasStaticAttribute;
use PHPUnit\Framework\Constraint\Constraint;
use PHPUnit\Framework\Constraint\Count;
use PHPUnit\Framework\Constraint\DirectoryExists;
use PHPUnit\Framework\Constraint\FileExists;
use PHPUnit\Framework\Constraint\GreaterThan;
use PHPUnit\Framework\Constraint\IsAnything;
use PHPUnit\Framework\Constraint\IsEmpty;
use PHPUnit\Framework\Constraint\IsEqual;
use PHPUnit\Framework\Constraint\IsFalse;
use PHPUnit\Framework\Constraint\IsFinite;
use PHPUnit\Framework\Constraint\IsIdentical;
use PHPUnit\Framework\Constraint\IsInfinite;
use PHPUnit\Framework\Constraint\IsInstanceOf;
use PHPUnit\Framework\Constraint\IsJson;
use PHPUnit\Framework\Constraint\IsNan;
use PHPUnit\Framework\Constraint\IsNull;
use PHPUnit\Framework\Constraint\IsReadable;
use PHPUnit\Framework\Constraint\IsTrue;
use PHPUnit\Framework\Constraint\IsType;
use PHPUnit\Framework\Constraint\IsWritable;
use PHPUnit\Framework\Constraint\LessThan;
use PHPUnit\Framework\Constraint\LogicalAnd;
use PHPUnit\Framework\Constraint\LogicalNot;
use PHPUnit\Framework\Constraint\LogicalOr;
use PHPUnit\Framework\Constraint\LogicalXor;
use PHPUnit\Framework\Constraint\ObjectHasAttribute;
use PHPUnit\Framework\Constraint\RegularExpression;
use PHPUnit\Framework\Constraint\StringContains;
use PHPUnit\Framework\Constraint\StringEndsWith;
use PHPUnit\Framework\Constraint\StringMatchesFormatDescription;
use PHPUnit\Framework\Constraint\StringStartsWith;
use PHPUnit\Framework\Constraint\TraversableContains;
use PHPUnit\Framework\Constraint\TraversableContainsEqual;
use PHPUnit\Framework\Constraint\TraversableContainsIdentical;
use PHPUnit\Framework\Constraint\TraversableContainsOnly;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount as AnyInvokedCountMatcher;
use PHPUnit\Framework\MockObject\Rule\InvokedAtIndex as InvokedAtIndexMatcher;
use PHPUnit\Framework\MockObject\Rule\InvokedAtLeastCount as InvokedAtLeastCountMatcher;
use PHPUnit\Framework\MockObject\Rule\InvokedAtLeastOnce as InvokedAtLeastOnceMatcher;
use PHPUnit\Framework\MockObject\Rule\InvokedAtMostCount as InvokedAtMostCountMatcher;
use PHPUnit\Framework\MockObject\Rule\InvokedCount as InvokedCountMatcher;
use PHPUnit\Framework\MockObject\Stub\ConsecutiveCalls as ConsecutiveCallsStub;
use PHPUnit\Framework\MockObject\Stub\Exception as ExceptionStub;
use PHPUnit\Framework\MockObject\Stub\ReturnArgument as ReturnArgumentStub;
use PHPUnit\Framework\MockObject\Stub\ReturnCallback as ReturnCallbackStub;
use PHPUnit\Framework\MockObject\Stub\ReturnSelf as ReturnSelfStub;
use PHPUnit\Framework\MockObject\Stub\ReturnStub;
use PHPUnit\Framework\MockObject\Stub\ReturnValueMap as ReturnValueMapStub;

if (!function_exists('PHPUnit\Framework\assertArrayHasKey')) {












function assertArrayHasKey($key, $array, string $message = ''): void
{
Assert::assertArrayHasKey(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertArraySubset')) {















function assertArraySubset($subset, $array, bool $checkForObjectIdentity = false, string $message = ''): void
{
Assert::assertArraySubset(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertArrayNotHasKey')) {












function assertArrayNotHasKey($key, $array, string $message = ''): void
{
Assert::assertArrayNotHasKey(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertContains')) {









function assertContains($needle, $haystack, string $message = '', bool $ignoreCase = false, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false): void
{
Assert::assertContains(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertContainsEquals')) {
function assertContainsEquals($needle, iterable $haystack, string $message = ''): void
{
Assert::assertContainsEquals(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeContains')) {















function assertAttributeContains($needle, string $haystackAttributeName, $haystackClassOrObject, string $message = '', bool $ignoreCase = false, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false): void
{
Assert::assertAttributeContains(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotContains')) {









function assertNotContains($needle, $haystack, string $message = '', bool $ignoreCase = false, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false): void
{
Assert::assertNotContains(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotContainsEquals')) {
function assertNotContainsEquals($needle, iterable $haystack, string $message = ''): void
{
Assert::assertNotContainsEquals(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeNotContains')) {















function assertAttributeNotContains($needle, string $haystackAttributeName, $haystackClassOrObject, string $message = '', bool $ignoreCase = false, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false): void
{
Assert::assertAttributeNotContains(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertContainsOnly')) {








function assertContainsOnly(string $type, iterable $haystack, ?bool $isNativeType = null, string $message = ''): void
{
Assert::assertContainsOnly(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertContainsOnlyInstancesOf')) {








function assertContainsOnlyInstancesOf(string $className, iterable $haystack, string $message = ''): void
{
Assert::assertContainsOnlyInstancesOf(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeContainsOnly')) {
















function assertAttributeContainsOnly(string $type, string $haystackAttributeName, $haystackClassOrObject, ?bool $isNativeType = null, string $message = ''): void
{
Assert::assertAttributeContainsOnly(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotContainsOnly')) {








function assertNotContainsOnly(string $type, iterable $haystack, ?bool $isNativeType = null, string $message = ''): void
{
Assert::assertNotContainsOnly(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeNotContainsOnly')) {

















function assertAttributeNotContainsOnly(string $type, string $haystackAttributeName, $haystackClassOrObject, ?bool $isNativeType = null, string $message = ''): void
{
Assert::assertAttributeNotContainsOnly(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertCount')) {











function assertCount(int $expectedCount, $haystack, string $message = ''): void
{
Assert::assertCount(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeCount')) {















function assertAttributeCount(int $expectedCount, string $haystackAttributeName, $haystackClassOrObject, string $message = ''): void
{
Assert::assertAttributeCount(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotCount')) {











function assertNotCount(int $expectedCount, $haystack, string $message = ''): void
{
Assert::assertNotCount(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeNotCount')) {















function assertAttributeNotCount(int $expectedCount, string $haystackAttributeName, $haystackClassOrObject, string $message = ''): void
{
Assert::assertAttributeNotCount(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertEquals')) {








function assertEquals($expected, $actual, string $message = '', float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): void
{
Assert::assertEquals(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertEqualsCanonicalizing')) {








function assertEqualsCanonicalizing($expected, $actual, string $message = ''): void
{
Assert::assertEqualsCanonicalizing(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertEqualsIgnoringCase')) {








function assertEqualsIgnoringCase($expected, $actual, string $message = ''): void
{
Assert::assertEqualsIgnoringCase(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertEqualsWithDelta')) {








function assertEqualsWithDelta($expected, $actual, float $delta, string $message = ''): void
{
Assert::assertEqualsWithDelta(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeEquals')) {














function assertAttributeEquals($expected, string $actualAttributeName, $actualClassOrObject, string $message = '', float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): void
{
Assert::assertAttributeEquals(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotEquals')) {













function assertNotEquals($expected, $actual, string $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false): void
{
Assert::assertNotEquals(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotEqualsCanonicalizing')) {








function assertNotEqualsCanonicalizing($expected, $actual, string $message = ''): void
{
Assert::assertNotEqualsCanonicalizing(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotEqualsIgnoringCase')) {








function assertNotEqualsIgnoringCase($expected, $actual, string $message = ''): void
{
Assert::assertNotEqualsIgnoringCase(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotEqualsWithDelta')) {








function assertNotEqualsWithDelta($expected, $actual, float $delta, string $message = ''): void
{
Assert::assertNotEqualsWithDelta(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeNotEquals')) {














function assertAttributeNotEquals($expected, string $actualAttributeName, $actualClassOrObject, string $message = '', float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): void
{
Assert::assertAttributeNotEquals(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertEmpty')) {










function assertEmpty($actual, string $message = ''): void
{
Assert::assertEmpty(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeEmpty')) {















function assertAttributeEmpty(string $haystackAttributeName, $haystackClassOrObject, string $message = ''): void
{
Assert::assertAttributeEmpty(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotEmpty')) {










function assertNotEmpty($actual, string $message = ''): void
{
Assert::assertNotEmpty(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeNotEmpty')) {















function assertAttributeNotEmpty(string $haystackAttributeName, $haystackClassOrObject, string $message = ''): void
{
Assert::assertAttributeNotEmpty(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertGreaterThan')) {








function assertGreaterThan($expected, $actual, string $message = ''): void
{
Assert::assertGreaterThan(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeGreaterThan')) {














function assertAttributeGreaterThan($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void
{
Assert::assertAttributeGreaterThan(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertGreaterThanOrEqual')) {








function assertGreaterThanOrEqual($expected, $actual, string $message = ''): void
{
Assert::assertGreaterThanOrEqual(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeGreaterThanOrEqual')) {














function assertAttributeGreaterThanOrEqual($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void
{
Assert::assertAttributeGreaterThanOrEqual(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertLessThan')) {








function assertLessThan($expected, $actual, string $message = ''): void
{
Assert::assertLessThan(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeLessThan')) {














function assertAttributeLessThan($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void
{
Assert::assertAttributeLessThan(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertLessThanOrEqual')) {








function assertLessThanOrEqual($expected, $actual, string $message = ''): void
{
Assert::assertLessThanOrEqual(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeLessThanOrEqual')) {














function assertAttributeLessThanOrEqual($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void
{
Assert::assertAttributeLessThanOrEqual(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertFileEquals')) {









function assertFileEquals(string $expected, string $actual, string $message = '', bool $canonicalize = false, bool $ignoreCase = false): void
{
Assert::assertFileEquals(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertFileEqualsCanonicalizing')) {









function assertFileEqualsCanonicalizing(string $expected, string $actual, string $message = ''): void
{
Assert::assertFileEqualsCanonicalizing(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertFileEqualsIgnoringCase')) {









function assertFileEqualsIgnoringCase(string $expected, string $actual, string $message = ''): void
{
Assert::assertFileEqualsIgnoringCase(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertFileNotEquals')) {









function assertFileNotEquals(string $expected, string $actual, string $message = '', bool $canonicalize = false, bool $ignoreCase = false): void
{
Assert::assertFileNotEquals(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertFileNotEqualsCanonicalizing')) {









function assertFileNotEqualsCanonicalizing(string $expected, string $actual, string $message = ''): void
{
Assert::assertFileNotEqualsCanonicalizing(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertFileNotEqualsIgnoringCase')) {









function assertFileNotEqualsIgnoringCase(string $expected, string $actual, string $message = ''): void
{
Assert::assertFileNotEqualsIgnoringCase(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringEqualsFile')) {









function assertStringEqualsFile(string $expectedFile, string $actualString, string $message = '', bool $canonicalize = false, bool $ignoreCase = false): void
{
Assert::assertStringEqualsFile(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringEqualsFileCanonicalizing')) {









function assertStringEqualsFileCanonicalizing(string $expectedFile, string $actualString, string $message = ''): void
{
Assert::assertStringEqualsFileCanonicalizing(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringEqualsFileIgnoringCase')) {









function assertStringEqualsFileIgnoringCase(string $expectedFile, string $actualString, string $message = ''): void
{
Assert::assertStringEqualsFileIgnoringCase(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringNotEqualsFile')) {









function assertStringNotEqualsFile(string $expectedFile, string $actualString, string $message = '', bool $canonicalize = false, bool $ignoreCase = false): void
{
Assert::assertStringNotEqualsFile(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringNotEqualsFileCanonicalizing')) {









function assertStringNotEqualsFileCanonicalizing(string $expectedFile, string $actualString, string $message = ''): void
{
Assert::assertStringNotEqualsFileCanonicalizing(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringNotEqualsFileIgnoringCase')) {









function assertStringNotEqualsFileIgnoringCase(string $expectedFile, string $actualString, string $message = ''): void
{
Assert::assertStringNotEqualsFileIgnoringCase(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsReadable')) {








function assertIsReadable(string $filename, string $message = ''): void
{
Assert::assertIsReadable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotIsReadable')) {








function assertNotIsReadable(string $filename, string $message = ''): void
{
Assert::assertNotIsReadable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsWritable')) {








function assertIsWritable(string $filename, string $message = ''): void
{
Assert::assertIsWritable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotIsWritable')) {








function assertNotIsWritable(string $filename, string $message = ''): void
{
Assert::assertNotIsWritable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertDirectoryExists')) {








function assertDirectoryExists(string $directory, string $message = ''): void
{
Assert::assertDirectoryExists(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertDirectoryNotExists')) {








function assertDirectoryNotExists(string $directory, string $message = ''): void
{
Assert::assertDirectoryNotExists(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertDirectoryIsReadable')) {








function assertDirectoryIsReadable(string $directory, string $message = ''): void
{
Assert::assertDirectoryIsReadable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertDirectoryNotIsReadable')) {








function assertDirectoryNotIsReadable(string $directory, string $message = ''): void
{
Assert::assertDirectoryNotIsReadable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertDirectoryIsWritable')) {








function assertDirectoryIsWritable(string $directory, string $message = ''): void
{
Assert::assertDirectoryIsWritable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertDirectoryNotIsWritable')) {








function assertDirectoryNotIsWritable(string $directory, string $message = ''): void
{
Assert::assertDirectoryNotIsWritable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertFileExists')) {








function assertFileExists(string $filename, string $message = ''): void
{
Assert::assertFileExists(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertFileNotExists')) {








function assertFileNotExists(string $filename, string $message = ''): void
{
Assert::assertFileNotExists(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertFileIsReadable')) {








function assertFileIsReadable(string $file, string $message = ''): void
{
Assert::assertFileIsReadable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertFileNotIsReadable')) {








function assertFileNotIsReadable(string $file, string $message = ''): void
{
Assert::assertFileNotIsReadable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertFileIsWritable')) {








function assertFileIsWritable(string $file, string $message = ''): void
{
Assert::assertFileIsWritable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertFileNotIsWritable')) {








function assertFileNotIsWritable(string $file, string $message = ''): void
{
Assert::assertFileNotIsWritable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertTrue')) {










function assertTrue($condition, string $message = ''): void
{
Assert::assertTrue(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotTrue')) {










function assertNotTrue($condition, string $message = ''): void
{
Assert::assertNotTrue(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertFalse')) {










function assertFalse($condition, string $message = ''): void
{
Assert::assertFalse(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotFalse')) {










function assertNotFalse($condition, string $message = ''): void
{
Assert::assertNotFalse(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNull')) {










function assertNull($actual, string $message = ''): void
{
Assert::assertNull(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotNull')) {










function assertNotNull($actual, string $message = ''): void
{
Assert::assertNotNull(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertFinite')) {








function assertFinite($actual, string $message = ''): void
{
Assert::assertFinite(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertInfinite')) {








function assertInfinite($actual, string $message = ''): void
{
Assert::assertInfinite(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNan')) {








function assertNan($actual, string $message = ''): void
{
Assert::assertNan(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertClassHasAttribute')) {









function assertClassHasAttribute(string $attributeName, string $className, string $message = ''): void
{
Assert::assertClassHasAttribute(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertClassNotHasAttribute')) {









function assertClassNotHasAttribute(string $attributeName, string $className, string $message = ''): void
{
Assert::assertClassNotHasAttribute(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertClassHasStaticAttribute')) {









function assertClassHasStaticAttribute(string $attributeName, string $className, string $message = ''): void
{
Assert::assertClassHasStaticAttribute(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertClassNotHasStaticAttribute')) {









function assertClassNotHasStaticAttribute(string $attributeName, string $className, string $message = ''): void
{
Assert::assertClassNotHasStaticAttribute(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertObjectHasAttribute')) {











function assertObjectHasAttribute(string $attributeName, $object, string $message = ''): void
{
Assert::assertObjectHasAttribute(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertObjectNotHasAttribute')) {











function assertObjectNotHasAttribute(string $attributeName, $object, string $message = ''): void
{
Assert::assertObjectNotHasAttribute(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertSame')) {














function assertSame($expected, $actual, string $message = ''): void
{
Assert::assertSame(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeSame')) {















function assertAttributeSame($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void
{
Assert::assertAttributeSame(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotSame')) {










function assertNotSame($expected, $actual, string $message = ''): void
{
Assert::assertNotSame(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeNotSame')) {















function assertAttributeNotSame($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void
{
Assert::assertAttributeNotSame(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertInstanceOf')) {













function assertInstanceOf(string $expected, $actual, string $message = ''): void
{
Assert::assertInstanceOf(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeInstanceOf')) {
















function assertAttributeInstanceOf(string $expected, string $attributeName, $classOrObject, string $message = ''): void
{
Assert::assertAttributeInstanceOf(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotInstanceOf')) {













function assertNotInstanceOf(string $expected, $actual, string $message = ''): void
{
Assert::assertNotInstanceOf(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeNotInstanceOf')) {
















function assertAttributeNotInstanceOf(string $expected, string $attributeName, $classOrObject, string $message = ''): void
{
Assert::assertAttributeNotInstanceOf(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertInternalType')) {











function assertInternalType(string $expected, $actual, string $message = ''): void
{
Assert::assertInternalType(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeInternalType')) {














function assertAttributeInternalType(string $expected, string $attributeName, $classOrObject, string $message = ''): void
{
Assert::assertAttributeInternalType(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsArray')) {










function assertIsArray($actual, string $message = ''): void
{
Assert::assertIsArray(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsBool')) {










function assertIsBool($actual, string $message = ''): void
{
Assert::assertIsBool(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsFloat')) {










function assertIsFloat($actual, string $message = ''): void
{
Assert::assertIsFloat(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsInt')) {










function assertIsInt($actual, string $message = ''): void
{
Assert::assertIsInt(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsNumeric')) {










function assertIsNumeric($actual, string $message = ''): void
{
Assert::assertIsNumeric(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsObject')) {










function assertIsObject($actual, string $message = ''): void
{
Assert::assertIsObject(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsResource')) {










function assertIsResource($actual, string $message = ''): void
{
Assert::assertIsResource(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsString')) {










function assertIsString($actual, string $message = ''): void
{
Assert::assertIsString(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsScalar')) {










function assertIsScalar($actual, string $message = ''): void
{
Assert::assertIsScalar(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsCallable')) {










function assertIsCallable($actual, string $message = ''): void
{
Assert::assertIsCallable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsIterable')) {










function assertIsIterable($actual, string $message = ''): void
{
Assert::assertIsIterable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotInternalType')) {











function assertNotInternalType(string $expected, $actual, string $message = ''): void
{
Assert::assertNotInternalType(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsNotArray')) {










function assertIsNotArray($actual, string $message = ''): void
{
Assert::assertIsNotArray(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsNotBool')) {










function assertIsNotBool($actual, string $message = ''): void
{
Assert::assertIsNotBool(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsNotFloat')) {










function assertIsNotFloat($actual, string $message = ''): void
{
Assert::assertIsNotFloat(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsNotInt')) {










function assertIsNotInt($actual, string $message = ''): void
{
Assert::assertIsNotInt(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsNotNumeric')) {










function assertIsNotNumeric($actual, string $message = ''): void
{
Assert::assertIsNotNumeric(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsNotObject')) {










function assertIsNotObject($actual, string $message = ''): void
{
Assert::assertIsNotObject(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsNotResource')) {










function assertIsNotResource($actual, string $message = ''): void
{
Assert::assertIsNotResource(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsNotString')) {










function assertIsNotString($actual, string $message = ''): void
{
Assert::assertIsNotString(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsNotScalar')) {










function assertIsNotScalar($actual, string $message = ''): void
{
Assert::assertIsNotScalar(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsNotCallable')) {










function assertIsNotCallable($actual, string $message = ''): void
{
Assert::assertIsNotCallable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertIsNotIterable')) {










function assertIsNotIterable($actual, string $message = ''): void
{
Assert::assertIsNotIterable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertAttributeNotInternalType')) {














function assertAttributeNotInternalType(string $expected, string $attributeName, $classOrObject, string $message = ''): void
{
Assert::assertAttributeNotInternalType(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertRegExp')) {








function assertRegExp(string $pattern, string $string, string $message = ''): void
{
Assert::assertRegExp(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotRegExp')) {








function assertNotRegExp(string $pattern, string $string, string $message = ''): void
{
Assert::assertNotRegExp(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertSameSize')) {













function assertSameSize($expected, $actual, string $message = ''): void
{
Assert::assertSameSize(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertNotSameSize')) {













function assertNotSameSize($expected, $actual, string $message = ''): void
{
Assert::assertNotSameSize(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringMatchesFormat')) {








function assertStringMatchesFormat(string $format, string $string, string $message = ''): void
{
Assert::assertStringMatchesFormat(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringNotMatchesFormat')) {








function assertStringNotMatchesFormat(string $format, string $string, string $message = ''): void
{
Assert::assertStringNotMatchesFormat(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringMatchesFormatFile')) {








function assertStringMatchesFormatFile(string $formatFile, string $string, string $message = ''): void
{
Assert::assertStringMatchesFormatFile(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringNotMatchesFormatFile')) {








function assertStringNotMatchesFormatFile(string $formatFile, string $string, string $message = ''): void
{
Assert::assertStringNotMatchesFormatFile(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringStartsWith')) {








function assertStringStartsWith(string $prefix, string $string, string $message = ''): void
{
Assert::assertStringStartsWith(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringStartsNotWith')) {











function assertStringStartsNotWith($prefix, $string, string $message = ''): void
{
Assert::assertStringStartsNotWith(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringContainsString')) {






function assertStringContainsString(string $needle, string $haystack, string $message = ''): void
{
Assert::assertStringContainsString(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringContainsStringIgnoringCase')) {






function assertStringContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void
{
Assert::assertStringContainsStringIgnoringCase(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringNotContainsString')) {






function assertStringNotContainsString(string $needle, string $haystack, string $message = ''): void
{
Assert::assertStringNotContainsString(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringNotContainsStringIgnoringCase')) {






function assertStringNotContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void
{
Assert::assertStringNotContainsStringIgnoringCase(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringEndsWith')) {








function assertStringEndsWith(string $suffix, string $string, string $message = ''): void
{
Assert::assertStringEndsWith(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertStringEndsNotWith')) {








function assertStringEndsNotWith(string $suffix, string $string, string $message = ''): void
{
Assert::assertStringEndsNotWith(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertXmlFileEqualsXmlFile')) {









function assertXmlFileEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void
{
Assert::assertXmlFileEqualsXmlFile(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertXmlFileNotEqualsXmlFile')) {









function assertXmlFileNotEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void
{
Assert::assertXmlFileNotEqualsXmlFile(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertXmlStringEqualsXmlFile')) {











function assertXmlStringEqualsXmlFile(string $expectedFile, $actualXml, string $message = ''): void
{
Assert::assertXmlStringEqualsXmlFile(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertXmlStringNotEqualsXmlFile')) {











function assertXmlStringNotEqualsXmlFile(string $expectedFile, $actualXml, string $message = ''): void
{
Assert::assertXmlStringNotEqualsXmlFile(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertXmlStringEqualsXmlString')) {












function assertXmlStringEqualsXmlString($expectedXml, $actualXml, string $message = ''): void
{
Assert::assertXmlStringEqualsXmlString(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertXmlStringNotEqualsXmlString')) {












function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, string $message = ''): void
{
Assert::assertXmlStringNotEqualsXmlString(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertEqualXMLStructure')) {









function assertEqualXMLStructure(DOMElement $expectedElement, DOMElement $actualElement, bool $checkAttributes = false, string $message = ''): void
{
Assert::assertEqualXMLStructure(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertThat')) {








function assertThat($value, Constraint $constraint, string $message = ''): void
{
Assert::assertThat(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertJson')) {








function assertJson(string $actualJson, string $message = ''): void
{
Assert::assertJson(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertJsonStringEqualsJsonString')) {








function assertJsonStringEqualsJsonString(string $expectedJson, string $actualJson, string $message = ''): void
{
Assert::assertJsonStringEqualsJsonString(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertJsonStringNotEqualsJsonString')) {











function assertJsonStringNotEqualsJsonString($expectedJson, $actualJson, string $message = ''): void
{
Assert::assertJsonStringNotEqualsJsonString(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertJsonStringEqualsJsonFile')) {








function assertJsonStringEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void
{
Assert::assertJsonStringEqualsJsonFile(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertJsonStringNotEqualsJsonFile')) {








function assertJsonStringNotEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void
{
Assert::assertJsonStringNotEqualsJsonFile(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertJsonFileEqualsJsonFile')) {








function assertJsonFileEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void
{
Assert::assertJsonFileEqualsJsonFile(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\assertJsonFileNotEqualsJsonFile')) {








function assertJsonFileNotEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void
{
Assert::assertJsonFileNotEqualsJsonFile(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\logicalAnd')) {
function logicalAnd(): LogicalAnd
{
return Assert::logicalAnd(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\logicalOr')) {
function logicalOr(): LogicalOr
{
return Assert::logicalOr(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\logicalNot')) {
function logicalNot(Constraint $constraint): LogicalNot
{
return Assert::logicalNot(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\logicalXor')) {
function logicalXor(): LogicalXor
{
return Assert::logicalXor(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\anything')) {
function anything(): IsAnything
{
return Assert::anything(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\isTrue')) {
function isTrue(): IsTrue
{
return Assert::isTrue(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\callback')) {
function callback(callable $callback): Callback
{
return Assert::callback(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\isFalse')) {
function isFalse(): IsFalse
{
return Assert::isFalse(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\isJson')) {
function isJson(): IsJson
{
return Assert::isJson(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\isNull')) {
function isNull(): IsNull
{
return Assert::isNull(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\isFinite')) {
function isFinite(): IsFinite
{
return Assert::isFinite(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\isInfinite')) {
function isInfinite(): IsInfinite
{
return Assert::isInfinite(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\isNan')) {
function isNan(): IsNan
{
return Assert::isNan(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\attribute')) {
function attribute(Constraint $constraint, string $attributeName): Attribute
{
return Assert::attribute(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\contains')) {
function contains($value, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false): TraversableContains
{
return Assert::contains(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\containsEqual')) {
function containsEqual($value): TraversableContainsEqual
{
return Assert::containsEqual(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\containsIdentical')) {
function containsIdentical($value): TraversableContainsIdentical
{
return Assert::containsIdentical(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\containsOnly')) {
function containsOnly(string $type): TraversableContainsOnly
{
return Assert::containsOnly(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\containsOnlyInstancesOf')) {
function containsOnlyInstancesOf(string $className): TraversableContainsOnly
{
return Assert::containsOnlyInstancesOf(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\arrayHasKey')) {
function arrayHasKey($key): ArrayHasKey
{
return Assert::arrayHasKey(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\equalTo')) {
function equalTo($value, float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): IsEqual
{
return Assert::equalTo(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\attributeEqualTo')) {
function attributeEqualTo(string $attributeName, $value, float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): Attribute
{
return Assert::attributeEqualTo(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\isEmpty')) {
function isEmpty(): IsEmpty
{
return Assert::isEmpty(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\isWritable')) {
function isWritable(): IsWritable
{
return Assert::isWritable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\isReadable')) {
function isReadable(): IsReadable
{
return Assert::isReadable(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\directoryExists')) {
function directoryExists(): DirectoryExists
{
return Assert::directoryExists(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\fileExists')) {
function fileExists(): FileExists
{
return Assert::fileExists(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\greaterThan')) {
function greaterThan($value): GreaterThan
{
return Assert::greaterThan(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\greaterThanOrEqual')) {
function greaterThanOrEqual($value): LogicalOr
{
return Assert::greaterThanOrEqual(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\classHasAttribute')) {
function classHasAttribute(string $attributeName): ClassHasAttribute
{
return Assert::classHasAttribute(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\classHasStaticAttribute')) {
function classHasStaticAttribute(string $attributeName): ClassHasStaticAttribute
{
return Assert::classHasStaticAttribute(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\objectHasAttribute')) {
function objectHasAttribute($attributeName): ObjectHasAttribute
{
return Assert::objectHasAttribute(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\identicalTo')) {
function identicalTo($value): IsIdentical
{
return Assert::identicalTo(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\isInstanceOf')) {
function isInstanceOf(string $className): IsInstanceOf
{
return Assert::isInstanceOf(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\isType')) {
function isType(string $type): IsType
{
return Assert::isType(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\lessThan')) {
function lessThan($value): LessThan
{
return Assert::lessThan(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\lessThanOrEqual')) {
function lessThanOrEqual($value): LogicalOr
{
return Assert::lessThanOrEqual(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\matchesRegularExpression')) {
function matchesRegularExpression(string $pattern): RegularExpression
{
return Assert::matchesRegularExpression(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\matches')) {
function matches(string $string): StringMatchesFormatDescription
{
return Assert::matches(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\stringStartsWith')) {
function stringStartsWith($prefix): StringStartsWith
{
return Assert::stringStartsWith(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\stringContains')) {
function stringContains(string $string, bool $case = true): StringContains
{
return Assert::stringContains(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\stringEndsWith')) {
function stringEndsWith(string $suffix): StringEndsWith
{
return Assert::stringEndsWith(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\countOf')) {
function countOf(int $count): Count
{
return Assert::countOf(...\func_get_args());
}
}

if (!function_exists('PHPUnit\Framework\any')) {




function any(): AnyInvokedCountMatcher
{
return new AnyInvokedCountMatcher;
}
}

if (!function_exists('PHPUnit\Framework\never')) {



function never(): InvokedCountMatcher
{
return new InvokedCountMatcher(0);
}
}

if (!function_exists('PHPUnit\Framework\atLeast')) {




function atLeast(int $requiredInvocations): InvokedAtLeastCountMatcher
{
return new InvokedAtLeastCountMatcher(
$requiredInvocations
);
}
}

if (!function_exists('PHPUnit\Framework\atLeastOnce')) {



function atLeastOnce(): InvokedAtLeastOnceMatcher
{
return new InvokedAtLeastOnceMatcher;
}
}

if (!function_exists('PHPUnit\Framework\once')) {



function once(): InvokedCountMatcher
{
return new InvokedCountMatcher(1);
}
}

if (!function_exists('PHPUnit\Framework\exactly')) {




function exactly(int $count): InvokedCountMatcher
{
return new InvokedCountMatcher($count);
}
}

if (!function_exists('PHPUnit\Framework\atMost')) {




function atMost(int $allowedInvocations): InvokedAtMostCountMatcher
{
return new InvokedAtMostCountMatcher($allowedInvocations);
}
}

if (!function_exists('PHPUnit\Framework\at')) {




function at(int $index): InvokedAtIndexMatcher
{
return new InvokedAtIndexMatcher($index);
}
}

if (!function_exists('PHPUnit\Framework\returnValue')) {
function returnValue($value): ReturnStub
{
return new ReturnStub($value);
}
}

if (!function_exists('PHPUnit\Framework\returnValueMap')) {
function returnValueMap(array $valueMap): ReturnValueMapStub
{
return new ReturnValueMapStub($valueMap);
}
}

if (!function_exists('PHPUnit\Framework\returnArgument')) {
function returnArgument(int $argumentIndex): ReturnArgumentStub
{
return new ReturnArgumentStub($argumentIndex);
}
}

if (!function_exists('PHPUnit\Framework\returnCallback')) {
function returnCallback($callback): ReturnCallbackStub
{
return new ReturnCallbackStub($callback);
}
}

if (!function_exists('PHPUnit\Framework\returnSelf')) {





function returnSelf(): ReturnSelfStub
{
return new ReturnSelfStub;
}
}

if (!function_exists('PHPUnit\Framework\throwException')) {
function throwException(Throwable $exception): ExceptionStub
{
return new ExceptionStub($exception);
}
}

if (!function_exists('PHPUnit\Framework\onConsecutiveCalls')) {
function onConsecutiveCalls(): ConsecutiveCallsStub
{
$args = \func_get_args();

return new ConsecutiveCallsStub($args);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class PHPTAssertionFailedError extends SyntheticError
{



private $diff;

public function __construct(string $message, int $code, string $file, int $line, array $trace, string $diff)
{
parent::__construct($message, $code, $file, $line, $trace);
$this->diff = $diff;
}

public function getDiff(): string
{
return $this->diff;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




class RiskyTestError extends AssertionFailedError
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class SkippedTestError extends AssertionFailedError implements SkippedTest
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class NoChildTestSuiteException extends Exception
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class CoveredCodeNotExecutedException extends RiskyTestError
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class UnintentionallyCoveredCodeError extends RiskyTestError
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class SkippedTestSuiteError extends AssertionFailedError implements SkippedTest
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;

use function array_keys;
use function get_object_vars;
use PHPUnit\Util\Filter;
use RuntimeException;
use Throwable;























class Exception extends RuntimeException implements \PHPUnit\Exception
{



protected $serializableTrace;

public function __construct($message = '', $code = 0, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);

$this->serializableTrace = $this->getTrace();

foreach (array_keys($this->serializableTrace) as $key) {
unset($this->serializableTrace[$key]['args']);
}
}

public function __toString(): string
{
$string = TestFailure::exceptionToString($this);

if ($trace = Filter::getFilteredStacktrace($this)) {
$string .= "\n" . $trace;
}

return $string;
}

public function __sleep(): array
{
return array_keys(get_object_vars($this));
}




public function getSerializableTrace(): array
{
return $this->serializableTrace;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class InvalidDataProviderException extends Exception
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class SyntheticSkippedError extends SyntheticError implements SkippedTest
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class Warning extends Exception implements SelfDescribing
{



public function toString(): string
{
return $this->getMessage();
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class MissingCoversAnnotationException extends RiskyTestError
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




class AssertionFailedError extends Exception implements SelfDescribing
{



public function toString(): string
{
return $this->getMessage();
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class InvalidCoversTargetException extends CodeCoverageException
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class IncompleteTestError extends AssertionFailedError implements IncompleteTest
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




final class OutputError extends AssertionFailedError
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;

use function debug_backtrace;
use function in_array;
use function lcfirst;
use function sprintf;




final class InvalidArgumentException extends Exception
{
public static function create(int $argument, string $type): self
{
$stack = debug_backtrace();

return new self(
sprintf(
'Argument #%d of %s::%s() must be %s %s',
$argument,
$stack[1]['class'],
$stack[1]['function'],
in_array(lcfirst($type)[0], ['a', 'e', 'i', 'o', 'u'], true) ? 'an' : 'a',
$type
)
);
}

private function __construct(string $message = '', int $code = 0, \Exception $previous = null)
{
parent::__construct($message, $code, $previous);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




class SyntheticError extends AssertionFailedError
{





protected $syntheticFile = '';






protected $syntheticLine = 0;






protected $syntheticTrace = [];

public function __construct(string $message, int $code, string $file, int $line, array $trace)
{
parent::__construct($message, $code);

$this->syntheticFile = $file;
$this->syntheticLine = $line;
$this->syntheticTrace = $trace;
}

public function getSyntheticFile(): string
{
return $this->syntheticFile;
}

public function getSyntheticLine(): int
{
return $this->syntheticLine;
}

public function getSyntheticTrace(): array
{
return $this->syntheticTrace;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;




class CodeCoverageException extends Exception
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;

use Exception;
use SebastianBergmann\Comparator\ComparisonFailure;










final class ExpectationFailedException extends AssertionFailedError
{



protected $comparisonFailure;

public function __construct(string $message, ComparisonFailure $comparisonFailure = null, Exception $previous = null)
{
$this->comparisonFailure = $comparisonFailure;

parent::__construct($message, 0, $previous);
}

public function getComparisonFailure(): ?ComparisonFailure
{
return $this->comparisonFailure;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;

use const DEBUG_BACKTRACE_IGNORE_ARGS;
use const PHP_EOL;
use function array_key_exists;
use function array_shift;
use function array_unshift;
use function assert;
use function class_exists;
use function count;
use function debug_backtrace;
use function explode;
use function file_get_contents;
use function func_get_args;
use function implode;
use function interface_exists;
use function is_array;
use function is_bool;
use function is_int;
use function is_iterable;
use function is_object;
use function is_string;
use function preg_match;
use function preg_split;
use function sprintf;
use function strpos;
use ArrayAccess;
use Countable;
use DOMAttr;
use DOMDocument;
use DOMElement;
use PHPUnit\Framework\Constraint\ArrayHasKey;
use PHPUnit\Framework\Constraint\ArraySubset;
use PHPUnit\Framework\Constraint\Attribute;
use PHPUnit\Framework\Constraint\Callback;
use PHPUnit\Framework\Constraint\ClassHasAttribute;
use PHPUnit\Framework\Constraint\ClassHasStaticAttribute;
use PHPUnit\Framework\Constraint\Constraint;
use PHPUnit\Framework\Constraint\Count;
use PHPUnit\Framework\Constraint\DirectoryExists;
use PHPUnit\Framework\Constraint\FileExists;
use PHPUnit\Framework\Constraint\GreaterThan;
use PHPUnit\Framework\Constraint\IsAnything;
use PHPUnit\Framework\Constraint\IsEmpty;
use PHPUnit\Framework\Constraint\IsEqual;
use PHPUnit\Framework\Constraint\IsFalse;
use PHPUnit\Framework\Constraint\IsFinite;
use PHPUnit\Framework\Constraint\IsIdentical;
use PHPUnit\Framework\Constraint\IsInfinite;
use PHPUnit\Framework\Constraint\IsInstanceOf;
use PHPUnit\Framework\Constraint\IsJson;
use PHPUnit\Framework\Constraint\IsNan;
use PHPUnit\Framework\Constraint\IsNull;
use PHPUnit\Framework\Constraint\IsReadable;
use PHPUnit\Framework\Constraint\IsTrue;
use PHPUnit\Framework\Constraint\IsType;
use PHPUnit\Framework\Constraint\IsWritable;
use PHPUnit\Framework\Constraint\JsonMatches;
use PHPUnit\Framework\Constraint\LessThan;
use PHPUnit\Framework\Constraint\LogicalAnd;
use PHPUnit\Framework\Constraint\LogicalNot;
use PHPUnit\Framework\Constraint\LogicalOr;
use PHPUnit\Framework\Constraint\LogicalXor;
use PHPUnit\Framework\Constraint\ObjectHasAttribute;
use PHPUnit\Framework\Constraint\RegularExpression;
use PHPUnit\Framework\Constraint\SameSize;
use PHPUnit\Framework\Constraint\StringContains;
use PHPUnit\Framework\Constraint\StringEndsWith;
use PHPUnit\Framework\Constraint\StringMatchesFormatDescription;
use PHPUnit\Framework\Constraint\StringStartsWith;
use PHPUnit\Framework\Constraint\TraversableContains;
use PHPUnit\Framework\Constraint\TraversableContainsEqual;
use PHPUnit\Framework\Constraint\TraversableContainsIdentical;
use PHPUnit\Framework\Constraint\TraversableContainsOnly;
use PHPUnit\Util\Type;
use PHPUnit\Util\Xml;
use ReflectionClass;
use ReflectionException;
use ReflectionObject;
use Traversable;




abstract class Assert
{



private static $count = 0;











public static function assertArrayHasKey($key, $array, string $message = ''): void
{
if (!(is_int($key) || is_string($key))) {
throw InvalidArgumentException::create(
1,
'integer or string'
);
}

if (!(is_array($array) || $array instanceof ArrayAccess)) {
throw InvalidArgumentException::create(
2,
'array or ArrayAccess'
);
}

$constraint = new ArrayHasKey($key);

static::assertThat($array, $constraint, $message);
}















public static function assertArraySubset($subset, $array, bool $checkForObjectIdentity = false, string $message = ''): void
{
self::createWarning('assertArraySubset() is deprecated and will be removed in PHPUnit 9.');

if (!(is_array($subset) || $subset instanceof ArrayAccess)) {
throw InvalidArgumentException::create(
1,
'array or ArrayAccess'
);
}

if (!(is_array($array) || $array instanceof ArrayAccess)) {
throw InvalidArgumentException::create(
2,
'array or ArrayAccess'
);
}

$constraint = new ArraySubset($subset, $checkForObjectIdentity);

static::assertThat($array, $constraint, $message);
}











public static function assertArrayNotHasKey($key, $array, string $message = ''): void
{
if (!(is_int($key) || is_string($key))) {
throw InvalidArgumentException::create(
1,
'integer or string'
);
}

if (!(is_array($array) || $array instanceof ArrayAccess)) {
throw InvalidArgumentException::create(
2,
'array or ArrayAccess'
);
}

$constraint = new LogicalNot(
new ArrayHasKey($key)
);

static::assertThat($array, $constraint, $message);
}








public static function assertContains($needle, $haystack, string $message = '', bool $ignoreCase = false, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false): void
{

 if (is_string($haystack)) {
self::createWarning('Using assertContains() with string haystacks is deprecated and will not be supported in PHPUnit 9. Refactor your test to use assertStringContainsString() or assertStringContainsStringIgnoringCase() instead.');
}

if (!$checkForObjectIdentity) {
self::createWarning('The optional $checkForObjectIdentity parameter of assertContains() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertContainsEquals() instead.');
}

if ($checkForNonObjectIdentity) {
self::createWarning('The optional $checkForNonObjectIdentity parameter of assertContains() is deprecated and will be removed in PHPUnit 9.');
}

if ($ignoreCase) {
self::createWarning('The optional $ignoreCase parameter of assertContains() is deprecated and will be removed in PHPUnit 9.');
}


if (is_array($haystack) ||
(is_object($haystack) && $haystack instanceof Traversable)) {
$constraint = new TraversableContains(
$needle,
$checkForObjectIdentity,
$checkForNonObjectIdentity
);
} elseif (is_string($haystack)) {
if (!is_string($needle)) {
throw InvalidArgumentException::create(
1,
'string'
);
}

$constraint = new StringContains(
$needle,
$ignoreCase
);
} else {
throw InvalidArgumentException::create(
2,
'array, traversable or string'
);
}

static::assertThat($haystack, $constraint, $message);
}

public static function assertContainsEquals($needle, iterable $haystack, string $message = ''): void
{
$constraint = new TraversableContainsEqual($needle);

static::assertThat($haystack, $constraint, $message);
}














public static function assertAttributeContains($needle, string $haystackAttributeName, $haystackClassOrObject, string $message = '', bool $ignoreCase = false, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false): void
{
self::createWarning('assertAttributeContains() is deprecated and will be removed in PHPUnit 9.');

static::assertContains(
$needle,
static::readAttribute($haystackClassOrObject, $haystackAttributeName),
$message,
$ignoreCase,
$checkForObjectIdentity,
$checkForNonObjectIdentity
);
}








public static function assertNotContains($needle, $haystack, string $message = '', bool $ignoreCase = false, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false): void
{

 if (is_string($haystack)) {
self::createWarning('Using assertNotContains() with string haystacks is deprecated and will not be supported in PHPUnit 9. Refactor your test to use assertStringNotContainsString() or assertStringNotContainsStringIgnoringCase() instead.');
}

if (!$checkForObjectIdentity) {
self::createWarning('The optional $checkForObjectIdentity parameter of assertNotContains() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertNotContainsEquals() instead.');
}

if ($checkForNonObjectIdentity) {
self::createWarning('The optional $checkForNonObjectIdentity parameter of assertNotContains() is deprecated and will be removed in PHPUnit 9.');
}

if ($ignoreCase) {
self::createWarning('The optional $ignoreCase parameter of assertNotContains() is deprecated and will be removed in PHPUnit 9.');
}


if (is_array($haystack) ||
(is_object($haystack) && $haystack instanceof Traversable)) {
$constraint = new LogicalNot(
new TraversableContains(
$needle,
$checkForObjectIdentity,
$checkForNonObjectIdentity
)
);
} elseif (is_string($haystack)) {
if (!is_string($needle)) {
throw InvalidArgumentException::create(
1,
'string'
);
}

$constraint = new LogicalNot(
new StringContains(
$needle,
$ignoreCase
)
);
} else {
throw InvalidArgumentException::create(
2,
'array, traversable or string'
);
}

static::assertThat($haystack, $constraint, $message);
}

public static function assertNotContainsEquals($needle, iterable $haystack, string $message = ''): void
{
$constraint = new LogicalNot(new TraversableContainsEqual($needle));

static::assertThat($haystack, $constraint, $message);
}














public static function assertAttributeNotContains($needle, string $haystackAttributeName, $haystackClassOrObject, string $message = '', bool $ignoreCase = false, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false): void
{
self::createWarning('assertAttributeNotContains() is deprecated and will be removed in PHPUnit 9.');

static::assertNotContains(
$needle,
static::readAttribute($haystackClassOrObject, $haystackAttributeName),
$message,
$ignoreCase,
$checkForObjectIdentity,
$checkForNonObjectIdentity
);
}







public static function assertContainsOnly(string $type, iterable $haystack, ?bool $isNativeType = null, string $message = ''): void
{
if ($isNativeType === null) {
$isNativeType = Type::isType($type);
}

static::assertThat(
$haystack,
new TraversableContainsOnly(
$type,
$isNativeType
),
$message
);
}







public static function assertContainsOnlyInstancesOf(string $className, iterable $haystack, string $message = ''): void
{
static::assertThat(
$haystack,
new TraversableContainsOnly(
$className,
false
),
$message
);
}















public static function assertAttributeContainsOnly(string $type, string $haystackAttributeName, $haystackClassOrObject, ?bool $isNativeType = null, string $message = ''): void
{
self::createWarning('assertAttributeContainsOnly() is deprecated and will be removed in PHPUnit 9.');

static::assertContainsOnly(
$type,
static::readAttribute($haystackClassOrObject, $haystackAttributeName),
$isNativeType,
$message
);
}







public static function assertNotContainsOnly(string $type, iterable $haystack, ?bool $isNativeType = null, string $message = ''): void
{
if ($isNativeType === null) {
$isNativeType = Type::isType($type);
}

static::assertThat(
$haystack,
new LogicalNot(
new TraversableContainsOnly(
$type,
$isNativeType
)
),
$message
);
}
















public static function assertAttributeNotContainsOnly(string $type, string $haystackAttributeName, $haystackClassOrObject, ?bool $isNativeType = null, string $message = ''): void
{
self::createWarning('assertAttributeNotContainsOnly() is deprecated and will be removed in PHPUnit 9.');

static::assertNotContainsOnly(
$type,
static::readAttribute($haystackClassOrObject, $haystackAttributeName),
$isNativeType,
$message
);
}










public static function assertCount(int $expectedCount, $haystack, string $message = ''): void
{
if (!$haystack instanceof Countable && !is_iterable($haystack)) {
throw InvalidArgumentException::create(2, 'countable or iterable');
}

static::assertThat(
$haystack,
new Count($expectedCount),
$message
);
}














public static function assertAttributeCount(int $expectedCount, string $haystackAttributeName, $haystackClassOrObject, string $message = ''): void
{
self::createWarning('assertAttributeCount() is deprecated and will be removed in PHPUnit 9.');

static::assertCount(
$expectedCount,
static::readAttribute($haystackClassOrObject, $haystackAttributeName),
$message
);
}










public static function assertNotCount(int $expectedCount, $haystack, string $message = ''): void
{
if (!$haystack instanceof Countable && !is_iterable($haystack)) {
throw InvalidArgumentException::create(2, 'countable or iterable');
}

$constraint = new LogicalNot(
new Count($expectedCount)
);

static::assertThat($haystack, $constraint, $message);
}














public static function assertAttributeNotCount(int $expectedCount, string $haystackAttributeName, $haystackClassOrObject, string $message = ''): void
{
self::createWarning('assertAttributeNotCount() is deprecated and will be removed in PHPUnit 9.');

static::assertNotCount(
$expectedCount,
static::readAttribute($haystackClassOrObject, $haystackAttributeName),
$message
);
}







public static function assertEquals($expected, $actual, string $message = '', float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): void
{

 if ($delta !== 0.0) {
self::createWarning('The optional $delta parameter of assertEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertEqualsWithDelta() instead.');
}

if ($maxDepth !== 10) {
self::createWarning('The optional $maxDepth parameter of assertEquals() is deprecated and will be removed in PHPUnit 9.');
}

if ($canonicalize) {
self::createWarning('The optional $canonicalize parameter of assertEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertEqualsCanonicalizing() instead.');
}

if ($ignoreCase) {
self::createWarning('The optional $ignoreCase parameter of assertEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertEqualsIgnoringCase() instead.');
}


$constraint = new IsEqual(
$expected,
$delta,
$maxDepth,
$canonicalize,
$ignoreCase
);

static::assertThat($actual, $constraint, $message);
}







public static function assertEqualsCanonicalizing($expected, $actual, string $message = ''): void
{
$constraint = new IsEqual(
$expected,
0.0,
10,
true,
false
);

static::assertThat($actual, $constraint, $message);
}







public static function assertEqualsIgnoringCase($expected, $actual, string $message = ''): void
{
$constraint = new IsEqual(
$expected,
0.0,
10,
false,
true
);

static::assertThat($actual, $constraint, $message);
}







public static function assertEqualsWithDelta($expected, $actual, float $delta, string $message = ''): void
{
$constraint = new IsEqual(
$expected,
$delta
);

static::assertThat($actual, $constraint, $message);
}













public static function assertAttributeEquals($expected, string $actualAttributeName, $actualClassOrObject, string $message = '', float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): void
{
self::createWarning('assertAttributeEquals() is deprecated and will be removed in PHPUnit 9.');

static::assertEquals(
$expected,
static::readAttribute($actualClassOrObject, $actualAttributeName),
$message,
$delta,
$maxDepth,
$canonicalize,
$ignoreCase
);
}












public static function assertNotEquals($expected, $actual, string $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false): void
{

 if ($delta !== 0.0) {
self::createWarning('The optional $delta parameter of assertNotEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertNotEqualsWithDelta() instead.');
}

if ($maxDepth !== 10) {
self::createWarning('The optional $maxDepth parameter of assertNotEquals() is deprecated and will be removed in PHPUnit 9.');
}

if ($canonicalize) {
self::createWarning('The optional $canonicalize parameter of assertNotEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertNotEqualsCanonicalizing() instead.');
}

if ($ignoreCase) {
self::createWarning('The optional $ignoreCase parameter of assertNotEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertNotEqualsIgnoringCase() instead.');
}


$constraint = new LogicalNot(
new IsEqual(
$expected,
$delta,
$maxDepth,
$canonicalize,
$ignoreCase
)
);

static::assertThat($actual, $constraint, $message);
}







public static function assertNotEqualsCanonicalizing($expected, $actual, string $message = ''): void
{
$constraint = new LogicalNot(
new IsEqual(
$expected,
0.0,
10,
true,
false
)
);

static::assertThat($actual, $constraint, $message);
}







public static function assertNotEqualsIgnoringCase($expected, $actual, string $message = ''): void
{
$constraint = new LogicalNot(
new IsEqual(
$expected,
0.0,
10,
false,
true
)
);

static::assertThat($actual, $constraint, $message);
}







public static function assertNotEqualsWithDelta($expected, $actual, float $delta, string $message = ''): void
{
$constraint = new LogicalNot(
new IsEqual(
$expected,
$delta
)
);

static::assertThat($actual, $constraint, $message);
}













public static function assertAttributeNotEquals($expected, string $actualAttributeName, $actualClassOrObject, string $message = '', float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): void
{
self::createWarning('assertAttributeNotEquals() is deprecated and will be removed in PHPUnit 9.');

static::assertNotEquals(
$expected,
static::readAttribute($actualClassOrObject, $actualAttributeName),
$message,
$delta,
$maxDepth,
$canonicalize,
$ignoreCase
);
}









public static function assertEmpty($actual, string $message = ''): void
{
static::assertThat($actual, static::isEmpty(), $message);
}














public static function assertAttributeEmpty(string $haystackAttributeName, $haystackClassOrObject, string $message = ''): void
{
self::createWarning('assertAttributeEmpty() is deprecated and will be removed in PHPUnit 9.');

static::assertEmpty(
static::readAttribute($haystackClassOrObject, $haystackAttributeName),
$message
);
}









public static function assertNotEmpty($actual, string $message = ''): void
{
static::assertThat($actual, static::logicalNot(static::isEmpty()), $message);
}














public static function assertAttributeNotEmpty(string $haystackAttributeName, $haystackClassOrObject, string $message = ''): void
{
self::createWarning('assertAttributeNotEmpty() is deprecated and will be removed in PHPUnit 9.');

static::assertNotEmpty(
static::readAttribute($haystackClassOrObject, $haystackAttributeName),
$message
);
}







public static function assertGreaterThan($expected, $actual, string $message = ''): void
{
static::assertThat($actual, static::greaterThan($expected), $message);
}













public static function assertAttributeGreaterThan($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void
{
self::createWarning('assertAttributeGreaterThan() is deprecated and will be removed in PHPUnit 9.');

static::assertGreaterThan(
$expected,
static::readAttribute($actualClassOrObject, $actualAttributeName),
$message
);
}







public static function assertGreaterThanOrEqual($expected, $actual, string $message = ''): void
{
static::assertThat(
$actual,
static::greaterThanOrEqual($expected),
$message
);
}













public static function assertAttributeGreaterThanOrEqual($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void
{
self::createWarning('assertAttributeGreaterThanOrEqual() is deprecated and will be removed in PHPUnit 9.');

static::assertGreaterThanOrEqual(
$expected,
static::readAttribute($actualClassOrObject, $actualAttributeName),
$message
);
}







public static function assertLessThan($expected, $actual, string $message = ''): void
{
static::assertThat($actual, static::lessThan($expected), $message);
}













public static function assertAttributeLessThan($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void
{
self::createWarning('assertAttributeLessThan() is deprecated and will be removed in PHPUnit 9.');

static::assertLessThan(
$expected,
static::readAttribute($actualClassOrObject, $actualAttributeName),
$message
);
}







public static function assertLessThanOrEqual($expected, $actual, string $message = ''): void
{
static::assertThat($actual, static::lessThanOrEqual($expected), $message);
}













public static function assertAttributeLessThanOrEqual($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void
{
self::createWarning('assertAttributeLessThanOrEqual() is deprecated and will be removed in PHPUnit 9.');

static::assertLessThanOrEqual(
$expected,
static::readAttribute($actualClassOrObject, $actualAttributeName),
$message
);
}








public static function assertFileEquals(string $expected, string $actual, string $message = '', bool $canonicalize = false, bool $ignoreCase = false): void
{

 if ($canonicalize) {
self::createWarning('The optional $canonicalize parameter of assertFileEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertFileEqualsCanonicalizing() instead.');
}

if ($ignoreCase) {
self::createWarning('The optional $ignoreCase parameter of assertFileEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertFileEqualsIgnoringCase() instead.');
}


static::assertFileExists($expected, $message);
static::assertFileExists($actual, $message);

$constraint = new IsEqual(
file_get_contents($expected),
0.0,
10,
$canonicalize,
$ignoreCase
);

static::assertThat(file_get_contents($actual), $constraint, $message);
}








public static function assertFileEqualsCanonicalizing(string $expected, string $actual, string $message = ''): void
{
static::assertFileExists($expected, $message);
static::assertFileExists($actual, $message);

$constraint = new IsEqual(
file_get_contents($expected),
0.0,
10,
true
);

static::assertThat(file_get_contents($actual), $constraint, $message);
}








public static function assertFileEqualsIgnoringCase(string $expected, string $actual, string $message = ''): void
{
static::assertFileExists($expected, $message);
static::assertFileExists($actual, $message);

$constraint = new IsEqual(
file_get_contents($expected),
0.0,
10,
false,
true
);

static::assertThat(file_get_contents($actual), $constraint, $message);
}








public static function assertFileNotEquals(string $expected, string $actual, string $message = '', bool $canonicalize = false, bool $ignoreCase = false): void
{

 if ($canonicalize) {
self::createWarning('The optional $canonicalize parameter of assertFileNotEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertFileNotEqualsCanonicalizing() instead.');
}

if ($ignoreCase) {
self::createWarning('The optional $ignoreCase parameter of assertFileNotEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertFileNotEqualsIgnoringCase() instead.');
}


static::assertFileExists($expected, $message);
static::assertFileExists($actual, $message);

$constraint = new LogicalNot(
new IsEqual(
file_get_contents($expected),
0.0,
10,
$canonicalize,
$ignoreCase
)
);

static::assertThat(file_get_contents($actual), $constraint, $message);
}








public static function assertFileNotEqualsCanonicalizing(string $expected, string $actual, string $message = ''): void
{
static::assertFileExists($expected, $message);
static::assertFileExists($actual, $message);

$constraint = new LogicalNot(
new IsEqual(
file_get_contents($expected),
0.0,
10,
true
)
);

static::assertThat(file_get_contents($actual), $constraint, $message);
}








public static function assertFileNotEqualsIgnoringCase(string $expected, string $actual, string $message = ''): void
{
static::assertFileExists($expected, $message);
static::assertFileExists($actual, $message);

$constraint = new LogicalNot(
new IsEqual(
file_get_contents($expected),
0.0,
10,
false,
true
)
);

static::assertThat(file_get_contents($actual), $constraint, $message);
}








public static function assertStringEqualsFile(string $expectedFile, string $actualString, string $message = '', bool $canonicalize = false, bool $ignoreCase = false): void
{

 if ($canonicalize) {
self::createWarning('The optional $canonicalize parameter of assertStringEqualsFile() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertStringEqualsFileCanonicalizing() instead.');
}

if ($ignoreCase) {
self::createWarning('The optional $ignoreCase parameter of assertStringEqualsFile() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertStringEqualsFileIgnoringCase() instead.');
}


static::assertFileExists($expectedFile, $message);

$constraint = new IsEqual(
file_get_contents($expectedFile),
0.0,
10,
$canonicalize,
$ignoreCase
);

static::assertThat($actualString, $constraint, $message);
}








public static function assertStringEqualsFileCanonicalizing(string $expectedFile, string $actualString, string $message = ''): void
{
static::assertFileExists($expectedFile, $message);

$constraint = new IsEqual(
file_get_contents($expectedFile),
0.0,
10,
true
);

static::assertThat($actualString, $constraint, $message);
}








public static function assertStringEqualsFileIgnoringCase(string $expectedFile, string $actualString, string $message = ''): void
{
static::assertFileExists($expectedFile, $message);

$constraint = new IsEqual(
file_get_contents($expectedFile),
0.0,
10,
false,
true
);

static::assertThat($actualString, $constraint, $message);
}








public static function assertStringNotEqualsFile(string $expectedFile, string $actualString, string $message = '', bool $canonicalize = false, bool $ignoreCase = false): void
{

 if ($canonicalize) {
self::createWarning('The optional $canonicalize parameter of assertStringNotEqualsFile() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertStringNotEqualsFileCanonicalizing() instead.');
}

if ($ignoreCase) {
self::createWarning('The optional $ignoreCase parameter of assertStringNotEqualsFile() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertStringNotEqualsFileIgnoringCase() instead.');
}


static::assertFileExists($expectedFile, $message);

$constraint = new LogicalNot(
new IsEqual(
file_get_contents($expectedFile),
0.0,
10,
$canonicalize,
$ignoreCase
)
);

static::assertThat($actualString, $constraint, $message);
}








public static function assertStringNotEqualsFileCanonicalizing(string $expectedFile, string $actualString, string $message = ''): void
{
static::assertFileExists($expectedFile, $message);

$constraint = new LogicalNot(
new IsEqual(
file_get_contents($expectedFile),
0.0,
10,
true
)
);

static::assertThat($actualString, $constraint, $message);
}








public static function assertStringNotEqualsFileIgnoringCase(string $expectedFile, string $actualString, string $message = ''): void
{
static::assertFileExists($expectedFile, $message);

$constraint = new LogicalNot(
new IsEqual(
file_get_contents($expectedFile),
0.0,
10,
false,
true
)
);

static::assertThat($actualString, $constraint, $message);
}







public static function assertIsReadable(string $filename, string $message = ''): void
{
static::assertThat($filename, new IsReadable, $message);
}







public static function assertNotIsReadable(string $filename, string $message = ''): void
{
static::assertThat($filename, new LogicalNot(new IsReadable), $message);
}







public static function assertIsWritable(string $filename, string $message = ''): void
{
static::assertThat($filename, new IsWritable, $message);
}







public static function assertNotIsWritable(string $filename, string $message = ''): void
{
static::assertThat($filename, new LogicalNot(new IsWritable), $message);
}







public static function assertDirectoryExists(string $directory, string $message = ''): void
{
static::assertThat($directory, new DirectoryExists, $message);
}







public static function assertDirectoryNotExists(string $directory, string $message = ''): void
{
static::assertThat($directory, new LogicalNot(new DirectoryExists), $message);
}







public static function assertDirectoryIsReadable(string $directory, string $message = ''): void
{
self::assertDirectoryExists($directory, $message);
self::assertIsReadable($directory, $message);
}







public static function assertDirectoryNotIsReadable(string $directory, string $message = ''): void
{
self::assertDirectoryExists($directory, $message);
self::assertNotIsReadable($directory, $message);
}







public static function assertDirectoryIsWritable(string $directory, string $message = ''): void
{
self::assertDirectoryExists($directory, $message);
self::assertIsWritable($directory, $message);
}







public static function assertDirectoryNotIsWritable(string $directory, string $message = ''): void
{
self::assertDirectoryExists($directory, $message);
self::assertNotIsWritable($directory, $message);
}







public static function assertFileExists(string $filename, string $message = ''): void
{
static::assertThat($filename, new FileExists, $message);
}







public static function assertFileNotExists(string $filename, string $message = ''): void
{
static::assertThat($filename, new LogicalNot(new FileExists), $message);
}







public static function assertFileIsReadable(string $file, string $message = ''): void
{
self::assertFileExists($file, $message);
self::assertIsReadable($file, $message);
}







public static function assertFileNotIsReadable(string $file, string $message = ''): void
{
self::assertFileExists($file, $message);
self::assertNotIsReadable($file, $message);
}







public static function assertFileIsWritable(string $file, string $message = ''): void
{
self::assertFileExists($file, $message);
self::assertIsWritable($file, $message);
}







public static function assertFileNotIsWritable(string $file, string $message = ''): void
{
self::assertFileExists($file, $message);
self::assertNotIsWritable($file, $message);
}









public static function assertTrue($condition, string $message = ''): void
{
static::assertThat($condition, static::isTrue(), $message);
}









public static function assertNotTrue($condition, string $message = ''): void
{
static::assertThat($condition, static::logicalNot(static::isTrue()), $message);
}









public static function assertFalse($condition, string $message = ''): void
{
static::assertThat($condition, static::isFalse(), $message);
}









public static function assertNotFalse($condition, string $message = ''): void
{
static::assertThat($condition, static::logicalNot(static::isFalse()), $message);
}









public static function assertNull($actual, string $message = ''): void
{
static::assertThat($actual, static::isNull(), $message);
}









public static function assertNotNull($actual, string $message = ''): void
{
static::assertThat($actual, static::logicalNot(static::isNull()), $message);
}







public static function assertFinite($actual, string $message = ''): void
{
static::assertThat($actual, static::isFinite(), $message);
}







public static function assertInfinite($actual, string $message = ''): void
{
static::assertThat($actual, static::isInfinite(), $message);
}







public static function assertNan($actual, string $message = ''): void
{
static::assertThat($actual, static::isNan(), $message);
}








public static function assertClassHasAttribute(string $attributeName, string $className, string $message = ''): void
{
if (!self::isValidClassAttributeName($attributeName)) {
throw InvalidArgumentException::create(1, 'valid attribute name');
}

if (!class_exists($className)) {
throw InvalidArgumentException::create(2, 'class name');
}

static::assertThat($className, new ClassHasAttribute($attributeName), $message);
}








public static function assertClassNotHasAttribute(string $attributeName, string $className, string $message = ''): void
{
if (!self::isValidClassAttributeName($attributeName)) {
throw InvalidArgumentException::create(1, 'valid attribute name');
}

if (!class_exists($className)) {
throw InvalidArgumentException::create(2, 'class name');
}

static::assertThat(
$className,
new LogicalNot(
new ClassHasAttribute($attributeName)
),
$message
);
}








public static function assertClassHasStaticAttribute(string $attributeName, string $className, string $message = ''): void
{
if (!self::isValidClassAttributeName($attributeName)) {
throw InvalidArgumentException::create(1, 'valid attribute name');
}

if (!class_exists($className)) {
throw InvalidArgumentException::create(2, 'class name');
}

static::assertThat(
$className,
new ClassHasStaticAttribute($attributeName),
$message
);
}








public static function assertClassNotHasStaticAttribute(string $attributeName, string $className, string $message = ''): void
{
if (!self::isValidClassAttributeName($attributeName)) {
throw InvalidArgumentException::create(1, 'valid attribute name');
}

if (!class_exists($className)) {
throw InvalidArgumentException::create(2, 'class name');
}

static::assertThat(
$className,
new LogicalNot(
new ClassHasStaticAttribute($attributeName)
),
$message
);
}










public static function assertObjectHasAttribute(string $attributeName, $object, string $message = ''): void
{
if (!self::isValidObjectAttributeName($attributeName)) {
throw InvalidArgumentException::create(1, 'valid attribute name');
}

if (!is_object($object)) {
throw InvalidArgumentException::create(2, 'object');
}

static::assertThat(
$object,
new ObjectHasAttribute($attributeName),
$message
);
}










public static function assertObjectNotHasAttribute(string $attributeName, $object, string $message = ''): void
{
if (!self::isValidObjectAttributeName($attributeName)) {
throw InvalidArgumentException::create(1, 'valid attribute name');
}

if (!is_object($object)) {
throw InvalidArgumentException::create(2, 'object');
}

static::assertThat(
$object,
new LogicalNot(
new ObjectHasAttribute($attributeName)
),
$message
);
}













public static function assertSame($expected, $actual, string $message = ''): void
{
static::assertThat(
$actual,
new IsIdentical($expected),
$message
);
}














public static function assertAttributeSame($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void
{
self::createWarning('assertAttributeSame() is deprecated and will be removed in PHPUnit 9.');

static::assertSame(
$expected,
static::readAttribute($actualClassOrObject, $actualAttributeName),
$message
);
}









public static function assertNotSame($expected, $actual, string $message = ''): void
{
if (is_bool($expected) && is_bool($actual)) {
static::assertNotEquals($expected, $actual, $message);
}

static::assertThat(
$actual,
new LogicalNot(
new IsIdentical($expected)
),
$message
);
}














public static function assertAttributeNotSame($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void
{
self::createWarning('assertAttributeNotSame() is deprecated and will be removed in PHPUnit 9.');

static::assertNotSame(
$expected,
static::readAttribute($actualClassOrObject, $actualAttributeName),
$message
);
}












public static function assertInstanceOf(string $expected, $actual, string $message = ''): void
{
if (!class_exists($expected) && !interface_exists($expected)) {
throw InvalidArgumentException::create(1, 'class or interface name');
}

static::assertThat(
$actual,
new IsInstanceOf($expected),
$message
);
}















public static function assertAttributeInstanceOf(string $expected, string $attributeName, $classOrObject, string $message = ''): void
{
self::createWarning('assertAttributeInstanceOf() is deprecated and will be removed in PHPUnit 9.');

static::assertInstanceOf(
$expected,
static::readAttribute($classOrObject, $attributeName),
$message
);
}












public static function assertNotInstanceOf(string $expected, $actual, string $message = ''): void
{
if (!class_exists($expected) && !interface_exists($expected)) {
throw InvalidArgumentException::create(1, 'class or interface name');
}

static::assertThat(
$actual,
new LogicalNot(
new IsInstanceOf($expected)
),
$message
);
}















public static function assertAttributeNotInstanceOf(string $expected, string $attributeName, $classOrObject, string $message = ''): void
{
self::createWarning('assertAttributeNotInstanceOf() is deprecated and will be removed in PHPUnit 9.');

static::assertNotInstanceOf(
$expected,
static::readAttribute($classOrObject, $attributeName),
$message
);
}










public static function assertInternalType(string $expected, $actual, string $message = ''): void
{
self::createWarning(
sprintf(
'assertInternalType() is deprecated and will be removed in PHPUnit 9. Refactor your test to use %s() instead.',
self::assertInternalTypeReplacement($expected, false)
)
);

static::assertThat(
$actual,
new IsType($expected),
$message
);
}













public static function assertAttributeInternalType(string $expected, string $attributeName, $classOrObject, string $message = ''): void
{
self::createWarning('assertAttributeInternalType() is deprecated and will be removed in PHPUnit 9.');

static::assertInternalType(
$expected,
static::readAttribute($classOrObject, $attributeName),
$message
);
}









public static function assertIsArray($actual, string $message = ''): void
{
static::assertThat(
$actual,
new IsType(IsType::TYPE_ARRAY),
$message
);
}









public static function assertIsBool($actual, string $message = ''): void
{
static::assertThat(
$actual,
new IsType(IsType::TYPE_BOOL),
$message
);
}









public static function assertIsFloat($actual, string $message = ''): void
{
static::assertThat(
$actual,
new IsType(IsType::TYPE_FLOAT),
$message
);
}









public static function assertIsInt($actual, string $message = ''): void
{
static::assertThat(
$actual,
new IsType(IsType::TYPE_INT),
$message
);
}









public static function assertIsNumeric($actual, string $message = ''): void
{
static::assertThat(
$actual,
new IsType(IsType::TYPE_NUMERIC),
$message
);
}









public static function assertIsObject($actual, string $message = ''): void
{
static::assertThat(
$actual,
new IsType(IsType::TYPE_OBJECT),
$message
);
}









public static function assertIsResource($actual, string $message = ''): void
{
static::assertThat(
$actual,
new IsType(IsType::TYPE_RESOURCE),
$message
);
}









public static function assertIsString($actual, string $message = ''): void
{
static::assertThat(
$actual,
new IsType(IsType::TYPE_STRING),
$message
);
}









public static function assertIsScalar($actual, string $message = ''): void
{
static::assertThat(
$actual,
new IsType(IsType::TYPE_SCALAR),
$message
);
}









public static function assertIsCallable($actual, string $message = ''): void
{
static::assertThat(
$actual,
new IsType(IsType::TYPE_CALLABLE),
$message
);
}









public static function assertIsIterable($actual, string $message = ''): void
{
static::assertThat(
$actual,
new IsType(IsType::TYPE_ITERABLE),
$message
);
}










public static function assertNotInternalType(string $expected, $actual, string $message = ''): void
{
self::createWarning(
sprintf(
'assertNotInternalType() is deprecated and will be removed in PHPUnit 9. Refactor your test to use %s() instead.',
self::assertInternalTypeReplacement($expected, true)
)
);

static::assertThat(
$actual,
new LogicalNot(
new IsType($expected)
),
$message
);
}









public static function assertIsNotArray($actual, string $message = ''): void
{
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_ARRAY)),
$message
);
}









public static function assertIsNotBool($actual, string $message = ''): void
{
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_BOOL)),
$message
);
}









public static function assertIsNotFloat($actual, string $message = ''): void
{
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_FLOAT)),
$message
);
}









public static function assertIsNotInt($actual, string $message = ''): void
{
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_INT)),
$message
);
}









public static function assertIsNotNumeric($actual, string $message = ''): void
{
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_NUMERIC)),
$message
);
}









public static function assertIsNotObject($actual, string $message = ''): void
{
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_OBJECT)),
$message
);
}









public static function assertIsNotResource($actual, string $message = ''): void
{
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_RESOURCE)),
$message
);
}









public static function assertIsNotString($actual, string $message = ''): void
{
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_STRING)),
$message
);
}









public static function assertIsNotScalar($actual, string $message = ''): void
{
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_SCALAR)),
$message
);
}









public static function assertIsNotCallable($actual, string $message = ''): void
{
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_CALLABLE)),
$message
);
}









public static function assertIsNotIterable($actual, string $message = ''): void
{
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_ITERABLE)),
$message
);
}













public static function assertAttributeNotInternalType(string $expected, string $attributeName, $classOrObject, string $message = ''): void
{
self::createWarning('assertAttributeNotInternalType() is deprecated and will be removed in PHPUnit 9.');

static::assertNotInternalType(
$expected,
static::readAttribute($classOrObject, $attributeName),
$message
);
}







public static function assertRegExp(string $pattern, string $string, string $message = ''): void
{
static::assertThat($string, new RegularExpression($pattern), $message);
}







public static function assertNotRegExp(string $pattern, string $string, string $message = ''): void
{
static::assertThat(
$string,
new LogicalNot(
new RegularExpression($pattern)
),
$message
);
}












public static function assertSameSize($expected, $actual, string $message = ''): void
{
if (!$expected instanceof Countable && !is_iterable($expected)) {
throw InvalidArgumentException::create(1, 'countable or iterable');
}

if (!$actual instanceof Countable && !is_iterable($actual)) {
throw InvalidArgumentException::create(2, 'countable or iterable');
}

static::assertThat(
$actual,
new SameSize($expected),
$message
);
}












public static function assertNotSameSize($expected, $actual, string $message = ''): void
{
if (!$expected instanceof Countable && !is_iterable($expected)) {
throw InvalidArgumentException::create(1, 'countable or iterable');
}

if (!$actual instanceof Countable && !is_iterable($actual)) {
throw InvalidArgumentException::create(2, 'countable or iterable');
}

static::assertThat(
$actual,
new LogicalNot(
new SameSize($expected)
),
$message
);
}







public static function assertStringMatchesFormat(string $format, string $string, string $message = ''): void
{
static::assertThat($string, new StringMatchesFormatDescription($format), $message);
}







public static function assertStringNotMatchesFormat(string $format, string $string, string $message = ''): void
{
static::assertThat(
$string,
new LogicalNot(
new StringMatchesFormatDescription($format)
),
$message
);
}







public static function assertStringMatchesFormatFile(string $formatFile, string $string, string $message = ''): void
{
static::assertFileExists($formatFile, $message);

static::assertThat(
$string,
new StringMatchesFormatDescription(
file_get_contents($formatFile)
),
$message
);
}







public static function assertStringNotMatchesFormatFile(string $formatFile, string $string, string $message = ''): void
{
static::assertFileExists($formatFile, $message);

static::assertThat(
$string,
new LogicalNot(
new StringMatchesFormatDescription(
file_get_contents($formatFile)
)
),
$message
);
}







public static function assertStringStartsWith(string $prefix, string $string, string $message = ''): void
{
static::assertThat($string, new StringStartsWith($prefix), $message);
}










public static function assertStringStartsNotWith($prefix, $string, string $message = ''): void
{
static::assertThat(
$string,
new LogicalNot(
new StringStartsWith($prefix)
),
$message
);
}





public static function assertStringContainsString(string $needle, string $haystack, string $message = ''): void
{
$constraint = new StringContains($needle, false);

static::assertThat($haystack, $constraint, $message);
}





public static function assertStringContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void
{
$constraint = new StringContains($needle, true);

static::assertThat($haystack, $constraint, $message);
}





public static function assertStringNotContainsString(string $needle, string $haystack, string $message = ''): void
{
$constraint = new LogicalNot(new StringContains($needle));

static::assertThat($haystack, $constraint, $message);
}





public static function assertStringNotContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void
{
$constraint = new LogicalNot(new StringContains($needle, true));

static::assertThat($haystack, $constraint, $message);
}







public static function assertStringEndsWith(string $suffix, string $string, string $message = ''): void
{
static::assertThat($string, new StringEndsWith($suffix), $message);
}







public static function assertStringEndsNotWith(string $suffix, string $string, string $message = ''): void
{
static::assertThat(
$string,
new LogicalNot(
new StringEndsWith($suffix)
),
$message
);
}








public static function assertXmlFileEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void
{
$expected = Xml::loadFile($expectedFile);
$actual = Xml::loadFile($actualFile);

static::assertEquals($expected, $actual, $message);
}








public static function assertXmlFileNotEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void
{
$expected = Xml::loadFile($expectedFile);
$actual = Xml::loadFile($actualFile);

static::assertNotEquals($expected, $actual, $message);
}










public static function assertXmlStringEqualsXmlFile(string $expectedFile, $actualXml, string $message = ''): void
{
$expected = Xml::loadFile($expectedFile);
$actual = Xml::load($actualXml);

static::assertEquals($expected, $actual, $message);
}










public static function assertXmlStringNotEqualsXmlFile(string $expectedFile, $actualXml, string $message = ''): void
{
$expected = Xml::loadFile($expectedFile);
$actual = Xml::load($actualXml);

static::assertNotEquals($expected, $actual, $message);
}











public static function assertXmlStringEqualsXmlString($expectedXml, $actualXml, string $message = ''): void
{
$expected = Xml::load($expectedXml);
$actual = Xml::load($actualXml);

static::assertEquals($expected, $actual, $message);
}











public static function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, string $message = ''): void
{
$expected = Xml::load($expectedXml);
$actual = Xml::load($actualXml);

static::assertNotEquals($expected, $actual, $message);
}








public static function assertEqualXMLStructure(DOMElement $expectedElement, DOMElement $actualElement, bool $checkAttributes = false, string $message = ''): void
{
$expectedElement = Xml::import($expectedElement);
$actualElement = Xml::import($actualElement);

static::assertSame(
$expectedElement->tagName,
$actualElement->tagName,
$message
);

if ($checkAttributes) {
static::assertSame(
$expectedElement->attributes->length,
$actualElement->attributes->length,
sprintf(
'%s%sNumber of attributes on node "%s" does not match',
$message,
!empty($message) ? "\n" : '',
$expectedElement->tagName
)
);

for ($i = 0; $i < $expectedElement->attributes->length; $i++) {
$expectedAttribute = $expectedElement->attributes->item($i);
$actualAttribute = $actualElement->attributes->getNamedItem($expectedAttribute->name);

assert($expectedAttribute instanceof DOMAttr);

if (!$actualAttribute) {
static::fail(
sprintf(
'%s%sCould not find attribute "%s" on node "%s"',
$message,
!empty($message) ? "\n" : '',
$expectedAttribute->name,
$expectedElement->tagName
)
);
}
}
}

Xml::removeCharacterDataNodes($expectedElement);
Xml::removeCharacterDataNodes($actualElement);

static::assertSame(
$expectedElement->childNodes->length,
$actualElement->childNodes->length,
sprintf(
'%s%sNumber of child nodes of "%s" differs',
$message,
!empty($message) ? "\n" : '',
$expectedElement->tagName
)
);

for ($i = 0; $i < $expectedElement->childNodes->length; $i++) {
static::assertEqualXMLStructure(
$expectedElement->childNodes->item($i),
$actualElement->childNodes->item($i),
$checkAttributes,
$message
);
}
}







public static function assertThat($value, Constraint $constraint, string $message = ''): void
{
self::$count += count($constraint);

$constraint->evaluate($value, $message);
}







public static function assertJson(string $actualJson, string $message = ''): void
{
static::assertThat($actualJson, static::isJson(), $message);
}







public static function assertJsonStringEqualsJsonString(string $expectedJson, string $actualJson, string $message = ''): void
{
static::assertJson($expectedJson, $message);
static::assertJson($actualJson, $message);

static::assertThat($actualJson, new JsonMatches($expectedJson), $message);
}










public static function assertJsonStringNotEqualsJsonString($expectedJson, $actualJson, string $message = ''): void
{
static::assertJson($expectedJson, $message);
static::assertJson($actualJson, $message);

static::assertThat(
$actualJson,
new LogicalNot(
new JsonMatches($expectedJson)
),
$message
);
}







public static function assertJsonStringEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void
{
static::assertFileExists($expectedFile, $message);
$expectedJson = file_get_contents($expectedFile);

static::assertJson($expectedJson, $message);
static::assertJson($actualJson, $message);

static::assertThat($actualJson, new JsonMatches($expectedJson), $message);
}







public static function assertJsonStringNotEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void
{
static::assertFileExists($expectedFile, $message);
$expectedJson = file_get_contents($expectedFile);

static::assertJson($expectedJson, $message);
static::assertJson($actualJson, $message);

static::assertThat(
$actualJson,
new LogicalNot(
new JsonMatches($expectedJson)
),
$message
);
}







public static function assertJsonFileEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void
{
static::assertFileExists($expectedFile, $message);
static::assertFileExists($actualFile, $message);

$actualJson = file_get_contents($actualFile);
$expectedJson = file_get_contents($expectedFile);

static::assertJson($expectedJson, $message);
static::assertJson($actualJson, $message);

$constraintExpected = new JsonMatches(
$expectedJson
);

$constraintActual = new JsonMatches($actualJson);

static::assertThat($expectedJson, $constraintActual, $message);
static::assertThat($actualJson, $constraintExpected, $message);
}







public static function assertJsonFileNotEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void
{
static::assertFileExists($expectedFile, $message);
static::assertFileExists($actualFile, $message);

$actualJson = file_get_contents($actualFile);
$expectedJson = file_get_contents($expectedFile);

static::assertJson($expectedJson, $message);
static::assertJson($actualJson, $message);

$constraintExpected = new JsonMatches(
$expectedJson
);

$constraintActual = new JsonMatches($actualJson);

static::assertThat($expectedJson, new LogicalNot($constraintActual), $message);
static::assertThat($actualJson, new LogicalNot($constraintExpected), $message);
}




public static function logicalAnd(): LogicalAnd
{
$constraints = func_get_args();

$constraint = new LogicalAnd;
$constraint->setConstraints($constraints);

return $constraint;
}

public static function logicalOr(): LogicalOr
{
$constraints = func_get_args();

$constraint = new LogicalOr;
$constraint->setConstraints($constraints);

return $constraint;
}

public static function logicalNot(Constraint $constraint): LogicalNot
{
return new LogicalNot($constraint);
}

public static function logicalXor(): LogicalXor
{
$constraints = func_get_args();

$constraint = new LogicalXor;
$constraint->setConstraints($constraints);

return $constraint;
}

public static function anything(): IsAnything
{
return new IsAnything;
}

public static function isTrue(): IsTrue
{
return new IsTrue;
}








public static function callback(callable $callback): Callback
{
return new Callback($callback);
}

public static function isFalse(): IsFalse
{
return new IsFalse;
}

public static function isJson(): IsJson
{
return new IsJson;
}

public static function isNull(): IsNull
{
return new IsNull;
}

public static function isFinite(): IsFinite
{
return new IsFinite;
}

public static function isInfinite(): IsInfinite
{
return new IsInfinite;
}

public static function isNan(): IsNan
{
return new IsNan;
}





public static function attribute(Constraint $constraint, string $attributeName): Attribute
{
self::createWarning('attribute() is deprecated and will be removed in PHPUnit 9.');

return new Attribute($constraint, $attributeName);
}




public static function contains($value, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false): TraversableContains
{
return new TraversableContains($value, $checkForObjectIdentity, $checkForNonObjectIdentity);
}

public static function containsEqual($value): TraversableContainsEqual
{
return new TraversableContainsEqual($value);
}

public static function containsIdentical($value): TraversableContainsIdentical
{
return new TraversableContainsIdentical($value);
}

public static function containsOnly(string $type): TraversableContainsOnly
{
return new TraversableContainsOnly($type);
}

public static function containsOnlyInstancesOf(string $className): TraversableContainsOnly
{
return new TraversableContainsOnly($className, false);
}




public static function arrayHasKey($key): ArrayHasKey
{
return new ArrayHasKey($key);
}

public static function equalTo($value, float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): IsEqual
{
return new IsEqual($value, $delta, $maxDepth, $canonicalize, $ignoreCase);
}





public static function attributeEqualTo(string $attributeName, $value, float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): Attribute
{
self::createWarning('attributeEqualTo() is deprecated and will be removed in PHPUnit 9.');

return static::attribute(
static::equalTo(
$value,
$delta,
$maxDepth,
$canonicalize,
$ignoreCase
),
$attributeName
);
}

public static function isEmpty(): IsEmpty
{
return new IsEmpty;
}

public static function isWritable(): IsWritable
{
return new IsWritable;
}

public static function isReadable(): IsReadable
{
return new IsReadable;
}

public static function directoryExists(): DirectoryExists
{
return new DirectoryExists;
}

public static function fileExists(): FileExists
{
return new FileExists;
}

public static function greaterThan($value): GreaterThan
{
return new GreaterThan($value);
}

public static function greaterThanOrEqual($value): LogicalOr
{
return static::logicalOr(
new IsEqual($value),
new GreaterThan($value)
);
}

public static function classHasAttribute(string $attributeName): ClassHasAttribute
{
return new ClassHasAttribute($attributeName);
}

public static function classHasStaticAttribute(string $attributeName): ClassHasStaticAttribute
{
return new ClassHasStaticAttribute($attributeName);
}

public static function objectHasAttribute($attributeName): ObjectHasAttribute
{
return new ObjectHasAttribute($attributeName);
}

public static function identicalTo($value): IsIdentical
{
return new IsIdentical($value);
}

public static function isInstanceOf(string $className): IsInstanceOf
{
return new IsInstanceOf($className);
}

public static function isType(string $type): IsType
{
return new IsType($type);
}

public static function lessThan($value): LessThan
{
return new LessThan($value);
}

public static function lessThanOrEqual($value): LogicalOr
{
return static::logicalOr(
new IsEqual($value),
new LessThan($value)
);
}

public static function matchesRegularExpression(string $pattern): RegularExpression
{
return new RegularExpression($pattern);
}

public static function matches(string $string): StringMatchesFormatDescription
{
return new StringMatchesFormatDescription($string);
}

public static function stringStartsWith($prefix): StringStartsWith
{
return new StringStartsWith($prefix);
}

public static function stringContains(string $string, bool $case = true): StringContains
{
return new StringContains($string, $case);
}

public static function stringEndsWith(string $suffix): StringEndsWith
{
return new StringEndsWith($suffix);
}

public static function countOf(int $count): Count
{
return new Count($count);
}








public static function fail(string $message = ''): void
{
self::$count++;

throw new AssertionFailedError($message);
}












public static function readAttribute($classOrObject, string $attributeName)
{
self::createWarning('readAttribute() is deprecated and will be removed in PHPUnit 9.');

if (!self::isValidClassAttributeName($attributeName)) {
throw InvalidArgumentException::create(2, 'valid attribute name');
}

if (is_string($classOrObject)) {
if (!class_exists($classOrObject)) {
throw InvalidArgumentException::create(
1,
'class name'
);
}

return static::getStaticAttribute(
$classOrObject,
$attributeName
);
}

if (is_object($classOrObject)) {
return static::getObjectAttribute(
$classOrObject,
$attributeName
);
}

throw InvalidArgumentException::create(
1,
'class name or object'
);
}










public static function getStaticAttribute(string $className, string $attributeName)
{
self::createWarning('getStaticAttribute() is deprecated and will be removed in PHPUnit 9.');

if (!class_exists($className)) {
throw InvalidArgumentException::create(1, 'class name');
}

if (!self::isValidClassAttributeName($attributeName)) {
throw InvalidArgumentException::create(2, 'valid attribute name');
}

try {
$class = new ReflectionClass($className);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


while ($class) {
$attributes = $class->getStaticProperties();

if (array_key_exists($attributeName, $attributes)) {
return $attributes[$attributeName];
}

$class = $class->getParentClass();
}

throw new Exception(
sprintf(
'Attribute "%s" not found in class.',
$attributeName
)
);
}












public static function getObjectAttribute($object, string $attributeName)
{
self::createWarning('getObjectAttribute() is deprecated and will be removed in PHPUnit 9.');

if (!is_object($object)) {
throw InvalidArgumentException::create(1, 'object');
}

if (!self::isValidClassAttributeName($attributeName)) {
throw InvalidArgumentException::create(2, 'valid attribute name');
}

$reflector = new ReflectionObject($object);

do {
try {
$attribute = $reflector->getProperty($attributeName);

if (!$attribute || $attribute->isPublic()) {
return $object->{$attributeName};
}

$attribute->setAccessible(true);
$value = $attribute->getValue($object);
$attribute->setAccessible(false);

return $value;
} catch (ReflectionException $e) {
}
} while ($reflector = $reflector->getParentClass());

throw new Exception(
sprintf(
'Attribute "%s" not found in object.',
$attributeName
)
);
}








public static function markTestIncomplete(string $message = ''): void
{
throw new IncompleteTestError($message);
}









public static function markTestSkipped(string $message = ''): void
{
if ($hint = self::detectLocationHint($message)) {
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
array_unshift($trace, $hint);

throw new SyntheticSkippedError($hint['message'], 0, $hint['file'], (int) $hint['line'], $trace);
}

throw new SkippedTestError($message);
}




public static function getCount(): int
{
return self::$count;
}




public static function resetCount(): void
{
self::$count = 0;
}

private static function detectLocationHint(string $message): ?array
{
$hint = null;
$lines = preg_split('/\r\n|\r|\n/', $message);

while (strpos($lines[0], '__OFFSET') !== false) {
$offset = explode('=', array_shift($lines));

if ($offset[0] === '__OFFSET_FILE') {
$hint['file'] = $offset[1];
}

if ($offset[0] === '__OFFSET_LINE') {
$hint['line'] = $offset[1];
}
}

if ($hint) {
$hint['message'] = implode(PHP_EOL, $lines);
}

return $hint;
}

private static function isValidObjectAttributeName(string $attributeName): bool
{
return (bool) preg_match('/[^\x00-\x1f\x7f-\x9f]+/', $attributeName);
}

private static function isValidClassAttributeName(string $attributeName): bool
{
return (bool) preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName);
}




private static function createWarning(string $warning): void
{
foreach (debug_backtrace() as $step) {
if (isset($step['object']) && $step['object'] instanceof TestCase) {
assert($step['object'] instanceof TestCase);

$step['object']->addWarning($warning);

break;
}
}
}




private static function assertInternalTypeReplacement(string $type, bool $not): string
{
switch ($type) {
case 'numeric':
return 'assertIs' . ($not ? 'Not' : '') . 'Numeric';

case 'integer':
case 'int':
return 'assertIs' . ($not ? 'Not' : '') . 'Int';

case 'double':
case 'float':
case 'real':
return 'assertIs' . ($not ? 'Not' : '') . 'Float';

case 'string':
return 'assertIs' . ($not ? 'Not' : '') . 'String';

case 'boolean':
case 'bool':
return 'assertIs' . ($not ? 'Not' : '') . 'Bool';

case 'null':
return 'assert' . ($not ? 'Not' : '') . 'Null';

case 'array':
return 'assertIs' . ($not ? 'Not' : '') . 'Array';

case 'object':
return 'assertIs' . ($not ? 'Not' : '') . 'Object';

case 'resource':
return 'assertIs' . ($not ? 'Not' : '') . 'Resource';

case 'scalar':
return 'assertIs' . ($not ? 'Not' : '') . 'Scalar';

case 'callable':
return 'assertIs' . ($not ? 'Not' : '') . 'Callable';

case 'iterable':
return 'assertIs' . ($not ? 'Not' : '') . 'Iterable';
}

throw new Exception(
sprintf(
'"%s" is not a type supported by assertInternalType() / assertNotInternalType()',
$type
)
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Framework;

use function assert;
use function count;
use RecursiveIterator;




final class TestSuiteIterator implements RecursiveIterator
{



private $position = 0;




private $tests;

public function __construct(TestSuite $testSuite)
{
$this->tests = $testSuite->tests();
}

public function rewind(): void
{
$this->position = 0;
}

public function valid(): bool
{
return $this->position < count($this->tests);
}

public function key(): int
{
return $this->position;
}

public function current(): Test
{
return $this->tests[$this->position];
}

public function next(): void
{
$this->position++;
}




public function getChildren(): self
{
if (!$this->hasChildren()) {
throw new NoChildTestSuiteException(
'The current item is not a TestSuite instance and therefore does not have any children.'
);
}

$current = $this->current();

assert($current instanceof TestSuite);

return new self($current);
}

public function hasChildren(): bool
{
return $this->valid() && $this->current() instanceof TestSuite;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use const PHP_EOL;
use function get_class;
use function sprintf;
use function str_replace;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Runner\PhptTestCase;
use RecursiveIteratorIterator;




final class TextTestListRenderer
{



public function render(TestSuite $suite): string
{
$buffer = 'Available test(s):' . PHP_EOL;

foreach (new RecursiveIteratorIterator($suite->getIterator()) as $test) {
if ($test instanceof TestCase) {
$name = sprintf(
'%s::%s',
get_class($test),
str_replace(' with data set ', '', $test->getName())
);
} elseif ($test instanceof PhptTestCase) {
$name = $test->getName();
} else {
continue;
}

$buffer .= sprintf(
' - %s' . PHP_EOL,
$name
);
}

return $buffer;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use function str_replace;




final class ConfigurationGenerator
{



private const TEMPLATE = <<<'EOT'
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/{phpunit_version}/phpunit.xsd"
         bootstrap="{bootstrap_script}"
         executionOrder="depends,defects"
         forceCoversAnnotation="true"
         beStrictAboutCoversAnnotation="true"
         beStrictAboutOutputDuringTests="true"
         beStrictAboutTodoAnnotatedTests="true"
         convertDeprecationsToExceptions="true"
         verbose="true">
    <testsuites>
        <testsuite name="default">
            <directory>{tests_directory}</directory>
        </testsuite>
    </testsuites>

    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">{src_directory}</directory>
        </whitelist>
    </filter>
</phpunit>

EOT;

public function generateDefaultConfiguration(string $phpunitVersion, string $bootstrapScript, string $testsDirectory, string $srcDirectory): string
{
return str_replace(
[
'{phpunit_version}',
'{bootstrap_script}',
'{tests_directory}',
'{src_directory}',
],
[
$phpunitVersion,
$bootstrapScript,
$testsDirectory,
$srcDirectory,
],
self::TEMPLATE
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use const DIRECTORY_SEPARATOR;
use function class_exists;
use function defined;
use function dirname;
use function strpos;
use function sys_get_temp_dir;
use Composer\Autoload\ClassLoader;
use DeepCopy\DeepCopy;
use Doctrine\Instantiator\Instantiator;
use PharIo\Manifest\Manifest;
use PharIo\Version\Version as PharIoVersion;
use PHP_Token;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\Project;
use phpDocumentor\Reflection\Type;
use PHPUnit\Framework\TestCase;
use Prophecy\Prophet;
use ReflectionClass;
use ReflectionException;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeUnitReverseLookup\Wizard;
use SebastianBergmann\Comparator\Comparator;
use SebastianBergmann\Diff\Diff;
use SebastianBergmann\Environment\Runtime;
use SebastianBergmann\Exporter\Exporter;
use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;
use SebastianBergmann\GlobalState\Snapshot;
use SebastianBergmann\Invoker\Invoker;
use SebastianBergmann\ObjectEnumerator\Enumerator;
use SebastianBergmann\RecursionContext\Context;
use SebastianBergmann\ResourceOperations\ResourceOperations;
use SebastianBergmann\Timer\Timer;
use SebastianBergmann\Type\TypeName;
use SebastianBergmann\Version;
use Text_Template;
use TheSeer\Tokenizer\Tokenizer;
use Webmozart\Assert\Assert;




final class Blacklist
{



public static $blacklistedClassNames = [

 ClassLoader::class => 1,


 Instantiator::class => 1,


 DeepCopy::class => 1,


 Manifest::class => 1,


 PharIoVersion::class => 1,


 Project::class => 1,


 DocBlock::class => 1,


 Type::class => 1,


 Prophet::class => 1,


 TestCase::class => 2,


 CodeCoverage::class => 1,


 FileIteratorFacade::class => 1,


 Invoker::class => 1,


 Text_Template::class => 1,


 Timer::class => 1,


 PHP_Token::class => 1,


 Wizard::class => 1,


 Comparator::class => 1,


 Diff::class => 1,


 Runtime::class => 1,


 Exporter::class => 1,


 Snapshot::class => 1,


 Enumerator::class => 1,


 Context::class => 1,


 ResourceOperations::class => 1,


 TypeName::class => 1,


 Version::class => 1,


 Tokenizer::class => 1,


 Assert::class => 1,
];




private static $directories;






public function getBlacklistedDirectories(): array
{
$this->initialize();

return self::$directories;
}




public function isBlacklisted(string $file): bool
{
if (defined('PHPUNIT_TESTSUITE')) {
return false;
}

$this->initialize();

foreach (self::$directories as $directory) {
if (strpos($file, $directory) === 0) {
return true;
}
}

return false;
}




private function initialize(): void
{
if (self::$directories === null) {
self::$directories = [];

foreach (self::$blacklistedClassNames as $className => $parent) {
if (!class_exists($className)) {
continue;
}

try {
$directory = (new ReflectionClass($className))->getFileName();

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


for ($i = 0; $i < $parent; $i++) {
$directory = dirname($directory);
}

self::$directories[] = $directory;
}


 if (DIRECTORY_SEPARATOR === '\\') {

 
 self::$directories[] = sys_get_temp_dir() . '\\PHP';
}
}
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util\PHP;

use const PHP_MAJOR_VERSION;
use function tmpfile;
use PHPUnit\Framework\Exception;






final class WindowsPhpProcess extends DefaultPhpProcess
{
public function getCommand(array $settings, string $file = null): string
{
if (PHP_MAJOR_VERSION < 8) {
return '"' . parent::getCommand($settings, $file) . '"';
}

return parent::getCommand($settings, $file);
}




protected function getHandles(): array
{
if (false === $stdout_handle = tmpfile()) {
throw new Exception(
'A temporary file could not be created; verify that your TEMP environment variable is writable'
);
}

return [
1 => $stdout_handle,
];
}

protected function useTemporaryFile(): bool
{
return true;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util\PHP;

use function array_merge;
use function fclose;
use function file_put_contents;
use function fread;
use function fwrite;
use function is_array;
use function is_resource;
use function proc_close;
use function proc_open;
use function proc_terminate;
use function rewind;
use function sprintf;
use function stream_get_contents;
use function stream_select;
use function sys_get_temp_dir;
use function tempnam;
use function unlink;
use PHPUnit\Framework\Exception;




class DefaultPhpProcess extends AbstractPhpProcess
{



protected $tempFile;






public function runJob(string $job, array $settings = []): array
{
if ($this->stdin || $this->useTemporaryFile()) {
if (!($this->tempFile = tempnam(sys_get_temp_dir(), 'PHPUnit')) ||
file_put_contents($this->tempFile, $job) === false) {
throw new Exception(
'Unable to write temporary file'
);
}

$job = $this->stdin;
}

return $this->runProcess($job, $settings);
}




protected function getHandles(): array
{
return [];
}






protected function runProcess(string $job, array $settings): array
{
$handles = $this->getHandles();

$env = null;

if ($this->env) {
$env = $_SERVER ?? [];
unset($env['argv'], $env['argc']);
$env = array_merge($env, $this->env);

foreach ($env as $envKey => $envVar) {
if (is_array($envVar)) {
unset($env[$envKey]);
}
}
}

$pipeSpec = [
0 => $handles[0] ?? ['pipe', 'r'],
1 => $handles[1] ?? ['pipe', 'w'],
2 => $handles[2] ?? ['pipe', 'w'],
];

$process = proc_open(
$this->getCommand($settings, $this->tempFile),
$pipeSpec,
$pipes,
null,
$env
);

if (!is_resource($process)) {
throw new Exception(
'Unable to spawn worker process'
);
}

if ($job) {
$this->process($pipes[0], $job);
}

fclose($pipes[0]);

$stderr = $stdout = '';

if ($this->timeout) {
unset($pipes[0]);

while (true) {
$r = $pipes;
$w = null;
$e = null;

$n = @stream_select($r, $w, $e, $this->timeout);

if ($n === false) {
break;
}

if ($n === 0) {
proc_terminate($process, 9);

throw new Exception(
sprintf(
'Job execution aborted after %d seconds',
$this->timeout
)
);
}

if ($n > 0) {
foreach ($r as $pipe) {
$pipeOffset = 0;

foreach ($pipes as $i => $origPipe) {
if ($pipe === $origPipe) {
$pipeOffset = $i;

break;
}
}

if (!$pipeOffset) {
break;
}

$line = fread($pipe, 8192);

if ($line === '' || $line === false) {
fclose($pipes[$pipeOffset]);

unset($pipes[$pipeOffset]);
} elseif ($pipeOffset === 1) {
$stdout .= $line;
} else {
$stderr .= $line;
}
}

if (empty($pipes)) {
break;
}
}
}
} else {
if (isset($pipes[1])) {
$stdout = stream_get_contents($pipes[1]);

fclose($pipes[1]);
}

if (isset($pipes[2])) {
$stderr = stream_get_contents($pipes[2]);

fclose($pipes[2]);
}
}

if (isset($handles[1])) {
rewind($handles[1]);

$stdout = stream_get_contents($handles[1]);

fclose($handles[1]);
}

if (isset($handles[2])) {
rewind($handles[2]);

$stderr = stream_get_contents($handles[2]);

fclose($handles[2]);
}

proc_close($process);

$this->cleanup();

return ['stdout' => $stdout, 'stderr' => $stderr];
}

protected function process($pipe, string $job): void
{
fwrite($pipe, $job);
}

protected function cleanup(): void
{
if ($this->tempFile) {
unlink($this->tempFile);
}
}

protected function useTemporaryFile(): bool
{
return false;
}
}
<?php
use SebastianBergmann\CodeCoverage\CodeCoverage;

$composerAutoload = {composerAutoload};
$phar = {phar};

ob_start();

$GLOBALS['__PHPUNIT_ISOLATION_BLACKLIST'][] = '{job}';

if ($composerAutoload) {
require_once $composerAutoload;
define('PHPUNIT_COMPOSER_INSTALL', $composerAutoload);
} else if ($phar) {
require $phar;
}

{globals}
$coverage = null;

if (isset($GLOBALS['__PHPUNIT_BOOTSTRAP'])) {
require_once $GLOBALS['__PHPUNIT_BOOTSTRAP'];
}

if (class_exists('SebastianBergmann\CodeCoverage\CodeCoverage')) {
$coverage = new CodeCoverage(null);
$coverage->start(__FILE__);
}

register_shutdown_function(function() use ($coverage) {
$output = null;
if ($coverage) {
$output = $coverage->stop();
}
file_put_contents('{coverageFile}', serialize($output));
});

ob_end_clean();

require '{job}';
<?php
use PHPUnit\Framework\TestCase;
use SebastianBergmann\CodeCoverage\CodeCoverage;

if (!defined('STDOUT')) {

 
 define('STDOUT', fopen('php://temp', 'w+b'));
define('STDERR', fopen('php://stderr', 'wb'));
}

{iniSettings}
ini_set('display_errors', 'stderr');
set_include_path('{include_path}');

$composerAutoload = {composerAutoload};
$phar = {phar};

ob_start();

if ($composerAutoload) {
require_once $composerAutoload;
define('PHPUNIT_COMPOSER_INSTALL', $composerAutoload);
} else if ($phar) {
require $phar;
}

function __phpunit_run_isolated_test()
{
if (!class_exists('{className}')) {
require_once '{filename}';
}

$result = new PHPUnit\Framework\TestResult;

if ({collectCodeCoverageInformation}) {
$result->setCodeCoverage(
new CodeCoverage(
null,
unserialize('{codeCoverageFilter}')
)
);
}

$result->beStrictAboutTestsThatDoNotTestAnything({isStrictAboutTestsThatDoNotTestAnything});
$result->beStrictAboutOutputDuringTests({isStrictAboutOutputDuringTests});
$result->enforceTimeLimit({enforcesTimeLimit});
$result->beStrictAboutTodoAnnotatedTests({isStrictAboutTodoAnnotatedTests});
$result->beStrictAboutResourceUsageDuringSmallTests({isStrictAboutResourceUsageDuringSmallTests});

$test = new {className}('{methodName}', unserialize('{data}'), '{dataName}');
\assert($test instanceof TestCase);

$test->setDependencyInput(unserialize('{dependencyInput}'));
$test->setInIsolation(true);

ob_end_clean();
$test->run($result);
$output = '';
if (!$test->hasExpectationOnOutput()) {
$output = $test->getActualOutput();
}

ini_set('xdebug.scream', '0');
@rewind(STDOUT); 
if ($stdout = @stream_get_contents(STDOUT)) {
$output = $stdout . $output;
$streamMetaData = stream_get_meta_data(STDOUT);
if (!empty($streamMetaData['stream_type']) && 'STDIO' === $streamMetaData['stream_type']) {
@ftruncate(STDOUT, 0);
@rewind(STDOUT);
}
}

print serialize(
[
'testResult' => $test->getResult(),
'numAssertions' => $test->getNumAssertions(),
'result' => $result,
'output' => $output
]
);
}

$configurationFilePath = '{configurationFilePath}';

if ('' !== $configurationFilePath) {
$configuration = PHPUnit\Util\Configuration::getInstance($configurationFilePath);
$configuration->handlePHPConfiguration();
unset($configuration);
}

function __phpunit_error_handler($errno, $errstr, $errfile, $errline)
{
return true;
}

set_error_handler('__phpunit_error_handler');

{constants}
{included_files}
{globals}

restore_error_handler();

if (isset($GLOBALS['__PHPUNIT_BOOTSTRAP'])) {
require_once $GLOBALS['__PHPUNIT_BOOTSTRAP'];
unset($GLOBALS['__PHPUNIT_BOOTSTRAP']);
}

__phpunit_run_isolated_test();
<?php
use SebastianBergmann\CodeCoverage\CodeCoverage;

if (!defined('STDOUT')) {

 
 define('STDOUT', fopen('php://temp', 'w+b'));
define('STDERR', fopen('php://stderr', 'wb'));
}

{iniSettings}
ini_set('display_errors', 'stderr');
set_include_path('{include_path}');

$composerAutoload = {composerAutoload};
$phar = {phar};

ob_start();

if ($composerAutoload) {
require_once $composerAutoload;
define('PHPUNIT_COMPOSER_INSTALL', $composerAutoload);
} else if ($phar) {
require $phar;
}

function __phpunit_run_isolated_test()
{
if (!class_exists('{className}')) {
require_once '{filename}';
}

$result = new PHPUnit\Framework\TestResult;

if ({collectCodeCoverageInformation}) {
$result->setCodeCoverage(
new CodeCoverage(
null,
unserialize('{codeCoverageFilter}')
)
);
}

$result->beStrictAboutTestsThatDoNotTestAnything({isStrictAboutTestsThatDoNotTestAnything});
$result->beStrictAboutOutputDuringTests({isStrictAboutOutputDuringTests});
$result->enforceTimeLimit({enforcesTimeLimit});
$result->beStrictAboutTodoAnnotatedTests({isStrictAboutTodoAnnotatedTests});
$result->beStrictAboutResourceUsageDuringSmallTests({isStrictAboutResourceUsageDuringSmallTests});

$test = new {className}('{name}', unserialize('{data}'), '{dataName}');
$test->setDependencyInput(unserialize('{dependencyInput}'));
$test->setInIsolation(TRUE);

ob_end_clean();
$test->run($result);
$output = '';
if (!$test->hasExpectationOnOutput()) {
$output = $test->getActualOutput();
}

ini_set('xdebug.scream', '0');
@rewind(STDOUT); 
if ($stdout = @stream_get_contents(STDOUT)) {
$output = $stdout . $output;
$streamMetaData = stream_get_meta_data(STDOUT);
if (!empty($streamMetaData['stream_type']) && 'STDIO' === $streamMetaData['stream_type']) {
@ftruncate(STDOUT, 0);
@rewind(STDOUT);
}
}

print serialize(
[
'testResult' => $test->getResult(),
'numAssertions' => $test->getNumAssertions(),
'result' => $result,
'output' => $output
]
);
}

$configurationFilePath = '{configurationFilePath}';

if ('' !== $configurationFilePath) {
$configuration = PHPUnit\Util\Configuration::getInstance($configurationFilePath);
$configuration->handlePHPConfiguration();
unset($configuration);
}

function __phpunit_error_handler($errno, $errstr, $errfile, $errline)
{
return true;
}

set_error_handler('__phpunit_error_handler');

{constants}
{included_files}
{globals}

restore_error_handler();

if (isset($GLOBALS['__PHPUNIT_BOOTSTRAP'])) {
require_once $GLOBALS['__PHPUNIT_BOOTSTRAP'];
unset($GLOBALS['__PHPUNIT_BOOTSTRAP']);
}

__phpunit_run_isolated_test();
<?php declare(strict_types=1);








namespace PHPUnit\Util\PHP;

use const DIRECTORY_SEPARATOR;
use const PHP_SAPI;
use function array_keys;
use function array_merge;
use function assert;
use function escapeshellarg;
use function ini_get_all;
use function restore_error_handler;
use function set_error_handler;
use function sprintf;
use function str_replace;
use function strpos;
use function strrpos;
use function substr;
use function trim;
use function unserialize;
use __PHP_Incomplete_Class;
use ErrorException;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\Exception;
use PHPUnit\Framework\SyntheticError;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestFailure;
use PHPUnit\Framework\TestResult;
use SebastianBergmann\Environment\Runtime;




abstract class AbstractPhpProcess
{



protected $runtime;




protected $stderrRedirection = false;




protected $stdin = '';




protected $args = '';




protected $env = [];




protected $timeout = 0;

public static function factory(): self
{
if (DIRECTORY_SEPARATOR === '\\') {
return new WindowsPhpProcess;
}

return new DefaultPhpProcess;
}

public function __construct()
{
$this->runtime = new Runtime;
}






public function setUseStderrRedirection(bool $stderrRedirection): void
{
$this->stderrRedirection = $stderrRedirection;
}




public function useStderrRedirection(): bool
{
return $this->stderrRedirection;
}




public function setStdin(string $stdin): void
{
$this->stdin = $stdin;
}




public function getStdin(): string
{
return $this->stdin;
}




public function setArgs(string $args): void
{
$this->args = $args;
}




public function getArgs(): string
{
return $this->args;
}






public function setEnv(array $env): void
{
$this->env = $env;
}




public function getEnv(): array
{
return $this->env;
}




public function setTimeout(int $timeout): void
{
$this->timeout = $timeout;
}




public function getTimeout(): int
{
return $this->timeout;
}






public function runTestJob(string $job, Test $test, TestResult $result): void
{
$result->startTest($test);

$_result = $this->runJob($job);

$this->processChildResult(
$test,
$result,
$_result['stdout'],
$_result['stderr']
);
}




public function getCommand(array $settings, string $file = null): string
{
$command = $this->runtime->getBinary();

if ($this->runtime->hasPCOV()) {
$settings = array_merge(
$settings,
$this->runtime->getCurrentSettings(
array_keys(ini_get_all('pcov'))
)
);
} elseif ($this->runtime->hasXdebug()) {
$settings = array_merge(
$settings,
$this->runtime->getCurrentSettings(
array_keys(ini_get_all('xdebug'))
)
);
}

$command .= $this->settingsToParameters($settings);

if (PHP_SAPI === 'phpdbg') {
$command .= ' -qrr';

if (!$file) {
$command .= 's=';
}
}

if ($file) {
$command .= ' ' . escapeshellarg($file);
}

if ($this->args) {
if (!$file) {
$command .= ' --';
}
$command .= ' ' . $this->args;
}

if ($this->stderrRedirection) {
$command .= ' 2>&1';
}

return $command;
}




abstract public function runJob(string $job, array $settings = []): array;

protected function settingsToParameters(array $settings): string
{
$buffer = '';

foreach ($settings as $setting) {
$buffer .= ' -d ' . escapeshellarg($setting);
}

return $buffer;
}






private function processChildResult(Test $test, TestResult $result, string $stdout, string $stderr): void
{
$time = 0;

if (!empty($stderr)) {
$result->addError(
$test,
new Exception(trim($stderr)),
$time
);
} else {
set_error_handler(



static function ($errno, $errstr, $errfile, $errline): void
{
throw new ErrorException($errstr, $errno, $errno, $errfile, $errline);
}
);

try {
if (strpos($stdout, "#!/usr/bin/env php\n") === 0) {
$stdout = substr($stdout, 19);
}

$childResult = unserialize(str_replace("#!/usr/bin/env php\n", '', $stdout));
restore_error_handler();

if ($childResult === false) {
$result->addFailure(
$test,
new AssertionFailedError('Test was run in child process and ended unexpectedly'),
$time
);
}
} catch (ErrorException $e) {
restore_error_handler();
$childResult = false;

$result->addError(
$test,
new Exception(trim($stdout), 0, $e),
$time
);
}

if ($childResult !== false) {
if (!empty($childResult['output'])) {
$output = $childResult['output'];
}



$test->setResult($childResult['testResult']);
$test->addToAssertionCount($childResult['numAssertions']);

$childResult = $childResult['result'];
assert($childResult instanceof TestResult);

if ($result->getCollectCodeCoverageInformation()) {
$result->getCodeCoverage()->merge(
$childResult->getCodeCoverage()
);
}

$time = $childResult->time();
$notImplemented = $childResult->notImplemented();
$risky = $childResult->risky();
$skipped = $childResult->skipped();
$errors = $childResult->errors();
$warnings = $childResult->warnings();
$failures = $childResult->failures();

if (!empty($notImplemented)) {
$result->addError(
$test,
$this->getException($notImplemented[0]),
$time
);
} elseif (!empty($risky)) {
$result->addError(
$test,
$this->getException($risky[0]),
$time
);
} elseif (!empty($skipped)) {
$result->addError(
$test,
$this->getException($skipped[0]),
$time
);
} elseif (!empty($errors)) {
$result->addError(
$test,
$this->getException($errors[0]),
$time
);
} elseif (!empty($warnings)) {
$result->addWarning(
$test,
$this->getException($warnings[0]),
$time
);
} elseif (!empty($failures)) {
$result->addFailure(
$test,
$this->getException($failures[0]),
$time
);
}
}
}

$result->endTest($test, $time);

if (!empty($output)) {
print $output;
}
}






private function getException(TestFailure $error): Exception
{
$exception = $error->thrownException();

if ($exception instanceof __PHP_Incomplete_Class) {
$exceptionArray = [];

foreach ((array) $exception as $key => $value) {
$key = substr($key, strrpos($key, "\0") + 1);
$exceptionArray[$key] = $value;
}

$exception = new SyntheticError(
sprintf(
'%s: %s',
$exceptionArray['_PHP_Incomplete_Class_Name'],
$exceptionArray['message']
),
$exceptionArray['code'],
$exceptionArray['file'],
$exceptionArray['line'],
$exceptionArray['trace']
);
}

return $exception;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use const DIRECTORY_SEPARATOR;
use function addslashes;
use function array_map;
use function implode;
use function is_string;
use function realpath;
use function sprintf;




final class XdebugFilterScriptGenerator
{
public function generate(array $filterData): string
{
$items = $this->getWhitelistItems($filterData);

$files = array_map(
static function ($item)
{
return sprintf(
"        '%s'",
$item
);
},
$items
);

$files = implode(",\n", $files);

return <<<EOF
<?php declare(strict_types=1);
if (!\\function_exists('xdebug_set_filter')) {
    return;
}

\\xdebug_set_filter(
    \\XDEBUG_FILTER_CODE_COVERAGE,
    \\XDEBUG_PATH_WHITELIST,
    [
{$files}
    ]
);

EOF;
}

private function getWhitelistItems(array $filterData): array
{
$files = [];

if (isset($filterData['include']['directory'])) {
foreach ($filterData['include']['directory'] as $directory) {
$path = realpath($directory['path']);

if (is_string($path)) {
$files[] = sprintf(
addslashes('%s' . DIRECTORY_SEPARATOR),
$path
);
}
}
}

if (isset($filterData['include']['directory'])) {
foreach ($filterData['include']['file'] as $file) {
$files[] = $file;
}
}

return $files;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use const DIRECTORY_SEPARATOR;
use const PATH_SEPARATOR;
use const PHP_VERSION;
use function assert;
use function constant;
use function count;
use function define;
use function defined;
use function dirname;
use function explode;
use function file_exists;
use function file_get_contents;
use function getenv;
use function implode;
use function in_array;
use function ini_get;
use function ini_set;
use function is_numeric;
use function libxml_clear_errors;
use function libxml_get_errors;
use function libxml_use_internal_errors;
use function preg_match;
use function putenv;
use function realpath;
use function sprintf;
use function stream_resolve_include_path;
use function strlen;
use function strpos;
use function strtolower;
use function strtoupper;
use function substr;
use function trim;
use function version_compare;
use DOMDocument;
use DOMElement;
use DOMNodeList;
use DOMXPath;
use LibXMLError;
use PHPUnit\Framework\Exception;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Runner\TestSuiteSorter;
use PHPUnit\TextUI\ResultPrinter;
use PHPUnit\Util\TestDox\CliTestDoxPrinter;
use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;




final class Configuration
{



private static $instances = [];




private $document;




private $xpath;




private $filename;




private $errors = [];






public static function getInstance(string $filename): self
{
$realPath = realpath($filename);

if ($realPath === false) {
throw new Exception(
sprintf(
'Could not read "%s".',
$filename
)
);
}

if (!isset(self::$instances[$realPath])) {
self::$instances[$realPath] = new self($realPath);
}

return self::$instances[$realPath];
}






private function __construct(string $filename)
{
$this->filename = $filename;
$this->document = Xml::loadFile($filename, false, true, true);
$this->xpath = new DOMXPath($this->document);

$this->validateConfigurationAgainstSchema();
}




private function __clone()
{
}

public function hasValidationErrors(): bool
{
return count($this->errors) > 0;
}

public function getValidationErrors(): array
{
$result = [];

foreach ($this->errors as $error) {
if (!isset($result[$error->line])) {
$result[$error->line] = [];
}
$result[$error->line][] = trim($error->message);
}

return $result;
}




public function getFilename(): string
{
return $this->filename;
}

public function getExtensionConfiguration(): array
{
$result = [];

foreach ($this->xpath->query('extensions/extension') as $extension) {
$result[] = $this->getElementConfigurationParameters($extension);
}

return $result;
}




public function getFilterConfiguration(): array
{
$addUncoveredFilesFromWhitelist = true;
$processUncoveredFilesFromWhitelist = false;
$includeDirectory = [];
$includeFile = [];
$excludeDirectory = [];
$excludeFile = [];

$tmp = $this->xpath->query('filter/whitelist');

if ($tmp->length === 1) {
if ($tmp->item(0)->hasAttribute('addUncoveredFilesFromWhitelist')) {
$addUncoveredFilesFromWhitelist = $this->getBoolean(
(string) $tmp->item(0)->getAttribute(
'addUncoveredFilesFromWhitelist'
),
true
);
}

if ($tmp->item(0)->hasAttribute('processUncoveredFilesFromWhitelist')) {
$processUncoveredFilesFromWhitelist = $this->getBoolean(
(string) $tmp->item(0)->getAttribute(
'processUncoveredFilesFromWhitelist'
),
false
);
}

$includeDirectory = $this->readFilterDirectories(
'filter/whitelist/directory'
);

$includeFile = $this->readFilterFiles(
'filter/whitelist/file'
);

$excludeDirectory = $this->readFilterDirectories(
'filter/whitelist/exclude/directory'
);

$excludeFile = $this->readFilterFiles(
'filter/whitelist/exclude/file'
);
}

return [
'whitelist' => [
'addUncoveredFilesFromWhitelist' => $addUncoveredFilesFromWhitelist,
'processUncoveredFilesFromWhitelist' => $processUncoveredFilesFromWhitelist,
'include' => [
'directory' => $includeDirectory,
'file' => $includeFile,
],
'exclude' => [
'directory' => $excludeDirectory,
'file' => $excludeFile,
],
],
];
}




public function getGroupConfiguration(): array
{
return $this->parseGroupConfiguration('groups');
}




public function getTestdoxGroupConfiguration(): array
{
return $this->parseGroupConfiguration('testdoxGroups');
}




public function getListenerConfiguration(): array
{
$result = [];

foreach ($this->xpath->query('listeners/listener') as $listener) {
$result[] = $this->getElementConfigurationParameters($listener);
}

return $result;
}




public function getLoggingConfiguration(): array
{
$result = [];

foreach ($this->xpath->query('logging/log') as $log) {
assert($log instanceof DOMElement);

$type = (string) $log->getAttribute('type');
$target = (string) $log->getAttribute('target');

if (!$target) {
continue;
}

$target = $this->toAbsolutePath($target);

if ($type === 'coverage-html') {
if ($log->hasAttribute('lowUpperBound')) {
$result['lowUpperBound'] = $this->getInteger(
(string) $log->getAttribute('lowUpperBound'),
50
);
}

if ($log->hasAttribute('highLowerBound')) {
$result['highLowerBound'] = $this->getInteger(
(string) $log->getAttribute('highLowerBound'),
90
);
}
} elseif ($type === 'coverage-crap4j') {
if ($log->hasAttribute('threshold')) {
$result['crap4jThreshold'] = $this->getInteger(
(string) $log->getAttribute('threshold'),
30
);
}
} elseif ($type === 'coverage-text') {
if ($log->hasAttribute('showUncoveredFiles')) {
$result['coverageTextShowUncoveredFiles'] = $this->getBoolean(
(string) $log->getAttribute('showUncoveredFiles'),
false
);
}

if ($log->hasAttribute('showOnlySummary')) {
$result['coverageTextShowOnlySummary'] = $this->getBoolean(
(string) $log->getAttribute('showOnlySummary'),
false
);
}
}

$result[$type] = $target;
}

return $result;
}




public function getPHPConfiguration(): array
{
$result = [
'include_path' => [],
'ini' => [],
'const' => [],
'var' => [],
'env' => [],
'post' => [],
'get' => [],
'cookie' => [],
'server' => [],
'files' => [],
'request' => [],
];

foreach ($this->xpath->query('php/includePath') as $includePath) {
$path = (string) $includePath->textContent;

if ($path) {
$result['include_path'][] = $this->toAbsolutePath($path);
}
}

foreach ($this->xpath->query('php/ini') as $ini) {
assert($ini instanceof DOMElement);

$name = (string) $ini->getAttribute('name');
$value = (string) $ini->getAttribute('value');

$result['ini'][$name]['value'] = $value;
}

foreach ($this->xpath->query('php/const') as $const) {
assert($const instanceof DOMElement);

$name = (string) $const->getAttribute('name');
$value = (string) $const->getAttribute('value');

$result['const'][$name]['value'] = $this->getBoolean($value, $value);
}

foreach (['var', 'env', 'post', 'get', 'cookie', 'server', 'files', 'request'] as $array) {
foreach ($this->xpath->query('php/' . $array) as $var) {
assert($var instanceof DOMElement);

$name = (string) $var->getAttribute('name');
$value = (string) $var->getAttribute('value');
$verbatim = false;

if ($var->hasAttribute('verbatim')) {
$verbatim = $this->getBoolean($var->getAttribute('verbatim'), false);
$result[$array][$name]['verbatim'] = $verbatim;
}

if ($var->hasAttribute('force')) {
$force = $this->getBoolean($var->getAttribute('force'), false);
$result[$array][$name]['force'] = $force;
}

if (!$verbatim) {
$value = $this->getBoolean($value, $value);
}

$result[$array][$name]['value'] = $value;
}
}

return $result;
}




public function handlePHPConfiguration(): void
{
$configuration = $this->getPHPConfiguration();

if (!empty($configuration['include_path'])) {
ini_set(
'include_path',
implode(PATH_SEPARATOR, $configuration['include_path']) .
PATH_SEPARATOR .
ini_get('include_path')
);
}

foreach ($configuration['ini'] as $name => $data) {
$value = $data['value'];

if (defined($value)) {
$value = (string) constant($value);
}

ini_set($name, $value);
}

foreach ($configuration['const'] as $name => $data) {
$value = $data['value'];

if (!defined($name)) {
define($name, $value);
}
}

foreach ($configuration['var'] as $name => $data) {
$GLOBALS[$name] = $data['value'];
}

foreach ($configuration['server'] as $name => $data) {
$_SERVER[$name] = $data['value'];
}

foreach (['post', 'get', 'cookie', 'files', 'request'] as $array) {
$target = &$GLOBALS['_' . strtoupper($array)];

foreach ($configuration[$array] as $name => $data) {
$target[$name] = $data['value'];
}
}

foreach ($configuration['env'] as $name => $data) {
$value = $data['value'];
$force = $data['force'] ?? false;

if ($force || getenv($name) === false) {
putenv("{$name}={$value}");
}

$value = getenv($name);

if (!isset($_ENV[$name])) {
$_ENV[$name] = $value;
}

if ($force) {
$_ENV[$name] = $value;
}
}
}




public function getPHPUnitConfiguration(): array
{
$result = [];
$root = $this->document->documentElement;

if ($root->hasAttribute('cacheTokens')) {
$result['cacheTokens'] = $this->getBoolean(
(string) $root->getAttribute('cacheTokens'),
false
);
}

if ($root->hasAttribute('columns')) {
$columns = (string) $root->getAttribute('columns');

if ($columns === 'max') {
$result['columns'] = 'max';
} else {
$result['columns'] = $this->getInteger($columns, 80);
}
}

if ($root->hasAttribute('colors')) {


if ($this->getBoolean($root->getAttribute('colors'), false)) {
$result['colors'] = ResultPrinter::COLOR_AUTO;
} else {
$result['colors'] = ResultPrinter::COLOR_NEVER;
}
}




if ($root->hasAttribute('stderr')) {
$result['stderr'] = $this->getBoolean(
(string) $root->getAttribute('stderr'),
false
);
}

if ($root->hasAttribute('backupGlobals')) {
$result['backupGlobals'] = $this->getBoolean(
(string) $root->getAttribute('backupGlobals'),
false
);
}

if ($root->hasAttribute('backupStaticAttributes')) {
$result['backupStaticAttributes'] = $this->getBoolean(
(string) $root->getAttribute('backupStaticAttributes'),
false
);
}

if ($root->getAttribute('bootstrap')) {
$result['bootstrap'] = $this->toAbsolutePath(
(string) $root->getAttribute('bootstrap')
);
}

if ($root->hasAttribute('convertDeprecationsToExceptions')) {
$result['convertDeprecationsToExceptions'] = $this->getBoolean(
(string) $root->getAttribute('convertDeprecationsToExceptions'),
false
);
}

if ($root->hasAttribute('convertErrorsToExceptions')) {
$result['convertErrorsToExceptions'] = $this->getBoolean(
(string) $root->getAttribute('convertErrorsToExceptions'),
true
);
}

if ($root->hasAttribute('convertNoticesToExceptions')) {
$result['convertNoticesToExceptions'] = $this->getBoolean(
(string) $root->getAttribute('convertNoticesToExceptions'),
true
);
}

if ($root->hasAttribute('convertWarningsToExceptions')) {
$result['convertWarningsToExceptions'] = $this->getBoolean(
(string) $root->getAttribute('convertWarningsToExceptions'),
true
);
}

if ($root->hasAttribute('forceCoversAnnotation')) {
$result['forceCoversAnnotation'] = $this->getBoolean(
(string) $root->getAttribute('forceCoversAnnotation'),
false
);
}

if ($root->hasAttribute('disableCodeCoverageIgnore')) {
$result['disableCodeCoverageIgnore'] = $this->getBoolean(
(string) $root->getAttribute('disableCodeCoverageIgnore'),
false
);
}

if ($root->hasAttribute('processIsolation')) {
$result['processIsolation'] = $this->getBoolean(
(string) $root->getAttribute('processIsolation'),
false
);
}

if ($root->hasAttribute('stopOnDefect')) {
$result['stopOnDefect'] = $this->getBoolean(
(string) $root->getAttribute('stopOnDefect'),
false
);
}

if ($root->hasAttribute('stopOnError')) {
$result['stopOnError'] = $this->getBoolean(
(string) $root->getAttribute('stopOnError'),
false
);
}

if ($root->hasAttribute('stopOnFailure')) {
$result['stopOnFailure'] = $this->getBoolean(
(string) $root->getAttribute('stopOnFailure'),
false
);
}

if ($root->hasAttribute('stopOnWarning')) {
$result['stopOnWarning'] = $this->getBoolean(
(string) $root->getAttribute('stopOnWarning'),
false
);
}

if ($root->hasAttribute('stopOnIncomplete')) {
$result['stopOnIncomplete'] = $this->getBoolean(
(string) $root->getAttribute('stopOnIncomplete'),
false
);
}

if ($root->hasAttribute('stopOnRisky')) {
$result['stopOnRisky'] = $this->getBoolean(
(string) $root->getAttribute('stopOnRisky'),
false
);
}

if ($root->hasAttribute('stopOnSkipped')) {
$result['stopOnSkipped'] = $this->getBoolean(
(string) $root->getAttribute('stopOnSkipped'),
false
);
}

if ($root->hasAttribute('failOnWarning')) {
$result['failOnWarning'] = $this->getBoolean(
(string) $root->getAttribute('failOnWarning'),
false
);
}

if ($root->hasAttribute('failOnRisky')) {
$result['failOnRisky'] = $this->getBoolean(
(string) $root->getAttribute('failOnRisky'),
false
);
}

if ($root->hasAttribute('testSuiteLoaderClass')) {
$result['testSuiteLoaderClass'] = (string) $root->getAttribute(
'testSuiteLoaderClass'
);
}

if ($root->hasAttribute('defaultTestSuite')) {
$result['defaultTestSuite'] = (string) $root->getAttribute(
'defaultTestSuite'
);
}

if ($root->getAttribute('testSuiteLoaderFile')) {
$result['testSuiteLoaderFile'] = $this->toAbsolutePath(
(string) $root->getAttribute('testSuiteLoaderFile')
);
}

if ($root->hasAttribute('printerClass')) {
$result['printerClass'] = (string) $root->getAttribute(
'printerClass'
);
}

if ($root->getAttribute('printerFile')) {
$result['printerFile'] = $this->toAbsolutePath(
(string) $root->getAttribute('printerFile')
);
}

if ($root->hasAttribute('beStrictAboutChangesToGlobalState')) {
$result['beStrictAboutChangesToGlobalState'] = $this->getBoolean(
(string) $root->getAttribute('beStrictAboutChangesToGlobalState'),
false
);
}

if ($root->hasAttribute('beStrictAboutOutputDuringTests')) {
$result['disallowTestOutput'] = $this->getBoolean(
(string) $root->getAttribute('beStrictAboutOutputDuringTests'),
false
);
}

if ($root->hasAttribute('beStrictAboutResourceUsageDuringSmallTests')) {
$result['beStrictAboutResourceUsageDuringSmallTests'] = $this->getBoolean(
(string) $root->getAttribute('beStrictAboutResourceUsageDuringSmallTests'),
false
);
}

if ($root->hasAttribute('beStrictAboutTestsThatDoNotTestAnything')) {
$result['reportUselessTests'] = $this->getBoolean(
(string) $root->getAttribute('beStrictAboutTestsThatDoNotTestAnything'),
true
);
}

if ($root->hasAttribute('beStrictAboutTodoAnnotatedTests')) {
$result['disallowTodoAnnotatedTests'] = $this->getBoolean(
(string) $root->getAttribute('beStrictAboutTodoAnnotatedTests'),
false
);
}

if ($root->hasAttribute('beStrictAboutCoversAnnotation')) {
$result['strictCoverage'] = $this->getBoolean(
(string) $root->getAttribute('beStrictAboutCoversAnnotation'),
false
);
}

if ($root->hasAttribute('defaultTimeLimit')) {
$result['defaultTimeLimit'] = $this->getInteger(
(string) $root->getAttribute('defaultTimeLimit'),
1
);
}

if ($root->hasAttribute('enforceTimeLimit')) {
$result['enforceTimeLimit'] = $this->getBoolean(
(string) $root->getAttribute('enforceTimeLimit'),
false
);
}

if ($root->hasAttribute('ignoreDeprecatedCodeUnitsFromCodeCoverage')) {
$result['ignoreDeprecatedCodeUnitsFromCodeCoverage'] = $this->getBoolean(
(string) $root->getAttribute('ignoreDeprecatedCodeUnitsFromCodeCoverage'),
false
);
}

if ($root->hasAttribute('timeoutForSmallTests')) {
$result['timeoutForSmallTests'] = $this->getInteger(
(string) $root->getAttribute('timeoutForSmallTests'),
1
);
}

if ($root->hasAttribute('timeoutForMediumTests')) {
$result['timeoutForMediumTests'] = $this->getInteger(
(string) $root->getAttribute('timeoutForMediumTests'),
10
);
}

if ($root->hasAttribute('timeoutForLargeTests')) {
$result['timeoutForLargeTests'] = $this->getInteger(
(string) $root->getAttribute('timeoutForLargeTests'),
60
);
}

if ($root->hasAttribute('reverseDefectList')) {
$result['reverseDefectList'] = $this->getBoolean(
(string) $root->getAttribute('reverseDefectList'),
false
);
}

if ($root->hasAttribute('verbose')) {
$result['verbose'] = $this->getBoolean(
(string) $root->getAttribute('verbose'),
false
);
}

if ($root->hasAttribute('testdox')) {
$testdox = $this->getBoolean(
(string) $root->getAttribute('testdox'),
false
);

if ($testdox) {
if (isset($result['printerClass'])) {
$result['conflictBetweenPrinterClassAndTestdox'] = true;
} else {
$result['printerClass'] = CliTestDoxPrinter::class;
}
}
}

if ($root->hasAttribute('registerMockObjectsFromTestArgumentsRecursively')) {
$result['registerMockObjectsFromTestArgumentsRecursively'] = $this->getBoolean(
(string) $root->getAttribute('registerMockObjectsFromTestArgumentsRecursively'),
false
);
}

if ($root->hasAttribute('extensionsDirectory')) {
$result['extensionsDirectory'] = $this->toAbsolutePath(
(string) $root->getAttribute(
'extensionsDirectory'
)
);
}

if ($root->hasAttribute('cacheResult')) {
$result['cacheResult'] = $this->getBoolean(
(string) $root->getAttribute('cacheResult'),
true
);
}

if ($root->hasAttribute('cacheResultFile')) {
$result['cacheResultFile'] = $this->toAbsolutePath(
(string) $root->getAttribute('cacheResultFile')
);
}

if ($root->hasAttribute('executionOrder')) {
foreach (explode(',', $root->getAttribute('executionOrder')) as $order) {
switch ($order) {
case 'default':
$result['executionOrder'] = TestSuiteSorter::ORDER_DEFAULT;
$result['executionOrderDefects'] = TestSuiteSorter::ORDER_DEFAULT;
$result['resolveDependencies'] = false;

break;

case 'defects':
$result['executionOrderDefects'] = TestSuiteSorter::ORDER_DEFECTS_FIRST;

break;

case 'depends':
$result['resolveDependencies'] = true;

break;

case 'duration':
$result['executionOrder'] = TestSuiteSorter::ORDER_DURATION;

break;

case 'no-depends':
$result['resolveDependencies'] = false;

break;

case 'random':
$result['executionOrder'] = TestSuiteSorter::ORDER_RANDOMIZED;

break;

case 'reverse':
$result['executionOrder'] = TestSuiteSorter::ORDER_REVERSED;

break;

case 'size':
$result['executionOrder'] = TestSuiteSorter::ORDER_SIZE;

break;
}
}
}

if ($root->hasAttribute('resolveDependencies')) {
$result['resolveDependencies'] = $this->getBoolean(
(string) $root->getAttribute('resolveDependencies'),
false
);
}

if ($root->hasAttribute('noInteraction')) {
$result['noInteraction'] = $this->getBoolean(
(string) $root->getAttribute('noInteraction'),
false
);
}

return $result;
}






public function getTestSuiteConfiguration(string $testSuiteFilter = ''): TestSuite
{
$testSuiteNodes = $this->xpath->query('testsuites/testsuite');

if ($testSuiteNodes->length === 0) {
$testSuiteNodes = $this->xpath->query('testsuite');
}

if ($testSuiteNodes->length === 1) {
return $this->getTestSuite($testSuiteNodes->item(0), $testSuiteFilter);
}

$suite = new TestSuite;

foreach ($testSuiteNodes as $testSuiteNode) {
$suite->addTestSuite(
$this->getTestSuite($testSuiteNode, $testSuiteFilter)
);
}

return $suite;
}




public function getTestSuiteNames(): array
{
$names = [];

foreach ($this->xpath->query('*/testsuite') as $node) {

$names[] = $node->getAttribute('name');
}

return $names;
}

private function validateConfigurationAgainstSchema(): void
{
$original = libxml_use_internal_errors(true);
$xsdFilename = __DIR__ . '/../../phpunit.xsd';

if (defined('__PHPUNIT_PHAR_ROOT__')) {
$xsdFilename = __PHPUNIT_PHAR_ROOT__ . '/phpunit.xsd';
}

$this->document->schemaValidateSource(file_get_contents($xsdFilename));
$this->errors = libxml_get_errors();
libxml_clear_errors();
libxml_use_internal_errors($original);
}





private function getConfigurationArguments(DOMNodeList $nodes): array
{
$arguments = [];

if ($nodes->length === 0) {
return $arguments;
}

foreach ($nodes as $node) {
if (!$node instanceof DOMElement) {
continue;
}

if ($node->tagName !== 'arguments') {
continue;
}

foreach ($node->childNodes as $argument) {
if (!$argument instanceof DOMElement) {
continue;
}

if ($argument->tagName === 'file' || $argument->tagName === 'directory') {
$arguments[] = $this->toAbsolutePath((string) $argument->textContent);
} else {
$arguments[] = Xml::xmlToVariable($argument);
}
}
}

return $arguments;
}




private function getTestSuite(DOMElement $testSuiteNode, string $testSuiteFilter = ''): TestSuite
{
if ($testSuiteNode->hasAttribute('name')) {
$suite = new TestSuite(
(string) $testSuiteNode->getAttribute('name')
);
} else {
$suite = new TestSuite;
}

$exclude = [];

foreach ($testSuiteNode->getElementsByTagName('exclude') as $excludeNode) {
$excludeFile = (string) $excludeNode->textContent;

if ($excludeFile) {
$exclude[] = $this->toAbsolutePath($excludeFile);
}
}

$fileIteratorFacade = new FileIteratorFacade;
$testSuiteFilter = $testSuiteFilter ? explode(',', $testSuiteFilter) : [];

foreach ($testSuiteNode->getElementsByTagName('directory') as $directoryNode) {
assert($directoryNode instanceof DOMElement);

if (!empty($testSuiteFilter) && !in_array($directoryNode->parentNode->getAttribute('name'), $testSuiteFilter, true)) {
continue;
}

$directory = (string) $directoryNode->textContent;

if (empty($directory)) {
continue;
}

if (!$this->satisfiesPhpVersion($directoryNode)) {
continue;
}

$files = $fileIteratorFacade->getFilesAsArray(
$this->toAbsolutePath($directory),
$directoryNode->hasAttribute('suffix') ? (string) $directoryNode->getAttribute('suffix') : 'Test.php',
$directoryNode->hasAttribute('prefix') ? (string) $directoryNode->getAttribute('prefix') : '',
$exclude
);

$suite->addTestFiles($files);
}

foreach ($testSuiteNode->getElementsByTagName('file') as $fileNode) {
assert($fileNode instanceof DOMElement);

if (!empty($testSuiteFilter) && !in_array($fileNode->parentNode->getAttribute('name'), $testSuiteFilter, true)) {
continue;
}

$file = (string) $fileNode->textContent;

if (empty($file)) {
continue;
}

$file = $fileIteratorFacade->getFilesAsArray(
$this->toAbsolutePath($file)
);

if (!isset($file[0])) {
continue;
}

$file = $file[0];

if (!$this->satisfiesPhpVersion($fileNode)) {
continue;
}

$suite->addTestFile($file);
}

return $suite;
}

private function satisfiesPhpVersion(DOMElement $node): bool
{
$phpVersion = PHP_VERSION;
$phpVersionOperator = '>=';

if ($node->hasAttribute('phpVersion')) {
$phpVersion = (string) $node->getAttribute('phpVersion');
}

if ($node->hasAttribute('phpVersionOperator')) {
$phpVersionOperator = (string) $node->getAttribute('phpVersionOperator');
}

return version_compare(PHP_VERSION, $phpVersion, (new VersionComparisonOperator($phpVersionOperator))->asString());
}










private function getBoolean(string $value, $default)
{
if (strtolower($value) === 'false') {
return false;
}

if (strtolower($value) === 'true') {
return true;
}

return $default;
}

private function getInteger(string $value, int $default): int
{
if (is_numeric($value)) {
return (int) $value;
}

return $default;
}

private function readFilterDirectories(string $query): array
{
$directories = [];

foreach ($this->xpath->query($query) as $directoryNode) {
assert($directoryNode instanceof DOMElement);

$directoryPath = (string) $directoryNode->textContent;

if (!$directoryPath) {
continue;
}

$directories[] = [
'path' => $this->toAbsolutePath($directoryPath),
'prefix' => $directoryNode->hasAttribute('prefix') ? (string) $directoryNode->getAttribute('prefix') : '',
'suffix' => $directoryNode->hasAttribute('suffix') ? (string) $directoryNode->getAttribute('suffix') : '.php',
'group' => $directoryNode->hasAttribute('group') ? (string) $directoryNode->getAttribute('group') : 'DEFAULT',
];
}

return $directories;
}




private function readFilterFiles(string $query): array
{
$files = [];

foreach ($this->xpath->query($query) as $file) {
$filePath = (string) $file->textContent;

if ($filePath) {
$files[] = $this->toAbsolutePath($filePath);
}
}

return $files;
}

private function toAbsolutePath(string $path, bool $useIncludePath = false): string
{
$path = trim($path);

if (strpos($path, '/') === 0) {
return $path;
}


 
 
 
 
 
 
 
 if (defined('PHP_WINDOWS_VERSION_BUILD') &&
($path[0] === '\\' || (strlen($path) >= 3 && preg_match('#^[A-Z]\:[/\\\]#i', substr($path, 0, 3))))) {
return $path;
}

if (strpos($path, '://') !== false) {
return $path;
}

$file = dirname($this->filename) . DIRECTORY_SEPARATOR . $path;

if ($useIncludePath && !file_exists($file)) {
$includePathFile = stream_resolve_include_path($path);

if ($includePathFile) {
$file = $includePathFile;
}
}

return $file;
}

private function parseGroupConfiguration(string $root): array
{
$groups = [
'include' => [],
'exclude' => [],
];

foreach ($this->xpath->query($root . '/include/group') as $group) {
$groups['include'][] = (string) $group->textContent;
}

foreach ($this->xpath->query($root . '/exclude/group') as $group) {
$groups['exclude'][] = (string) $group->textContent;
}

return $groups;
}

private function getElementConfigurationParameters(DOMElement $element): array
{
$class = (string) $element->getAttribute('class');
$file = '';
$arguments = $this->getConfigurationArguments($element->childNodes);

if ($element->getAttribute('file')) {
$file = $this->toAbsolutePath(
(string) $element->getAttribute('file'),
true
);
}

return [
'class' => $class,
'file' => $file,
'arguments' => $arguments,
];
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use RuntimeException;




final class Exception extends RuntimeException implements \PHPUnit\Exception
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use RuntimeException;




final class InvalidDataSetException extends RuntimeException implements \PHPUnit\Exception
{
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use const JSON_PRETTY_PRINT;
use const JSON_UNESCAPED_SLASHES;
use const JSON_UNESCAPED_UNICODE;
use function count;
use function is_array;
use function is_object;
use function json_decode;
use function json_encode;
use function json_last_error;
use function ksort;
use PHPUnit\Framework\Exception;




final class Json
{





public static function prettify(string $json): string
{
$decodedJson = json_decode($json, false);

if (json_last_error()) {
throw new Exception(
'Cannot prettify invalid json'
);
}

return json_encode($decodedJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
}









public static function canonicalize(string $json): array
{
$decodedJson = json_decode($json);

if (json_last_error()) {
return [true, null];
}

self::recursiveSort($decodedJson);

$reencodedJson = json_encode($decodedJson);

return [false, $reencodedJson];
}







private static function recursiveSort(&$json): void
{
if (!is_array($json)) {

 
 
 
 
 
 if (is_object($json) && count((array) $json) > 0) {
$json = (array) $json;
} else {
return;
}
}

ksort($json);

foreach ($json as $key => &$value) {
self::recursiveSort($value);
}
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use function array_map;
use function array_merge;
use function array_shift;
use function array_slice;
use function count;
use function current;
use function explode;
use function key;
use function next;
use function preg_replace;
use function reset;
use function sort;
use function strlen;
use function strpos;
use function strstr;
use function substr;
use PHPUnit\Framework\Exception;




final class Getopt
{



public static function parse(array $args, string $short_options, array $long_options = null): array
{
if (empty($args)) {
return [[], []];
}

$opts = [];
$non_opts = [];

if ($long_options) {
sort($long_options);
}

if (isset($args[0][0]) && $args[0][0] !== '-') {
array_shift($args);
}

reset($args);

$args = array_map('trim', $args);


while (false !== $arg = current($args)) {
$i = key($args);
next($args);

if ($arg === '') {
continue;
}

if ($arg === '--') {
$non_opts = array_merge($non_opts, array_slice($args, $i + 1));

break;
}

if ($arg[0] !== '-' || (strlen($arg) > 1 && $arg[1] === '-' && !$long_options)) {
$non_opts[] = $args[$i];

continue;
}

if (strlen($arg) > 1 && $arg[1] === '-') {
self::parseLongOption(
substr($arg, 2),
$long_options,
$opts,
$args
);
} else {
self::parseShortOption(
substr($arg, 1),
$short_options,
$opts,
$args
);
}
}

return [$opts, $non_opts];
}




private static function parseShortOption(string $arg, string $short_options, array &$opts, array &$args): void
{
$argLen = strlen($arg);

for ($i = 0; $i < $argLen; $i++) {
$opt = $arg[$i];
$opt_arg = null;

if ($arg[$i] === ':' || ($spec = strstr($short_options, $opt)) === false) {
throw new Exception(
"unrecognized option -- {$opt}"
);
}

if (strlen($spec) > 1 && $spec[1] === ':') {
if ($i + 1 < $argLen) {
$opts[] = [$opt, substr($arg, $i + 1)];

break;
}

if (!(strlen($spec) > 2 && $spec[2] === ':')) {

if (false === $opt_arg = current($args)) {
throw new Exception(
"option requires an argument -- {$opt}"
);
}

next($args);
}
}

$opts[] = [$opt, $opt_arg];
}
}




private static function parseLongOption(string $arg, array $long_options, array &$opts, array &$args): void
{
$count = count($long_options);
$list = explode('=', $arg);
$opt = $list[0];
$opt_arg = null;

if (count($list) > 1) {
$opt_arg = $list[1];
}

$opt_len = strlen($opt);

foreach ($long_options as $i => $long_opt) {
$opt_start = substr($long_opt, 0, $opt_len);

if ($opt_start !== $opt) {
continue;
}

$opt_rest = substr($long_opt, $opt_len);

if ($opt_rest !== '' && $i + 1 < $count && $opt[0] !== '=' && strpos($long_options[$i + 1], $opt) === 0) {
throw new Exception(
"option --{$opt} is ambiguous"
);
}

if (substr($long_opt, -1) === '=') {

if (substr($long_opt, -2) !== '==' && !strlen((string) $opt_arg)) {

if (false === $opt_arg = current($args)) {
throw new Exception(
"option --{$opt} requires an argument"
);
}

next($args);
}
} elseif ($opt_arg) {
throw new Exception(
"option --{$opt} doesn't allow an argument"
);
}

$full_option = '--' . preg_replace('/={1,2}$/', '', $long_opt);
$opts[] = [$full_option, $opt_arg];

return;
}

throw new Exception("unrecognized option --{$opt}");
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use const E_DEPRECATED;
use const E_NOTICE;
use const E_STRICT;
use const E_USER_DEPRECATED;
use const E_USER_NOTICE;
use const E_USER_WARNING;
use const E_WARNING;
use function error_reporting;
use function restore_error_handler;
use function set_error_handler;
use PHPUnit\Framework\Error\Deprecated;
use PHPUnit\Framework\Error\Error;
use PHPUnit\Framework\Error\Notice;
use PHPUnit\Framework\Error\Warning;




final class ErrorHandler
{



private $convertDeprecationsToExceptions;




private $convertErrorsToExceptions;




private $convertNoticesToExceptions;




private $convertWarningsToExceptions;




private $registered = false;

public static function invokeIgnoringWarnings(callable $callable)
{
set_error_handler(
static function ($errorNumber, $errorString)
{
if ($errorNumber === E_WARNING) {
return;
}

return false;
}
);

$result = $callable();

restore_error_handler();

return $result;
}

public function __construct(bool $convertDeprecationsToExceptions, bool $convertErrorsToExceptions, bool $convertNoticesToExceptions, bool $convertWarningsToExceptions)
{
$this->convertDeprecationsToExceptions = $convertDeprecationsToExceptions;
$this->convertErrorsToExceptions = $convertErrorsToExceptions;
$this->convertNoticesToExceptions = $convertNoticesToExceptions;
$this->convertWarningsToExceptions = $convertWarningsToExceptions;
}

public function __invoke(int $errorNumber, string $errorString, string $errorFile, int $errorLine): bool
{





if (!($errorNumber & error_reporting())) {
return false;
}

switch ($errorNumber) {
case E_NOTICE:
case E_USER_NOTICE:
case E_STRICT:
if (!$this->convertNoticesToExceptions) {
return false;
}

throw new Notice($errorString, $errorNumber, $errorFile, $errorLine);

case E_WARNING:
case E_USER_WARNING:
if (!$this->convertWarningsToExceptions) {
return false;
}

throw new Warning($errorString, $errorNumber, $errorFile, $errorLine);

case E_DEPRECATED:
case E_USER_DEPRECATED:
if (!$this->convertDeprecationsToExceptions) {
return false;
}

throw new Deprecated($errorString, $errorNumber, $errorFile, $errorLine);

default:
if (!$this->convertErrorsToExceptions) {
return false;
}

throw new Error($errorString, $errorNumber, $errorFile, $errorLine);
}
}

public function register(): void
{
if ($this->registered) {
return;
}

$oldErrorHandler = set_error_handler($this);

if ($oldErrorHandler !== null) {
restore_error_handler();

return;
}

$this->registered = true;
}

public function unregister(): void
{
if (!$this->registered) {
return;
}

restore_error_handler();
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use const DIRECTORY_SEPARATOR;
use function is_dir;
use function mkdir;
use function str_replace;




final class Filesystem
{





public static function classNameToFilename(string $className): string
{
return str_replace(
['_', '\\'],
DIRECTORY_SEPARATOR,
$className
) . '.php';
}

public static function createDirectory(string $directory): bool
{
return !(!is_dir($directory) && !@mkdir($directory, 0777, true) && !is_dir($directory));
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use const ENT_SUBSTITUTE;
use const PHP_SAPI;
use function assert;
use function count;
use function dirname;
use function explode;
use function fclose;
use function fflush;
use function flush;
use function fopen;
use function fsockopen;
use function fwrite;
use function htmlspecialchars;
use function is_resource;
use function is_string;
use function sprintf;
use function str_replace;
use function strncmp;
use function strpos;
use PHPUnit\Framework\Exception;




class Printer
{





protected $autoFlush = false;




protected $out;




protected $outTarget;








public function __construct($out = null)
{
if ($out === null) {
return;
}

if (is_string($out) === false) {
$this->out = $out;

return;
}

if (strpos($out, 'socket://') === 0) {
$out = explode(':', str_replace('socket://', '', $out));

if (count($out) !== 2) {
throw new Exception;
}

$this->out = fsockopen($out[0], $out[1]);
} else {
if (strpos($out, 'php://') === false && !Filesystem::createDirectory(dirname($out))) {
throw new Exception(sprintf('Directory "%s" was not created', dirname($out)));
}

$this->out = fopen($out, 'wt');
}

$this->outTarget = $out;
}




public function flush(): void
{
if ($this->out && strncmp($this->outTarget, 'php://', 6) !== 0) {
assert(is_resource($this->out));

fclose($this->out);
}
}








public function incrementalFlush(): void
{
if ($this->out) {
assert(is_resource($this->out));

fflush($this->out);
} else {
flush();
}
}

public function write(string $buffer): void
{
if ($this->out) {
assert(is_resource($this->out));

fwrite($this->out, $buffer);

if ($this->autoFlush) {
$this->incrementalFlush();
}
} else {
if (PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg') {
$buffer = htmlspecialchars($buffer, ENT_SUBSTITUTE);
}

print $buffer;

if ($this->autoFlush) {
$this->incrementalFlush();
}
}
}




public function getAutoFlush(): bool
{
return $this->autoFlush;
}







public function setAutoFlush(bool $autoFlush): void
{
$this->autoFlush = $autoFlush;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util\Log;

use function class_exists;
use function count;
use function explode;
use function get_class;
use function getmypid;
use function ini_get;
use function is_bool;
use function is_scalar;
use function method_exists;
use function print_r;
use function round;
use function str_replace;
use function stripos;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\ExceptionWrapper;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestFailure;
use PHPUnit\Framework\TestResult;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Framework\Warning;
use PHPUnit\TextUI\ResultPrinter;
use PHPUnit\Util\Exception;
use PHPUnit\Util\Filter;
use ReflectionClass;
use ReflectionException;
use SebastianBergmann\Comparator\ComparisonFailure;
use Throwable;




final class TeamCity extends ResultPrinter
{



private $isSummaryTestCountPrinted = false;




private $startedTestName;




private $flowId;




public function printResult(TestResult $result): void
{
$this->printHeader($result);
$this->printFooter($result);
}




public function addError(Test $test, Throwable $t, float $time): void
{
$this->printEvent(
'testFailed',
[
'name' => $test->getName(),
'message' => self::getMessage($t),
'details' => self::getDetails($t),
'duration' => self::toMilliseconds($time),
]
);
}




public function addWarning(Test $test, Warning $e, float $time): void
{
$this->write(self::getMessage($e) . PHP_EOL);
}




public function addFailure(Test $test, AssertionFailedError $e, float $time): void
{
$parameters = [
'name' => $test->getName(),
'message' => self::getMessage($e),
'details' => self::getDetails($e),
'duration' => self::toMilliseconds($time),
];

if ($e instanceof ExpectationFailedException) {
$comparisonFailure = $e->getComparisonFailure();

if ($comparisonFailure instanceof ComparisonFailure) {
$expectedString = $comparisonFailure->getExpectedAsString();

if ($expectedString === null || empty($expectedString)) {
$expectedString = self::getPrimitiveValueAsString($comparisonFailure->getExpected());
}

$actualString = $comparisonFailure->getActualAsString();

if ($actualString === null || empty($actualString)) {
$actualString = self::getPrimitiveValueAsString($comparisonFailure->getActual());
}

if ($actualString !== null && $expectedString !== null) {
$parameters['type'] = 'comparisonFailure';
$parameters['actual'] = $actualString;
$parameters['expected'] = $expectedString;
}
}
}

$this->printEvent('testFailed', $parameters);
}




public function addIncompleteTest(Test $test, Throwable $t, float $time): void
{
$this->printIgnoredTest($test->getName(), $t, $time);
}




public function addRiskyTest(Test $test, Throwable $t, float $time): void
{
$this->addError($test, $t, $time);
}




public function addSkippedTest(Test $test, Throwable $t, float $time): void
{
$testName = $test->getName();

if ($this->startedTestName !== $testName) {
$this->startTest($test);
$this->printIgnoredTest($testName, $t, $time);
$this->endTest($test, $time);
} else {
$this->printIgnoredTest($testName, $t, $time);
}
}

public function printIgnoredTest($testName, Throwable $t, float $time): void
{
$this->printEvent(
'testIgnored',
[
'name' => $testName,
'message' => self::getMessage($t),
'details' => self::getDetails($t),
'duration' => self::toMilliseconds($time),
]
);
}




public function startTestSuite(TestSuite $suite): void
{
if (stripos(ini_get('disable_functions'), 'getmypid') === false) {
$this->flowId = getmypid();
} else {
$this->flowId = false;
}

if (!$this->isSummaryTestCountPrinted) {
$this->isSummaryTestCountPrinted = true;

$this->printEvent(
'testCount',
['count' => count($suite)]
);
}

$suiteName = $suite->getName();

if (empty($suiteName)) {
return;
}

$parameters = ['name' => $suiteName];

if (class_exists($suiteName, false)) {
$fileName = self::getFileName($suiteName);
$parameters['locationHint'] = "php_qn://{$fileName}::\\{$suiteName}";
} else {
$split = explode('::', $suiteName);

if (count($split) === 2 && class_exists($split[0]) && method_exists($split[0], $split[1])) {
$fileName = self::getFileName($split[0]);
$parameters['locationHint'] = "php_qn://{$fileName}::\\{$suiteName}";
$parameters['name'] = $split[1];
}
}

$this->printEvent('testSuiteStarted', $parameters);
}




public function endTestSuite(TestSuite $suite): void
{
$suiteName = $suite->getName();

if (empty($suiteName)) {
return;
}

$parameters = ['name' => $suiteName];

if (!class_exists($suiteName, false)) {
$split = explode('::', $suiteName);

if (count($split) === 2 && class_exists($split[0]) && method_exists($split[0], $split[1])) {
$parameters['name'] = $split[1];
}
}

$this->printEvent('testSuiteFinished', $parameters);
}




public function startTest(Test $test): void
{
$testName = $test->getName();
$this->startedTestName = $testName;
$params = ['name' => $testName];

if ($test instanceof TestCase) {
$className = get_class($test);
$fileName = self::getFileName($className);
$params['locationHint'] = "php_qn://{$fileName}::\\{$className}::{$testName}";
}

$this->printEvent('testStarted', $params);
}




public function endTest(Test $test, float $time): void
{
parent::endTest($test, $time);

$this->printEvent(
'testFinished',
[
'name' => $test->getName(),
'duration' => self::toMilliseconds($time),
]
);
}

protected function writeProgress(string $progress): void
{
}

private function printEvent(string $eventName, array $params = []): void
{
$this->write("\n##teamcity[{$eventName}");

if ($this->flowId) {
$params['flowId'] = $this->flowId;
}

foreach ($params as $key => $value) {
$escapedValue = self::escapeValue((string) $value);
$this->write(" {$key}='{$escapedValue}'");
}

$this->write("]\n");
}

private static function getMessage(Throwable $t): string
{
$message = '';

if ($t instanceof ExceptionWrapper) {
if ($t->getClassName() !== '') {
$message .= $t->getClassName();
}

if ($message !== '' && $t->getMessage() !== '') {
$message .= ' : ';
}
}

return $message . $t->getMessage();
}

private static function getDetails(Throwable $t): string
{
$stackTrace = Filter::getFilteredStacktrace($t);
$previous = $t instanceof ExceptionWrapper ? $t->getPreviousWrapped() : $t->getPrevious();

while ($previous) {
$stackTrace .= "\nCaused by\n" .
TestFailure::exceptionToString($previous) . "\n" .
Filter::getFilteredStacktrace($previous);

$previous = $previous instanceof ExceptionWrapper ?
$previous->getPreviousWrapped() : $previous->getPrevious();
}

return ' ' . str_replace("\n", "\n ", $stackTrace);
}

private static function getPrimitiveValueAsString($value): ?string
{
if ($value === null) {
return 'null';
}

if (is_bool($value)) {
return $value ? 'true' : 'false';
}

if (is_scalar($value)) {
return print_r($value, true);
}

return null;
}

private static function escapeValue(string $text): string
{
return str_replace(
['|', "'", "\n", "\r", ']', '['],
['||', "|'", '|n', '|r', '|]', '|['],
$text
);
}




private static function getFileName($className): string
{
try {
return (new ReflectionClass($className))->getFileName();

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}

 }




private static function toMilliseconds(float $time): int
{
return (int) round($time * 1000);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util\Log;

use function class_exists;
use function get_class;
use function method_exists;
use function sprintf;
use function str_replace;
use DOMDocument;
use DOMElement;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\ExceptionWrapper;
use PHPUnit\Framework\SelfDescribing;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestFailure;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Framework\Warning;
use PHPUnit\Util\Exception;
use PHPUnit\Util\Filter;
use PHPUnit\Util\Printer;
use PHPUnit\Util\Xml;
use ReflectionClass;
use ReflectionException;
use Throwable;




final class JUnit extends Printer implements TestListener
{



private $document;




private $root;




private $reportRiskyTests = false;




private $testSuites = [];




private $testSuiteTests = [0];




private $testSuiteAssertions = [0];




private $testSuiteErrors = [0];




private $testSuiteWarnings = [0];




private $testSuiteFailures = [0];




private $testSuiteSkipped = [0];




private $testSuiteTimes = [0];




private $testSuiteLevel = 0;




private $currentTestCase;




public function __construct($out = null, bool $reportRiskyTests = false)
{
$this->document = new DOMDocument('1.0', 'UTF-8');
$this->document->formatOutput = true;

$this->root = $this->document->createElement('testsuites');
$this->document->appendChild($this->root);

parent::__construct($out);

$this->reportRiskyTests = $reportRiskyTests;
}




public function flush(): void
{
$this->write($this->getXML());

parent::flush();
}




public function addError(Test $test, Throwable $t, float $time): void
{
$this->doAddFault($test, $t, $time, 'error');
$this->testSuiteErrors[$this->testSuiteLevel]++;
}




public function addWarning(Test $test, Warning $e, float $time): void
{
$this->doAddFault($test, $e, $time, 'warning');
$this->testSuiteWarnings[$this->testSuiteLevel]++;
}




public function addFailure(Test $test, AssertionFailedError $e, float $time): void
{
$this->doAddFault($test, $e, $time, 'failure');
$this->testSuiteFailures[$this->testSuiteLevel]++;
}




public function addIncompleteTest(Test $test, Throwable $t, float $time): void
{
$this->doAddSkipped();
}




public function addRiskyTest(Test $test, Throwable $t, float $time): void
{
if (!$this->reportRiskyTests || $this->currentTestCase === null) {
return;
}

$error = $this->document->createElement(
'error',
Xml::prepareString(
"Risky Test\n" .
Filter::getFilteredStacktrace($t)
)
);

$error->setAttribute('type', get_class($t));

$this->currentTestCase->appendChild($error);

$this->testSuiteErrors[$this->testSuiteLevel]++;
}




public function addSkippedTest(Test $test, Throwable $t, float $time): void
{
$this->doAddSkipped();
}




public function startTestSuite(TestSuite $suite): void
{
$testSuite = $this->document->createElement('testsuite');
$testSuite->setAttribute('name', $suite->getName());

if (class_exists($suite->getName(), false)) {
try {
$class = new ReflectionClass($suite->getName());

$testSuite->setAttribute('file', $class->getFileName());
} catch (ReflectionException $e) {
}
}

if ($this->testSuiteLevel > 0) {
$this->testSuites[$this->testSuiteLevel]->appendChild($testSuite);
} else {
$this->root->appendChild($testSuite);
}

$this->testSuiteLevel++;
$this->testSuites[$this->testSuiteLevel] = $testSuite;
$this->testSuiteTests[$this->testSuiteLevel] = 0;
$this->testSuiteAssertions[$this->testSuiteLevel] = 0;
$this->testSuiteErrors[$this->testSuiteLevel] = 0;
$this->testSuiteWarnings[$this->testSuiteLevel] = 0;
$this->testSuiteFailures[$this->testSuiteLevel] = 0;
$this->testSuiteSkipped[$this->testSuiteLevel] = 0;
$this->testSuiteTimes[$this->testSuiteLevel] = 0;
}




public function endTestSuite(TestSuite $suite): void
{
$this->testSuites[$this->testSuiteLevel]->setAttribute(
'tests',
(string) $this->testSuiteTests[$this->testSuiteLevel]
);

$this->testSuites[$this->testSuiteLevel]->setAttribute(
'assertions',
(string) $this->testSuiteAssertions[$this->testSuiteLevel]
);

$this->testSuites[$this->testSuiteLevel]->setAttribute(
'errors',
(string) $this->testSuiteErrors[$this->testSuiteLevel]
);

$this->testSuites[$this->testSuiteLevel]->setAttribute(
'warnings',
(string) $this->testSuiteWarnings[$this->testSuiteLevel]
);

$this->testSuites[$this->testSuiteLevel]->setAttribute(
'failures',
(string) $this->testSuiteFailures[$this->testSuiteLevel]
);

$this->testSuites[$this->testSuiteLevel]->setAttribute(
'skipped',
(string) $this->testSuiteSkipped[$this->testSuiteLevel]
);

$this->testSuites[$this->testSuiteLevel]->setAttribute(
'time',
sprintf('%F', $this->testSuiteTimes[$this->testSuiteLevel])
);

if ($this->testSuiteLevel > 1) {
$this->testSuiteTests[$this->testSuiteLevel - 1] += $this->testSuiteTests[$this->testSuiteLevel];
$this->testSuiteAssertions[$this->testSuiteLevel - 1] += $this->testSuiteAssertions[$this->testSuiteLevel];
$this->testSuiteErrors[$this->testSuiteLevel - 1] += $this->testSuiteErrors[$this->testSuiteLevel];
$this->testSuiteWarnings[$this->testSuiteLevel - 1] += $this->testSuiteWarnings[$this->testSuiteLevel];
$this->testSuiteFailures[$this->testSuiteLevel - 1] += $this->testSuiteFailures[$this->testSuiteLevel];
$this->testSuiteSkipped[$this->testSuiteLevel - 1] += $this->testSuiteSkipped[$this->testSuiteLevel];
$this->testSuiteTimes[$this->testSuiteLevel - 1] += $this->testSuiteTimes[$this->testSuiteLevel];
}

$this->testSuiteLevel--;
}




public function startTest(Test $test): void
{
$usesDataprovider = false;

if (method_exists($test, 'usesDataProvider')) {
$usesDataprovider = $test->usesDataProvider();
}

$testCase = $this->document->createElement('testcase');
$testCase->setAttribute('name', $test->getName());

try {
$class = new ReflectionClass($test);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


$methodName = $test->getName(!$usesDataprovider);

if ($class->hasMethod($methodName)) {
try {
$method = $class->getMethod($methodName);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


$testCase->setAttribute('class', $class->getName());
$testCase->setAttribute('classname', str_replace('\\', '.', $class->getName()));
$testCase->setAttribute('file', $class->getFileName());
$testCase->setAttribute('line', (string) $method->getStartLine());
}

$this->currentTestCase = $testCase;
}




public function endTest(Test $test, float $time): void
{
$numAssertions = 0;

if (method_exists($test, 'getNumAssertions')) {
$numAssertions = $test->getNumAssertions();
}

$this->testSuiteAssertions[$this->testSuiteLevel] += $numAssertions;

$this->currentTestCase->setAttribute(
'assertions',
(string) $numAssertions
);

$this->currentTestCase->setAttribute(
'time',
sprintf('%F', $time)
);

$this->testSuites[$this->testSuiteLevel]->appendChild(
$this->currentTestCase
);

$this->testSuiteTests[$this->testSuiteLevel]++;
$this->testSuiteTimes[$this->testSuiteLevel] += $time;

$testOutput = '';

if (method_exists($test, 'hasOutput') && method_exists($test, 'getActualOutput')) {
$testOutput = $test->hasOutput() ? $test->getActualOutput() : '';
}

if (!empty($testOutput)) {
$systemOut = $this->document->createElement(
'system-out',
Xml::prepareString($testOutput)
);

$this->currentTestCase->appendChild($systemOut);
}

$this->currentTestCase = null;
}




public function getXML(): string
{
return $this->document->saveXML();
}

private function doAddFault(Test $test, Throwable $t, float $time, $type): void
{
if ($this->currentTestCase === null) {
return;
}

if ($test instanceof SelfDescribing) {
$buffer = $test->toString() . "\n";
} else {
$buffer = '';
}

$buffer .= TestFailure::exceptionToString($t) . "\n" .
Filter::getFilteredStacktrace($t);

$fault = $this->document->createElement(
$type,
Xml::prepareString($buffer)
);

if ($t instanceof ExceptionWrapper) {
$fault->setAttribute('type', $t->getClassName());
} else {
$fault->setAttribute('type', get_class($t));
}

$this->currentTestCase->appendChild($fault);
}

private function doAddSkipped(): void
{
if ($this->currentTestCase === null) {
return;
}

$skipped = $this->document->createElement('skipped');

$this->currentTestCase->appendChild($skipped);

$this->testSuiteSkipped[$this->testSuiteLevel]++;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use function array_unshift;
use function defined;
use function in_array;
use function is_file;
use function realpath;
use function sprintf;
use function strpos;
use PHPUnit\Framework\Exception;
use PHPUnit\Framework\SyntheticError;
use Throwable;




final class Filter
{



public static function getFilteredStacktrace(Throwable $t): string
{
$filteredStacktrace = '';

if ($t instanceof SyntheticError) {
$eTrace = $t->getSyntheticTrace();
$eFile = $t->getSyntheticFile();
$eLine = $t->getSyntheticLine();
} elseif ($t instanceof Exception) {
$eTrace = $t->getSerializableTrace();
$eFile = $t->getFile();
$eLine = $t->getLine();
} else {
if ($t->getPrevious()) {
$t = $t->getPrevious();
}

$eTrace = $t->getTrace();
$eFile = $t->getFile();
$eLine = $t->getLine();
}

if (!self::frameExists($eTrace, $eFile, $eLine)) {
array_unshift(
$eTrace,
['file' => $eFile, 'line' => $eLine]
);
}

$prefix = defined('__PHPUNIT_PHAR_ROOT__') ? __PHPUNIT_PHAR_ROOT__ : false;
$blacklist = new Blacklist;

foreach ($eTrace as $frame) {
if (self::shouldPrintFrame($frame, $prefix, $blacklist)) {
$filteredStacktrace .= sprintf(
"%s:%s\n",
$frame['file'],
$frame['line'] ?? '?'
);
}
}

return $filteredStacktrace;
}

private static function shouldPrintFrame($frame, $prefix, Blacklist $blacklist): bool
{
if (!isset($frame['file'])) {
return false;
}

$file = $frame['file'];
$fileIsNotPrefixed = $prefix === false || strpos($file, $prefix) !== 0;


 if (isset($GLOBALS['_SERVER']['SCRIPT_NAME'])) {
$script = realpath($GLOBALS['_SERVER']['SCRIPT_NAME']);
} else {
$script = '';
}

return is_file($file) &&
self::fileIsBlacklisted($file, $blacklist) &&
$fileIsNotPrefixed &&
$file !== $script;
}

private static function fileIsBlacklisted($file, Blacklist $blacklist): bool
{
return (empty($GLOBALS['__PHPUNIT_ISOLATION_BLACKLIST']) ||
!in_array($file, $GLOBALS['__PHPUNIT_ISOLATION_BLACKLIST'], true)) &&
!$blacklist->isBlacklisted($file);
}

private static function frameExists(array $trace, string $file, int $line): bool
{
foreach ($trace as $frame) {
if (isset($frame['file'], $frame['line']) && $frame['file'] === $file && $frame['line'] === $line) {
return true;
}
}

return false;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use const DIRECTORY_SEPARATOR;
use function array_diff;
use function array_keys;
use function fopen;
use function get_defined_vars;
use function sprintf;
use function stream_resolve_include_path;
use PHPUnit\Framework\Exception;




final class FileLoader
{










public static function checkAndLoad(string $filename): string
{
$includePathFilename = stream_resolve_include_path($filename);

if (!$includePathFilename) {
throw new Exception(
sprintf('Cannot open file "%s".' . "\n", $filename)
);
}

$localFile = __DIR__ . DIRECTORY_SEPARATOR . $filename;

if ($includePathFilename === $localFile || !self::isReadable($includePathFilename)) {
throw new Exception(
sprintf('Cannot open file "%s".' . "\n", $filename)
);
}

self::load($includePathFilename);

return $includePathFilename;
}




public static function load(string $filename): void
{
$oldVariableNames = array_keys(get_defined_vars());

include_once $filename;

$newVariables = get_defined_vars();

foreach (array_diff(array_keys($newVariables), $oldVariableNames) as $variableName) {
if ($variableName !== 'oldVariableNames') {
$GLOBALS[$variableName] = $newVariables[$variableName];
}
}
}




private static function isReadable(string $filename): bool
{
return @fopen($filename, 'r') !== false;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use const ENT_QUOTES;
use function assert;
use function chdir;
use function class_exists;
use function dirname;
use function error_reporting;
use function file_get_contents;
use function getcwd;
use function gettype;
use function htmlspecialchars;
use function is_string;
use function libxml_get_errors;
use function libxml_use_internal_errors;
use function mb_convert_encoding;
use function ord;
use function preg_replace;
use function settype;
use function sprintf;
use function strlen;
use DOMCharacterData;
use DOMDocument;
use DOMElement;
use DOMNode;
use DOMText;
use PHPUnit\Framework\Exception;
use ReflectionClass;
use ReflectionException;




final class Xml
{
public static function import(DOMElement $element): DOMElement
{
return (new DOMDocument)->importNode($element, true);
}



















public static function load($actual, bool $isHtml = false, string $filename = '', bool $xinclude = false, bool $strict = false): DOMDocument
{
if ($actual instanceof DOMDocument) {
return $actual;
}

if (!is_string($actual)) {
throw new Exception('Could not load XML from ' . gettype($actual));
}

if ($actual === '') {
throw new Exception('Could not load XML from empty string');
}


 if ($xinclude) {
$cwd = getcwd();
@chdir(dirname($filename));
}

$document = new DOMDocument;
$document->preserveWhiteSpace = false;

$internal = libxml_use_internal_errors(true);
$message = '';
$reporting = error_reporting(0);

if ($filename !== '') {

 $document->documentURI = $filename;
}

if ($isHtml) {
$loaded = $document->loadHTML($actual);
} else {
$loaded = $document->loadXML($actual);
}

if (!$isHtml && $xinclude) {
$document->xinclude();
}

foreach (libxml_get_errors() as $error) {
$message .= "\n" . $error->message;
}

libxml_use_internal_errors($internal);
error_reporting($reporting);

if (isset($cwd)) {
@chdir($cwd);
}

if ($loaded === false || ($strict && $message !== '')) {
if ($filename !== '') {
throw new Exception(
sprintf(
'Could not load "%s".%s',
$filename,
$message !== '' ? "\n" . $message : ''
)
);
}

if ($message === '') {
$message = 'Could not load XML for unknown reason';
}

throw new Exception($message);
}

return $document;
}






public static function loadFile(string $filename, bool $isHtml = false, bool $xinclude = false, bool $strict = false): DOMDocument
{
$reporting = error_reporting(0);
$contents = file_get_contents($filename);

error_reporting($reporting);

if ($contents === false) {
throw new Exception(
sprintf(
'Could not read "%s".',
$filename
)
);
}

return self::load($contents, $isHtml, $filename, $xinclude, $strict);
}

public static function removeCharacterDataNodes(DOMNode $node): void
{
if ($node->hasChildNodes()) {
for ($i = $node->childNodes->length - 1; $i >= 0; $i--) {
if (($child = $node->childNodes->item($i)) instanceof DOMCharacterData) {
$node->removeChild($child);
}
}
}
}









public static function prepareString(string $string): string
{
return preg_replace(
'/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]/',
'',
htmlspecialchars(
self::convertToUtf8($string),
ENT_QUOTES
)
);
}




public static function xmlToVariable(DOMElement $element)
{
$variable = null;

switch ($element->tagName) {
case 'array':
$variable = [];

foreach ($element->childNodes as $entry) {
if (!$entry instanceof DOMElement || $entry->tagName !== 'element') {
continue;
}
$item = $entry->childNodes->item(0);

if ($item instanceof DOMText) {
$item = $entry->childNodes->item(1);
}

$value = self::xmlToVariable($item);

if ($entry->hasAttribute('key')) {
$variable[(string) $entry->getAttribute('key')] = $value;
} else {
$variable[] = $value;
}
}

break;

case 'object':
$className = $element->getAttribute('class');

if ($element->hasChildNodes()) {
$arguments = $element->childNodes->item(0)->childNodes;
$constructorArgs = [];

foreach ($arguments as $argument) {
if ($argument instanceof DOMElement) {
$constructorArgs[] = self::xmlToVariable($argument);
}
}

try {
assert(class_exists($className));

$variable = (new ReflectionClass($className))->newInstanceArgs($constructorArgs);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}

 } else {
$variable = new $className;
}

break;

case 'boolean':
$variable = $element->textContent === 'true';

break;

case 'integer':
case 'double':
case 'string':
$variable = $element->textContent;

settype($variable, $element->tagName);

break;
}

return $variable;
}

private static function convertToUtf8(string $string): string
{
if (!self::isUtf8($string)) {
$string = mb_convert_encoding($string, 'UTF-8');
}

return $string;
}

private static function isUtf8(string $string): bool
{
$length = strlen($string);

for ($i = 0; $i < $length; $i++) {
if (ord($string[$i]) < 0x80) {
$n = 0;
} elseif ((ord($string[$i]) & 0xE0) === 0xC0) {
$n = 1;
} elseif ((ord($string[$i]) & 0xF0) === 0xE0) {
$n = 2;
} elseif ((ord($string[$i]) & 0xF0) === 0xF0) {
$n = 3;
} else {
return false;
}

for ($j = 0; $j < $n; $j++) {
if ((++$i === $length) || ((ord($string[$i]) & 0xC0) !== 0x80)) {
return false;
}
}
}

return true;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use const DIRECTORY_SEPARATOR;
use function array_keys;
use function array_map;
use function array_values;
use function count;
use function explode;
use function implode;
use function min;
use function preg_replace;
use function preg_replace_callback;
use function sprintf;
use function strtr;
use function trim;




final class Color
{



private const WHITESPACE_MAP = [
' ' => '·',
"\t" => '⇥',
];




private const WHITESPACE_EOL_MAP = [
' ' => '·',
"\t" => '⇥',
"\n" => '↵',
"\r" => '⟵',
];




private static $ansiCodes = [
'reset' => '0',
'bold' => '1',
'dim' => '2',
'dim-reset' => '22',
'underlined' => '4',
'fg-default' => '39',
'fg-black' => '30',
'fg-red' => '31',
'fg-green' => '32',
'fg-yellow' => '33',
'fg-blue' => '34',
'fg-magenta' => '35',
'fg-cyan' => '36',
'fg-white' => '37',
'bg-default' => '49',
'bg-black' => '40',
'bg-red' => '41',
'bg-green' => '42',
'bg-yellow' => '43',
'bg-blue' => '44',
'bg-magenta' => '45',
'bg-cyan' => '46',
'bg-white' => '47',
];

public static function colorize(string $color, string $buffer): string
{
if (trim($buffer) === '') {
return $buffer;
}

$codes = array_map('\trim', explode(',', $color));
$styles = [];

foreach ($codes as $code) {
if (isset(self::$ansiCodes[$code])) {
$styles[] = self::$ansiCodes[$code] ?? '';
}
}

if (empty($styles)) {
return $buffer;
}

return self::optimizeColor(sprintf("\x1b[%sm", implode(';', $styles)) . $buffer . "\x1b[0m");
}

public static function colorizePath(string $path, ?string $prevPath = null, bool $colorizeFilename = false): string
{
if ($prevPath === null) {
$prevPath = '';
}

$path = explode(DIRECTORY_SEPARATOR, $path);
$prevPath = explode(DIRECTORY_SEPARATOR, $prevPath);

for ($i = 0; $i < min(count($path), count($prevPath)); $i++) {
if ($path[$i] == $prevPath[$i]) {
$path[$i] = self::dim($path[$i]);
}
}

if ($colorizeFilename) {
$last = count($path) - 1;
$path[$last] = preg_replace_callback(
'/([\-_\.]+|phpt$)/',
static function ($matches)
{
return self::dim($matches[0]);
},
$path[$last]
);
}

return self::optimizeColor(implode(self::dim(DIRECTORY_SEPARATOR), $path));
}

public static function dim(string $buffer): string
{
if (trim($buffer) === '') {
return $buffer;
}

return "\e[2m{$buffer}\e[22m";
}

public static function visualizeWhitespace(string $buffer, bool $visualizeEOL = false): string
{
$replaceMap = $visualizeEOL ? self::WHITESPACE_EOL_MAP : self::WHITESPACE_MAP;

return preg_replace_callback('/\s+/', static function ($matches) use ($replaceMap)
{
return self::dim(strtr($matches[0], $replaceMap));
}, $buffer);
}

private static function optimizeColor(string $buffer): string
{
$patterns = [
"/\e\\[22m\e\\[2m/" => '',
"/\e\\[([^m]*)m\e\\[([1-9][0-9;]*)m/" => "\e[$1;$2m",
"/(\e\\[[^m]*m)+(\e\\[0m)/" => '$2',
];

return preg_replace(array_keys($patterns), array_values($patterns), $buffer);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use function preg_match;




final class RegularExpression
{



public static function safeMatch(string $pattern, string $subject)
{
return ErrorHandler::invokeIgnoringWarnings(
static function () use ($pattern, $subject)
{
return preg_match($pattern, $subject);
}
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util\Annotation;

use const JSON_ERROR_NONE;
use const PREG_OFFSET_CAPTURE;
use function array_filter;
use function array_key_exists;
use function array_map;
use function array_merge;
use function array_pop;
use function array_slice;
use function array_values;
use function constant;
use function count;
use function defined;
use function explode;
use function file;
use function implode;
use function is_array;
use function is_int;
use function is_numeric;
use function is_string;
use function json_decode;
use function json_last_error;
use function json_last_error_msg;
use function preg_match;
use function preg_match_all;
use function preg_replace;
use function preg_split;
use function realpath;
use function rtrim;
use function sprintf;
use function str_replace;
use function strlen;
use function strpos;
use function strtolower;
use function substr;
use function substr_count;
use function trim;
use PharIo\Version\VersionConstraintParser;
use PHPUnit\Framework\InvalidDataProviderException;
use PHPUnit\Framework\SkippedTestError;
use PHPUnit\Framework\Warning;
use PHPUnit\Util\Exception;
use PHPUnit\Util\InvalidDataSetException;
use ReflectionClass;
use ReflectionException;
use ReflectionFunctionAbstract;
use ReflectionMethod;
use Reflector;
use Traversable;








final class DocBlock
{



public const REGEX_DATA_PROVIDER = '/@dataProvider\s+([a-zA-Z0-9._:-\\\\x7f-\xff]+)/';

private const REGEX_REQUIRES_VERSION = '/@requires\s+(?P<name>PHP(?:Unit)?)\s+(?P<operator>[<>=!]{0,2})\s*(?P<version>[\d\.-]+(dev|(RC|alpha|beta)[\d\.])?)[ \t]*\r?$/m';

private const REGEX_REQUIRES_VERSION_CONSTRAINT = '/@requires\s+(?P<name>PHP(?:Unit)?)\s+(?P<constraint>[\d\t \-.|~^]+)[ \t]*\r?$/m';

private const REGEX_REQUIRES_OS = '/@requires\s+(?P<name>OS(?:FAMILY)?)\s+(?P<value>.+?)[ \t]*\r?$/m';

private const REGEX_REQUIRES_SETTING = '/@requires\s+(?P<name>setting)\s+(?P<setting>([^ ]+?))\s*(?P<value>[\w\.-]+[\w\.]?)?[ \t]*\r?$/m';

private const REGEX_REQUIRES = '/@requires\s+(?P<name>function|extension)\s+(?P<value>([^\s<>=!]+))\s*(?P<operator>[<>=!]{0,2})\s*(?P<version>[\d\.-]+[\d\.]?)?[ \t]*\r?$/m';

private const REGEX_TEST_WITH = '/@testWith\s+/';

private const REGEX_EXPECTED_EXCEPTION = '(@expectedException\s+([:.\w\\\\x7f-\xff]+)(?:[\t ]+(\S*))?(?:[\t ]+(\S*))?\s*$)m';


private $docComment;


private $isMethod;


private $symbolAnnotations;













private $parsedRequirements;


private $startLine;


private $endLine;


private $fileName;


private $name;






private $className;

public static function ofClass(ReflectionClass $class): self
{
$className = $class->getName();

return new self(
(string) $class->getDocComment(),
false,
self::extractAnnotationsFromReflector($class),
$class->getStartLine(),
$class->getEndLine(),
$class->getFileName(),
$className,
$className
);
}




public static function ofMethod(ReflectionMethod $method, string $classNameInHierarchy): self
{
return new self(
(string) $method->getDocComment(),
true,
self::extractAnnotationsFromReflector($method),
$method->getStartLine(),
$method->getEndLine(),
$method->getFileName(),
$method->getName(),
$classNameInHierarchy
);
}








private function __construct(string $docComment, bool $isMethod, array $symbolAnnotations, int $startLine, int $endLine, string $fileName, string $name, string $className)
{
$this->docComment = $docComment;
$this->isMethod = $isMethod;
$this->symbolAnnotations = $symbolAnnotations;
$this->startLine = $startLine;
$this->endLine = $endLine;
$this->fileName = $fileName;
$this->name = $name;
$this->className = $className;
}













public function requirements(): array
{
if ($this->parsedRequirements !== null) {
return $this->parsedRequirements;
}

$offset = $this->startLine;
$requires = [];
$recordedSettings = [];
$extensionVersions = [];
$recordedOffsets = [
'__FILE' => realpath($this->fileName),
];


 $lines = preg_replace(['#^/\*{2}#', '#\*/$#'], '', preg_split('/\r\n|\r|\n/', $this->docComment));
$offset -= count($lines);

foreach ($lines as $line) {
if (preg_match(self::REGEX_REQUIRES_OS, $line, $matches)) {
$requires[$matches['name']] = $matches['value'];
$recordedOffsets[$matches['name']] = $offset;
}

if (preg_match(self::REGEX_REQUIRES_VERSION, $line, $matches)) {
$requires[$matches['name']] = [
'version' => $matches['version'],
'operator' => $matches['operator'],
];
$recordedOffsets[$matches['name']] = $offset;
}

if (preg_match(self::REGEX_REQUIRES_VERSION_CONSTRAINT, $line, $matches)) {
if (!empty($requires[$matches['name']])) {
$offset++;

continue;
}

try {
$versionConstraintParser = new VersionConstraintParser;

$requires[$matches['name'] . '_constraint'] = [
'constraint' => $versionConstraintParser->parse(trim($matches['constraint'])),
];
$recordedOffsets[$matches['name'] . '_constraint'] = $offset;
} catch (\PharIo\Version\Exception $e) {

throw new Warning($e->getMessage(), $e->getCode(), $e);
}
}

if (preg_match(self::REGEX_REQUIRES_SETTING, $line, $matches)) {
$recordedSettings[$matches['setting']] = $matches['value'];
$recordedOffsets['__SETTING_' . $matches['setting']] = $offset;
}

if (preg_match(self::REGEX_REQUIRES, $line, $matches)) {
$name = $matches['name'] . 's';

if (!isset($requires[$name])) {
$requires[$name] = [];
}

$requires[$name][] = $matches['value'];
$recordedOffsets[$matches['name'] . '_' . $matches['value']] = $offset;

if ($name === 'extensions' && !empty($matches['version'])) {
$extensionVersions[$matches['value']] = [
'version' => $matches['version'],
'operator' => $matches['operator'],
];
}
}

$offset++;
}

return $this->parsedRequirements = array_merge(
$requires,
['__OFFSET' => $recordedOffsets],
array_filter([
'setting' => $recordedSettings,
'extension_versions' => $extensionVersions,
])
);
}











public function expectedException()
{
$docComment = (string) substr($this->docComment, 3, -2);

if (1 !== preg_match(self::REGEX_EXPECTED_EXCEPTION, $docComment, $matches)) {
return false;
}


$class = $matches[1];
$annotations = $this->symbolAnnotations();
$code = null;
$message = '';
$messageRegExp = '';

if (isset($matches[2])) {
$message = trim($matches[2]);
} elseif (isset($annotations['expectedExceptionMessage'])) {
$message = $this->parseAnnotationContent($annotations['expectedExceptionMessage'][0]);
}

if (isset($annotations['expectedExceptionMessageRegExp'])) {
$messageRegExp = $this->parseAnnotationContent($annotations['expectedExceptionMessageRegExp'][0]);
}

if (isset($matches[3])) {
$code = $matches[3];
} elseif (isset($annotations['expectedExceptionCode'])) {
$code = $this->parseAnnotationContent($annotations['expectedExceptionCode'][0]);
}

if (is_numeric($code)) {
$code = (int) $code;
} elseif (is_string($code) && defined($code)) {
$code = (int) constant($code);
}

return [
'class' => $class,
'code' => $code,
'message' => $message,
'message_regex' => $messageRegExp,
];
}






public function getProvidedData(): ?array
{

$data = $this->getDataFromDataProviderAnnotation($this->docComment) ?? $this->getDataFromTestWithAnnotation($this->docComment);

if ($data === null) {
return null;
}

if ($data === []) {
throw new SkippedTestError;
}

foreach ($data as $key => $value) {
if (!is_array($value)) {
throw new InvalidDataSetException(
sprintf(
'Data set %s is invalid.',
is_int($key) ? '#' . $key : '"' . $key . '"'
)
);
}
}

return $data;
}




public function getInlineAnnotations(): array
{
$code = file($this->fileName);
$lineNumber = $this->startLine;
$startLine = $this->startLine - 1;
$endLine = $this->endLine - 1;
$codeLines = array_slice($code, $startLine, $endLine - $startLine + 1);
$annotations = [];

foreach ($codeLines as $line) {
if (preg_match('#/\*\*?\s*@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?[ \t]*\r?\*/$#m', $line, $matches)) {
$annotations[strtolower($matches['name'])] = [
'line' => $lineNumber,
'value' => $matches['value'],
];
}

$lineNumber++;
}

return $annotations;
}

public function symbolAnnotations(): array
{
return $this->symbolAnnotations;
}

public function isHookToBeExecutedBeforeClass(): bool
{
return $this->isMethod &&
false !== strpos($this->docComment, '@beforeClass');
}

public function isHookToBeExecutedAfterClass(): bool
{
return $this->isMethod &&
false !== strpos($this->docComment, '@afterClass');
}

public function isToBeExecutedBeforeTest(): bool
{
return 1 === preg_match('/@before\b/', $this->docComment);
}

public function isToBeExecutedAfterTest(): bool
{
return 1 === preg_match('/@after\b/', $this->docComment);
}








private function parseAnnotationContent(string $message): string
{
if (defined($message) &&
(strpos($message, '::') !== false && substr_count($message, '::') + 1 === 2)) {
return constant($message);
}

return $message;
}

private function getDataFromDataProviderAnnotation(string $docComment): ?array
{
$methodName = null;
$className = $this->className;

if ($this->isMethod) {
$methodName = $this->name;
}

if (!preg_match_all(self::REGEX_DATA_PROVIDER, $docComment, $matches)) {
return null;
}

$result = [];

foreach ($matches[1] as $match) {
$dataProviderMethodNameNamespace = explode('\\', $match);
$leaf = explode('::', array_pop($dataProviderMethodNameNamespace));
$dataProviderMethodName = array_pop($leaf);

if (empty($dataProviderMethodNameNamespace)) {
$dataProviderMethodNameNamespace = '';
} else {
$dataProviderMethodNameNamespace = implode('\\', $dataProviderMethodNameNamespace) . '\\';
}

if (empty($leaf)) {
$dataProviderClassName = $className;
} else {

$dataProviderClassName = $dataProviderMethodNameNamespace . array_pop($leaf);
}

try {
$dataProviderClass = new ReflectionClass($dataProviderClassName);

$dataProviderMethod = $dataProviderClass->getMethod(
$dataProviderMethodName
);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);

 }

if ($dataProviderMethod->isStatic()) {
$object = null;
} else {
$object = $dataProviderClass->newInstance();
}

if ($dataProviderMethod->getNumberOfParameters() === 0) {
$data = $dataProviderMethod->invoke($object);
} else {
$data = $dataProviderMethod->invoke($object, $methodName);
}

if ($data instanceof Traversable) {
$origData = $data;
$data = [];

foreach ($origData as $key => $value) {
if (is_int($key)) {
$data[] = $value;
} elseif (array_key_exists($key, $data)) {
throw new InvalidDataProviderException(
sprintf(
'The key "%s" has already been defined in the data provider "%s".',
$key,
$match
)
);
} else {
$data[$key] = $value;
}
}
}

if (is_array($data)) {
$result = array_merge($result, $data);
}
}

return $result;
}




private function getDataFromTestWithAnnotation(string $docComment): ?array
{
$docComment = $this->cleanUpMultiLineAnnotation($docComment);

if (!preg_match(self::REGEX_TEST_WITH, $docComment, $matches, PREG_OFFSET_CAPTURE)) {
return null;
}

$offset = strlen($matches[0][0]) + $matches[0][1];
$annotationContent = substr($docComment, $offset);
$data = [];

foreach (explode("\n", $annotationContent) as $candidateRow) {
$candidateRow = trim($candidateRow);

if ($candidateRow[0] !== '[') {
break;
}

$dataSet = json_decode($candidateRow, true);

if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception(
'The data set for the @testWith annotation cannot be parsed: ' . json_last_error_msg()
);
}

$data[] = $dataSet;
}

if (!$data) {
throw new Exception('The data set for the @testWith annotation cannot be parsed.');
}

return $data;
}

private function cleanUpMultiLineAnnotation(string $docComment): string
{

 $docComment = str_replace("\r\n", "\n", $docComment);
$docComment = preg_replace('/' . '\n' . '\s*' . '\*' . '\s?' . '/', "\n", $docComment);
$docComment = (string) substr($docComment, 0, -1);

return rtrim($docComment, "\n");
}


private static function parseDocBlock(string $docBlock): array
{

 $docBlock = (string) substr($docBlock, 3, -2);
$annotations = [];

if (preg_match_all('/@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?[ \t]*\r?$/m', $docBlock, $matches)) {
$numMatches = count($matches[0]);

for ($i = 0; $i < $numMatches; $i++) {
$annotations[$matches['name'][$i]][] = (string) $matches['value'][$i];
}
}

return $annotations;
}


private static function extractAnnotationsFromReflector(Reflector $reflector): array
{
$annotations = [];

if ($reflector instanceof ReflectionClass) {
$annotations = array_merge(
$annotations,
...array_map(
static function (ReflectionClass $trait): array
{
return self::parseDocBlock((string) $trait->getDocComment());
},
array_values($reflector->getTraits())
)
);
}

return array_merge(
$annotations,
self::parseDocBlock((string) $reflector->getDocComment())
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util\Annotation;

use function array_key_exists;
use PHPUnit\Util\Exception;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;







final class Registry
{

private static $instance;


private $classDocBlocks = [];


private $methodDocBlocks = [];

public static function getInstance(): self
{
return self::$instance ?? self::$instance = new self;
}

private function __construct()
{
}





public function forClassName(string $class): DocBlock
{
if (array_key_exists($class, $this->classDocBlocks)) {
return $this->classDocBlocks[$class];
}

try {
$reflection = new ReflectionClass($class);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


return $this->classDocBlocks[$class] = DocBlock::ofClass($reflection);
}





public function forMethod(string $classInHierarchy, string $method): DocBlock
{
if (isset($this->methodDocBlocks[$classInHierarchy][$method])) {
return $this->methodDocBlocks[$classInHierarchy][$method];
}

try {
$reflection = new ReflectionMethod($classInHierarchy, $method);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


return $this->methodDocBlocks[$classInHierarchy][$method] = DocBlock::ofMethod($reflection, $classInHierarchy);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use Throwable;




final class Type
{
public static function isType(string $type): bool
{
switch ($type) {
case 'numeric':
case 'integer':
case 'int':
case 'iterable':
case 'float':
case 'string':
case 'boolean':
case 'bool':
case 'null':
case 'array':
case 'object':
case 'resource':
case 'scalar':
return true;

default:
return false;
}
}

public static function isCloneable(object $object): bool
{
try {
$clone = clone $object;
} catch (Throwable $t) {
return false;
}

return $clone instanceof $object;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use const PHP_OS;
use const PHP_VERSION;
use function addcslashes;
use function array_flip;
use function array_key_exists;
use function array_keys;
use function array_merge;
use function array_unique;
use function array_unshift;
use function class_exists;
use function class_implements;
use function class_parents;
use function count;
use function explode;
use function extension_loaded;
use function function_exists;
use function get_class;
use function ini_get;
use function interface_exists;
use function is_array;
use function is_int;
use function method_exists;
use function phpversion;
use function preg_match;
use function preg_replace;
use function range;
use function sprintf;
use function str_replace;
use function strncmp;
use function strpos;
use function trait_exists;
use function version_compare;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\CodeCoverageException;
use PHPUnit\Framework\InvalidCoversTargetException;
use PHPUnit\Framework\SelfDescribing;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Warning;
use PHPUnit\Runner\Version;
use PHPUnit\Util\Annotation\Registry;
use ReflectionClass;
use ReflectionException;
use ReflectionFunction;
use ReflectionMethod;
use SebastianBergmann\Environment\OperatingSystem;




final class Test
{



public const UNKNOWN = -1;




public const SMALL = 0;




public const MEDIUM = 1;




public const LARGE = 2;




private static $hookMethods = [];




public static function describe(\PHPUnit\Framework\Test $test): array
{
if ($test instanceof TestCase) {
return [get_class($test), $test->getName()];
}

if ($test instanceof SelfDescribing) {
return ['', $test->toString()];
}

return ['', get_class($test)];
}

public static function describeAsString(\PHPUnit\Framework\Test $test): string
{
if ($test instanceof SelfDescribing) {
return $test->toString();
}

return get_class($test);
}







public static function getLinesToBeCovered(string $className, string $methodName)
{
$annotations = self::parseTestMethodAnnotations(
$className,
$methodName
);

if (!self::shouldCoversAnnotationBeUsed($annotations)) {
return false;
}

return self::getLinesToBeCoveredOrUsed($className, $methodName, 'covers');
}







public static function getLinesToBeUsed(string $className, string $methodName): array
{
return self::getLinesToBeCoveredOrUsed($className, $methodName, 'uses');
}

public static function requiresCodeCoverageDataCollection(TestCase $test): bool
{
$annotations = $test->getAnnotations();


 
 if (isset($annotations['method']['coversNothing'])) {
return false;
}


 
 if (isset($annotations['method']['covers'])) {
return true;
}


 
 if (isset($annotations['class']['coversNothing'])) {
return false;
}


 
 return true;
}





public static function getRequirements(string $className, string $methodName): array
{
return self::mergeArraysRecursively(
Registry::getInstance()->forClassName($className)->requirements(),
Registry::getInstance()->forMethod($className, $methodName)->requirements()
);
}








public static function getMissingRequirements(string $className, string $methodName): array
{
$required = self::getRequirements($className, $methodName);
$missing = [];
$hint = null;

if (!empty($required['PHP'])) {
$operator = new VersionComparisonOperator(empty($required['PHP']['operator']) ? '>=' : $required['PHP']['operator']);

if (!version_compare(PHP_VERSION, $required['PHP']['version'], $operator->asString())) {
$missing[] = sprintf('PHP %s %s is required.', $operator->asString(), $required['PHP']['version']);
$hint = 'PHP';
}
} elseif (!empty($required['PHP_constraint'])) {
$version = new \PharIo\Version\Version(self::sanitizeVersionNumber(PHP_VERSION));

if (!$required['PHP_constraint']['constraint']->complies($version)) {
$missing[] = sprintf(
'PHP version does not match the required constraint %s.',
$required['PHP_constraint']['constraint']->asString()
);

$hint = 'PHP_constraint';
}
}

if (!empty($required['PHPUnit'])) {
$phpunitVersion = Version::id();

$operator = new VersionComparisonOperator(empty($required['PHPUnit']['operator']) ? '>=' : $required['PHPUnit']['operator']);

if (!version_compare($phpunitVersion, $required['PHPUnit']['version'], $operator->asString())) {
$missing[] = sprintf('PHPUnit %s %s is required.', $operator->asString(), $required['PHPUnit']['version']);
$hint = $hint ?? 'PHPUnit';
}
} elseif (!empty($required['PHPUnit_constraint'])) {
$phpunitVersion = new \PharIo\Version\Version(self::sanitizeVersionNumber(Version::id()));

if (!$required['PHPUnit_constraint']['constraint']->complies($phpunitVersion)) {
$missing[] = sprintf(
'PHPUnit version does not match the required constraint %s.',
$required['PHPUnit_constraint']['constraint']->asString()
);

$hint = $hint ?? 'PHPUnit_constraint';
}
}

if (!empty($required['OSFAMILY']) && $required['OSFAMILY'] !== (new OperatingSystem)->getFamily()) {
$missing[] = sprintf('Operating system %s is required.', $required['OSFAMILY']);
$hint = $hint ?? 'OSFAMILY';
}

if (!empty($required['OS'])) {
$requiredOsPattern = sprintf('/%s/i', addcslashes($required['OS'], '/'));

if (!preg_match($requiredOsPattern, PHP_OS)) {
$missing[] = sprintf('Operating system matching %s is required.', $requiredOsPattern);
$hint = $hint ?? 'OS';
}
}

if (!empty($required['functions'])) {
foreach ($required['functions'] as $function) {
$pieces = explode('::', $function);

if (count($pieces) === 2 && class_exists($pieces[0]) && method_exists($pieces[0], $pieces[1])) {
continue;
}

if (function_exists($function)) {
continue;
}

$missing[] = sprintf('Function %s is required.', $function);
$hint = $hint ?? 'function_' . $function;
}
}

if (!empty($required['setting'])) {
foreach ($required['setting'] as $setting => $value) {
if (ini_get($setting) !== $value) {
$missing[] = sprintf('Setting "%s" must be "%s".', $setting, $value);
$hint = $hint ?? '__SETTING_' . $setting;
}
}
}

if (!empty($required['extensions'])) {
foreach ($required['extensions'] as $extension) {
if (isset($required['extension_versions'][$extension])) {
continue;
}

if (!extension_loaded($extension)) {
$missing[] = sprintf('Extension %s is required.', $extension);
$hint = $hint ?? 'extension_' . $extension;
}
}
}

if (!empty($required['extension_versions'])) {
foreach ($required['extension_versions'] as $extension => $req) {
$actualVersion = phpversion($extension);

$operator = new VersionComparisonOperator(empty($req['operator']) ? '>=' : $req['operator']);

if ($actualVersion === false || !version_compare($actualVersion, $req['version'], $operator->asString())) {
$missing[] = sprintf('Extension %s %s %s is required.', $extension, $operator->asString(), $req['version']);
$hint = $hint ?? 'extension_' . $extension;
}
}
}

if ($hint && isset($required['__OFFSET'])) {
array_unshift($missing, '__OFFSET_FILE=' . $required['__OFFSET']['__FILE']);
array_unshift($missing, '__OFFSET_LINE=' . ($required['__OFFSET'][$hint] ?? 1));
}

return $missing;
}










public static function getExpectedException(string $className, string $methodName)
{
return Registry::getInstance()->forMethod($className, $methodName)->expectedException();
}







public static function getProvidedData(string $className, string $methodName): ?array
{
return Registry::getInstance()->forMethod($className, $methodName)->getProvidedData();
}




public static function parseTestMethodAnnotations(string $className, ?string $methodName = ''): array
{
$registry = Registry::getInstance();

if ($methodName !== null) {
try {
return [
'method' => $registry->forMethod($className, $methodName)->symbolAnnotations(),
'class' => $registry->forClassName($className)->symbolAnnotations(),
];
} catch (Exception $methodNotFound) {

 }
}

return [
'method' => null,
'class' => $registry->forClassName($className)->symbolAnnotations(),
];
}




public static function getInlineAnnotations(string $className, string $methodName): array
{
return Registry::getInstance()->forMethod($className, $methodName)->getInlineAnnotations();
}


public static function getBackupSettings(string $className, string $methodName): array
{
return [
'backupGlobals' => self::getBooleanAnnotationSetting(
$className,
$methodName,
'backupGlobals'
),
'backupStaticAttributes' => self::getBooleanAnnotationSetting(
$className,
$methodName,
'backupStaticAttributes'
),
];
}


public static function getDependencies(string $className, string $methodName): array
{
$annotations = self::parseTestMethodAnnotations(
$className,
$methodName
);

$dependencies = $annotations['class']['depends'] ?? [];

if (isset($annotations['method']['depends'])) {
$dependencies = array_merge(
$dependencies,
$annotations['method']['depends']
);
}

return array_unique($dependencies);
}


public static function getGroups(string $className, ?string $methodName = ''): array
{
$annotations = self::parseTestMethodAnnotations(
$className,
$methodName
);

$groups = [];

if (isset($annotations['method']['author'])) {
$groups[] = $annotations['method']['author'];
} elseif (isset($annotations['class']['author'])) {
$groups[] = $annotations['class']['author'];
}

if (isset($annotations['class']['group'])) {
$groups[] = $annotations['class']['group'];
}

if (isset($annotations['method']['group'])) {
$groups[] = $annotations['method']['group'];
}

if (isset($annotations['class']['ticket'])) {
$groups[] = $annotations['class']['ticket'];
}

if (isset($annotations['method']['ticket'])) {
$groups[] = $annotations['method']['ticket'];
}

foreach (['method', 'class'] as $element) {
foreach (['small', 'medium', 'large'] as $size) {
if (isset($annotations[$element][$size])) {
$groups[] = [$size];

break 2;
}
}
}

return array_unique(array_merge([], ...$groups));
}


public static function getSize(string $className, ?string $methodName): int
{
$groups = array_flip(self::getGroups($className, $methodName));

if (isset($groups['large'])) {
return self::LARGE;
}

if (isset($groups['medium'])) {
return self::MEDIUM;
}

if (isset($groups['small'])) {
return self::SMALL;
}

return self::UNKNOWN;
}


public static function getProcessIsolationSettings(string $className, string $methodName): bool
{
$annotations = self::parseTestMethodAnnotations(
$className,
$methodName
);

return isset($annotations['class']['runTestsInSeparateProcesses']) || isset($annotations['method']['runInSeparateProcess']);
}


public static function getClassProcessIsolationSettings(string $className, string $methodName): bool
{
$annotations = self::parseTestMethodAnnotations(
$className,
$methodName
);

return isset($annotations['class']['runClassInSeparateProcess']);
}


public static function getPreserveGlobalStateSettings(string $className, string $methodName): ?bool
{
return self::getBooleanAnnotationSetting(
$className,
$methodName,
'preserveGlobalState'
);
}


public static function getHookMethods(string $className): array
{
if (!class_exists($className, false)) {
return self::emptyHookMethodsArray();
}

if (!isset(self::$hookMethods[$className])) {
self::$hookMethods[$className] = self::emptyHookMethodsArray();

try {
foreach ((new ReflectionClass($className))->getMethods() as $method) {
if ($method->getDeclaringClass()->getName() === Assert::class) {
continue;
}

if ($method->getDeclaringClass()->getName() === TestCase::class) {
continue;
}

$docBlock = Registry::getInstance()->forMethod($className, $method->getName());

if ($method->isStatic()) {
if ($docBlock->isHookToBeExecutedBeforeClass()) {
array_unshift(
self::$hookMethods[$className]['beforeClass'],
$method->getName()
);
}

if ($docBlock->isHookToBeExecutedAfterClass()) {
self::$hookMethods[$className]['afterClass'][] = $method->getName();
}
}

if ($docBlock->isToBeExecutedBeforeTest()) {
array_unshift(
self::$hookMethods[$className]['before'],
$method->getName()
);
}

if ($docBlock->isToBeExecutedAfterTest()) {
self::$hookMethods[$className]['after'][] = $method->getName();
}
}
} catch (ReflectionException $e) {
}
}

return self::$hookMethods[$className];
}

public static function isTestMethod(ReflectionMethod $method): bool
{
if (!$method->isPublic()) {
return false;
}

if (strpos($method->getName(), 'test') === 0) {
return true;
}

return array_key_exists(
'test',
Registry::getInstance()->forMethod(
$method->getDeclaringClass()->getName(),
$method->getName()
)
->symbolAnnotations()
);
}





private static function getLinesToBeCoveredOrUsed(string $className, string $methodName, string $mode): array
{
$annotations = self::parseTestMethodAnnotations(
$className,
$methodName
);

$classShortcut = null;

if (!empty($annotations['class'][$mode . 'DefaultClass'])) {
if (count($annotations['class'][$mode . 'DefaultClass']) > 1) {
throw new CodeCoverageException(
sprintf(
'More than one @%sClass annotation in class or interface "%s".',
$mode,
$className
)
);
}

$classShortcut = $annotations['class'][$mode . 'DefaultClass'][0];
}

$list = $annotations['class'][$mode] ?? [];

if (isset($annotations['method'][$mode])) {
$list = array_merge($list, $annotations['method'][$mode]);
}

$codeList = [];

foreach (array_unique($list) as $element) {
if ($classShortcut && strncmp($element, '::', 2) === 0) {
$element = $classShortcut . $element;
}

$element = preg_replace('/[\s()]+$/', '', $element);
$element = explode(' ', $element);
$element = $element[0];

if ($mode === 'covers' && interface_exists($element)) {
throw new InvalidCoversTargetException(
sprintf(
'Trying to @cover interface "%s".',
$element
)
);
}

$codeList[] = self::resolveElementToReflectionObjects($element);
}

return self::resolveReflectionObjectsToLines(array_merge([], ...$codeList));
}

private static function emptyHookMethodsArray(): array
{
return [
'beforeClass' => ['setUpBeforeClass'],
'before' => ['setUp'],
'after' => ['tearDown'],
'afterClass' => ['tearDownAfterClass'],
];
}


private static function getBooleanAnnotationSetting(string $className, ?string $methodName, string $settingName): ?bool
{
$annotations = self::parseTestMethodAnnotations(
$className,
$methodName
);

if (isset($annotations['method'][$settingName])) {
if ($annotations['method'][$settingName][0] === 'enabled') {
return true;
}

if ($annotations['method'][$settingName][0] === 'disabled') {
return false;
}
}

if (isset($annotations['class'][$settingName])) {
if ($annotations['class'][$settingName][0] === 'enabled') {
return true;
}

if ($annotations['class'][$settingName][0] === 'disabled') {
return false;
}
}

return null;
}




private static function resolveElementToReflectionObjects(string $element): array
{
$codeToCoverList = [];

if (function_exists($element) && strpos($element, '\\') !== false) {
try {
$codeToCoverList[] = new ReflectionFunction($element);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}

 } elseif (strpos($element, '::') !== false) {
[$className, $methodName] = explode('::', $element);

if (isset($methodName[0]) && $methodName[0] === '<') {
$classes = [$className];

foreach ($classes as $className) {
if (!class_exists($className) &&
!interface_exists($className) &&
!trait_exists($className)) {
throw new InvalidCoversTargetException(
sprintf(
'Trying to @cover or @use not existing class or ' .
'interface "%s".',
$className
)
);
}

try {
$methods = (new ReflectionClass($className))->getMethods();

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


$inverse = isset($methodName[1]) && $methodName[1] === '!';
$visibility = 'isPublic';

if (strpos($methodName, 'protected')) {
$visibility = 'isProtected';
} elseif (strpos($methodName, 'private')) {
$visibility = 'isPrivate';
}

foreach ($methods as $method) {
if ($inverse && !$method->{$visibility}()) {
$codeToCoverList[] = $method;
} elseif (!$inverse && $method->{$visibility}()) {
$codeToCoverList[] = $method;
}
}
}
} else {
$classes = [$className];

foreach ($classes as $className) {
if ($className === '' && function_exists($methodName)) {
try {
$codeToCoverList[] = new ReflectionFunction(
$methodName
);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}

 } else {
if (!((class_exists($className) || interface_exists($className) || trait_exists($className)) &&
method_exists($className, $methodName))) {
throw new InvalidCoversTargetException(
sprintf(
'Trying to @cover or @use not existing method "%s::%s".',
$className,
$methodName
)
);
}

try {
$codeToCoverList[] = new ReflectionMethod(
$className,
$methodName
);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}

 }
}
}
} else {
$extended = false;

if (strpos($element, '<extended>') !== false) {
$element = str_replace('<extended>', '', $element);
$extended = true;
}

$classes = [$element];

if ($extended) {
$classes = array_merge(
$classes,
class_implements($element),
class_parents($element)
);
}

foreach ($classes as $className) {
if (!class_exists($className) &&
!interface_exists($className) &&
!trait_exists($className)) {
throw new InvalidCoversTargetException(
sprintf(
'Trying to @cover or @use not existing class or ' .
'interface "%s".',
$className
)
);
}

try {
$codeToCoverList[] = new ReflectionClass($className);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}

 }
}

return $codeToCoverList;
}

private static function resolveReflectionObjectsToLines(array $reflectors): array
{
$result = [];

foreach ($reflectors as $reflector) {
if ($reflector instanceof ReflectionClass) {
foreach ($reflector->getTraits() as $trait) {
$reflectors[] = $trait;
}
}
}

foreach ($reflectors as $reflector) {
$filename = $reflector->getFileName();

if (!isset($result[$filename])) {
$result[$filename] = [];
}

$result[$filename] = array_merge(
$result[$filename],
range($reflector->getStartLine(), $reflector->getEndLine())
);
}

foreach ($result as $filename => $lineNumbers) {
$result[$filename] = array_keys(array_flip($lineNumbers));
}

return $result;
}





private static function sanitizeVersionNumber(string $version)
{
return preg_replace(
'/^(\d+\.\d+(?:.\d+)?).*$/',
'$1',
$version
);
}

private static function shouldCoversAnnotationBeUsed(array $annotations): bool
{
if (isset($annotations['method']['coversNothing'])) {
return false;
}

if (isset($annotations['method']['covers'])) {
return true;
}

if (isset($annotations['class']['coversNothing'])) {
return false;
}

return true;
}

















private static function mergeArraysRecursively(array $a, array $b): array
{
foreach ($b as $key => $value) {
if (array_key_exists($key, $a)) {
if (is_int($key)) {
$a[] = $value;
} elseif (is_array($value) && is_array($a[$key])) {
$a[$key] = self::mergeArraysRecursively($a[$key], $value);
} else {
$a[$key] = $value;
}
} else {
$a[$key] = $value;
}
}

return $a;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use function array_keys;
use function count;
use function defined;
use function get_defined_constants;
use function get_included_files;
use function in_array;
use function ini_get_all;
use function is_array;
use function is_file;
use function is_scalar;
use function preg_match;
use function serialize;
use function sprintf;
use function strpos;
use function var_export;
use Closure;




final class GlobalState
{



private const SUPER_GLOBAL_ARRAYS = [
'_ENV',
'_POST',
'_GET',
'_COOKIE',
'_SERVER',
'_FILES',
'_REQUEST',
];




public static function getIncludedFilesAsString(): string
{
return self::processIncludedFilesAsString(get_included_files());
}






public static function processIncludedFilesAsString(array $files): string
{
$blacklist = new Blacklist;
$prefix = false;
$result = '';

if (defined('__PHPUNIT_PHAR__')) {
$prefix = 'phar://' . __PHPUNIT_PHAR__ . '/';
}

for ($i = count($files) - 1; $i > 0; $i--) {
$file = $files[$i];

if (!empty($GLOBALS['__PHPUNIT_ISOLATION_BLACKLIST']) &&
in_array($file, $GLOBALS['__PHPUNIT_ISOLATION_BLACKLIST'], true)) {
continue;
}

if ($prefix !== false && strpos($file, $prefix) === 0) {
continue;
}


 if (preg_match('/^(vfs|phpvfs[a-z0-9]+):/', $file)) {
continue;
}

if (!$blacklist->isBlacklisted($file) && is_file($file)) {
$result = 'require_once \'' . $file . "';\n" . $result;
}
}

return $result;
}

public static function getIniSettingsAsString(): string
{
$result = '';

foreach (ini_get_all(null, false) as $key => $value) {
$result .= sprintf(
'@ini_set(%s, %s);' . "\n",
self::exportVariable($key),
self::exportVariable((string) $value)
);
}

return $result;
}

public static function getConstantsAsString(): string
{
$constants = get_defined_constants(true);
$result = '';

if (isset($constants['user'])) {
foreach ($constants['user'] as $name => $value) {
$result .= sprintf(
'if (!defined(\'%s\')) define(\'%s\', %s);' . "\n",
$name,
$name,
self::exportVariable($value)
);
}
}

return $result;
}

public static function getGlobalsAsString(): string
{
$result = '';

foreach (self::SUPER_GLOBAL_ARRAYS as $superGlobalArray) {
if (isset($GLOBALS[$superGlobalArray]) && is_array($GLOBALS[$superGlobalArray])) {
foreach (array_keys($GLOBALS[$superGlobalArray]) as $key) {
if ($GLOBALS[$superGlobalArray][$key] instanceof Closure) {
continue;
}

$result .= sprintf(
'$GLOBALS[\'%s\'][\'%s\'] = %s;' . "\n",
$superGlobalArray,
$key,
self::exportVariable($GLOBALS[$superGlobalArray][$key])
);
}
}
}

$blacklist = self::SUPER_GLOBAL_ARRAYS;
$blacklist[] = 'GLOBALS';

foreach (array_keys($GLOBALS) as $key) {
if (!$GLOBALS[$key] instanceof Closure && !in_array($key, $blacklist, true)) {
$result .= sprintf(
'$GLOBALS[\'%s\'] = %s;' . "\n",
$key,
self::exportVariable($GLOBALS[$key])
);
}
}

return $result;
}

private static function exportVariable($variable): string
{
if (is_scalar($variable) || $variable === null ||
(is_array($variable) && self::arrayOnlyContainsScalars($variable))) {
return var_export($variable, true);
}

return 'unserialize(' . var_export(serialize($variable), true) . ')';
}

private static function arrayOnlyContainsScalars(array $array): bool
{
$result = true;

foreach ($array as $element) {
if (is_array($element)) {
$result = self::arrayOnlyContainsScalars($element);
} elseif (!is_scalar($element) && $element !== null) {
$result = false;
}

if (!$result) {
break;
}
}

return $result;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use function get_class;
use function implode;
use function str_replace;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Runner\PhptTestCase;
use RecursiveIteratorIterator;
use XMLWriter;




final class XmlTestListRenderer
{



public function render(TestSuite $suite): string
{
$writer = new XMLWriter;

$writer->openMemory();
$writer->setIndent(true);
$writer->startDocument();
$writer->startElement('tests');

$currentTestCase = null;

foreach (new RecursiveIteratorIterator($suite->getIterator()) as $test) {
if ($test instanceof TestCase) {
if (get_class($test) !== $currentTestCase) {
if ($currentTestCase !== null) {
$writer->endElement();
}

$writer->startElement('testCaseClass');
$writer->writeAttribute('name', get_class($test));

$currentTestCase = get_class($test);
}

$writer->startElement('testCaseMethod');
$writer->writeAttribute('name', $test->getName(false));
$writer->writeAttribute('groups', implode(',', $test->getGroups()));

if (!empty($test->getDataSetAsString(false))) {
$writer->writeAttribute(
'dataSet',
str_replace(
' with data set ',
'',
$test->getDataSetAsString(false)
)
);
}

$writer->endElement();
} elseif ($test instanceof PhptTestCase) {
if ($currentTestCase !== null) {
$writer->endElement();

$currentTestCase = null;
}

$writer->startElement('phptFile');
$writer->writeAttribute('path', $test->getName());
$writer->endElement();
}
}

if ($currentTestCase !== null) {
$writer->endElement();
}

$writer->endElement();

return $writer->outputMemory();
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util;

use function in_array;
use function sprintf;





final class VersionComparisonOperator
{



private $operator;

public function __construct(string $operator)
{
$this->ensureOperatorIsValid($operator);

$this->operator = $operator;
}




public function asString(): string
{
return $this->operator;
}






private function ensureOperatorIsValid(string $operator): void
{
if (!in_array($operator, ['<', 'lt', '<=', 'le', '>', 'gt', '>=', 'ge', '==', '=', 'eq', '!=', '<>', 'ne'], true)) {
throw new Exception(
sprintf(
'"%s" is not a valid version_compare() operator',
$operator
)
);
}
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util\TestDox;

use const PHP_EOL;
use function array_map;
use function get_class;
use function implode;
use function preg_split;
use function trim;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestResult;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Framework\Warning;
use PHPUnit\Runner\BaseTestRunner;
use PHPUnit\Runner\PhptTestCase;
use PHPUnit\Runner\TestSuiteSorter;
use PHPUnit\TextUI\ResultPrinter;
use Throwable;




class TestDoxPrinter extends ResultPrinter
{



protected $prettifier;




protected $testIndex = 0;




protected $testFlushIndex = 0;




protected $testResults = [];




protected $testNameResultIndex = [];




protected $enableOutputBuffer = false;




protected $originalExecutionOrder = [];




protected $spinState = 0;




protected $showProgress = true;






public function __construct($out = null, bool $verbose = false, string $colors = self::COLOR_DEFAULT, bool $debug = false, $numberOfColumns = 80, bool $reverse = false)
{
parent::__construct($out, $verbose, $colors, $debug, $numberOfColumns, $reverse);

$this->prettifier = new NamePrettifier($this->colors);
}

public function setOriginalExecutionOrder(array $order): void
{
$this->originalExecutionOrder = $order;
$this->enableOutputBuffer = !empty($order);
}

public function setShowProgressAnimation(bool $showProgress): void
{
$this->showProgress = $showProgress;
}

public function printResult(TestResult $result): void
{
}




public function endTest(Test $test, float $time): void
{
if (!$test instanceof TestCase && !$test instanceof PhptTestCase && !$test instanceof TestSuite) {
return;
}

if ($this->testHasPassed()) {
$this->registerTestResult($test, null, BaseTestRunner::STATUS_PASSED, $time, false);
}

if ($test instanceof TestCase || $test instanceof PhptTestCase) {
$this->testIndex++;
}

parent::endTest($test, $time);
}




public function addError(Test $test, Throwable $t, float $time): void
{
$this->registerTestResult($test, $t, BaseTestRunner::STATUS_ERROR, $time, true);
}




public function addWarning(Test $test, Warning $e, float $time): void
{
$this->registerTestResult($test, $e, BaseTestRunner::STATUS_WARNING, $time, true);
}




public function addFailure(Test $test, AssertionFailedError $e, float $time): void
{
$this->registerTestResult($test, $e, BaseTestRunner::STATUS_FAILURE, $time, true);
}




public function addIncompleteTest(Test $test, Throwable $t, float $time): void
{
$this->registerTestResult($test, $t, BaseTestRunner::STATUS_INCOMPLETE, $time, false);
}




public function addRiskyTest(Test $test, Throwable $t, float $time): void
{
$this->registerTestResult($test, $t, BaseTestRunner::STATUS_RISKY, $time, false);
}




public function addSkippedTest(Test $test, Throwable $t, float $time): void
{
$this->registerTestResult($test, $t, BaseTestRunner::STATUS_SKIPPED, $time, false);
}

public function writeProgress(string $progress): void
{
$this->flushOutputBuffer();
}

public function flush(): void
{
$this->flushOutputBuffer(true);
}




protected function registerTestResult(Test $test, ?Throwable $t, int $status, float $time, bool $verbose): void
{
$testName = TestSuiteSorter::getTestSorterUID($test);

$result = [
'className' => $this->formatClassName($test),
'testName' => $testName,
'testMethod' => $this->formatTestName($test),
'message' => '',
'status' => $status,
'time' => $time,
'verbose' => $verbose,
];

if ($t !== null) {
$result['message'] = $this->formatTestResultMessage($t, $result);
}

$this->testResults[$this->testIndex] = $result;
$this->testNameResultIndex[$testName] = $this->testIndex;
}

protected function formatTestName(Test $test): string
{
return $test->getName();
}

protected function formatClassName(Test $test): string
{
return get_class($test);
}

protected function testHasPassed(): bool
{
if (!isset($this->testResults[$this->testIndex]['status'])) {
return true;
}

if ($this->testResults[$this->testIndex]['status'] === BaseTestRunner::STATUS_PASSED) {
return true;
}

return false;
}

protected function flushOutputBuffer(bool $forceFlush = false): void
{
if ($this->testFlushIndex === $this->testIndex) {
return;
}

if ($this->testFlushIndex > 0) {
if ($this->enableOutputBuffer) {
$prevResult = $this->getTestResultByName($this->originalExecutionOrder[$this->testFlushIndex - 1]);
} else {
$prevResult = $this->testResults[$this->testFlushIndex - 1];
}
} else {
$prevResult = $this->getEmptyTestResult();
}

if (!$this->enableOutputBuffer) {
$this->writeTestResult($prevResult, $this->testResults[$this->testFlushIndex++]);
} else {
do {
$flushed = false;

if (!$forceFlush && isset($this->originalExecutionOrder[$this->testFlushIndex])) {
$result = $this->getTestResultByName($this->originalExecutionOrder[$this->testFlushIndex]);
} else {

 
 $result = $this->testResults[$this->testFlushIndex];
}

if (!empty($result)) {
$this->hideSpinner();
$this->writeTestResult($prevResult, $result);
$this->testFlushIndex++;
$prevResult = $result;
$flushed = true;
} else {
$this->showSpinner();
}
} while ($flushed && $this->testFlushIndex < $this->testIndex);
}
}

protected function showSpinner(): void
{
if (!$this->showProgress) {
return;
}

if ($this->spinState) {
$this->undrawSpinner();
}

$this->spinState++;
$this->drawSpinner();
}

protected function hideSpinner(): void
{
if (!$this->showProgress) {
return;
}

if ($this->spinState) {
$this->undrawSpinner();
}

$this->spinState = 0;
}

protected function drawSpinner(): void
{

 }

protected function undrawSpinner(): void
{

 }

protected function writeTestResult(array $prevResult, array $result): void
{
}

protected function getEmptyTestResult(): array
{
return [
'className' => '',
'testName' => '',
'message' => '',
'failed' => '',
'verbose' => '',
];
}

protected function getTestResultByName(?string $testName): array
{
if (isset($this->testNameResultIndex[$testName])) {
return $this->testResults[$this->testNameResultIndex[$testName]];
}

return [];
}

protected function formatThrowable(Throwable $t, ?int $status = null): string
{
$message = trim(\PHPUnit\Framework\TestFailure::exceptionToString($t));

if ($message) {
$message .= PHP_EOL . PHP_EOL . $this->formatStacktrace($t);
} else {
$message = $this->formatStacktrace($t);
}

return $message;
}

protected function formatStacktrace(Throwable $t): string
{
return \PHPUnit\Util\Filter::getFilteredStacktrace($t);
}

protected function formatTestResultMessage(Throwable $t, array $result, string $prefix = '│'): string
{
$message = $this->formatThrowable($t, $result['status']);

if ($message === '') {
return '';
}

if (!($this->verbose || $result['verbose'])) {
return '';
}

return $this->prefixLines($prefix, $message);
}

protected function prefixLines(string $prefix, string $message): string
{
$message = trim($message);

return implode(
PHP_EOL,
array_map(
static function (string $text) use ($prefix)
{
return '   ' . $prefix . ($text ? ' ' . $text : '');
},
preg_split('/\r\n|\r|\n/', $message)
)
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util\TestDox;

use function array_filter;
use function get_class;
use function implode;
use DOMDocument;
use DOMElement;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\Exception;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Framework\Warning;
use PHPUnit\Util\Printer;
use ReflectionClass;
use ReflectionException;
use Throwable;




final class XmlResultPrinter extends Printer implements TestListener
{



private $document;




private $root;




private $prettifier;




private $exception;






public function __construct($out = null)
{
$this->document = new DOMDocument('1.0', 'UTF-8');
$this->document->formatOutput = true;

$this->root = $this->document->createElement('tests');
$this->document->appendChild($this->root);

$this->prettifier = new NamePrettifier;

parent::__construct($out);
}




public function flush(): void
{
$this->write($this->document->saveXML());

parent::flush();
}




public function addError(Test $test, Throwable $t, float $time): void
{
$this->exception = $t;
}




public function addWarning(Test $test, Warning $e, float $time): void
{
}




public function addFailure(Test $test, AssertionFailedError $e, float $time): void
{
$this->exception = $e;
}




public function addIncompleteTest(Test $test, Throwable $t, float $time): void
{
}




public function addRiskyTest(Test $test, Throwable $t, float $time): void
{
}




public function addSkippedTest(Test $test, Throwable $t, float $time): void
{
}




public function startTestSuite(TestSuite $suite): void
{
}




public function endTestSuite(TestSuite $suite): void
{
}




public function startTest(Test $test): void
{
$this->exception = null;
}






public function endTest(Test $test, float $time): void
{
if (!$test instanceof TestCase) {
return;
}

$groups = array_filter(
$test->getGroups(),
static function ($group)
{
return !($group === 'small' || $group === 'medium' || $group === 'large');
}
);

$testNode = $this->document->createElement('test');

$testNode->setAttribute('className', get_class($test));
$testNode->setAttribute('methodName', $test->getName());
$testNode->setAttribute('prettifiedClassName', $this->prettifier->prettifyTestClass(get_class($test)));
$testNode->setAttribute('prettifiedMethodName', $this->prettifier->prettifyTestCase($test));
$testNode->setAttribute('status', (string) $test->getStatus());
$testNode->setAttribute('time', (string) $time);
$testNode->setAttribute('size', (string) $test->getSize());
$testNode->setAttribute('groups', implode(',', $groups));

foreach ($groups as $group) {
$groupNode = $this->document->createElement('group');

$groupNode->setAttribute('name', $group);

$testNode->appendChild($groupNode);
}

$annotations = $test->getAnnotations();

foreach (['class', 'method'] as $type) {
foreach ($annotations[$type] as $annotation => $values) {
if ($annotation !== 'covers' && $annotation !== 'uses') {
continue;
}

foreach ($values as $value) {
$coversNode = $this->document->createElement($annotation);

$coversNode->setAttribute('target', $value);

$testNode->appendChild($coversNode);
}
}
}

foreach ($test->doubledTypes() as $doubledType) {
$testDoubleNode = $this->document->createElement('testDouble');

$testDoubleNode->setAttribute('type', $doubledType);

$testNode->appendChild($testDoubleNode);
}

$inlineAnnotations = \PHPUnit\Util\Test::getInlineAnnotations(get_class($test), $test->getName(false));

if (isset($inlineAnnotations['given'], $inlineAnnotations['when'], $inlineAnnotations['then'])) {
$testNode->setAttribute('given', $inlineAnnotations['given']['value']);
$testNode->setAttribute('givenStartLine', (string) $inlineAnnotations['given']['line']);
$testNode->setAttribute('when', $inlineAnnotations['when']['value']);
$testNode->setAttribute('whenStartLine', (string) $inlineAnnotations['when']['line']);
$testNode->setAttribute('then', $inlineAnnotations['then']['value']);
$testNode->setAttribute('thenStartLine', (string) $inlineAnnotations['then']['line']);
}

if ($this->exception !== null) {
if ($this->exception instanceof Exception) {
$steps = $this->exception->getSerializableTrace();
} else {
$steps = $this->exception->getTrace();
}

try {
$file = (new ReflectionClass($test))->getFileName();

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


foreach ($steps as $step) {
if (isset($step['file']) && $step['file'] === $file) {
$testNode->setAttribute('exceptionLine', (string) $step['line']);

break;
}
}

$testNode->setAttribute('exceptionMessage', $this->exception->getMessage());
}

$this->root->appendChild($testNode);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util\TestDox;

use function sprintf;




final class HtmlResultPrinter extends ResultPrinter
{



private const PAGE_HEADER = <<<'EOT'
<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8"/>
        <title>Test Documentation</title>
        <style>
            body {
                text-rendering: optimizeLegibility;
                font-variant-ligatures: common-ligatures;
                font-kerning: normal;
                margin-left: 2em;
                background-color: #ffffff;
                color: #000000;
            }

            body > ul > li {
                font-family: Source Serif Pro, PT Sans, Trebuchet MS, Helvetica, Arial;
                font-size: 2em;
            }

            h2 {
                font-family: Tahoma, Helvetica, Arial;
                font-size: 3em;
            }

            ul {
                list-style: none;
                margin-bottom: 1em;
            }
        </style>
    </head>
    <body>
EOT;




private const CLASS_HEADER = <<<'EOT'

        <h2 id="%s">%s</h2>
        <ul>

EOT;




private const CLASS_FOOTER = <<<'EOT'
        </ul>
EOT;




private const PAGE_FOOTER = <<<'EOT'

    </body>
</html>
EOT;




protected function startRun(): void
{
$this->write(self::PAGE_HEADER);
}




protected function startClass(string $name): void
{
$this->write(
sprintf(
self::CLASS_HEADER,
$name,
$this->currentTestClassPrettified
)
);
}




protected function onTest($name, bool $success = true): void
{
$this->write(
sprintf(
"            <li style=\"color: %s;\">%s %s</li>\n",
$success ? '#555753' : '#ef2929',
$success ? '✓' : '❌',
$name
)
);
}




protected function endClass(string $name): void
{
$this->write(self::CLASS_FOOTER);
}




protected function endRun(): void
{
$this->write(self::PAGE_FOOTER);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util\TestDox;

use const PHP_EOL;
use function array_map;
use function ceil;
use function count;
use function explode;
use function get_class;
use function implode;
use function preg_match;
use function sprintf;
use function strlen;
use function strpos;
use function trim;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestResult;
use PHPUnit\Runner\BaseTestRunner;
use PHPUnit\Runner\PhptTestCase;
use PHPUnit\Util\Color;
use SebastianBergmann\Timer\Timer;
use Throwable;




class CliTestDoxPrinter extends TestDoxPrinter
{



private const PREFIX_SIMPLE = [
'default' => '│',
'start' => '│',
'message' => '│',
'diff' => '│',
'trace' => '│',
'last' => '│',
];




private const PREFIX_DECORATED = [
'default' => '│',
'start' => '┐',
'message' => '├',
'diff' => '┊',
'trace' => '╵',
'last' => '┴',
];

private const SPINNER_ICONS = [
" \e[36m◐\e[0m running tests",
" \e[36m◓\e[0m running tests",
" \e[36m◑\e[0m running tests",
" \e[36m◒\e[0m running tests",
];

private const STATUS_STYLES = [
BaseTestRunner::STATUS_PASSED => [
'symbol' => '✔',
'color' => 'fg-green',
],
BaseTestRunner::STATUS_ERROR => [
'symbol' => '✘',
'color' => 'fg-yellow',
'message' => 'bg-yellow,fg-black',
],
BaseTestRunner::STATUS_FAILURE => [
'symbol' => '✘',
'color' => 'fg-red',
'message' => 'bg-red,fg-white',
],
BaseTestRunner::STATUS_SKIPPED => [
'symbol' => '↩',
'color' => 'fg-cyan',
'message' => 'fg-cyan',
],
BaseTestRunner::STATUS_RISKY => [
'symbol' => '☢',
'color' => 'fg-yellow',
'message' => 'fg-yellow',
],
BaseTestRunner::STATUS_INCOMPLETE => [
'symbol' => '∅',
'color' => 'fg-yellow',
'message' => 'fg-yellow',
],
BaseTestRunner::STATUS_WARNING => [
'symbol' => '⚠',
'color' => 'fg-yellow',
'message' => 'fg-yellow',
],
BaseTestRunner::STATUS_UNKNOWN => [
'symbol' => '?',
'color' => 'fg-blue',
'message' => 'fg-white,bg-blue',
],
];




private $nonSuccessfulTestResults = [];




public function printResult(TestResult $result): void
{
$this->printHeader($result);

$this->printNonSuccessfulTestsSummary($result->count());

$this->printFooter($result);
}




protected function printHeader(TestResult $result): void
{
$this->write("\n" . Timer::resourceUsage() . "\n\n");
}

protected function formatClassName(Test $test): string
{
if ($test instanceof TestCase) {
return $this->prettifier->prettifyTestClass(get_class($test));
}

return get_class($test);
}




protected function registerTestResult(Test $test, ?Throwable $t, int $status, float $time, bool $verbose): void
{
if ($status !== BaseTestRunner::STATUS_PASSED) {
$this->nonSuccessfulTestResults[] = $this->testIndex;
}

parent::registerTestResult($test, $t, $status, $time, $verbose);
}




protected function formatTestName(Test $test): string
{
if ($test instanceof TestCase) {
return $this->prettifier->prettifyTestCase($test);
}

return parent::formatTestName($test);
}

protected function writeTestResult(array $prevResult, array $result): void
{

 if ($prevResult['testName'] !== '' &&
(!empty($prevResult['message']) || $prevResult['className'] !== $result['className'])) {
$this->write(PHP_EOL);
}


 if ($prevResult['className'] !== $result['className']) {
$this->write($this->colorizeTextBox('underlined', $result['className']) . PHP_EOL);
}


 if ($this->colors && $result['className'] === PhptTestCase::class) {
$testName = Color::colorizePath($result['testName'], $prevResult['testName'], true);
} else {
$testName = $result['testMethod'];
}

$style = self::STATUS_STYLES[$result['status']];
$line = sprintf(
' %s %s%s' . PHP_EOL,
$this->colorizeTextBox($style['color'], $style['symbol']),
$testName,
$this->verbose ? ' ' . $this->formatRuntime($result['time'], $style['color']) : ''
);

$this->write($line);


 $this->write($result['message']);
}

protected function formatThrowable(Throwable $t, ?int $status = null): string
{
return trim(\PHPUnit\Framework\TestFailure::exceptionToString($t));
}

protected function colorizeMessageAndDiff(string $style, string $buffer): array
{
$lines = $buffer ? array_map('\rtrim', explode(PHP_EOL, $buffer)) : [];
$message = [];
$diff = [];
$insideDiff = false;

foreach ($lines as $line) {
if ($line === '--- Expected') {
$insideDiff = true;
}

if (!$insideDiff) {
$message[] = $line;
} else {
if (strpos($line, '-') === 0) {
$line = Color::colorize('fg-red', Color::visualizeWhitespace($line, true));
} elseif (strpos($line, '+') === 0) {
$line = Color::colorize('fg-green', Color::visualizeWhitespace($line, true));
} elseif ($line === '@@ @@') {
$line = Color::colorize('fg-cyan', $line);
}
$diff[] = $line;
}
}
$diff = implode(PHP_EOL, $diff);

if (!empty($message)) {
$message = $this->colorizeTextBox($style, implode(PHP_EOL, $message));
}

return [$message, $diff];
}

protected function formatStacktrace(Throwable $t): string
{
$trace = \PHPUnit\Util\Filter::getFilteredStacktrace($t);

if (!$this->colors) {
return $trace;
}

$lines = [];
$prevPath = '';

foreach (explode(PHP_EOL, $trace) as $line) {
if (preg_match('/^(.*):(\d+)$/', $line, $matches)) {
$lines[] = Color::colorizePath($matches[1], $prevPath) .
Color::dim(':') .
Color::colorize('fg-blue', $matches[2]) .
"\n";
$prevPath = $matches[1];
} else {
$lines[] = $line;
$prevPath = '';
}
}

return implode('', $lines);
}

protected function formatTestResultMessage(Throwable $t, array $result, ?string $prefix = null): string
{
$message = $this->formatThrowable($t, $result['status']);
$diff = '';

if (!($this->verbose || $result['verbose'])) {
return '';
}

if ($message && $this->colors) {
$style = self::STATUS_STYLES[$result['status']]['message'] ?? '';
[$message, $diff] = $this->colorizeMessageAndDiff($style, $message);
}

if ($prefix === null || !$this->colors) {
$prefix = self::PREFIX_SIMPLE;
}

if ($this->colors) {
$color = self::STATUS_STYLES[$result['status']]['color'] ?? '';
$prefix = array_map(static function ($p) use ($color)
{
return Color::colorize($color, $p);
}, self::PREFIX_DECORATED);
}

$trace = $this->formatStacktrace($t);
$out = $this->prefixLines($prefix['start'], PHP_EOL) . PHP_EOL;

if ($message) {
$out .= $this->prefixLines($prefix['message'], $message . PHP_EOL) . PHP_EOL;
}

if ($diff) {
$out .= $this->prefixLines($prefix['diff'], $diff . PHP_EOL) . PHP_EOL;
}

if ($trace) {
if ($message || $diff) {
$out .= $this->prefixLines($prefix['default'], PHP_EOL) . PHP_EOL;
}
$out .= $this->prefixLines($prefix['trace'], $trace . PHP_EOL) . PHP_EOL;
}
$out .= $this->prefixLines($prefix['last'], PHP_EOL) . PHP_EOL;

return $out;
}

protected function drawSpinner(): void
{
if ($this->colors) {
$id = $this->spinState % count(self::SPINNER_ICONS);
$this->write(self::SPINNER_ICONS[$id]);
}
}

protected function undrawSpinner(): void
{
if ($this->colors) {
$id = $this->spinState % count(self::SPINNER_ICONS);
$this->write("\e[1K\e[" . strlen(self::SPINNER_ICONS[$id]) . 'D');
}
}

private function formatRuntime(float $time, string $color = ''): string
{
if (!$this->colors) {
return sprintf('[%.2f ms]', $time * 1000);
}

if ($time > 1) {
$color = 'fg-magenta';
}

return Color::colorize($color, ' ' . (int) ceil($time * 1000) . ' ' . Color::dim('ms'));
}

private function printNonSuccessfulTestsSummary(int $numberOfExecutedTests): void
{
if (empty($this->nonSuccessfulTestResults)) {
return;
}

if ((count($this->nonSuccessfulTestResults) / $numberOfExecutedTests) >= 0.7) {
return;
}

$this->write("Summary of non-successful tests:\n\n");

$prevResult = $this->getEmptyTestResult();

foreach ($this->nonSuccessfulTestResults as $testIndex) {
$result = $this->testResults[$testIndex];
$this->writeTestResult($prevResult, $result);
$prevResult = $result;
}
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util\TestDox;




final class TextResultPrinter extends ResultPrinter
{



protected function startClass(string $name): void
{
$this->write($this->currentTestClassPrettified . "\n");
}




protected function onTest($name, bool $success = true): void
{
if ($success) {
$this->write(' [x] ');
} else {
$this->write(' [ ] ');
}

$this->write($name . "\n");
}




protected function endClass(string $name): void
{
$this->write("\n");
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util\TestDox;

use function get_class;
use function in_array;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Framework\Warning;
use PHPUnit\Framework\WarningTestCase;
use PHPUnit\Runner\BaseTestRunner;
use PHPUnit\Util\Printer;
use Throwable;




abstract class ResultPrinter extends Printer implements TestListener
{



protected $prettifier;




protected $testClass = '';




protected $testStatus;




protected $tests = [];




protected $successful = 0;




protected $warned = 0;




protected $failed = 0;




protected $risky = 0;




protected $skipped = 0;




protected $incomplete = 0;




protected $currentTestClassPrettified;




protected $currentTestMethodPrettified;




private $groups;




private $excludeGroups;






public function __construct($out = null, array $groups = [], array $excludeGroups = [])
{
parent::__construct($out);

$this->groups = $groups;
$this->excludeGroups = $excludeGroups;

$this->prettifier = new NamePrettifier;
$this->startRun();
}




public function flush(): void
{
$this->doEndClass();
$this->endRun();

parent::flush();
}




public function addError(Test $test, Throwable $t, float $time): void
{
if (!$this->isOfInterest($test)) {
return;
}

$this->testStatus = BaseTestRunner::STATUS_ERROR;
$this->failed++;
}




public function addWarning(Test $test, Warning $e, float $time): void
{
if (!$this->isOfInterest($test)) {
return;
}

$this->testStatus = BaseTestRunner::STATUS_WARNING;
$this->warned++;
}




public function addFailure(Test $test, AssertionFailedError $e, float $time): void
{
if (!$this->isOfInterest($test)) {
return;
}

$this->testStatus = BaseTestRunner::STATUS_FAILURE;
$this->failed++;
}




public function addIncompleteTest(Test $test, Throwable $t, float $time): void
{
if (!$this->isOfInterest($test)) {
return;
}

$this->testStatus = BaseTestRunner::STATUS_INCOMPLETE;
$this->incomplete++;
}




public function addRiskyTest(Test $test, Throwable $t, float $time): void
{
if (!$this->isOfInterest($test)) {
return;
}

$this->testStatus = BaseTestRunner::STATUS_RISKY;
$this->risky++;
}




public function addSkippedTest(Test $test, Throwable $t, float $time): void
{
if (!$this->isOfInterest($test)) {
return;
}

$this->testStatus = BaseTestRunner::STATUS_SKIPPED;
$this->skipped++;
}




public function startTestSuite(TestSuite $suite): void
{
}




public function endTestSuite(TestSuite $suite): void
{
}






public function startTest(Test $test): void
{
if (!$this->isOfInterest($test)) {
return;
}

$class = get_class($test);

if ($this->testClass !== $class) {
if ($this->testClass !== '') {
$this->doEndClass();
}

$this->currentTestClassPrettified = $this->prettifier->prettifyTestClass($class);
$this->testClass = $class;
$this->tests = [];

$this->startClass($class);
}

if ($test instanceof TestCase) {
$this->currentTestMethodPrettified = $this->prettifier->prettifyTestCase($test);
}

$this->testStatus = BaseTestRunner::STATUS_PASSED;
}




public function endTest(Test $test, float $time): void
{
if (!$this->isOfInterest($test)) {
return;
}

$this->tests[] = [$this->currentTestMethodPrettified, $this->testStatus];

$this->currentTestClassPrettified = null;
$this->currentTestMethodPrettified = null;
}

protected function doEndClass(): void
{
foreach ($this->tests as $test) {
$this->onTest($test[0], $test[1] === BaseTestRunner::STATUS_PASSED);
}

$this->endClass($this->testClass);
}




protected function startRun(): void
{
}




protected function startClass(string $name): void
{
}




protected function onTest($name, bool $success = true): void
{
}




protected function endClass(string $name): void
{
}




protected function endRun(): void
{
}

private function isOfInterest(Test $test): bool
{
if (!$test instanceof TestCase) {
return false;
}

if ($test instanceof WarningTestCase) {
return false;
}

if (!empty($this->groups)) {
foreach ($test->getGroups() as $group) {
if (in_array($group, $this->groups, true)) {
return true;
}
}

return false;
}

if (!empty($this->excludeGroups)) {
foreach ($test->getGroups() as $group) {
if (in_array($group, $this->excludeGroups, true)) {
return false;
}
}

return true;
}

return true;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\Util\TestDox;

use function array_key_exists;
use function array_keys;
use function array_map;
use function array_pop;
use function array_values;
use function explode;
use function get_class;
use function gettype;
use function implode;
use function in_array;
use function is_bool;
use function is_float;
use function is_int;
use function is_numeric;
use function is_object;
use function is_scalar;
use function is_string;
use function mb_strtolower;
use function ord;
use function preg_quote;
use function preg_replace;
use function range;
use function sprintf;
use function str_replace;
use function strlen;
use function strpos;
use function strtolower;
use function strtoupper;
use function substr;
use function trim;
use PHPUnit\Framework\TestCase;
use PHPUnit\Util\Color;
use PHPUnit\Util\Exception as UtilException;
use PHPUnit\Util\Test;
use ReflectionException;
use ReflectionMethod;
use ReflectionObject;
use SebastianBergmann\Exporter\Exporter;




final class NamePrettifier
{



private $strings = [];




private $useColor;

public function __construct($useColor = false)
{
$this->useColor = $useColor;
}






public function prettifyTestClass(string $className): string
{
try {
$annotations = Test::parseTestMethodAnnotations($className);

if (isset($annotations['class']['testdox'][0])) {
return $annotations['class']['testdox'][0];
}
} catch (UtilException $e) {

 }

$parts = explode('\\', $className);
$className = array_pop($parts);

if (substr($className, -1 * strlen('Test')) === 'Test') {
$className = substr($className, 0, strlen($className) - strlen('Test'));
}

if (strpos($className, 'Tests') === 0) {
$className = substr($className, strlen('Tests'));
} elseif (strpos($className, 'Test') === 0) {
$className = substr($className, strlen('Test'));
}

if (empty($className)) {
$className = 'UnnamedTests';
}

if (!empty($parts)) {
$parts[] = $className;
$fullyQualifiedName = implode('\\', $parts);
} else {
$fullyQualifiedName = $className;
}

$result = '';
$wasLowerCase = false;

foreach (range(0, strlen($className) - 1) as $i) {
$isLowerCase = mb_strtolower($className[$i], 'UTF-8') === $className[$i];

if ($wasLowerCase && !$isLowerCase) {
$result .= ' ';
}

$result .= $className[$i];

if ($isLowerCase) {
$wasLowerCase = true;
} else {
$wasLowerCase = false;
}
}

if ($fullyQualifiedName !== $className) {
return $result . ' (' . $fullyQualifiedName . ')';
}

return $result;
}




public function prettifyTestCase(TestCase $test): string
{
$annotations = $test->getAnnotations();
$annotationWithPlaceholders = false;

$callback = static function (string $variable): string
{
return sprintf('/%s(?=\b)/', preg_quote($variable, '/'));
};

if (isset($annotations['method']['testdox'][0])) {
$result = $annotations['method']['testdox'][0];

if (strpos($result, '$') !== false) {
$annotation = $annotations['method']['testdox'][0];
$providedData = $this->mapTestMethodParameterNamesToProvidedDataValues($test);
$variables = array_map($callback, array_keys($providedData));

$result = trim(preg_replace($variables, $providedData, $annotation));

$annotationWithPlaceholders = true;
}
} else {
$result = $this->prettifyTestMethod($test->getName(false));
}

if (!$annotationWithPlaceholders && $test->usesDataProvider()) {
$result .= $this->prettifyDataSet($test);
}

return $result;
}

public function prettifyDataSet(TestCase $test): string
{
if (!$this->useColor) {
return $test->getDataSetAsString(false);
}

if (is_int($test->dataName())) {
$data = Color::dim(' with data set ') . Color::colorize('fg-cyan', (string) $test->dataName());
} else {
$data = Color::dim(' with ') . Color::colorize('fg-cyan', Color::visualizeWhitespace((string) $test->dataName()));
}

return $data;
}




public function prettifyTestMethod(string $name): string
{
$buffer = '';

if ($name === '') {
return $buffer;
}

$string = (string) preg_replace('#\d+$#', '', $name, -1, $count);

if (in_array($string, $this->strings, true)) {
$name = $string;
} elseif ($count === 0) {
$this->strings[] = $string;
}

if (strpos($name, 'test_') === 0) {
$name = substr($name, 5);
} elseif (strpos($name, 'test') === 0) {
$name = substr($name, 4);
}

if ($name === '') {
return $buffer;
}

$name[0] = strtoupper($name[0]);

if (strpos($name, '_') !== false) {
return trim(str_replace('_', ' ', $name));
}

$wasNumeric = false;

foreach (range(0, strlen($name) - 1) as $i) {
if ($i > 0 && ord($name[$i]) >= 65 && ord($name[$i]) <= 90) {
$buffer .= ' ' . strtolower($name[$i]);
} else {
$isNumeric = is_numeric($name[$i]);

if (!$wasNumeric && $isNumeric) {
$buffer .= ' ';
$wasNumeric = true;
}

if ($wasNumeric && !$isNumeric) {
$wasNumeric = false;
}

$buffer .= $name[$i];
}
}

return $buffer;
}




private function mapTestMethodParameterNamesToProvidedDataValues(TestCase $test): array
{
try {
$reflector = new ReflectionMethod(get_class($test), $test->getName(false));

 } catch (ReflectionException $e) {
throw new UtilException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


$providedData = [];
$providedDataValues = array_values($test->getProvidedData());
$i = 0;

$providedData['$_dataName'] = $test->dataName();

foreach ($reflector->getParameters() as $parameter) {
if (!array_key_exists($i, $providedDataValues) && $parameter->isDefaultValueAvailable()) {
try {
$providedDataValues[$i] = $parameter->getDefaultValue();

 } catch (ReflectionException $e) {
throw new UtilException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}

 }

$value = $providedDataValues[$i++] ?? null;

if (is_object($value)) {
$reflector = new ReflectionObject($value);

if ($reflector->hasMethod('__toString')) {
$value = (string) $value;
} else {
$value = get_class($value);
}
}

if (!is_scalar($value)) {
$value = gettype($value);
}

if (is_bool($value) || is_int($value) || is_float($value)) {
$value = (new Exporter)->export($value);
}

if (is_string($value) && $value === '') {
if ($this->useColor) {
$value = Color::colorize('dim,underlined', 'empty');
} else {
$value = "''";
}
}

$providedData['$' . $parameter->getName()] = $value;
}

if ($this->useColor) {
$providedData = array_map(static function ($value)
{
return Color::colorize('fg-cyan', Color::visualizeWhitespace((string) $value, true));
}, $providedData);
}

return $providedData;
}
}
<?php declare(strict_types=1);








namespace PHPUnit\TextUI;

use const PHP_EOL;
use const PHP_MAJOR_VERSION;
use const PHP_SAPI;
use function array_diff;
use function assert;
use function class_exists;
use function count;
use function dirname;
use function extension_loaded;
use function file_put_contents;
use function htmlspecialchars;
use function ini_get;
use function is_int;
use function is_string;
use function is_subclass_of;
use function mt_srand;
use function range;
use function realpath;
use function sprintf;
use function strpos;
use function time;
use PHPUnit\Framework\Exception;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestResult;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Runner\AfterLastTestHook;
use PHPUnit\Runner\BaseTestRunner;
use PHPUnit\Runner\BeforeFirstTestHook;
use PHPUnit\Runner\DefaultTestResultCache;
use PHPUnit\Runner\Filter\ExcludeGroupFilterIterator;
use PHPUnit\Runner\Filter\Factory;
use PHPUnit\Runner\Filter\IncludeGroupFilterIterator;
use PHPUnit\Runner\Filter\NameFilterIterator;
use PHPUnit\Runner\Hook;
use PHPUnit\Runner\NullTestResultCache;
use PHPUnit\Runner\ResultCacheExtension;
use PHPUnit\Runner\StandardTestSuiteLoader;
use PHPUnit\Runner\TestHook;
use PHPUnit\Runner\TestListenerAdapter;
use PHPUnit\Runner\TestSuiteLoader;
use PHPUnit\Runner\TestSuiteSorter;
use PHPUnit\Runner\Version;
use PHPUnit\Util\Configuration;
use PHPUnit\Util\Filesystem;
use PHPUnit\Util\Log\JUnit;
use PHPUnit\Util\Log\TeamCity;
use PHPUnit\Util\Printer;
use PHPUnit\Util\TestDox\CliTestDoxPrinter;
use PHPUnit\Util\TestDox\HtmlResultPrinter;
use PHPUnit\Util\TestDox\TextResultPrinter;
use PHPUnit\Util\TestDox\XmlResultPrinter;
use PHPUnit\Util\XdebugFilterScriptGenerator;
use ReflectionClass;
use ReflectionException;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Exception as CodeCoverageException;
use SebastianBergmann\CodeCoverage\Filter as CodeCoverageFilter;
use SebastianBergmann\CodeCoverage\Report\Clover as CloverReport;
use SebastianBergmann\CodeCoverage\Report\Crap4j as Crap4jReport;
use SebastianBergmann\CodeCoverage\Report\Html\Facade as HtmlReport;
use SebastianBergmann\CodeCoverage\Report\PHP as PhpReport;
use SebastianBergmann\CodeCoverage\Report\Text as TextReport;
use SebastianBergmann\CodeCoverage\Report\Xml\Facade as XmlReport;
use SebastianBergmann\Comparator\Comparator;
use SebastianBergmann\Environment\Runtime;
use SebastianBergmann\Invoker\Invoker;
use SebastianBergmann\Timer\Timer;




final class TestRunner extends BaseTestRunner
{
public const SUCCESS_EXIT = 0;

public const FAILURE_EXIT = 1;

public const EXCEPTION_EXIT = 2;




private static $versionStringPrinted = false;




private $codeCoverageFilter;




private $loader;




private $printer;




private $runtime;




private $messagePrinted = false;




private $extensions = [];

public function __construct(TestSuiteLoader $loader = null, CodeCoverageFilter $filter = null)
{
if ($filter === null) {
$filter = new CodeCoverageFilter;
}

$this->codeCoverageFilter = $filter;
$this->loader = $loader;
$this->runtime = new Runtime;
}





public function doRun(Test $suite, array $arguments = [], array $warnings = [], bool $exit = true): TestResult
{
if (isset($arguments['configuration'])) {
$GLOBALS['__PHPUNIT_CONFIGURATION_FILE'] = $arguments['configuration'];
}

$this->handleConfiguration($arguments);

if (is_int($arguments['columns']) && $arguments['columns'] < 16) {
$arguments['columns'] = 16;
$tooFewColumnsRequested = true;
}

if (isset($arguments['bootstrap'])) {
$GLOBALS['__PHPUNIT_BOOTSTRAP'] = $arguments['bootstrap'];
}

if ($suite instanceof TestCase || $suite instanceof TestSuite) {
if ($arguments['backupGlobals'] === true) {
$suite->setBackupGlobals(true);
}

if ($arguments['backupStaticAttributes'] === true) {
$suite->setBackupStaticAttributes(true);
}

if ($arguments['beStrictAboutChangesToGlobalState'] === true) {
$suite->setBeStrictAboutChangesToGlobalState(true);
}
}

if ($arguments['executionOrder'] === TestSuiteSorter::ORDER_RANDOMIZED) {
mt_srand($arguments['randomOrderSeed']);
}

if ($arguments['cacheResult']) {
if (!isset($arguments['cacheResultFile'])) {
if (isset($arguments['configuration']) && $arguments['configuration'] instanceof Configuration) {
$cacheLocation = $arguments['configuration']->getFilename();
} else {
$cacheLocation = $_SERVER['PHP_SELF'];
}

$arguments['cacheResultFile'] = null;

$cacheResultFile = realpath($cacheLocation);

if ($cacheResultFile !== false) {
$arguments['cacheResultFile'] = dirname($cacheResultFile);
}
}

$cache = new DefaultTestResultCache($arguments['cacheResultFile']);

$this->addExtension(new ResultCacheExtension($cache));
}

if ($arguments['executionOrder'] !== TestSuiteSorter::ORDER_DEFAULT || $arguments['executionOrderDefects'] !== TestSuiteSorter::ORDER_DEFAULT || $arguments['resolveDependencies']) {
$cache = $cache ?? new NullTestResultCache;

$cache->load();

$sorter = new TestSuiteSorter($cache);

$sorter->reorderTestsInSuite($suite, $arguments['executionOrder'], $arguments['resolveDependencies'], $arguments['executionOrderDefects']);
$originalExecutionOrder = $sorter->getOriginalExecutionOrder();

unset($sorter);
}

if (is_int($arguments['repeat']) && $arguments['repeat'] > 0) {
$_suite = new TestSuite;


foreach (range(1, $arguments['repeat']) as $step) {
$_suite->addTest($suite);
}

$suite = $_suite;

unset($_suite);
}

$result = $this->createTestResult();

$listener = new TestListenerAdapter;
$listenerNeeded = false;

foreach ($this->extensions as $extension) {
if ($extension instanceof TestHook) {
$listener->add($extension);

$listenerNeeded = true;
}
}

if ($listenerNeeded) {
$result->addListener($listener);
}

unset($listener, $listenerNeeded);

if ($arguments['convertDeprecationsToExceptions']) {
$result->convertDeprecationsToExceptions(true);
}

if (!$arguments['convertErrorsToExceptions']) {
$result->convertErrorsToExceptions(false);
}

if (!$arguments['convertNoticesToExceptions']) {
$result->convertNoticesToExceptions(false);
}

if (!$arguments['convertWarningsToExceptions']) {
$result->convertWarningsToExceptions(false);
}

if ($arguments['stopOnError']) {
$result->stopOnError(true);
}

if ($arguments['stopOnFailure']) {
$result->stopOnFailure(true);
}

if ($arguments['stopOnWarning']) {
$result->stopOnWarning(true);
}

if ($arguments['stopOnIncomplete']) {
$result->stopOnIncomplete(true);
}

if ($arguments['stopOnRisky']) {
$result->stopOnRisky(true);
}

if ($arguments['stopOnSkipped']) {
$result->stopOnSkipped(true);
}

if ($arguments['stopOnDefect']) {
$result->stopOnDefect(true);
}

if ($arguments['registerMockObjectsFromTestArgumentsRecursively']) {
$result->setRegisterMockObjectsFromTestArgumentsRecursively(true);
}

if ($this->printer === null) {
if (isset($arguments['printer'])) {
if ($arguments['printer'] instanceof Printer && $arguments['printer'] instanceof TestListener) {
$this->printer = $arguments['printer'];
} elseif (is_string($arguments['printer']) && class_exists($arguments['printer'], false)) {
try {
new ReflectionClass($arguments['printer']);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if (is_subclass_of($arguments['printer'], ResultPrinter::class)) {
$this->printer = $this->createPrinter($arguments['printer'], $arguments);
}
}
} else {
$this->printer = $this->createPrinter(ResultPrinter::class, $arguments);
}
}

if (isset($originalExecutionOrder) && $this->printer instanceof CliTestDoxPrinter) {
assert($this->printer instanceof CliTestDoxPrinter);

$this->printer->setOriginalExecutionOrder($originalExecutionOrder);
$this->printer->setShowProgressAnimation(!$arguments['noInteraction']);
}

$this->printer->write(
Version::getVersionString() . "\n"
);

self::$versionStringPrinted = true;

if ($arguments['verbose']) {
$this->writeMessage('Runtime', $this->runtime->getNameWithVersionAndCodeCoverageDriver());

if (isset($arguments['configuration'])) {
$this->writeMessage(
'Configuration',
$arguments['configuration']->getFilename()
);
}

foreach ($arguments['loadedExtensions'] as $extension) {
$this->writeMessage(
'Extension',
$extension
);
}

foreach ($arguments['notLoadedExtensions'] as $extension) {
$this->writeMessage(
'Extension',
$extension
);
}
}

foreach ($warnings as $warning) {
$this->writeMessage('Warning', $warning);
}

if ($arguments['executionOrder'] === TestSuiteSorter::ORDER_RANDOMIZED) {
$this->writeMessage(
'Random seed',
(string) $arguments['randomOrderSeed']
);
}

if (isset($tooFewColumnsRequested)) {
$this->writeMessage('Error', 'Less than 16 columns requested, number of columns set to 16');
}

if ($this->runtime->discardsComments()) {
$this->writeMessage('Warning', 'opcache.save_comments=0 set; annotations will not work');
}

if (isset($arguments['configuration']) && $arguments['configuration']->hasValidationErrors()) {
$this->write(
"\n  Warning - The configuration file did not pass validation!\n  The following problems have been detected:\n"
);

foreach ($arguments['configuration']->getValidationErrors() as $line => $errors) {
$this->write(sprintf("\n  Line %d:\n", $line));

foreach ($errors as $msg) {
$this->write(sprintf("  - %s\n", $msg));
}
}

$this->write("\n  Test results may not be as expected.\n\n");
}

if (isset($arguments['conflictBetweenPrinterClassAndTestdox'])) {
$this->writeMessage('Warning', 'Directives printerClass and testdox are mutually exclusive');
}

foreach ($arguments['listeners'] as $listener) {
$result->addListener($listener);
}

$result->addListener($this->printer);

$codeCoverageReports = 0;

if (!isset($arguments['noLogging'])) {
if (isset($arguments['testdoxHTMLFile'])) {
$result->addListener(
new HtmlResultPrinter(
$arguments['testdoxHTMLFile'],
$arguments['testdoxGroups'],
$arguments['testdoxExcludeGroups']
)
);
}

if (isset($arguments['testdoxTextFile'])) {
$result->addListener(
new TextResultPrinter(
$arguments['testdoxTextFile'],
$arguments['testdoxGroups'],
$arguments['testdoxExcludeGroups']
)
);
}

if (isset($arguments['testdoxXMLFile'])) {
$result->addListener(
new XmlResultPrinter(
$arguments['testdoxXMLFile']
)
);
}

if (isset($arguments['teamcityLogfile'])) {
$result->addListener(
new TeamCity($arguments['teamcityLogfile'])
);
}

if (isset($arguments['junitLogfile'])) {
$result->addListener(
new JUnit(
$arguments['junitLogfile'],
$arguments['reportUselessTests']
)
);
}

if (isset($arguments['coverageClover'])) {
$codeCoverageReports++;
}

if (isset($arguments['coverageCrap4J'])) {
$codeCoverageReports++;
}

if (isset($arguments['coverageHtml'])) {
$codeCoverageReports++;
}

if (isset($arguments['coveragePHP'])) {
$codeCoverageReports++;
}

if (isset($arguments['coverageText'])) {
$codeCoverageReports++;
}

if (isset($arguments['coverageXml'])) {
$codeCoverageReports++;
}
}

if (isset($arguments['noCoverage'])) {
$codeCoverageReports = 0;
}

if ($codeCoverageReports > 0 && PHP_MAJOR_VERSION < 8 && !$this->runtime->canCollectCodeCoverage()) {
$this->writeMessage('Error', 'No code coverage driver is available');

$codeCoverageReports = 0;
}

if ($codeCoverageReports > 0 || isset($arguments['xdebugFilterFile'])) {
$whitelistFromConfigurationFile = false;
$whitelistFromOption = false;

if (isset($arguments['whitelist'])) {
$this->codeCoverageFilter->addDirectoryToWhitelist($arguments['whitelist']);

$whitelistFromOption = true;
}

if (isset($arguments['configuration'])) {
$filterConfiguration = $arguments['configuration']->getFilterConfiguration();

if (!empty($filterConfiguration['whitelist'])) {
$whitelistFromConfigurationFile = true;
}

if (!empty($filterConfiguration['whitelist'])) {
foreach ($filterConfiguration['whitelist']['include']['directory'] as $dir) {
$this->codeCoverageFilter->addDirectoryToWhitelist(
$dir['path'],
$dir['suffix'],
$dir['prefix']
);
}

foreach ($filterConfiguration['whitelist']['include']['file'] as $file) {
$this->codeCoverageFilter->addFileToWhitelist($file);
}

foreach ($filterConfiguration['whitelist']['exclude']['directory'] as $dir) {
$this->codeCoverageFilter->removeDirectoryFromWhitelist(
$dir['path'],
$dir['suffix'],
$dir['prefix']
);
}

foreach ($filterConfiguration['whitelist']['exclude']['file'] as $file) {
$this->codeCoverageFilter->removeFileFromWhitelist($file);
}
}
}
}

if ($codeCoverageReports > 0) {
if (PHP_MAJOR_VERSION >= 8) {
$this->writeMessage('Error', 'This version of PHPUnit does not support code coverage on PHP 8');

$codeCoverageReports = 0;
} else {
try {
$codeCoverage = new CodeCoverage(
null,
$this->codeCoverageFilter
);

$codeCoverage->setUnintentionallyCoveredSubclassesWhitelist(
[Comparator::class]
);

$codeCoverage->setCheckForUnintentionallyCoveredCode(
$arguments['strictCoverage']
);

$codeCoverage->setCheckForMissingCoversAnnotation(
$arguments['strictCoverage']
);

if (isset($arguments['forceCoversAnnotation'])) {
$codeCoverage->setForceCoversAnnotation(
$arguments['forceCoversAnnotation']
);
}

if (isset($arguments['ignoreDeprecatedCodeUnitsFromCodeCoverage'])) {
$codeCoverage->setIgnoreDeprecatedCode(
$arguments['ignoreDeprecatedCodeUnitsFromCodeCoverage']
);
}

if (isset($arguments['disableCodeCoverageIgnore'])) {
$codeCoverage->setDisableIgnoredLines(true);
}

if (!empty($filterConfiguration['whitelist'])) {
$codeCoverage->setAddUncoveredFilesFromWhitelist(
$filterConfiguration['whitelist']['addUncoveredFilesFromWhitelist']
);

$codeCoverage->setProcessUncoveredFilesFromWhitelist(
$filterConfiguration['whitelist']['processUncoveredFilesFromWhitelist']
);
}

if (!$this->codeCoverageFilter->hasWhitelist()) {
if (!$whitelistFromConfigurationFile && !$whitelistFromOption) {
$this->writeMessage('Error', 'No whitelist is configured, no code coverage will be generated.');
} else {
$this->writeMessage('Error', 'Incorrect whitelist config, no code coverage will be generated.');
}

$codeCoverageReports = 0;

unset($codeCoverage);
}
} catch (CodeCoverageException $e) {
$this->writeMessage('Error', $e->getMessage());

$codeCoverageReports = 0;
}
}
}

if (isset($arguments['xdebugFilterFile'], $filterConfiguration)) {
$this->write("\n");

$script = (new XdebugFilterScriptGenerator)->generate($filterConfiguration['whitelist']);

if ($arguments['xdebugFilterFile'] !== 'php://stdout' && $arguments['xdebugFilterFile'] !== 'php://stderr' && !Filesystem::createDirectory(dirname($arguments['xdebugFilterFile']))) {
$this->write(sprintf('Cannot write Xdebug filter script to %s ' . PHP_EOL, $arguments['xdebugFilterFile']));

exit(self::EXCEPTION_EXIT);
}

file_put_contents($arguments['xdebugFilterFile'], $script);

$this->write(sprintf('Wrote Xdebug filter script to %s ' . PHP_EOL, $arguments['xdebugFilterFile']));

exit(self::SUCCESS_EXIT);
}

$this->printer->write("\n");

if (isset($codeCoverage)) {
$result->setCodeCoverage($codeCoverage);

if ($codeCoverageReports > 1 && isset($arguments['cacheTokens'])) {
$codeCoverage->setCacheTokens($arguments['cacheTokens']);
}
}

$result->beStrictAboutTestsThatDoNotTestAnything($arguments['reportUselessTests']);
$result->beStrictAboutOutputDuringTests($arguments['disallowTestOutput']);
$result->beStrictAboutTodoAnnotatedTests($arguments['disallowTodoAnnotatedTests']);
$result->beStrictAboutResourceUsageDuringSmallTests($arguments['beStrictAboutResourceUsageDuringSmallTests']);

if ($arguments['enforceTimeLimit'] === true) {
if (!class_exists(Invoker::class)) {
$this->writeMessage('Error', 'Package phpunit/php-invoker is required for enforcing time limits');
}

if (!extension_loaded('pcntl') || strpos(ini_get('disable_functions'), 'pcntl') !== false) {
$this->writeMessage('Error', 'PHP extension pcntl is required for enforcing time limits');
}
}
$result->enforceTimeLimit($arguments['enforceTimeLimit']);
$result->setDefaultTimeLimit($arguments['defaultTimeLimit']);
$result->setTimeoutForSmallTests($arguments['timeoutForSmallTests']);
$result->setTimeoutForMediumTests($arguments['timeoutForMediumTests']);
$result->setTimeoutForLargeTests($arguments['timeoutForLargeTests']);

if ($suite instanceof TestSuite) {
$this->processSuiteFilters($suite, $arguments);
$suite->setRunTestInSeparateProcess($arguments['processIsolation']);
}

foreach ($this->extensions as $extension) {
if ($extension instanceof BeforeFirstTestHook) {
$extension->executeBeforeFirstTest();
}
}

$suite->run($result);

foreach ($this->extensions as $extension) {
if ($extension instanceof AfterLastTestHook) {
$extension->executeAfterLastTest();
}
}

$result->flushListeners();

if ($this->printer instanceof ResultPrinter) {
$this->printer->printResult($result);
}

if (isset($codeCoverage)) {
if (isset($arguments['coverageClover'])) {
$this->codeCoverageGenerationStart('Clover XML');

try {
$writer = new CloverReport;
$writer->process($codeCoverage, $arguments['coverageClover']);

$this->codeCoverageGenerationSucceeded();

unset($writer);
} catch (CodeCoverageException $e) {
$this->codeCoverageGenerationFailed($e);
}
}

if (isset($arguments['coverageCrap4J'])) {
$this->codeCoverageGenerationStart('Crap4J XML');

try {
$writer = new Crap4jReport($arguments['crap4jThreshold']);
$writer->process($codeCoverage, $arguments['coverageCrap4J']);

$this->codeCoverageGenerationSucceeded();

unset($writer);
} catch (CodeCoverageException $e) {
$this->codeCoverageGenerationFailed($e);
}
}

if (isset($arguments['coverageHtml'])) {
$this->codeCoverageGenerationStart('HTML');

try {
$writer = new HtmlReport(
$arguments['reportLowUpperBound'],
$arguments['reportHighLowerBound'],
sprintf(
' and <a href="https://phpunit.de/">PHPUnit %s</a>',
Version::id()
)
);

$writer->process($codeCoverage, $arguments['coverageHtml']);

$this->codeCoverageGenerationSucceeded();

unset($writer);
} catch (CodeCoverageException $e) {
$this->codeCoverageGenerationFailed($e);
}
}

if (isset($arguments['coveragePHP'])) {
$this->codeCoverageGenerationStart('PHP');

try {
$writer = new PhpReport;
$writer->process($codeCoverage, $arguments['coveragePHP']);

$this->codeCoverageGenerationSucceeded();

unset($writer);
} catch (CodeCoverageException $e) {
$this->codeCoverageGenerationFailed($e);
}
}

if (isset($arguments['coverageText'])) {
if ($arguments['coverageText'] === 'php://stdout') {
$outputStream = $this->printer;
$colors = $arguments['colors'] && $arguments['colors'] !== ResultPrinter::COLOR_NEVER;
} else {
$outputStream = new Printer($arguments['coverageText']);
$colors = false;
}

$processor = new TextReport(
$arguments['reportLowUpperBound'],
$arguments['reportHighLowerBound'],
$arguments['coverageTextShowUncoveredFiles'],
$arguments['coverageTextShowOnlySummary']
);

$outputStream->write(
$processor->process($codeCoverage, $colors)
);
}

if (isset($arguments['coverageXml'])) {
$this->codeCoverageGenerationStart('PHPUnit XML');

try {
$writer = new XmlReport(Version::id());
$writer->process($codeCoverage, $arguments['coverageXml']);

$this->codeCoverageGenerationSucceeded();

unset($writer);
} catch (CodeCoverageException $e) {
$this->codeCoverageGenerationFailed($e);
}
}
}

if ($exit) {
if ($result->wasSuccessfulIgnoringWarnings()) {
if ($arguments['failOnRisky'] && !$result->allHarmless()) {
exit(self::FAILURE_EXIT);
}

if ($arguments['failOnWarning'] && $result->warningCount() > 0) {
exit(self::FAILURE_EXIT);
}

exit(self::SUCCESS_EXIT);
}

if ($result->errorCount() > 0) {
exit(self::EXCEPTION_EXIT);
}

if ($result->failureCount() > 0) {
exit(self::FAILURE_EXIT);
}
}

return $result;
}

public function setPrinter(ResultPrinter $resultPrinter): void
{
$this->printer = $resultPrinter;
}




public function getLoader(): TestSuiteLoader
{
if ($this->loader === null) {
$this->loader = new StandardTestSuiteLoader;
}

return $this->loader;
}

public function addExtension(Hook $extension): void
{
$this->extensions[] = $extension;
}





protected function runFailed(string $message): void
{
$this->write($message . PHP_EOL);

exit(self::FAILURE_EXIT);
}

private function createTestResult(): TestResult
{
return new TestResult;
}

private function write(string $buffer): void
{
if (PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg') {
$buffer = htmlspecialchars($buffer);
}

if ($this->printer !== null) {
$this->printer->write($buffer);
} else {
print $buffer;
}
}




private function handleConfiguration(array &$arguments): void
{
if (isset($arguments['configuration']) &&
!$arguments['configuration'] instanceof Configuration) {
$arguments['configuration'] = Configuration::getInstance(
$arguments['configuration']
);
}

$arguments['debug'] = $arguments['debug'] ?? false;
$arguments['filter'] = $arguments['filter'] ?? false;
$arguments['listeners'] = $arguments['listeners'] ?? [];

if (isset($arguments['configuration'])) {
$arguments['configuration']->handlePHPConfiguration();

$phpunitConfiguration = $arguments['configuration']->getPHPUnitConfiguration();

if (isset($phpunitConfiguration['backupGlobals']) && !isset($arguments['backupGlobals'])) {
$arguments['backupGlobals'] = $phpunitConfiguration['backupGlobals'];
}

if (isset($phpunitConfiguration['backupStaticAttributes']) && !isset($arguments['backupStaticAttributes'])) {
$arguments['backupStaticAttributes'] = $phpunitConfiguration['backupStaticAttributes'];
}

if (isset($phpunitConfiguration['beStrictAboutChangesToGlobalState']) && !isset($arguments['beStrictAboutChangesToGlobalState'])) {
$arguments['beStrictAboutChangesToGlobalState'] = $phpunitConfiguration['beStrictAboutChangesToGlobalState'];
}

if (isset($phpunitConfiguration['bootstrap']) && !isset($arguments['bootstrap'])) {
$arguments['bootstrap'] = $phpunitConfiguration['bootstrap'];
}

if (isset($phpunitConfiguration['cacheResult']) && !isset($arguments['cacheResult'])) {
$arguments['cacheResult'] = $phpunitConfiguration['cacheResult'];
}

if (isset($phpunitConfiguration['cacheResultFile']) && !isset($arguments['cacheResultFile'])) {
$arguments['cacheResultFile'] = $phpunitConfiguration['cacheResultFile'];
}

if (isset($phpunitConfiguration['cacheTokens']) && !isset($arguments['cacheTokens'])) {
$arguments['cacheTokens'] = $phpunitConfiguration['cacheTokens'];
}

if (isset($phpunitConfiguration['cacheTokens']) && !isset($arguments['cacheTokens'])) {
$arguments['cacheTokens'] = $phpunitConfiguration['cacheTokens'];
}

if (isset($phpunitConfiguration['colors']) && !isset($arguments['colors'])) {
$arguments['colors'] = $phpunitConfiguration['colors'];
}

if (isset($phpunitConfiguration['convertDeprecationsToExceptions']) && !isset($arguments['convertDeprecationsToExceptions'])) {
$arguments['convertDeprecationsToExceptions'] = $phpunitConfiguration['convertDeprecationsToExceptions'];
}

if (isset($phpunitConfiguration['convertErrorsToExceptions']) && !isset($arguments['convertErrorsToExceptions'])) {
$arguments['convertErrorsToExceptions'] = $phpunitConfiguration['convertErrorsToExceptions'];
}

if (isset($phpunitConfiguration['convertNoticesToExceptions']) && !isset($arguments['convertNoticesToExceptions'])) {
$arguments['convertNoticesToExceptions'] = $phpunitConfiguration['convertNoticesToExceptions'];
}

if (isset($phpunitConfiguration['convertWarningsToExceptions']) && !isset($arguments['convertWarningsToExceptions'])) {
$arguments['convertWarningsToExceptions'] = $phpunitConfiguration['convertWarningsToExceptions'];
}

if (isset($phpunitConfiguration['processIsolation']) && !isset($arguments['processIsolation'])) {
$arguments['processIsolation'] = $phpunitConfiguration['processIsolation'];
}

if (isset($phpunitConfiguration['stopOnDefect']) && !isset($arguments['stopOnDefect'])) {
$arguments['stopOnDefect'] = $phpunitConfiguration['stopOnDefect'];
}

if (isset($phpunitConfiguration['stopOnError']) && !isset($arguments['stopOnError'])) {
$arguments['stopOnError'] = $phpunitConfiguration['stopOnError'];
}

if (isset($phpunitConfiguration['stopOnFailure']) && !isset($arguments['stopOnFailure'])) {
$arguments['stopOnFailure'] = $phpunitConfiguration['stopOnFailure'];
}

if (isset($phpunitConfiguration['stopOnWarning']) && !isset($arguments['stopOnWarning'])) {
$arguments['stopOnWarning'] = $phpunitConfiguration['stopOnWarning'];
}

if (isset($phpunitConfiguration['stopOnIncomplete']) && !isset($arguments['stopOnIncomplete'])) {
$arguments['stopOnIncomplete'] = $phpunitConfiguration['stopOnIncomplete'];
}

if (isset($phpunitConfiguration['stopOnRisky']) && !isset($arguments['stopOnRisky'])) {
$arguments['stopOnRisky'] = $phpunitConfiguration['stopOnRisky'];
}

if (isset($phpunitConfiguration['stopOnSkipped']) && !isset($arguments['stopOnSkipped'])) {
$arguments['stopOnSkipped'] = $phpunitConfiguration['stopOnSkipped'];
}

if (isset($phpunitConfiguration['failOnWarning']) && !isset($arguments['failOnWarning'])) {
$arguments['failOnWarning'] = $phpunitConfiguration['failOnWarning'];
}

if (isset($phpunitConfiguration['failOnRisky']) && !isset($arguments['failOnRisky'])) {
$arguments['failOnRisky'] = $phpunitConfiguration['failOnRisky'];
}

if (isset($phpunitConfiguration['timeoutForSmallTests']) && !isset($arguments['timeoutForSmallTests'])) {
$arguments['timeoutForSmallTests'] = $phpunitConfiguration['timeoutForSmallTests'];
}

if (isset($phpunitConfiguration['timeoutForMediumTests']) && !isset($arguments['timeoutForMediumTests'])) {
$arguments['timeoutForMediumTests'] = $phpunitConfiguration['timeoutForMediumTests'];
}

if (isset($phpunitConfiguration['timeoutForLargeTests']) && !isset($arguments['timeoutForLargeTests'])) {
$arguments['timeoutForLargeTests'] = $phpunitConfiguration['timeoutForLargeTests'];
}

if (isset($phpunitConfiguration['reportUselessTests']) && !isset($arguments['reportUselessTests'])) {
$arguments['reportUselessTests'] = $phpunitConfiguration['reportUselessTests'];
}

if (isset($phpunitConfiguration['strictCoverage']) && !isset($arguments['strictCoverage'])) {
$arguments['strictCoverage'] = $phpunitConfiguration['strictCoverage'];
}

if (isset($phpunitConfiguration['ignoreDeprecatedCodeUnitsFromCodeCoverage']) && !isset($arguments['ignoreDeprecatedCodeUnitsFromCodeCoverage'])) {
$arguments['ignoreDeprecatedCodeUnitsFromCodeCoverage'] = $phpunitConfiguration['ignoreDeprecatedCodeUnitsFromCodeCoverage'];
}

if (isset($phpunitConfiguration['disallowTestOutput']) && !isset($arguments['disallowTestOutput'])) {
$arguments['disallowTestOutput'] = $phpunitConfiguration['disallowTestOutput'];
}

if (isset($phpunitConfiguration['defaultTimeLimit']) && !isset($arguments['defaultTimeLimit'])) {
$arguments['defaultTimeLimit'] = $phpunitConfiguration['defaultTimeLimit'];
}

if (isset($phpunitConfiguration['enforceTimeLimit']) && !isset($arguments['enforceTimeLimit'])) {
$arguments['enforceTimeLimit'] = $phpunitConfiguration['enforceTimeLimit'];
}

if (isset($phpunitConfiguration['disallowTodoAnnotatedTests']) && !isset($arguments['disallowTodoAnnotatedTests'])) {
$arguments['disallowTodoAnnotatedTests'] = $phpunitConfiguration['disallowTodoAnnotatedTests'];
}

if (isset($phpunitConfiguration['beStrictAboutResourceUsageDuringSmallTests']) && !isset($arguments['beStrictAboutResourceUsageDuringSmallTests'])) {
$arguments['beStrictAboutResourceUsageDuringSmallTests'] = $phpunitConfiguration['beStrictAboutResourceUsageDuringSmallTests'];
}

if (isset($phpunitConfiguration['verbose']) && !isset($arguments['verbose'])) {
$arguments['verbose'] = $phpunitConfiguration['verbose'];
}

if (isset($phpunitConfiguration['reverseDefectList']) && !isset($arguments['reverseList'])) {
$arguments['reverseList'] = $phpunitConfiguration['reverseDefectList'];
}

if (isset($phpunitConfiguration['forceCoversAnnotation']) && !isset($arguments['forceCoversAnnotation'])) {
$arguments['forceCoversAnnotation'] = $phpunitConfiguration['forceCoversAnnotation'];
}

if (isset($phpunitConfiguration['disableCodeCoverageIgnore']) && !isset($arguments['disableCodeCoverageIgnore'])) {
$arguments['disableCodeCoverageIgnore'] = $phpunitConfiguration['disableCodeCoverageIgnore'];
}

if (isset($phpunitConfiguration['registerMockObjectsFromTestArgumentsRecursively']) && !isset($arguments['registerMockObjectsFromTestArgumentsRecursively'])) {
$arguments['registerMockObjectsFromTestArgumentsRecursively'] = $phpunitConfiguration['registerMockObjectsFromTestArgumentsRecursively'];
}

if (isset($phpunitConfiguration['executionOrder']) && !isset($arguments['executionOrder'])) {
$arguments['executionOrder'] = $phpunitConfiguration['executionOrder'];
}

if (isset($phpunitConfiguration['executionOrderDefects']) && !isset($arguments['executionOrderDefects'])) {
$arguments['executionOrderDefects'] = $phpunitConfiguration['executionOrderDefects'];
}

if (isset($phpunitConfiguration['resolveDependencies']) && !isset($arguments['resolveDependencies'])) {
$arguments['resolveDependencies'] = $phpunitConfiguration['resolveDependencies'];
}

if (isset($phpunitConfiguration['noInteraction']) && !isset($arguments['noInteraction'])) {
$arguments['noInteraction'] = $phpunitConfiguration['noInteraction'];
}

if (isset($phpunitConfiguration['conflictBetweenPrinterClassAndTestdox'])) {
$arguments['conflictBetweenPrinterClassAndTestdox'] = true;
}

$groupCliArgs = [];

if (!empty($arguments['groups'])) {
$groupCliArgs = $arguments['groups'];
}

$groupConfiguration = $arguments['configuration']->getGroupConfiguration();

if (!empty($groupConfiguration['include']) && !isset($arguments['groups'])) {
$arguments['groups'] = $groupConfiguration['include'];
}

if (!empty($groupConfiguration['exclude']) && !isset($arguments['excludeGroups'])) {
$arguments['excludeGroups'] = array_diff($groupConfiguration['exclude'], $groupCliArgs);
}

foreach ($arguments['configuration']->getExtensionConfiguration() as $extension) {
if ($extension['file'] !== '' && !class_exists($extension['class'], false)) {
require_once $extension['file'];
}

if (!class_exists($extension['class'])) {
throw new Exception(
sprintf(
'Class "%s" does not exist',
$extension['class']
)
);
}

try {
$extensionClass = new ReflectionClass($extension['class']);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if (!$extensionClass->implementsInterface(Hook::class)) {
throw new Exception(
sprintf(
'Class "%s" does not implement a PHPUnit\Runner\Hook interface',
$extension['class']
)
);
}

if (count($extension['arguments']) === 0) {
$extensionObject = $extensionClass->newInstance();
} else {
$extensionObject = $extensionClass->newInstanceArgs(
$extension['arguments']
);
}

assert($extensionObject instanceof Hook);

$this->addExtension($extensionObject);
}

foreach ($arguments['configuration']->getListenerConfiguration() as $listener) {
if ($listener['file'] !== '' && !class_exists($listener['class'], false)) {
require_once $listener['file'];
}

if (!class_exists($listener['class'])) {
throw new Exception(
sprintf(
'Class "%s" does not exist',
$listener['class']
)
);
}

try {
$listenerClass = new ReflectionClass($listener['class']);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if (!$listenerClass->implementsInterface(TestListener::class)) {
throw new Exception(
sprintf(
'Class "%s" does not implement the PHPUnit\Framework\TestListener interface',
$listener['class']
)
);
}

if (count($listener['arguments']) === 0) {
$listener = new $listener['class'];
} else {
$listener = $listenerClass->newInstanceArgs(
$listener['arguments']
);
}

$arguments['listeners'][] = $listener;
}

$loggingConfiguration = $arguments['configuration']->getLoggingConfiguration();

if (isset($loggingConfiguration['coverage-clover']) && !isset($arguments['coverageClover'])) {
$arguments['coverageClover'] = $loggingConfiguration['coverage-clover'];
}

if (isset($loggingConfiguration['coverage-crap4j']) && !isset($arguments['coverageCrap4J'])) {
$arguments['coverageCrap4J'] = $loggingConfiguration['coverage-crap4j'];

if (isset($loggingConfiguration['crap4jThreshold']) && !isset($arguments['crap4jThreshold'])) {
$arguments['crap4jThreshold'] = $loggingConfiguration['crap4jThreshold'];
}
}

if (isset($loggingConfiguration['coverage-html']) && !isset($arguments['coverageHtml'])) {
if (isset($loggingConfiguration['lowUpperBound']) && !isset($arguments['reportLowUpperBound'])) {
$arguments['reportLowUpperBound'] = $loggingConfiguration['lowUpperBound'];
}

if (isset($loggingConfiguration['highLowerBound']) && !isset($arguments['reportHighLowerBound'])) {
$arguments['reportHighLowerBound'] = $loggingConfiguration['highLowerBound'];
}

$arguments['coverageHtml'] = $loggingConfiguration['coverage-html'];
}

if (isset($loggingConfiguration['coverage-php']) && !isset($arguments['coveragePHP'])) {
$arguments['coveragePHP'] = $loggingConfiguration['coverage-php'];
}

if (isset($loggingConfiguration['coverage-text']) && !isset($arguments['coverageText'])) {
$arguments['coverageText'] = $loggingConfiguration['coverage-text'];
$arguments['coverageTextShowUncoveredFiles'] = $loggingConfiguration['coverageTextShowUncoveredFiles'] ?? false;
$arguments['coverageTextShowOnlySummary'] = $loggingConfiguration['coverageTextShowOnlySummary'] ?? false;
}

if (isset($loggingConfiguration['coverage-xml']) && !isset($arguments['coverageXml'])) {
$arguments['coverageXml'] = $loggingConfiguration['coverage-xml'];
}

if (isset($loggingConfiguration['plain'])) {
$arguments['listeners'][] = new ResultPrinter(
$loggingConfiguration['plain'],
true
);
}

if (isset($loggingConfiguration['teamcity']) && !isset($arguments['teamcityLogfile'])) {
$arguments['teamcityLogfile'] = $loggingConfiguration['teamcity'];
}

if (isset($loggingConfiguration['junit']) && !isset($arguments['junitLogfile'])) {
$arguments['junitLogfile'] = $loggingConfiguration['junit'];
}

if (isset($loggingConfiguration['testdox-html']) && !isset($arguments['testdoxHTMLFile'])) {
$arguments['testdoxHTMLFile'] = $loggingConfiguration['testdox-html'];
}

if (isset($loggingConfiguration['testdox-text']) && !isset($arguments['testdoxTextFile'])) {
$arguments['testdoxTextFile'] = $loggingConfiguration['testdox-text'];
}

if (isset($loggingConfiguration['testdox-xml']) && !isset($arguments['testdoxXMLFile'])) {
$arguments['testdoxXMLFile'] = $loggingConfiguration['testdox-xml'];
}

$testdoxGroupConfiguration = $arguments['configuration']->getTestdoxGroupConfiguration();

if (isset($testdoxGroupConfiguration['include']) &&
!isset($arguments['testdoxGroups'])) {
$arguments['testdoxGroups'] = $testdoxGroupConfiguration['include'];
}

if (isset($testdoxGroupConfiguration['exclude']) &&
!isset($arguments['testdoxExcludeGroups'])) {
$arguments['testdoxExcludeGroups'] = $testdoxGroupConfiguration['exclude'];
}
}

$arguments['addUncoveredFilesFromWhitelist'] = $arguments['addUncoveredFilesFromWhitelist'] ?? true;
$arguments['backupGlobals'] = $arguments['backupGlobals'] ?? null;
$arguments['backupStaticAttributes'] = $arguments['backupStaticAttributes'] ?? null;
$arguments['beStrictAboutChangesToGlobalState'] = $arguments['beStrictAboutChangesToGlobalState'] ?? null;
$arguments['beStrictAboutResourceUsageDuringSmallTests'] = $arguments['beStrictAboutResourceUsageDuringSmallTests'] ?? false;
$arguments['cacheResult'] = $arguments['cacheResult'] ?? true;
$arguments['cacheTokens'] = $arguments['cacheTokens'] ?? false;
$arguments['colors'] = $arguments['colors'] ?? ResultPrinter::COLOR_DEFAULT;
$arguments['columns'] = $arguments['columns'] ?? 80;
$arguments['convertDeprecationsToExceptions'] = $arguments['convertDeprecationsToExceptions'] ?? false;
$arguments['convertErrorsToExceptions'] = $arguments['convertErrorsToExceptions'] ?? true;
$arguments['convertNoticesToExceptions'] = $arguments['convertNoticesToExceptions'] ?? true;
$arguments['convertWarningsToExceptions'] = $arguments['convertWarningsToExceptions'] ?? true;
$arguments['crap4jThreshold'] = $arguments['crap4jThreshold'] ?? 30;
$arguments['disallowTestOutput'] = $arguments['disallowTestOutput'] ?? false;
$arguments['disallowTodoAnnotatedTests'] = $arguments['disallowTodoAnnotatedTests'] ?? false;
$arguments['defaultTimeLimit'] = $arguments['defaultTimeLimit'] ?? 0;
$arguments['enforceTimeLimit'] = $arguments['enforceTimeLimit'] ?? false;
$arguments['excludeGroups'] = $arguments['excludeGroups'] ?? [];
$arguments['executionOrder'] = $arguments['executionOrder'] ?? TestSuiteSorter::ORDER_DEFAULT;
$arguments['executionOrderDefects'] = $arguments['executionOrderDefects'] ?? TestSuiteSorter::ORDER_DEFAULT;
$arguments['failOnRisky'] = $arguments['failOnRisky'] ?? false;
$arguments['failOnWarning'] = $arguments['failOnWarning'] ?? false;
$arguments['groups'] = $arguments['groups'] ?? [];
$arguments['noInteraction'] = $arguments['noInteraction'] ?? false;
$arguments['processIsolation'] = $arguments['processIsolation'] ?? false;
$arguments['processUncoveredFilesFromWhitelist'] = $arguments['processUncoveredFilesFromWhitelist'] ?? false;
$arguments['randomOrderSeed'] = $arguments['randomOrderSeed'] ?? time();
$arguments['registerMockObjectsFromTestArgumentsRecursively'] = $arguments['registerMockObjectsFromTestArgumentsRecursively'] ?? false;
$arguments['repeat'] = $arguments['repeat'] ?? false;
$arguments['reportHighLowerBound'] = $arguments['reportHighLowerBound'] ?? 90;
$arguments['reportLowUpperBound'] = $arguments['reportLowUpperBound'] ?? 50;
$arguments['reportUselessTests'] = $arguments['reportUselessTests'] ?? true;
$arguments['reverseList'] = $arguments['reverseList'] ?? false;
$arguments['resolveDependencies'] = $arguments['resolveDependencies'] ?? true;
$arguments['stopOnError'] = $arguments['stopOnError'] ?? false;
$arguments['stopOnFailure'] = $arguments['stopOnFailure'] ?? false;
$arguments['stopOnIncomplete'] = $arguments['stopOnIncomplete'] ?? false;
$arguments['stopOnRisky'] = $arguments['stopOnRisky'] ?? false;
$arguments['stopOnSkipped'] = $arguments['stopOnSkipped'] ?? false;
$arguments['stopOnWarning'] = $arguments['stopOnWarning'] ?? false;
$arguments['stopOnDefect'] = $arguments['stopOnDefect'] ?? false;
$arguments['strictCoverage'] = $arguments['strictCoverage'] ?? false;
$arguments['testdoxExcludeGroups'] = $arguments['testdoxExcludeGroups'] ?? [];
$arguments['testdoxGroups'] = $arguments['testdoxGroups'] ?? [];
$arguments['timeoutForLargeTests'] = $arguments['timeoutForLargeTests'] ?? 60;
$arguments['timeoutForMediumTests'] = $arguments['timeoutForMediumTests'] ?? 10;
$arguments['timeoutForSmallTests'] = $arguments['timeoutForSmallTests'] ?? 1;
$arguments['verbose'] = $arguments['verbose'] ?? false;
}

private function processSuiteFilters(TestSuite $suite, array $arguments): void
{
if (!$arguments['filter'] &&
empty($arguments['groups']) &&
empty($arguments['excludeGroups'])) {
return;
}

$filterFactory = new Factory;

if (!empty($arguments['excludeGroups'])) {
$filterFactory->addFilter(
new ReflectionClass(ExcludeGroupFilterIterator::class),
$arguments['excludeGroups']
);
}

if (!empty($arguments['groups'])) {
$filterFactory->addFilter(
new ReflectionClass(IncludeGroupFilterIterator::class),
$arguments['groups']
);
}

if ($arguments['filter']) {
$filterFactory->addFilter(
new ReflectionClass(NameFilterIterator::class),
$arguments['filter']
);
}

$suite->injectFilter($filterFactory);
}

private function writeMessage(string $type, string $message): void
{
if (!$this->messagePrinted) {
$this->write("\n");
}

$this->write(
sprintf(
"%-15s%s\n",
$type . ':',
$message
)
);

$this->messagePrinted = true;
}








private function createPrinter(string $class, array $arguments): Printer
{
return new $class(
(isset($arguments['stderr']) && $arguments['stderr'] === true) ? 'php://stderr' : null,
$arguments['verbose'],
$arguments['colors'],
$arguments['debug'],
$arguments['columns'],
$arguments['reverseList']
);
}

private function codeCoverageGenerationStart(string $format): void
{
$this->printer->write(
sprintf(
"\nGenerating code coverage report in %s format ... ",
$format
)
);

Timer::start();
}

private function codeCoverageGenerationSucceeded(): void
{
$this->printer->write(
sprintf(
"done [%s]\n",
Timer::secondsToTimeString(Timer::stop())
)
);
}

private function codeCoverageGenerationFailed(\Exception $e): void
{
$this->printer->write(
sprintf(
"failed [%s]\n%s\n",
Timer::secondsToTimeString(Timer::stop()),
$e->getMessage()
)
);
}
}
<?php declare(strict_types=1);








namespace PHPUnit\TextUI;

use RuntimeException;




final class Exception extends RuntimeException implements \PHPUnit\Exception
{
}
<?php declare(strict_types=1);








namespace PHPUnit\TextUI;

use const PHP_EOL;
use function array_map;
use function array_reverse;
use function count;
use function floor;
use function implode;
use function in_array;
use function is_int;
use function max;
use function preg_split;
use function sprintf;
use function str_pad;
use function str_repeat;
use function strlen;
use function vsprintf;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\Exception;
use PHPUnit\Framework\InvalidArgumentException;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestFailure;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestResult;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Framework\Warning;
use PHPUnit\Runner\PhptTestCase;
use PHPUnit\Util\Color;
use PHPUnit\Util\Printer;
use SebastianBergmann\Environment\Console;
use SebastianBergmann\Timer\Timer;
use Throwable;




class ResultPrinter extends Printer implements TestListener
{
public const EVENT_TEST_START = 0;

public const EVENT_TEST_END = 1;

public const EVENT_TESTSUITE_START = 2;

public const EVENT_TESTSUITE_END = 3;

public const COLOR_NEVER = 'never';

public const COLOR_AUTO = 'auto';

public const COLOR_ALWAYS = 'always';

public const COLOR_DEFAULT = self::COLOR_NEVER;

private const AVAILABLE_COLORS = [self::COLOR_NEVER, self::COLOR_AUTO, self::COLOR_ALWAYS];




protected $column = 0;




protected $maxColumn;




protected $lastTestFailed = false;




protected $numAssertions = 0;




protected $numTests = -1;




protected $numTestsRun = 0;




protected $numTestsWidth;




protected $colors = false;




protected $debug = false;




protected $verbose = false;




private $numberOfColumns;




private $reverse;




private $defectListPrinted = false;









public function __construct($out = null, bool $verbose = false, string $colors = self::COLOR_DEFAULT, bool $debug = false, $numberOfColumns = 80, bool $reverse = false)
{
parent::__construct($out);

if (!in_array($colors, self::AVAILABLE_COLORS, true)) {
throw InvalidArgumentException::create(
3,
vsprintf('value from "%s", "%s" or "%s"', self::AVAILABLE_COLORS)
);
}

if (!is_int($numberOfColumns) && $numberOfColumns !== 'max') {
throw InvalidArgumentException::create(5, 'integer or "max"');
}

$console = new Console;
$maxNumberOfColumns = $console->getNumberOfColumns();

if ($numberOfColumns === 'max' || ($numberOfColumns !== 80 && $numberOfColumns > $maxNumberOfColumns)) {
$numberOfColumns = $maxNumberOfColumns;
}

$this->numberOfColumns = $numberOfColumns;
$this->verbose = $verbose;
$this->debug = $debug;
$this->reverse = $reverse;

if ($colors === self::COLOR_AUTO && $console->hasColorSupport()) {
$this->colors = true;
} else {
$this->colors = (self::COLOR_ALWAYS === $colors);
}
}




public function printResult(TestResult $result): void
{
$this->printHeader($result);
$this->printErrors($result);
$this->printWarnings($result);
$this->printFailures($result);
$this->printRisky($result);

if ($this->verbose) {
$this->printIncompletes($result);
$this->printSkipped($result);
}

$this->printFooter($result);
}




public function addError(Test $test, Throwable $t, float $time): void
{
$this->writeProgressWithColor('fg-red, bold', 'E');
$this->lastTestFailed = true;
}




public function addFailure(Test $test, AssertionFailedError $e, float $time): void
{
$this->writeProgressWithColor('bg-red, fg-white', 'F');
$this->lastTestFailed = true;
}




public function addWarning(Test $test, Warning $e, float $time): void
{
$this->writeProgressWithColor('fg-yellow, bold', 'W');
$this->lastTestFailed = true;
}




public function addIncompleteTest(Test $test, Throwable $t, float $time): void
{
$this->writeProgressWithColor('fg-yellow, bold', 'I');
$this->lastTestFailed = true;
}




public function addRiskyTest(Test $test, Throwable $t, float $time): void
{
$this->writeProgressWithColor('fg-yellow, bold', 'R');
$this->lastTestFailed = true;
}




public function addSkippedTest(Test $test, Throwable $t, float $time): void
{
$this->writeProgressWithColor('fg-cyan, bold', 'S');
$this->lastTestFailed = true;
}




public function startTestSuite(TestSuite $suite): void
{
if ($this->numTests == -1) {
$this->numTests = count($suite);
$this->numTestsWidth = strlen((string) $this->numTests);
$this->maxColumn = $this->numberOfColumns - strlen('  /  (XXX%)') - (2 * $this->numTestsWidth);
}
}




public function endTestSuite(TestSuite $suite): void
{
}




public function startTest(Test $test): void
{
if ($this->debug) {
$this->write(
sprintf(
"Test '%s' started\n",
\PHPUnit\Util\Test::describeAsString($test)
)
);
}
}




public function endTest(Test $test, float $time): void
{
if ($this->debug) {
$this->write(
sprintf(
"Test '%s' ended\n",
\PHPUnit\Util\Test::describeAsString($test)
)
);
}

if (!$this->lastTestFailed) {
$this->writeProgress('.');
}

if ($test instanceof TestCase) {
$this->numAssertions += $test->getNumAssertions();
} elseif ($test instanceof PhptTestCase) {
$this->numAssertions++;
}

$this->lastTestFailed = false;

if ($test instanceof TestCase && !$test->hasExpectationOnOutput()) {
$this->write($test->getActualOutput());
}
}

protected function printDefects(array $defects, string $type): void
{
$count = count($defects);

if ($count == 0) {
return;
}

if ($this->defectListPrinted) {
$this->write("\n--\n\n");
}

$this->write(
sprintf(
"There %s %d %s%s:\n",
($count == 1) ? 'was' : 'were',
$count,
$type,
($count == 1) ? '' : 's'
)
);

$i = 1;

if ($this->reverse) {
$defects = array_reverse($defects);
}

foreach ($defects as $defect) {
$this->printDefect($defect, $i++);
}

$this->defectListPrinted = true;
}

protected function printDefect(TestFailure $defect, int $count): void
{
$this->printDefectHeader($defect, $count);
$this->printDefectTrace($defect);
}

protected function printDefectHeader(TestFailure $defect, int $count): void
{
$this->write(
sprintf(
"\n%d) %s\n",
$count,
$defect->getTestName()
)
);
}

protected function printDefectTrace(TestFailure $defect): void
{
$e = $defect->thrownException();
$this->write((string) $e);

while ($e = $e->getPrevious()) {
$this->write("\nCaused by\n" . $e);
}
}

protected function printErrors(TestResult $result): void
{
$this->printDefects($result->errors(), 'error');
}

protected function printFailures(TestResult $result): void
{
$this->printDefects($result->failures(), 'failure');
}

protected function printWarnings(TestResult $result): void
{
$this->printDefects($result->warnings(), 'warning');
}

protected function printIncompletes(TestResult $result): void
{
$this->printDefects($result->notImplemented(), 'incomplete test');
}

protected function printRisky(TestResult $result): void
{
$this->printDefects($result->risky(), 'risky test');
}

protected function printSkipped(TestResult $result): void
{
$this->printDefects($result->skipped(), 'skipped test');
}




protected function printHeader(TestResult $result): void
{
if (count($result) > 0) {
$this->write(PHP_EOL . PHP_EOL . Timer::resourceUsage() . PHP_EOL . PHP_EOL);
}
}

protected function printFooter(TestResult $result): void
{
if (count($result) === 0) {
$this->writeWithColor(
'fg-black, bg-yellow',
'No tests executed!'
);

return;
}

if ($result->wasSuccessfulAndNoTestIsRiskyOrSkippedOrIncomplete()) {
$this->writeWithColor(
'fg-black, bg-green',
sprintf(
'OK (%d test%s, %d assertion%s)',
count($result),
(count($result) == 1) ? '' : 's',
$this->numAssertions,
($this->numAssertions == 1) ? '' : 's'
)
);

return;
}

$color = 'fg-black, bg-yellow';

if ($result->wasSuccessful()) {
if ($this->verbose || !$result->allHarmless()) {
$this->write("\n");
}

$this->writeWithColor(
$color,
'OK, but incomplete, skipped, or risky tests!'
);
} else {
$this->write("\n");

if ($result->errorCount()) {
$color = 'fg-white, bg-red';

$this->writeWithColor(
$color,
'ERRORS!'
);
} elseif ($result->failureCount()) {
$color = 'fg-white, bg-red';

$this->writeWithColor(
$color,
'FAILURES!'
);
} elseif ($result->warningCount()) {
$color = 'fg-black, bg-yellow';

$this->writeWithColor(
$color,
'WARNINGS!'
);
}
}

$this->writeCountString(count($result), 'Tests', $color, true);
$this->writeCountString($this->numAssertions, 'Assertions', $color, true);
$this->writeCountString($result->errorCount(), 'Errors', $color);
$this->writeCountString($result->failureCount(), 'Failures', $color);
$this->writeCountString($result->warningCount(), 'Warnings', $color);
$this->writeCountString($result->skippedCount(), 'Skipped', $color);
$this->writeCountString($result->notImplementedCount(), 'Incomplete', $color);
$this->writeCountString($result->riskyCount(), 'Risky', $color);
$this->writeWithColor($color, '.');
}

protected function writeProgress(string $progress): void
{
if ($this->debug) {
return;
}

$this->write($progress);
$this->column++;
$this->numTestsRun++;

if ($this->column == $this->maxColumn || $this->numTestsRun == $this->numTests) {
if ($this->numTestsRun == $this->numTests) {
$this->write(str_repeat(' ', $this->maxColumn - $this->column));
}

$this->write(
sprintf(
' %' . $this->numTestsWidth . 'd / %' .
$this->numTestsWidth . 'd (%3s%%)',
$this->numTestsRun,
$this->numTests,
floor(($this->numTestsRun / $this->numTests) * 100)
)
);

if ($this->column == $this->maxColumn) {
$this->writeNewLine();
}
}
}

protected function writeNewLine(): void
{
$this->column = 0;
$this->write("\n");
}





protected function colorizeTextBox(string $color, string $buffer): string
{
if (!$this->colors) {
return $buffer;
}

$lines = preg_split('/\r\n|\r|\n/', $buffer);
$padding = max(array_map('\strlen', $lines));

$styledLines = [];

foreach ($lines as $line) {
$styledLines[] = Color::colorize($color, str_pad($line, $padding));
}

return implode(PHP_EOL, $styledLines);
}




protected function writeWithColor(string $color, string $buffer, bool $lf = true): void
{
$this->write($this->colorizeTextBox($color, $buffer));

if ($lf) {
$this->write(PHP_EOL);
}
}




protected function writeProgressWithColor(string $color, string $buffer): void
{
$buffer = $this->colorizeTextBox($color, $buffer);
$this->writeProgress($buffer);
}

private function writeCountString(int $count, string $name, string $color, bool $always = false): void
{
static $first = true;

if ($always || $count > 0) {
$this->writeWithColor(
$color,
sprintf(
'%s%s: %d',
!$first ? ', ' : '',
$name,
$count
),
false
);

$first = false;
}
}
}
<?php declare(strict_types=1);








namespace PHPUnit\TextUI;

use const PHP_EOL;
use function count;
use function explode;
use function max;
use function preg_replace_callback;
use function str_pad;
use function str_repeat;
use function strlen;
use function wordwrap;
use PHPUnit\Util\Color;
use SebastianBergmann\Environment\Console;




final class Help
{
private const LEFT_MARGIN = '  ';

private const HELP_TEXT = [
'Usage' => [
['text' => 'phpunit [options] UnitTest [UnitTest.php]'],
['text' => 'phpunit [options] <directory>'],
],
'Code Coverage Options' => [
['arg' => '--coverage-clover <file>', 'desc' => 'Generate code coverage report in Clover XML format'],
['arg' => '--coverage-crap4j <file>', 'desc' => 'Generate code coverage report in Crap4J XML format'],
['arg' => '--coverage-html <dir>', 'desc' => 'Generate code coverage report in HTML format'],
['arg' => '--coverage-php <file>', 'desc' => 'Export PHP_CodeCoverage object to file'],
['arg' => '--coverage-text=<file>', 'desc' => 'Generate code coverage report in text format [default: standard output]'],
['arg' => '--coverage-xml <dir>', 'desc' => 'Generate code coverage report in PHPUnit XML format'],
['arg' => '--whitelist <dir>', 'desc' => 'Whitelist <dir> for code coverage analysis'],
['arg' => '--disable-coverage-ignore', 'desc' => 'Disable annotations for ignoring code coverage'],
['arg' => '--no-coverage', 'desc' => 'Ignore code coverage configuration'],
['arg' => '--dump-xdebug-filter <file>', 'desc' => 'Generate script to set Xdebug code coverage filter'],
],

'Logging Options' => [
['arg' => '--log-junit <file>', 'desc' => 'Log test execution in JUnit XML format to file'],
['arg' => '--log-teamcity <file>', 'desc' => 'Log test execution in TeamCity format to file'],
['arg' => '--testdox-html <file>', 'desc' => 'Write agile documentation in HTML format to file'],
['arg' => '--testdox-text <file>', 'desc' => 'Write agile documentation in Text format to file'],
['arg' => '--testdox-xml <file>', 'desc' => 'Write agile documentation in XML format to file'],
['arg' => '--reverse-list', 'desc' => 'Print defects in reverse order'],
['arg' => '--no-logging', 'desc' => 'Ignore logging configuration'],
],

'Test Selection Options' => [
['arg' => '--filter <pattern>', 'desc' => 'Filter which tests to run'],
['arg' => '--testsuite <name>', 'desc' => 'Filter which testsuite to run'],
['arg' => '--group <name>', 'desc' => 'Only runs tests from the specified group(s)'],
['arg' => '--exclude-group <name>', 'desc' => 'Exclude tests from the specified group(s)'],
['arg' => '--list-groups', 'desc' => 'List available test groups'],
['arg' => '--list-suites', 'desc' => 'List available test suites'],
['arg' => '--list-tests', 'desc' => 'List available tests'],
['arg' => '--list-tests-xml <file>', 'desc' => 'List available tests in XML format'],
['arg' => '--test-suffix <suffixes>', 'desc' => 'Only search for test in files with specified suffix(es). Default: Test.php,.phpt'],
],

'Test Execution Options' => [
['arg' => '--dont-report-useless-tests', 'desc' => 'Do not report tests that do not test anything'],
['arg' => '--strict-coverage', 'desc' => 'Be strict about @covers annotation usage'],
['arg' => '--strict-global-state', 'desc' => 'Be strict about changes to global state'],
['arg' => '--disallow-test-output', 'desc' => 'Be strict about output during tests'],
['arg' => '--disallow-resource-usage', 'desc' => 'Be strict about resource usage during small tests'],
['arg' => '--enforce-time-limit', 'desc' => 'Enforce time limit based on test size'],
['arg' => '--default-time-limit=<sec>', 'desc' => 'Timeout in seconds for tests without @small, @medium or @large'],
['arg' => '--disallow-todo-tests', 'desc' => 'Disallow @todo-annotated tests'],
['spacer' => ''],

['arg' => '--process-isolation', 'desc' => 'Run each test in a separate PHP process'],
['arg' => '--globals-backup', 'desc' => 'Backup and restore $GLOBALS for each test'],
['arg' => '--static-backup', 'desc' => 'Backup and restore static attributes for each test'],
['spacer' => ''],

['arg' => '--colors=<flag>', 'desc' => 'Use colors in output ("never", "auto" or "always")'],
['arg' => '--columns <n>', 'desc' => 'Number of columns to use for progress output'],
['arg' => '--columns max', 'desc' => 'Use maximum number of columns for progress output'],
['arg' => '--stderr', 'desc' => 'Write to STDERR instead of STDOUT'],
['arg' => '--stop-on-defect', 'desc' => 'Stop execution upon first not-passed test'],
['arg' => '--stop-on-error', 'desc' => 'Stop execution upon first error'],
['arg' => '--stop-on-failure', 'desc' => 'Stop execution upon first error or failure'],
['arg' => '--stop-on-warning', 'desc' => 'Stop execution upon first warning'],
['arg' => '--stop-on-risky', 'desc' => 'Stop execution upon first risky test'],
['arg' => '--stop-on-skipped', 'desc' => 'Stop execution upon first skipped test'],
['arg' => '--stop-on-incomplete', 'desc' => 'Stop execution upon first incomplete test'],
['arg' => '--fail-on-warning', 'desc' => 'Treat tests with warnings as failures'],
['arg' => '--fail-on-risky', 'desc' => 'Treat risky tests as failures'],
['arg' => '-v|--verbose', 'desc' => 'Output more verbose information'],
['arg' => '--debug', 'desc' => 'Display debugging information'],
['spacer' => ''],

['arg' => '--loader <loader>', 'desc' => 'TestSuiteLoader implementation to use'],
['arg' => '--repeat <times>', 'desc' => 'Runs the test(s) repeatedly'],
['arg' => '--teamcity', 'desc' => 'Report test execution progress in TeamCity format'],
['arg' => '--testdox', 'desc' => 'Report test execution progress in TestDox format'],
['arg' => '--testdox-group', 'desc' => 'Only include tests from the specified group(s)'],
['arg' => '--testdox-exclude-group', 'desc' => 'Exclude tests from the specified group(s)'],
['arg' => '--no-interaction', 'desc' => 'Disable TestDox progress animation'],
['arg' => '--printer <printer>', 'desc' => 'TestListener implementation to use'],
['spacer' => ''],

['arg' => '--order-by=<order>', 'desc' => 'Run tests in order: default|defects|duration|no-depends|random|reverse|size'],
['arg' => '--random-order-seed=<N>', 'desc' => 'Use a specific random seed <N> for random order'],
['arg' => '--cache-result', 'desc' => 'Write test results to cache file'],
['arg' => '--do-not-cache-result', 'desc' => 'Do not write test results to cache file'],
],

'Configuration Options' => [
['arg' => '--prepend <file>', 'desc' => 'A PHP script that is included as early as possible'],
['arg' => '--bootstrap <file>', 'desc' => 'A PHP script that is included before the tests run'],
['arg' => '-c|--configuration <file>', 'desc' => 'Read configuration from XML file'],
['arg' => '--no-configuration', 'desc' => 'Ignore default configuration file (phpunit.xml)'],
['arg' => '--no-extensions', 'desc' => 'Do not load PHPUnit extensions'],
['arg' => '--include-path <path(s)>', 'desc' => 'Prepend PHP\'s include_path with given path(s)'],
['arg' => '-d <key[=value]>', 'desc' => 'Sets a php.ini value'],
['arg' => '--generate-configuration', 'desc' => 'Generate configuration file with suggested settings'],
['arg' => '--cache-result-file=<file>', 'desc' => 'Specify result cache path and filename'],
],

'Miscellaneous Options' => [
['arg' => '-h|--help', 'desc' => 'Prints this usage information'],
['arg' => '--version', 'desc' => 'Prints the version and exits'],
['arg' => '--atleast-version <min>', 'desc' => 'Checks that version is greater than min and exits'],
['arg' => '--check-version', 'desc' => 'Check whether PHPUnit is the latest version'],
],

];




private $maxArgLength = 0;




private $maxDescLength;




private $hasColor = false;

public function __construct(?int $width = null, ?bool $withColor = null)
{
if ($width === null) {
$width = (new Console)->getNumberOfColumns();
}

if ($withColor === null) {
$this->hasColor = (new Console)->hasColorSupport();
} else {
$this->hasColor = $withColor;
}

foreach (self::HELP_TEXT as $options) {
foreach ($options as $option) {
if (isset($option['arg'])) {
$this->maxArgLength = max($this->maxArgLength, isset($option['arg']) ? strlen($option['arg']) : 0);
}
}
}

$this->maxDescLength = $width - $this->maxArgLength - 4;
}




public function writeToConsole(): void
{
if ($this->hasColor) {
$this->writeWithColor();
} else {
$this->writePlaintext();
}
}

private function writePlaintext(): void
{
foreach (self::HELP_TEXT as $section => $options) {
print "{$section}:" . PHP_EOL;

if ($section !== 'Usage') {
print PHP_EOL;
}

foreach ($options as $option) {
if (isset($option['spacer'])) {
print PHP_EOL;
}

if (isset($option['text'])) {
print self::LEFT_MARGIN . $option['text'] . PHP_EOL;
}

if (isset($option['arg'])) {
$arg = str_pad($option['arg'], $this->maxArgLength);
print self::LEFT_MARGIN . $arg . ' ' . $option['desc'] . PHP_EOL;
}
}

print PHP_EOL;
}
}

private function writeWithColor(): void
{
foreach (self::HELP_TEXT as $section => $options) {
print Color::colorize('fg-yellow', "{$section}:") . PHP_EOL;

foreach ($options as $option) {
if (isset($option['spacer'])) {
print PHP_EOL;
}

if (isset($option['text'])) {
print self::LEFT_MARGIN . $option['text'] . PHP_EOL;
}

if (isset($option['arg'])) {
$arg = Color::colorize('fg-green', str_pad($option['arg'], $this->maxArgLength));
$arg = preg_replace_callback(
'/(<[^>]+>)/',
static function ($matches)
{
return Color::colorize('fg-cyan', $matches[0]);
},
$arg
);
$desc = explode(PHP_EOL, wordwrap($option['desc'], $this->maxDescLength, PHP_EOL));

print self::LEFT_MARGIN . $arg . ' ' . $desc[0] . PHP_EOL;

for ($i = 1; $i < count($desc); $i++) {
print str_repeat(' ', $this->maxArgLength + 3) . $desc[$i] . PHP_EOL;
}
}
}

print PHP_EOL;
}
}
}
<?php declare(strict_types=1);








namespace PHPUnit\TextUI;

use const PATH_SEPARATOR;
use const PHP_EOL;
use const STDIN;
use function array_keys;
use function assert;
use function class_exists;
use function explode;
use function extension_loaded;
use function fgets;
use function file_exists;
use function file_get_contents;
use function file_put_contents;
use function getcwd;
use function ini_get;
use function ini_set;
use function is_callable;
use function is_dir;
use function is_file;
use function is_numeric;
use function is_string;
use function printf;
use function realpath;
use function sort;
use function sprintf;
use function str_replace;
use function stream_resolve_include_path;
use function strrpos;
use function substr;
use function trim;
use function version_compare;
use PharIo\Manifest\ApplicationName;
use PharIo\Manifest\Exception as ManifestException;
use PharIo\Manifest\ManifestLoader;
use PharIo\Version\Version as PharIoVersion;
use PHPUnit\Framework\Exception;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Runner\StandardTestSuiteLoader;
use PHPUnit\Runner\TestSuiteLoader;
use PHPUnit\Runner\TestSuiteSorter;
use PHPUnit\Runner\Version;
use PHPUnit\Util\Configuration;
use PHPUnit\Util\ConfigurationGenerator;
use PHPUnit\Util\FileLoader;
use PHPUnit\Util\Filesystem;
use PHPUnit\Util\Getopt;
use PHPUnit\Util\Log\TeamCity;
use PHPUnit\Util\Printer;
use PHPUnit\Util\TestDox\CliTestDoxPrinter;
use PHPUnit\Util\TextTestListRenderer;
use PHPUnit\Util\XmlTestListRenderer;
use ReflectionClass;
use ReflectionException;
use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;
use Throwable;





class Command
{



protected $arguments = [
'listGroups' => false,
'listSuites' => false,
'listTests' => false,
'listTestsXml' => false,
'loader' => null,
'useDefaultConfiguration' => true,
'loadedExtensions' => [],
'notLoadedExtensions' => [],
];




protected $options = [];




protected $longOptions = [
'atleast-version=' => null,
'prepend=' => null,
'bootstrap=' => null,
'cache-result' => null,
'do-not-cache-result' => null,
'cache-result-file=' => null,
'check-version' => null,
'colors==' => null,
'columns=' => null,
'configuration=' => null,
'coverage-clover=' => null,
'coverage-crap4j=' => null,
'coverage-html=' => null,
'coverage-php=' => null,
'coverage-text==' => null,
'coverage-xml=' => null,
'debug' => null,
'disallow-test-output' => null,
'disallow-resource-usage' => null,
'disallow-todo-tests' => null,
'default-time-limit=' => null,
'enforce-time-limit' => null,
'exclude-group=' => null,
'filter=' => null,
'generate-configuration' => null,
'globals-backup' => null,
'group=' => null,
'help' => null,
'resolve-dependencies' => null,
'ignore-dependencies' => null,
'include-path=' => null,
'list-groups' => null,
'list-suites' => null,
'list-tests' => null,
'list-tests-xml=' => null,
'loader=' => null,
'log-junit=' => null,
'log-teamcity=' => null,
'no-configuration' => null,
'no-coverage' => null,
'no-logging' => null,
'no-interaction' => null,
'no-extensions' => null,
'order-by=' => null,
'printer=' => null,
'process-isolation' => null,
'repeat=' => null,
'dont-report-useless-tests' => null,
'random-order' => null,
'random-order-seed=' => null,
'reverse-order' => null,
'reverse-list' => null,
'static-backup' => null,
'stderr' => null,
'stop-on-defect' => null,
'stop-on-error' => null,
'stop-on-failure' => null,
'stop-on-warning' => null,
'stop-on-incomplete' => null,
'stop-on-risky' => null,
'stop-on-skipped' => null,
'fail-on-warning' => null,
'fail-on-risky' => null,
'strict-coverage' => null,
'disable-coverage-ignore' => null,
'strict-global-state' => null,
'teamcity' => null,
'testdox' => null,
'testdox-group=' => null,
'testdox-exclude-group=' => null,
'testdox-html=' => null,
'testdox-text=' => null,
'testdox-xml=' => null,
'test-suffix=' => null,
'testsuite=' => null,
'verbose' => null,
'version' => null,
'whitelist=' => null,
'dump-xdebug-filter=' => null,
];




private $warnings = [];




private $versionStringPrinted = false;




public static function main(bool $exit = true): int
{
return (new static)->run($_SERVER['argv'], $exit);
}




public function run(array $argv, bool $exit = true): int
{
$this->handleArguments($argv);

$runner = $this->createRunner();

if ($this->arguments['test'] instanceof Test) {
$suite = $this->arguments['test'];
} else {
$suite = $runner->getTest(
$this->arguments['test'],
$this->arguments['testFile'],
$this->arguments['testSuffixes']
);
}

if ($this->arguments['listGroups']) {
return $this->handleListGroups($suite, $exit);
}

if ($this->arguments['listSuites']) {
return $this->handleListSuites($exit);
}

if ($this->arguments['listTests']) {
return $this->handleListTests($suite, $exit);
}

if ($this->arguments['listTestsXml']) {
return $this->handleListTestsXml($suite, $this->arguments['listTestsXml'], $exit);
}

unset($this->arguments['test'], $this->arguments['testFile']);

try {
$result = $runner->doRun($suite, $this->arguments, $this->warnings, $exit);
} catch (Exception $e) {
print $e->getMessage() . PHP_EOL;
}

$return = TestRunner::FAILURE_EXIT;

if (isset($result) && $result->wasSuccessful()) {
$return = TestRunner::SUCCESS_EXIT;
} elseif (!isset($result) || $result->errorCount() > 0) {
$return = TestRunner::EXCEPTION_EXIT;
}

if ($exit) {
exit($return);
}

return $return;
}




protected function createRunner(): TestRunner
{
return new TestRunner($this->arguments['loader']);
}














































protected function handleArguments(array $argv): void
{
try {
$this->options = Getopt::parse(
$argv,
'd:c:hv',
array_keys($this->longOptions)
);
} catch (Exception $t) {
$this->exitWithErrorMessage($t->getMessage());
}

foreach ($this->options[0] as $option) {
switch ($option[0]) {
case '--colors':
$this->arguments['colors'] = $option[1] ?: ResultPrinter::COLOR_AUTO;

break;

case '--bootstrap':
$this->arguments['bootstrap'] = $option[1];

break;

case '--cache-result':
$this->arguments['cacheResult'] = true;

break;

case '--do-not-cache-result':
$this->arguments['cacheResult'] = false;

break;

case '--cache-result-file':
$this->arguments['cacheResultFile'] = $option[1];

break;

case '--columns':
if (is_numeric($option[1])) {
$this->arguments['columns'] = (int) $option[1];
} elseif ($option[1] === 'max') {
$this->arguments['columns'] = 'max';
}

break;

case 'c':
case '--configuration':
$this->arguments['configuration'] = $option[1];

break;

case '--coverage-clover':
$this->arguments['coverageClover'] = $option[1];

break;

case '--coverage-crap4j':
$this->arguments['coverageCrap4J'] = $option[1];

break;

case '--coverage-html':
$this->arguments['coverageHtml'] = $option[1];

break;

case '--coverage-php':
$this->arguments['coveragePHP'] = $option[1];

break;

case '--coverage-text':
if ($option[1] === null) {
$option[1] = 'php://stdout';
}

$this->arguments['coverageText'] = $option[1];
$this->arguments['coverageTextShowUncoveredFiles'] = false;
$this->arguments['coverageTextShowOnlySummary'] = false;

break;

case '--coverage-xml':
$this->arguments['coverageXml'] = $option[1];

break;

case 'd':
$ini = explode('=', $option[1]);

if (isset($ini[0])) {
if (isset($ini[1])) {
ini_set($ini[0], $ini[1]);
} else {
ini_set($ini[0], '1');
}
}

break;

case '--debug':
$this->arguments['debug'] = true;

break;

case 'h':
case '--help':
$this->showHelp();

exit(TestRunner::SUCCESS_EXIT);

break;

case '--filter':
$this->arguments['filter'] = $option[1];

break;

case '--testsuite':
$this->arguments['testsuite'] = $option[1];

break;

case '--generate-configuration':
$this->printVersionString();

print 'Generating phpunit.xml in ' . getcwd() . PHP_EOL . PHP_EOL;

print 'Bootstrap script (relative to path shown above; default: vendor/autoload.php): ';
$bootstrapScript = trim(fgets(STDIN));

print 'Tests directory (relative to path shown above; default: tests): ';
$testsDirectory = trim(fgets(STDIN));

print 'Source directory (relative to path shown above; default: src): ';
$src = trim(fgets(STDIN));

if ($bootstrapScript === '') {
$bootstrapScript = 'vendor/autoload.php';
}

if ($testsDirectory === '') {
$testsDirectory = 'tests';
}

if ($src === '') {
$src = 'src';
}

$generator = new ConfigurationGenerator;

file_put_contents(
'phpunit.xml',
$generator->generateDefaultConfiguration(
Version::series(),
$bootstrapScript,
$testsDirectory,
$src
)
);

print PHP_EOL . 'Generated phpunit.xml in ' . getcwd() . PHP_EOL;

exit(TestRunner::SUCCESS_EXIT);

break;

case '--group':
$this->arguments['groups'] = explode(',', $option[1]);

break;

case '--exclude-group':
$this->arguments['excludeGroups'] = explode(
',',
$option[1]
);

break;

case '--test-suffix':
$this->arguments['testSuffixes'] = explode(
',',
$option[1]
);

break;

case '--include-path':
$includePath = $option[1];

break;

case '--list-groups':
$this->arguments['listGroups'] = true;

break;

case '--list-suites':
$this->arguments['listSuites'] = true;

break;

case '--list-tests':
$this->arguments['listTests'] = true;

break;

case '--list-tests-xml':
$this->arguments['listTestsXml'] = $option[1];

break;

case '--printer':
$this->arguments['printer'] = $option[1];

break;

case '--loader':
$this->arguments['loader'] = $option[1];

break;

case '--log-junit':
$this->arguments['junitLogfile'] = $option[1];

break;

case '--log-teamcity':
$this->arguments['teamcityLogfile'] = $option[1];

break;

case '--order-by':
$this->handleOrderByOption($option[1]);

break;

case '--process-isolation':
$this->arguments['processIsolation'] = true;

break;

case '--repeat':
$this->arguments['repeat'] = (int) $option[1];

break;

case '--stderr':
$this->arguments['stderr'] = true;

break;

case '--stop-on-defect':
$this->arguments['stopOnDefect'] = true;

break;

case '--stop-on-error':
$this->arguments['stopOnError'] = true;

break;

case '--stop-on-failure':
$this->arguments['stopOnFailure'] = true;

break;

case '--stop-on-warning':
$this->arguments['stopOnWarning'] = true;

break;

case '--stop-on-incomplete':
$this->arguments['stopOnIncomplete'] = true;

break;

case '--stop-on-risky':
$this->arguments['stopOnRisky'] = true;

break;

case '--stop-on-skipped':
$this->arguments['stopOnSkipped'] = true;

break;

case '--fail-on-warning':
$this->arguments['failOnWarning'] = true;

break;

case '--fail-on-risky':
$this->arguments['failOnRisky'] = true;

break;

case '--teamcity':
$this->arguments['printer'] = TeamCity::class;

break;

case '--testdox':
$this->arguments['printer'] = CliTestDoxPrinter::class;

break;

case '--testdox-group':
$this->arguments['testdoxGroups'] = explode(
',',
$option[1]
);

break;

case '--testdox-exclude-group':
$this->arguments['testdoxExcludeGroups'] = explode(
',',
$option[1]
);

break;

case '--testdox-html':
$this->arguments['testdoxHTMLFile'] = $option[1];

break;

case '--testdox-text':
$this->arguments['testdoxTextFile'] = $option[1];

break;

case '--testdox-xml':
$this->arguments['testdoxXMLFile'] = $option[1];

break;

case '--no-configuration':
$this->arguments['useDefaultConfiguration'] = false;

break;

case '--no-extensions':
$this->arguments['noExtensions'] = true;

break;

case '--no-coverage':
$this->arguments['noCoverage'] = true;

break;

case '--no-logging':
$this->arguments['noLogging'] = true;

break;

case '--no-interaction':
$this->arguments['noInteraction'] = true;

break;

case '--globals-backup':
$this->arguments['backupGlobals'] = true;

break;

case '--static-backup':
$this->arguments['backupStaticAttributes'] = true;

break;

case 'v':
case '--verbose':
$this->arguments['verbose'] = true;

break;

case '--atleast-version':
if (version_compare(Version::id(), $option[1], '>=')) {
exit(TestRunner::SUCCESS_EXIT);
}

exit(TestRunner::FAILURE_EXIT);

break;

case '--version':
$this->printVersionString();

exit(TestRunner::SUCCESS_EXIT);

break;

case '--dont-report-useless-tests':
$this->arguments['reportUselessTests'] = false;

break;

case '--strict-coverage':
$this->arguments['strictCoverage'] = true;

break;

case '--disable-coverage-ignore':
$this->arguments['disableCodeCoverageIgnore'] = true;

break;

case '--strict-global-state':
$this->arguments['beStrictAboutChangesToGlobalState'] = true;

break;

case '--disallow-test-output':
$this->arguments['disallowTestOutput'] = true;

break;

case '--disallow-resource-usage':
$this->arguments['beStrictAboutResourceUsageDuringSmallTests'] = true;

break;

case '--default-time-limit':
$this->arguments['defaultTimeLimit'] = (int) $option[1];

break;

case '--enforce-time-limit':
$this->arguments['enforceTimeLimit'] = true;

break;

case '--disallow-todo-tests':
$this->arguments['disallowTodoAnnotatedTests'] = true;

break;

case '--reverse-list':
$this->arguments['reverseList'] = true;

break;

case '--check-version':
$this->handleVersionCheck();

break;

case '--whitelist':
$this->arguments['whitelist'] = $option[1];

break;

case '--random-order':
$this->handleOrderByOption('random');

break;

case '--random-order-seed':
$this->arguments['randomOrderSeed'] = (int) $option[1];

break;

case '--resolve-dependencies':
$this->handleOrderByOption('depends');

break;

case '--ignore-dependencies':
$this->handleOrderByOption('no-depends');

break;

case '--reverse-order':
$this->handleOrderByOption('reverse');

break;

case '--dump-xdebug-filter':
$this->arguments['xdebugFilterFile'] = $option[1];

break;

default:
$optionName = str_replace('--', '', $option[0]);

$handler = null;

if (isset($this->longOptions[$optionName])) {
$handler = $this->longOptions[$optionName];
} elseif (isset($this->longOptions[$optionName . '='])) {
$handler = $this->longOptions[$optionName . '='];
}

if (isset($handler) && is_callable([$this, $handler])) {
$this->{$handler}($option[1]);
}
}
}

$this->handleCustomTestSuite();

if (!isset($this->arguments['testSuffixes'])) {
$this->arguments['testSuffixes'] = ['Test.php', '.phpt'];
}

if (isset($this->options[1][0]) &&
substr($this->options[1][0], -5, 5) !== '.phpt' &&
substr($this->options[1][0], -4, 4) !== '.php' &&
substr($this->options[1][0], -1, 1) !== '/' &&
!is_dir($this->options[1][0])) {
$this->warnings[] = 'Invocation with class name is deprecated';
}

if (!isset($this->arguments['test'])) {
if (isset($this->options[1][0])) {
$this->arguments['test'] = $this->options[1][0];
}

if (isset($this->options[1][1])) {
$testFile = realpath($this->options[1][1]);

if ($testFile === false) {
$this->exitWithErrorMessage(
sprintf(
'Cannot open file "%s".',
$this->options[1][1]
)
);
}
$this->arguments['testFile'] = $testFile;
} else {
$this->arguments['testFile'] = '';
}

if (isset($this->arguments['test']) &&
is_file($this->arguments['test']) &&
strrpos($this->arguments['test'], '.') !== false &&
substr($this->arguments['test'], -5, 5) !== '.phpt') {
$this->arguments['testFile'] = realpath($this->arguments['test']);
$this->arguments['test'] = substr($this->arguments['test'], 0, strrpos($this->arguments['test'], '.'));
}

if (isset($this->arguments['test']) &&
is_string($this->arguments['test']) &&
substr($this->arguments['test'], -5, 5) === '.phpt') {
$suite = new TestSuite;
$suite->addTestFile($this->arguments['test']);
$this->arguments['test'] = $suite;
}
}

if (isset($includePath)) {
ini_set(
'include_path',
$includePath . PATH_SEPARATOR . ini_get('include_path')
);
}

if ($this->arguments['loader'] !== null) {
$this->arguments['loader'] = $this->handleLoader($this->arguments['loader']);
}

if (isset($this->arguments['configuration']) &&
is_dir($this->arguments['configuration'])) {
$configurationFile = $this->arguments['configuration'] . '/phpunit.xml';

if (file_exists($configurationFile)) {
$this->arguments['configuration'] = realpath(
$configurationFile
);
} elseif (file_exists($configurationFile . '.dist')) {
$this->arguments['configuration'] = realpath(
$configurationFile . '.dist'
);
}
} elseif (!isset($this->arguments['configuration']) &&
$this->arguments['useDefaultConfiguration']) {
if (file_exists('phpunit.xml')) {
$this->arguments['configuration'] = realpath('phpunit.xml');
} elseif (file_exists('phpunit.xml.dist')) {
$this->arguments['configuration'] = realpath(
'phpunit.xml.dist'
);
}
}

if (isset($this->arguments['configuration'])) {
try {
$configuration = Configuration::getInstance(
$this->arguments['configuration']
);
} catch (Throwable $t) {
print $t->getMessage() . PHP_EOL;

exit(TestRunner::FAILURE_EXIT);
}

$phpunitConfiguration = $configuration->getPHPUnitConfiguration();

$configuration->handlePHPConfiguration();




if (isset($this->arguments['bootstrap'])) {
$this->handleBootstrap($this->arguments['bootstrap']);
} elseif (isset($phpunitConfiguration['bootstrap'])) {
$this->handleBootstrap($phpunitConfiguration['bootstrap']);
}




if (isset($phpunitConfiguration['stderr']) && !isset($this->arguments['stderr'])) {
$this->arguments['stderr'] = $phpunitConfiguration['stderr'];
}

if (isset($phpunitConfiguration['extensionsDirectory']) && !isset($this->arguments['noExtensions']) && extension_loaded('phar')) {
$this->handleExtensions($phpunitConfiguration['extensionsDirectory']);
}

if (isset($phpunitConfiguration['columns']) && !isset($this->arguments['columns'])) {
$this->arguments['columns'] = $phpunitConfiguration['columns'];
}

if (!isset($this->arguments['printer']) && isset($phpunitConfiguration['printerClass'])) {
$file = $phpunitConfiguration['printerFile'] ?? '';

$this->arguments['printer'] = $this->handlePrinter(
$phpunitConfiguration['printerClass'],
$file
);
}

if (isset($phpunitConfiguration['testSuiteLoaderClass'])) {
$file = $phpunitConfiguration['testSuiteLoaderFile'] ?? '';

$this->arguments['loader'] = $this->handleLoader(
$phpunitConfiguration['testSuiteLoaderClass'],
$file
);
}

if (!isset($this->arguments['testsuite']) && isset($phpunitConfiguration['defaultTestSuite'])) {
$this->arguments['testsuite'] = $phpunitConfiguration['defaultTestSuite'];
}

if (!isset($this->arguments['test'])) {
$testSuite = $configuration->getTestSuiteConfiguration($this->arguments['testsuite'] ?? '');

if ($testSuite !== null) {
$this->arguments['test'] = $testSuite;
}
}
} elseif (isset($this->arguments['bootstrap'])) {
$this->handleBootstrap($this->arguments['bootstrap']);
}

if (isset($this->arguments['printer']) &&
is_string($this->arguments['printer'])) {
$this->arguments['printer'] = $this->handlePrinter($this->arguments['printer']);
}

if (!isset($this->arguments['test'])) {
$this->showHelp();

exit(TestRunner::EXCEPTION_EXIT);
}
}




protected function handleLoader(string $loaderClass, string $loaderFile = ''): ?TestSuiteLoader
{
if (!class_exists($loaderClass, false)) {
if ($loaderFile == '') {
$loaderFile = Filesystem::classNameToFilename(
$loaderClass
);
}

$loaderFile = stream_resolve_include_path($loaderFile);

if ($loaderFile) {
require $loaderFile;
}
}

if (class_exists($loaderClass, false)) {
try {
$class = new ReflectionClass($loaderClass);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}


if ($class->implementsInterface(TestSuiteLoader::class) && $class->isInstantiable()) {
$object = $class->newInstance();

assert($object instanceof TestSuiteLoader);

return $object;
}
}

if ($loaderClass == StandardTestSuiteLoader::class) {
return null;
}

$this->exitWithErrorMessage(
sprintf(
'Could not use "%s" as loader.',
$loaderClass
)
);

return null;
}






protected function handlePrinter(string $printerClass, string $printerFile = '')
{
if (!class_exists($printerClass, false)) {
if ($printerFile == '') {
$printerFile = Filesystem::classNameToFilename(
$printerClass
);
}

$printerFile = stream_resolve_include_path($printerFile);

if ($printerFile) {
require $printerFile;
}
}

if (!class_exists($printerClass)) {
$this->exitWithErrorMessage(
sprintf(
'Could not use "%s" as printer: class does not exist',
$printerClass
)
);
}

try {
$class = new ReflectionClass($printerClass);

 } catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
);

 }

if (!$class->implementsInterface(TestListener::class)) {
$this->exitWithErrorMessage(
sprintf(
'Could not use "%s" as printer: class does not implement %s',
$printerClass,
TestListener::class
)
);
}

if (!$class->isSubclassOf(Printer::class)) {
$this->exitWithErrorMessage(
sprintf(
'Could not use "%s" as printer: class does not extend %s',
$printerClass,
Printer::class
)
);
}

if (!$class->isInstantiable()) {
$this->exitWithErrorMessage(
sprintf(
'Could not use "%s" as printer: class cannot be instantiated',
$printerClass
)
);
}

if ($class->isSubclassOf(ResultPrinter::class)) {
return $printerClass;
}

$outputStream = isset($this->arguments['stderr']) ? 'php://stderr' : null;

return $class->newInstance($outputStream);
}




protected function handleBootstrap(string $filename): void
{
try {
FileLoader::checkAndLoad($filename);
} catch (Exception $e) {
$this->exitWithErrorMessage($e->getMessage());
}
}

protected function handleVersionCheck(): void
{
$this->printVersionString();

$latestVersion = file_get_contents('https://phar.phpunit.de/latest-version-of/phpunit');
$isOutdated = version_compare($latestVersion, Version::id(), '>');

if ($isOutdated) {
printf(
'You are not using the latest version of PHPUnit.' . PHP_EOL .
'The latest version is PHPUnit %s.' . PHP_EOL,
$latestVersion
);
} else {
print 'You are using the latest version of PHPUnit.' . PHP_EOL;
}

exit(TestRunner::SUCCESS_EXIT);
}




protected function showHelp(): void
{
$this->printVersionString();
(new Help)->writeToConsole();
}




protected function handleCustomTestSuite(): void
{
}

private function printVersionString(): void
{
if ($this->versionStringPrinted) {
return;
}

print Version::getVersionString() . PHP_EOL . PHP_EOL;

$this->versionStringPrinted = true;
}

private function exitWithErrorMessage(string $message): void
{
$this->printVersionString();

print $message . PHP_EOL;

exit(TestRunner::FAILURE_EXIT);
}

private function handleExtensions(string $directory): void
{
foreach ((new FileIteratorFacade)->getFilesAsArray($directory, '.phar') as $file) {
if (!file_exists('phar://' . $file . '/manifest.xml')) {
$this->arguments['notLoadedExtensions'][] = $file . ' is not an extension for PHPUnit';

continue;
}

try {
$applicationName = new ApplicationName('phpunit/phpunit');
$version = new PharIoVersion(Version::series());
$manifest = ManifestLoader::fromFile('phar://' . $file . '/manifest.xml');

if (!$manifest->isExtensionFor($applicationName)) {
$this->arguments['notLoadedExtensions'][] = $file . ' is not an extension for PHPUnit';

continue;
}

if (!$manifest->isExtensionFor($applicationName, $version)) {
$this->arguments['notLoadedExtensions'][] = $file . ' is not compatible with this version of PHPUnit';

continue;
}
} catch (ManifestException $e) {
$this->arguments['notLoadedExtensions'][] = $file . ': ' . $e->getMessage();

continue;
}

require $file;

$this->arguments['loadedExtensions'][] = $manifest->getName()->asString() . ' ' . $manifest->getVersion()->getVersionString();
}
}

private function handleListGroups(TestSuite $suite, bool $exit): int
{
$this->printVersionString();

print 'Available test group(s):' . PHP_EOL;

$groups = $suite->getGroups();
sort($groups);

foreach ($groups as $group) {
printf(
' - %s' . PHP_EOL,
$group
);
}

if ($exit) {
exit(TestRunner::SUCCESS_EXIT);
}

return TestRunner::SUCCESS_EXIT;
}




private function handleListSuites(bool $exit): int
{
$this->printVersionString();

print 'Available test suite(s):' . PHP_EOL;

$configuration = Configuration::getInstance(
$this->arguments['configuration']
);

foreach ($configuration->getTestSuiteNames() as $suiteName) {
printf(
' - %s' . PHP_EOL,
$suiteName
);
}

if ($exit) {
exit(TestRunner::SUCCESS_EXIT);
}

return TestRunner::SUCCESS_EXIT;
}




private function handleListTests(TestSuite $suite, bool $exit): int
{
$this->printVersionString();

$renderer = new TextTestListRenderer;

print $renderer->render($suite);

if ($exit) {
exit(TestRunner::SUCCESS_EXIT);
}

return TestRunner::SUCCESS_EXIT;
}




private function handleListTestsXml(TestSuite $suite, string $target, bool $exit): int
{
$this->printVersionString();

$renderer = new XmlTestListRenderer;

file_put_contents($target, $renderer->render($suite));

printf(
'Wrote list of tests that would have been run to %s' . PHP_EOL,
$target
);

if ($exit) {
exit(TestRunner::SUCCESS_EXIT);
}

return TestRunner::SUCCESS_EXIT;
}

private function handleOrderByOption(string $value): void
{
foreach (explode(',', $value) as $order) {
switch ($order) {
case 'default':
$this->arguments['executionOrder'] = TestSuiteSorter::ORDER_DEFAULT;
$this->arguments['executionOrderDefects'] = TestSuiteSorter::ORDER_DEFAULT;
$this->arguments['resolveDependencies'] = true;

break;

case 'defects':
$this->arguments['executionOrderDefects'] = TestSuiteSorter::ORDER_DEFECTS_FIRST;

break;

case 'depends':
$this->arguments['resolveDependencies'] = true;

break;

case 'duration':
$this->arguments['executionOrder'] = TestSuiteSorter::ORDER_DURATION;

break;

case 'no-depends':
$this->arguments['resolveDependencies'] = false;

break;

case 'random':
$this->arguments['executionOrder'] = TestSuiteSorter::ORDER_RANDOMIZED;

break;

case 'reverse':
$this->arguments['executionOrder'] = TestSuiteSorter::ORDER_REVERSED;

break;

case 'size':
$this->arguments['executionOrder'] = TestSuiteSorter::ORDER_SIZE;

break;

default:
$this->exitWithErrorMessage("unrecognized --order-by option: {$order}");
}
}
}
}
<?php declare(strict_types=1);









final class PHP_Token_Util
{
public static function getClass($object): string
{
$parts = explode('\\', get_class($object));

return array_pop($parts);
}
}<?php












class PHP_Token_Stream_CachingFactory
{



protected static $cache = [];






public static function get($filename)
{
if (!isset(self::$cache[$filename])) {
self::$cache[$filename] = new PHP_Token_Stream($filename);
}

return self::$cache[$filename];
}




public static function clear($filename = null)
{
if (is_string($filename)) {
unset(self::$cache[$filename]);
} else {
self::$cache = [];
}
}
}
<?php












class PHP_Token_Stream implements ArrayAccess, Countable, SeekableIterator
{



protected static $customTokens = [
'(' => 'PHP_Token_OPEN_BRACKET',
')' => 'PHP_Token_CLOSE_BRACKET',
'[' => 'PHP_Token_OPEN_SQUARE',
']' => 'PHP_Token_CLOSE_SQUARE',
'{' => 'PHP_Token_OPEN_CURLY',
'}' => 'PHP_Token_CLOSE_CURLY',
';' => 'PHP_Token_SEMICOLON',
'.' => 'PHP_Token_DOT',
',' => 'PHP_Token_COMMA',
'=' => 'PHP_Token_EQUAL',
'<' => 'PHP_Token_LT',
'>' => 'PHP_Token_GT',
'+' => 'PHP_Token_PLUS',
'-' => 'PHP_Token_MINUS',
'*' => 'PHP_Token_MULT',
'/' => 'PHP_Token_DIV',
'?' => 'PHP_Token_QUESTION_MARK',
'!' => 'PHP_Token_EXCLAMATION_MARK',
':' => 'PHP_Token_COLON',
'"' => 'PHP_Token_DOUBLE_QUOTES',
'@' => 'PHP_Token_AT',
'&' => 'PHP_Token_AMPERSAND',
'%' => 'PHP_Token_PERCENT',
'|' => 'PHP_Token_PIPE',
'$' => 'PHP_Token_DOLLAR',
'^' => 'PHP_Token_CARET',
'~' => 'PHP_Token_TILDE',
'`' => 'PHP_Token_BACKTICK'
];




protected $filename;




protected $tokens = [];




protected $position = 0;




protected $linesOfCode = ['loc' => 0, 'cloc' => 0, 'ncloc' => 0];




protected $classes;




protected $functions;




protected $includes;




protected $interfaces;




protected $traits;




protected $lineToFunctionMap = [];






public function __construct($sourceCode)
{
if (is_file($sourceCode)) {
$this->filename = $sourceCode;
$sourceCode = file_get_contents($sourceCode);
}

$this->scan($sourceCode);
}




public function __destruct()
{
$this->tokens = [];
}




public function __toString()
{
$buffer = '';

foreach ($this as $token) {
$buffer .= $token;
}

return $buffer;
}




public function getFilename()
{
return $this->filename;
}







protected function scan($sourceCode)
{
$id = 0;
$line = 1;
$tokens = token_get_all($sourceCode);
$numTokens = count($tokens);

$lastNonWhitespaceTokenWasDoubleColon = false;

for ($i = 0; $i < $numTokens; ++$i) {
$token = $tokens[$i];
$skip = 0;

if (is_array($token)) {
$name = substr(token_name($token[0]), 2);
$text = $token[1];

if ($lastNonWhitespaceTokenWasDoubleColon && $name == 'CLASS') {
$name = 'CLASS_NAME_CONSTANT';
} elseif ($name == 'USE' && isset($tokens[$i + 2][0]) && $tokens[$i + 2][0] == T_FUNCTION) {
$name = 'USE_FUNCTION';
$text .= $tokens[$i + 1][1] . $tokens[$i + 2][1];
$skip = 2;
}

$tokenClass = 'PHP_Token_' . $name;
} else {
$text = $token;
$tokenClass = self::$customTokens[$token];
}

$this->tokens[] = new $tokenClass($text, $line, $this, $id++);
$lines = substr_count($text, "\n");
$line += $lines;

if ($tokenClass == 'PHP_Token_HALT_COMPILER') {
break;
} elseif ($tokenClass == 'PHP_Token_COMMENT' ||
$tokenClass == 'PHP_Token_DOC_COMMENT') {
$this->linesOfCode['cloc'] += $lines + 1;
}

if ($name == 'DOUBLE_COLON') {
$lastNonWhitespaceTokenWasDoubleColon = true;
} elseif ($name != 'WHITESPACE') {
$lastNonWhitespaceTokenWasDoubleColon = false;
}

$i += $skip;
}

$this->linesOfCode['loc'] = substr_count($sourceCode, "\n");
$this->linesOfCode['ncloc'] = $this->linesOfCode['loc'] -
$this->linesOfCode['cloc'];
}

public function count(): int
{
return count($this->tokens);
}




public function tokens()
{
return $this->tokens;
}




public function getClasses()
{
if ($this->classes !== null) {
return $this->classes;
}

$this->parse();

return $this->classes;
}




public function getFunctions()
{
if ($this->functions !== null) {
return $this->functions;
}

$this->parse();

return $this->functions;
}




public function getInterfaces()
{
if ($this->interfaces !== null) {
return $this->interfaces;
}

$this->parse();

return $this->interfaces;
}




public function getTraits()
{
if ($this->traits !== null) {
return $this->traits;
}

$this->parse();

return $this->traits;
}

















public function getIncludes($categorize = false, $category = null)
{
if ($this->includes === null) {
$this->includes = [
'require_once' => [],
'require' => [],
'include_once' => [],
'include' => []
];

foreach ($this->tokens as $token) {
switch (PHP_Token_Util::getClass($token)) {
case 'PHP_Token_REQUIRE_ONCE':
case 'PHP_Token_REQUIRE':
case 'PHP_Token_INCLUDE_ONCE':
case 'PHP_Token_INCLUDE':
$this->includes[$token->getType()][] = $token->getName();
break;
}
}
}

if (isset($this->includes[$category])) {
$includes = $this->includes[$category];
} elseif ($categorize === false) {
$includes = array_merge(
$this->includes['require_once'],
$this->includes['require'],
$this->includes['include_once'],
$this->includes['include']
);
} else {
$includes = $this->includes;
}

return $includes;
}






public function getFunctionForLine($line)
{
$this->parse();

if (isset($this->lineToFunctionMap[$line])) {
return $this->lineToFunctionMap[$line];
}
}

protected function parse()
{
$this->interfaces = [];
$this->classes = [];
$this->traits = [];
$this->functions = [];
$class = [];
$classEndLine = [];
$trait = false;
$traitEndLine = false;
$interface = false;
$interfaceEndLine = false;

foreach ($this->tokens as $token) {
switch (PHP_Token_Util::getClass($token)) {
case 'PHP_Token_HALT_COMPILER':
return;

case 'PHP_Token_INTERFACE':
$interface = $token->getName();
$interfaceEndLine = $token->getEndLine();

$this->interfaces[$interface] = [
'methods' => [],
'parent' => $token->getParent(),
'keywords' => $token->getKeywords(),
'docblock' => $token->getDocblock(),
'startLine' => $token->getLine(),
'endLine' => $interfaceEndLine,
'package' => $token->getPackage(),
'file' => $this->filename
];
break;

case 'PHP_Token_CLASS':
case 'PHP_Token_TRAIT':
$tmp = [
'methods' => [],
'parent' => $token->getParent(),
'interfaces'=> $token->getInterfaces(),
'keywords' => $token->getKeywords(),
'docblock' => $token->getDocblock(),
'startLine' => $token->getLine(),
'endLine' => $token->getEndLine(),
'package' => $token->getPackage(),
'file' => $this->filename
];

if ($token->getName() !== null) {
if ($token instanceof PHP_Token_CLASS) {
$class[] = $token->getName();
$classEndLine[] = $token->getEndLine();

$this->classes[$class[count($class) - 1]] = $tmp;
} else {
$trait = $token->getName();
$traitEndLine = $token->getEndLine();
$this->traits[$trait] = $tmp;
}
}
break;

case 'PHP_Token_FUNCTION':
$name = $token->getName();
$tmp = [
'docblock' => $token->getDocblock(),
'keywords' => $token->getKeywords(),
'visibility'=> $token->getVisibility(),
'signature' => $token->getSignature(),
'startLine' => $token->getLine(),
'endLine' => $token->getEndLine(),
'ccn' => $token->getCCN(),
'file' => $this->filename
];

if (empty($class) &&
$trait === false &&
$interface === false) {
$this->functions[$name] = $tmp;

$this->addFunctionToMap(
$name,
$tmp['startLine'],
$tmp['endLine']
);
} elseif (!empty($class)) {
$this->classes[$class[count($class) - 1]]['methods'][$name] = $tmp;

$this->addFunctionToMap(
$class[count($class) - 1] . '::' . $name,
$tmp['startLine'],
$tmp['endLine']
);
} elseif ($trait !== false) {
$this->traits[$trait]['methods'][$name] = $tmp;

$this->addFunctionToMap(
$trait . '::' . $name,
$tmp['startLine'],
$tmp['endLine']
);
} else {
$this->interfaces[$interface]['methods'][$name] = $tmp;
}
break;

case 'PHP_Token_CLOSE_CURLY':
if (!empty($classEndLine) &&
$classEndLine[count($classEndLine) - 1] == $token->getLine()) {
array_pop($classEndLine);
array_pop($class);
} elseif ($traitEndLine !== false &&
$traitEndLine == $token->getLine()) {
$trait = false;
$traitEndLine = false;
} elseif ($interfaceEndLine !== false &&
$interfaceEndLine == $token->getLine()) {
$interface = false;
$interfaceEndLine = false;
}
break;
}
}
}




public function getLinesOfCode()
{
return $this->linesOfCode;
}

public function rewind(): void
{
$this->position = 0;
}

public function valid(): bool
{
return isset($this->tokens[$this->position]);
}


 public function key()
{
return $this->position;
}


 public function current()
{
return $this->tokens[$this->position];
}

public function next(): void
{
$this->position++;
}




public function offsetExists($offset): bool
{
return isset($this->tokens[$offset]);
}


 public function offsetGet($offset)
{
if (!$this->offsetExists($offset)) {
throw new OutOfBoundsException(
sprintf(
'No token at position "%s"',
$offset
)
);
}

return $this->tokens[$offset];
}





public function offsetSet($offset, $value): void
{
$this->tokens[$offset] = $value;
}






public function offsetUnset($offset): void
{
if (!$this->offsetExists($offset)) {
throw new OutOfBoundsException(
sprintf(
'No token at position "%s"',
$offset
)
);
}

unset($this->tokens[$offset]);
}








public function seek($position): void
{
$this->position = $position;

if (!$this->valid()) {
throw new OutOfBoundsException(
sprintf(
'No token at position "%s"',
$this->position
)
);
}
}






private function addFunctionToMap($name, $startLine, $endLine)
{
for ($line = $startLine; $line <= $endLine; $line++) {
$this->lineToFunctionMap[$line] = $name;
}
}
}
<?php












abstract class PHP_Token
{



protected $text;




protected $line;




protected $tokenStream;




protected $id;







public function __construct($text, $line, PHP_Token_Stream $tokenStream, $id)
{
$this->text = $text;
$this->line = $line;
$this->tokenStream = $tokenStream;
$this->id = $id;
}




public function __toString()
{
return $this->text;
}




public function getLine()
{
return $this->line;
}




public function getId()
{
return $this->id;
}
}

abstract class PHP_TokenWithScope extends PHP_Token
{



protected $endTokenId;










public function getDocblock()
{
$tokens = $this->tokenStream->tokens();
$currentLineNumber = $tokens[$this->id]->getLine();
$prevLineNumber = $currentLineNumber - 1;

for ($i = $this->id - 1; $i; $i--) {
if (!isset($tokens[$i])) {
return;
}

if ($tokens[$i] instanceof PHP_Token_FUNCTION ||
$tokens[$i] instanceof PHP_Token_CLASS ||
$tokens[$i] instanceof PHP_Token_TRAIT) {

 
 break;
}

$line = $tokens[$i]->getLine();

if ($line == $currentLineNumber ||
($line == $prevLineNumber &&
$tokens[$i] instanceof PHP_Token_WHITESPACE)) {
continue;
}

if ($line < $currentLineNumber &&
!$tokens[$i] instanceof PHP_Token_DOC_COMMENT) {
break;
}

return (string) $tokens[$i];
}
}




public function getEndTokenId()
{
$block = 0;
$i = $this->id;
$tokens = $this->tokenStream->tokens();

while ($this->endTokenId === null && isset($tokens[$i])) {
if ($tokens[$i] instanceof PHP_Token_OPEN_CURLY ||
$tokens[$i] instanceof PHP_Token_DOLLAR_OPEN_CURLY_BRACES ||
$tokens[$i] instanceof PHP_Token_CURLY_OPEN) {
$block++;
} elseif ($tokens[$i] instanceof PHP_Token_CLOSE_CURLY) {
$block--;

if ($block === 0) {
$this->endTokenId = $i;
}
} elseif (($this instanceof PHP_Token_FUNCTION ||
$this instanceof PHP_Token_NAMESPACE) &&
$tokens[$i] instanceof PHP_Token_SEMICOLON) {
if ($block === 0) {
$this->endTokenId = $i;
}
}

$i++;
}

if ($this->endTokenId === null) {
$this->endTokenId = $this->id;
}

return $this->endTokenId;
}




public function getEndLine()
{
return $this->tokenStream[$this->getEndTokenId()]->getLine();
}
}

abstract class PHP_TokenWithScopeAndVisibility extends PHP_TokenWithScope
{



public function getVisibility()
{
$tokens = $this->tokenStream->tokens();

for ($i = $this->id - 2; $i > $this->id - 7; $i -= 2) {
if (isset($tokens[$i]) &&
($tokens[$i] instanceof PHP_Token_PRIVATE ||
$tokens[$i] instanceof PHP_Token_PROTECTED ||
$tokens[$i] instanceof PHP_Token_PUBLIC)) {
return strtolower(
str_replace('PHP_Token_', '', PHP_Token_Util::getClass($tokens[$i]))
);
}
if (isset($tokens[$i]) &&
!($tokens[$i] instanceof PHP_Token_STATIC ||
$tokens[$i] instanceof PHP_Token_FINAL ||
$tokens[$i] instanceof PHP_Token_ABSTRACT)) {

 break;
}
}
}




public function getKeywords()
{
$keywords = [];
$tokens = $this->tokenStream->tokens();

for ($i = $this->id - 2; $i > $this->id - 7; $i -= 2) {
if (isset($tokens[$i]) &&
($tokens[$i] instanceof PHP_Token_PRIVATE ||
$tokens[$i] instanceof PHP_Token_PROTECTED ||
$tokens[$i] instanceof PHP_Token_PUBLIC)) {
continue;
}

if (isset($tokens[$i]) &&
($tokens[$i] instanceof PHP_Token_STATIC ||
$tokens[$i] instanceof PHP_Token_FINAL ||
$tokens[$i] instanceof PHP_Token_ABSTRACT)) {
$keywords[] = strtolower(
str_replace('PHP_Token_', '', PHP_Token_Util::getClass($tokens[$i]))
);
}
}

return implode(',', $keywords);
}
}

abstract class PHP_Token_Includes extends PHP_Token
{



protected $name;




protected $type;




public function getName()
{
if ($this->name === null) {
$this->process();
}

return $this->name;
}




public function getType()
{
if ($this->type === null) {
$this->process();
}

return $this->type;
}

private function process()
{
$tokens = $this->tokenStream->tokens();

if ($tokens[$this->id + 2] instanceof PHP_Token_CONSTANT_ENCAPSED_STRING) {
$this->name = trim($tokens[$this->id + 2], "'\"");
$this->type = strtolower(
str_replace('PHP_Token_', '', PHP_Token_Util::getClass($tokens[$this->id]))
);
}
}
}

class PHP_Token_FUNCTION extends PHP_TokenWithScopeAndVisibility
{



protected $arguments;




protected $ccn;




protected $name;




protected $signature;




private $anonymous = false;




public function getArguments()
{
if ($this->arguments !== null) {
return $this->arguments;
}

$this->arguments = [];
$tokens = $this->tokenStream->tokens();
$typeDeclaration = null;


 $i = $this->id + 2;

while (!$tokens[$i - 1] instanceof PHP_Token_OPEN_BRACKET) {
$i++;
}

while (!$tokens[$i] instanceof PHP_Token_CLOSE_BRACKET) {
if ($tokens[$i] instanceof PHP_Token_STRING) {
$typeDeclaration = (string) $tokens[$i];
} elseif ($tokens[$i] instanceof PHP_Token_VARIABLE) {
$this->arguments[(string) $tokens[$i]] = $typeDeclaration;
$typeDeclaration = null;
}

$i++;
}

return $this->arguments;
}




public function getName()
{
if ($this->name !== null) {
return $this->name;
}

$tokens = $this->tokenStream->tokens();

$i = $this->id + 1;

if ($tokens[$i] instanceof PHP_Token_WHITESPACE) {
$i++;
}

if ($tokens[$i] instanceof PHP_Token_AMPERSAND) {
$i++;
}

if ($tokens[$i + 1] instanceof PHP_Token_OPEN_BRACKET) {
$this->name = (string) $tokens[$i];
} elseif ($tokens[$i + 1] instanceof PHP_Token_WHITESPACE && $tokens[$i + 2] instanceof PHP_Token_OPEN_BRACKET) {
$this->name = (string) $tokens[$i];
} else {
$this->anonymous = true;

$this->name = sprintf(
'anonymousFunction:%s#%s',
$this->getLine(),
$this->getId()
);
}

if (!$this->isAnonymous()) {
for ($i = $this->id; $i; --$i) {
if ($tokens[$i] instanceof PHP_Token_NAMESPACE) {
$this->name = $tokens[$i]->getName() . '\\' . $this->name;

break;
}

if ($tokens[$i] instanceof PHP_Token_INTERFACE) {
break;
}
}
}

return $this->name;
}




public function getCCN()
{
if ($this->ccn !== null) {
return $this->ccn;
}

$this->ccn = 1;
$end = $this->getEndTokenId();
$tokens = $this->tokenStream->tokens();

for ($i = $this->id; $i <= $end; $i++) {
switch (PHP_Token_Util::getClass($tokens[$i])) {
case 'PHP_Token_IF':
case 'PHP_Token_ELSEIF':
case 'PHP_Token_FOR':
case 'PHP_Token_FOREACH':
case 'PHP_Token_WHILE':
case 'PHP_Token_CASE':
case 'PHP_Token_CATCH':
case 'PHP_Token_BOOLEAN_AND':
case 'PHP_Token_LOGICAL_AND':
case 'PHP_Token_BOOLEAN_OR':
case 'PHP_Token_LOGICAL_OR':
case 'PHP_Token_QUESTION_MARK':
$this->ccn++;
break;
}
}

return $this->ccn;
}




public function getSignature()
{
if ($this->signature !== null) {
return $this->signature;
}

if ($this->isAnonymous()) {
$this->signature = 'anonymousFunction';
$i = $this->id + 1;
} else {
$this->signature = '';
$i = $this->id + 2;
}

$tokens = $this->tokenStream->tokens();

while (isset($tokens[$i]) &&
!$tokens[$i] instanceof PHP_Token_OPEN_CURLY &&
!$tokens[$i] instanceof PHP_Token_SEMICOLON) {
$this->signature .= $tokens[$i++];
}

$this->signature = trim($this->signature);

return $this->signature;
}




public function isAnonymous()
{
return $this->anonymous;
}
}

class PHP_Token_INTERFACE extends PHP_TokenWithScopeAndVisibility
{



protected $interfaces;




public function getName()
{
return (string) $this->tokenStream[$this->id + 2];
}




public function hasParent()
{
return $this->tokenStream[$this->id + 4] instanceof PHP_Token_EXTENDS;
}




public function getPackage()
{
$className = $this->getName();
$docComment = $this->getDocblock();

$result = [
'namespace' => '',
'fullPackage' => '',
'category' => '',
'package' => '',
'subpackage' => ''
];

for ($i = $this->id; $i; --$i) {
if ($this->tokenStream[$i] instanceof PHP_Token_NAMESPACE) {
$result['namespace'] = $this->tokenStream[$i]->getName();
break;
}
}

if (preg_match('/@category[\s]+([\.\w]+)/', $docComment, $matches)) {
$result['category'] = $matches[1];
}

if (preg_match('/@package[\s]+([\.\w]+)/', $docComment, $matches)) {
$result['package'] = $matches[1];
$result['fullPackage'] = $matches[1];
}

if (preg_match('/@subpackage[\s]+([\.\w]+)/', $docComment, $matches)) {
$result['subpackage'] = $matches[1];
$result['fullPackage'] .= '.' . $matches[1];
}

if (empty($result['fullPackage'])) {
$result['fullPackage'] = $this->arrayToName(
explode('_', str_replace('\\', '_', $className)),
'.'
);
}

return $result;
}







protected function arrayToName(array $parts, $join = '\\')
{
$result = '';

if (count($parts) > 1) {
array_pop($parts);

$result = implode($join, $parts);
}

return $result;
}




public function getParent()
{
if (!$this->hasParent()) {
return false;
}

$i = $this->id + 6;
$tokens = $this->tokenStream->tokens();
$className = (string) $tokens[$i];

while (isset($tokens[$i + 1]) &&
!$tokens[$i + 1] instanceof PHP_Token_WHITESPACE) {
$className .= (string) $tokens[++$i];
}

return $className;
}




public function hasInterfaces()
{
return (isset($this->tokenStream[$this->id + 4]) &&
$this->tokenStream[$this->id + 4] instanceof PHP_Token_IMPLEMENTS) ||
(isset($this->tokenStream[$this->id + 8]) &&
$this->tokenStream[$this->id + 8] instanceof PHP_Token_IMPLEMENTS);
}




public function getInterfaces()
{
if ($this->interfaces !== null) {
return $this->interfaces;
}

if (!$this->hasInterfaces()) {
return ($this->interfaces = false);
}

if ($this->tokenStream[$this->id + 4] instanceof PHP_Token_IMPLEMENTS) {
$i = $this->id + 3;
} else {
$i = $this->id + 7;
}

$tokens = $this->tokenStream->tokens();

while (!$tokens[$i + 1] instanceof PHP_Token_OPEN_CURLY) {
$i++;

if ($tokens[$i] instanceof PHP_Token_STRING) {
$this->interfaces[] = (string) $tokens[$i];
}
}

return $this->interfaces;
}
}

class PHP_Token_ABSTRACT extends PHP_Token
{
}

class PHP_Token_AMPERSAND extends PHP_Token
{
}

class PHP_Token_AND_EQUAL extends PHP_Token
{
}

class PHP_Token_ARRAY extends PHP_Token
{
}

class PHP_Token_ARRAY_CAST extends PHP_Token
{
}

class PHP_Token_AS extends PHP_Token
{
}

class PHP_Token_AT extends PHP_Token
{
}

class PHP_Token_BACKTICK extends PHP_Token
{
}

class PHP_Token_BAD_CHARACTER extends PHP_Token
{
}

class PHP_Token_BOOLEAN_AND extends PHP_Token
{
}

class PHP_Token_BOOLEAN_OR extends PHP_Token
{
}

class PHP_Token_BOOL_CAST extends PHP_Token
{
}

class PHP_Token_BREAK extends PHP_Token
{
}

class PHP_Token_CARET extends PHP_Token
{
}

class PHP_Token_CASE extends PHP_Token
{
}

class PHP_Token_CATCH extends PHP_Token
{
}

class PHP_Token_CHARACTER extends PHP_Token
{
}

class PHP_Token_CLASS extends PHP_Token_INTERFACE
{



private $anonymous = false;




private $name;




public function getName()
{
if ($this->name !== null) {
return $this->name;
}

$next = $this->tokenStream[$this->id + 1];

if ($next instanceof PHP_Token_WHITESPACE) {
$next = $this->tokenStream[$this->id + 2];
}

if ($next instanceof PHP_Token_STRING) {
$this->name =(string) $next;

return $this->name;
}

if ($next instanceof PHP_Token_OPEN_CURLY ||
$next instanceof PHP_Token_EXTENDS ||
$next instanceof PHP_Token_IMPLEMENTS) {

$this->name = sprintf(
'AnonymousClass:%s#%s',
$this->getLine(),
$this->getId()
);

$this->anonymous = true;

return $this->name;
}
}

public function isAnonymous()
{
return $this->anonymous;
}
}

class PHP_Token_CLASS_C extends PHP_Token
{
}

class PHP_Token_CLASS_NAME_CONSTANT extends PHP_Token
{
}

class PHP_Token_CLONE extends PHP_Token
{
}

class PHP_Token_CLOSE_BRACKET extends PHP_Token
{
}

class PHP_Token_CLOSE_CURLY extends PHP_Token
{
}

class PHP_Token_CLOSE_SQUARE extends PHP_Token
{
}

class PHP_Token_CLOSE_TAG extends PHP_Token
{
}

class PHP_Token_COLON extends PHP_Token
{
}

class PHP_Token_COMMA extends PHP_Token
{
}

class PHP_Token_COMMENT extends PHP_Token
{
}

class PHP_Token_CONCAT_EQUAL extends PHP_Token
{
}

class PHP_Token_CONST extends PHP_Token
{
}

class PHP_Token_CONSTANT_ENCAPSED_STRING extends PHP_Token
{
}

class PHP_Token_CONTINUE extends PHP_Token
{
}

class PHP_Token_CURLY_OPEN extends PHP_Token
{
}

class PHP_Token_DEC extends PHP_Token
{
}

class PHP_Token_DECLARE extends PHP_Token
{
}

class PHP_Token_DEFAULT extends PHP_Token
{
}

class PHP_Token_DIV extends PHP_Token
{
}

class PHP_Token_DIV_EQUAL extends PHP_Token
{
}

class PHP_Token_DNUMBER extends PHP_Token
{
}

class PHP_Token_DO extends PHP_Token
{
}

class PHP_Token_DOC_COMMENT extends PHP_Token
{
}

class PHP_Token_DOLLAR extends PHP_Token
{
}

class PHP_Token_DOLLAR_OPEN_CURLY_BRACES extends PHP_Token
{
}

class PHP_Token_DOT extends PHP_Token
{
}

class PHP_Token_DOUBLE_ARROW extends PHP_Token
{
}

class PHP_Token_DOUBLE_CAST extends PHP_Token
{
}

class PHP_Token_DOUBLE_COLON extends PHP_Token
{
}

class PHP_Token_DOUBLE_QUOTES extends PHP_Token
{
}

class PHP_Token_ECHO extends PHP_Token
{
}

class PHP_Token_ELSE extends PHP_Token
{
}

class PHP_Token_ELSEIF extends PHP_Token
{
}

class PHP_Token_EMPTY extends PHP_Token
{
}

class PHP_Token_ENCAPSED_AND_WHITESPACE extends PHP_Token
{
}

class PHP_Token_ENDDECLARE extends PHP_Token
{
}

class PHP_Token_ENDFOR extends PHP_Token
{
}

class PHP_Token_ENDFOREACH extends PHP_Token
{
}

class PHP_Token_ENDIF extends PHP_Token
{
}

class PHP_Token_ENDSWITCH extends PHP_Token
{
}

class PHP_Token_ENDWHILE extends PHP_Token
{
}

class PHP_Token_END_HEREDOC extends PHP_Token
{
}

class PHP_Token_EQUAL extends PHP_Token
{
}

class PHP_Token_EVAL extends PHP_Token
{
}

class PHP_Token_EXCLAMATION_MARK extends PHP_Token
{
}

class PHP_Token_EXIT extends PHP_Token
{
}

class PHP_Token_EXTENDS extends PHP_Token
{
}

class PHP_Token_FILE extends PHP_Token
{
}

class PHP_Token_FINAL extends PHP_Token
{
}

class PHP_Token_FOR extends PHP_Token
{
}

class PHP_Token_FOREACH extends PHP_Token
{
}

class PHP_Token_FUNC_C extends PHP_Token
{
}

class PHP_Token_GLOBAL extends PHP_Token
{
}

class PHP_Token_GT extends PHP_Token
{
}

class PHP_Token_IF extends PHP_Token
{
}

class PHP_Token_IMPLEMENTS extends PHP_Token
{
}

class PHP_Token_INC extends PHP_Token
{
}

class PHP_Token_INCLUDE extends PHP_Token_Includes
{
}

class PHP_Token_INCLUDE_ONCE extends PHP_Token_Includes
{
}

class PHP_Token_INLINE_HTML extends PHP_Token
{
}

class PHP_Token_INSTANCEOF extends PHP_Token
{
}

class PHP_Token_INT_CAST extends PHP_Token
{
}

class PHP_Token_ISSET extends PHP_Token
{
}

class PHP_Token_IS_EQUAL extends PHP_Token
{
}

class PHP_Token_IS_GREATER_OR_EQUAL extends PHP_Token
{
}

class PHP_Token_IS_IDENTICAL extends PHP_Token
{
}

class PHP_Token_IS_NOT_EQUAL extends PHP_Token
{
}

class PHP_Token_IS_NOT_IDENTICAL extends PHP_Token
{
}

class PHP_Token_IS_SMALLER_OR_EQUAL extends PHP_Token
{
}

class PHP_Token_LINE extends PHP_Token
{
}

class PHP_Token_LIST extends PHP_Token
{
}

class PHP_Token_LNUMBER extends PHP_Token
{
}

class PHP_Token_LOGICAL_AND extends PHP_Token
{
}

class PHP_Token_LOGICAL_OR extends PHP_Token
{
}

class PHP_Token_LOGICAL_XOR extends PHP_Token
{
}

class PHP_Token_LT extends PHP_Token
{
}

class PHP_Token_METHOD_C extends PHP_Token
{
}

class PHP_Token_MINUS extends PHP_Token
{
}

class PHP_Token_MINUS_EQUAL extends PHP_Token
{
}

class PHP_Token_MOD_EQUAL extends PHP_Token
{
}

class PHP_Token_MULT extends PHP_Token
{
}

class PHP_Token_MUL_EQUAL extends PHP_Token
{
}

class PHP_Token_NEW extends PHP_Token
{
}

class PHP_Token_NUM_STRING extends PHP_Token
{
}

class PHP_Token_OBJECT_CAST extends PHP_Token
{
}

class PHP_Token_OBJECT_OPERATOR extends PHP_Token
{
}

class PHP_Token_OPEN_BRACKET extends PHP_Token
{
}

class PHP_Token_OPEN_CURLY extends PHP_Token
{
}

class PHP_Token_OPEN_SQUARE extends PHP_Token
{
}

class PHP_Token_OPEN_TAG extends PHP_Token
{
}

class PHP_Token_OPEN_TAG_WITH_ECHO extends PHP_Token
{
}

class PHP_Token_OR_EQUAL extends PHP_Token
{
}

class PHP_Token_PAAMAYIM_NEKUDOTAYIM extends PHP_Token
{
}

class PHP_Token_PERCENT extends PHP_Token
{
}

class PHP_Token_PIPE extends PHP_Token
{
}

class PHP_Token_PLUS extends PHP_Token
{
}

class PHP_Token_PLUS_EQUAL extends PHP_Token
{
}

class PHP_Token_PRINT extends PHP_Token
{
}

class PHP_Token_PRIVATE extends PHP_Token
{
}

class PHP_Token_PROTECTED extends PHP_Token
{
}

class PHP_Token_PUBLIC extends PHP_Token
{
}

class PHP_Token_QUESTION_MARK extends PHP_Token
{
}

class PHP_Token_REQUIRE extends PHP_Token_Includes
{
}

class PHP_Token_REQUIRE_ONCE extends PHP_Token_Includes
{
}

class PHP_Token_RETURN extends PHP_Token
{
}

class PHP_Token_SEMICOLON extends PHP_Token
{
}

class PHP_Token_SL extends PHP_Token
{
}

class PHP_Token_SL_EQUAL extends PHP_Token
{
}

class PHP_Token_SR extends PHP_Token
{
}

class PHP_Token_SR_EQUAL extends PHP_Token
{
}

class PHP_Token_START_HEREDOC extends PHP_Token
{
}

class PHP_Token_STATIC extends PHP_Token
{
}

class PHP_Token_STRING extends PHP_Token
{
}

class PHP_Token_STRING_CAST extends PHP_Token
{
}

class PHP_Token_STRING_VARNAME extends PHP_Token
{
}

class PHP_Token_SWITCH extends PHP_Token
{
}

class PHP_Token_THROW extends PHP_Token
{
}

class PHP_Token_TILDE extends PHP_Token
{
}

class PHP_Token_TRY extends PHP_Token
{
}

class PHP_Token_UNSET extends PHP_Token
{
}

class PHP_Token_UNSET_CAST extends PHP_Token
{
}

class PHP_Token_USE extends PHP_Token
{
}

class PHP_Token_USE_FUNCTION extends PHP_Token
{
}

class PHP_Token_VAR extends PHP_Token
{
}

class PHP_Token_VARIABLE extends PHP_Token
{
}

class PHP_Token_WHILE extends PHP_Token
{
}

class PHP_Token_WHITESPACE extends PHP_Token
{
}

class PHP_Token_XOR_EQUAL extends PHP_Token
{
}


class PHP_Token_HALT_COMPILER extends PHP_Token
{
}


class PHP_Token_DIR extends PHP_Token
{
}

class PHP_Token_GOTO extends PHP_Token
{
}

class PHP_Token_NAMESPACE extends PHP_TokenWithScope
{



public function getName()
{
$tokens = $this->tokenStream->tokens();
$namespace = (string) $tokens[$this->id + 2];

for ($i = $this->id + 3;; $i += 2) {
if (isset($tokens[$i]) &&
$tokens[$i] instanceof PHP_Token_NS_SEPARATOR) {
$namespace .= '\\' . $tokens[$i + 1];
} else {
break;
}
}

return $namespace;
}
}

class PHP_Token_NS_C extends PHP_Token
{
}

class PHP_Token_NS_SEPARATOR extends PHP_Token
{
}


class PHP_Token_CALLABLE extends PHP_Token
{
}

class PHP_Token_INSTEADOF extends PHP_Token
{
}

class PHP_Token_TRAIT extends PHP_Token_INTERFACE
{
}

class PHP_Token_TRAIT_C extends PHP_Token
{
}


class PHP_Token_FINALLY extends PHP_Token
{
}

class PHP_Token_YIELD extends PHP_Token
{
}


class PHP_Token_ELLIPSIS extends PHP_Token
{
}

class PHP_Token_POW extends PHP_Token
{
}

class PHP_Token_POW_EQUAL extends PHP_Token
{
}


class PHP_Token_COALESCE extends PHP_Token
{
}

class PHP_Token_SPACESHIP extends PHP_Token
{
}

class PHP_Token_YIELD_FROM extends PHP_Token
{
}


class PHP_Token_COALESCE_EQUAL extends PHP_Token
{
}

class PHP_Token_FN extends PHP_Token
{
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Driver;

use SebastianBergmann\CodeCoverage\Filter;
use SebastianBergmann\CodeCoverage\RuntimeException;






final class Xdebug implements Driver
{



private $cacheNumLines = [];




private $filter;




public function __construct(Filter $filter = null)
{
if (!\extension_loaded('xdebug')) {
throw new RuntimeException('This driver requires Xdebug');
}

if (\version_compare(\phpversion('xdebug'), '3', '>=')) {
$mode = \getenv('XDEBUG_MODE');

if ($mode === false) {
$mode = \ini_get('xdebug.mode');
}

if ($mode === false ||
!\in_array('coverage', \explode(',', $mode), true)) {
throw new RuntimeException('XDEBUG_MODE=coverage or xdebug.mode=coverage has to be set');
}
} elseif (!\ini_get('xdebug.coverage_enable')) {
throw new RuntimeException('xdebug.coverage_enable=On has to be set');
}

if ($filter === null) {
$filter = new Filter;
}

$this->filter = $filter;
}




public function start(bool $determineUnusedAndDead = true): void
{
if ($determineUnusedAndDead) {
\xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
} else {
\xdebug_start_code_coverage();
}
}




public function stop(): array
{
$data = \xdebug_get_code_coverage();

\xdebug_stop_code_coverage();

return $this->cleanup($data);
}

private function cleanup(array $data): array
{
foreach (\array_keys($data) as $file) {
unset($data[$file][0]);

if (!$this->filter->isFile($file)) {
continue;
}

$numLines = $this->getNumberOfLinesInFile($file);

foreach (\array_keys($data[$file]) as $line) {
if ($line > $numLines) {
unset($data[$file][$line]);
}
}
}

return $data;
}

private function getNumberOfLinesInFile(string $fileName): int
{
if (!isset($this->cacheNumLines[$fileName])) {
$buffer = \file_get_contents($fileName);
$lines = \substr_count($buffer, "\n");

if (\substr($buffer, -1) !== "\n") {
$lines++;
}

$this->cacheNumLines[$fileName] = $lines;
}

return $this->cacheNumLines[$fileName];
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Driver;




interface Driver
{





public const LINE_EXECUTED = 1;






public const LINE_NOT_EXECUTED = -1;






public const LINE_NOT_EXECUTABLE = -2;




public function start(bool $determineUnusedAndDead = true): void;




public function stop(): array;
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Driver;






final class PCOV implements Driver
{



public function start(bool $determineUnusedAndDead = true): void
{
\pcov\start();
}




public function stop(): array
{
\pcov\stop();

$waiting = \pcov\waiting();
$collect = [];

if ($waiting) {
$collect = \pcov\collect(\pcov\inclusive, $waiting);

\pcov\clear();
}

return $collect;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Driver;

use SebastianBergmann\CodeCoverage\RuntimeException;






final class PHPDBG implements Driver
{



public function __construct()
{
if (\PHP_SAPI !== 'phpdbg') {
throw new RuntimeException(
'This driver requires the PHPDBG SAPI'
);
}

if (!\function_exists('phpdbg_start_oplog')) {
throw new RuntimeException(
'This build of PHPDBG does not support code coverage'
);
}
}




public function start(bool $determineUnusedAndDead = true): void
{
\phpdbg_start_oplog();
}




public function stop(): array
{
static $fetchedLines = [];

$dbgData = \phpdbg_end_oplog();

if ($fetchedLines == []) {
$sourceLines = \phpdbg_get_executable();
} else {
$newFiles = \array_diff(\get_included_files(), \array_keys($fetchedLines));

$sourceLines = [];

if ($newFiles) {
$sourceLines = phpdbg_get_executable(['files' => $newFiles]);
}
}

foreach ($sourceLines as $file => $lines) {
foreach ($lines as $lineNo => $numExecuted) {
$sourceLines[$file][$lineNo] = self::LINE_NOT_EXECUTED;
}
}

$fetchedLines = \array_merge($fetchedLines, $sourceLines);

return $this->detectExecutedLines($fetchedLines, $dbgData);
}




private function detectExecutedLines(array $sourceLines, array $dbgData): array
{
foreach ($dbgData as $file => $coveredLines) {
foreach ($coveredLines as $lineNo => $numExecuted) {

 
 if (isset($sourceLines[$file][$lineNo])) {
$sourceLines[$file][$lineNo] = self::LINE_EXECUTED;
}
}
}

return $sourceLines;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage;




final class Util
{



public static function percent(float $a, float $b, bool $asString = false, bool $fixedWidth = false)
{
if ($asString && $b == 0) {
return '';
}

$percent = 100;

if ($b > 0) {
$percent = ($a / $b) * 100;
}

if ($asString) {
$format = $fixedWidth ? '%6.2F%%' : '%01.2F%%';

return \sprintf($format, $percent);
}

return $percent;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage;

use PHPUnit\Framework\TestCase;
use PHPUnit\Runner\PhptTestCase;
use PHPUnit\Util\Test;
use SebastianBergmann\CodeCoverage\Driver\Driver;
use SebastianBergmann\CodeCoverage\Driver\PCOV;
use SebastianBergmann\CodeCoverage\Driver\PHPDBG;
use SebastianBergmann\CodeCoverage\Driver\Xdebug;
use SebastianBergmann\CodeCoverage\Node\Builder;
use SebastianBergmann\CodeCoverage\Node\Directory;
use SebastianBergmann\CodeUnitReverseLookup\Wizard;
use SebastianBergmann\Environment\Runtime;




final class CodeCoverage
{



private $driver;




private $filter;




private $wizard;




private $cacheTokens = false;




private $checkForUnintentionallyCoveredCode = false;




private $forceCoversAnnotation = false;




private $checkForUnexecutedCoveredCode = false;




private $checkForMissingCoversAnnotation = false;




private $addUncoveredFilesFromWhitelist = true;




private $processUncoveredFilesFromWhitelist = false;




private $ignoreDeprecatedCode = false;




private $currentId;






private $data = [];




private $ignoredLines = [];




private $disableIgnoredLines = false;






private $tests = [];




private $unintentionallyCoveredSubclassesWhitelist = [];






private $isInitialized = false;






private $shouldCheckForDeadAndUnused = true;




private $report;




public function __construct(Driver $driver = null, Filter $filter = null)
{
if ($filter === null) {
$filter = new Filter;
}

if ($driver === null) {
$driver = $this->selectDriver($filter);
}

$this->driver = $driver;
$this->filter = $filter;

$this->wizard = new Wizard;
}




public function getReport(): Directory
{
if ($this->report === null) {
$this->report = (new Builder)->build($this);
}

return $this->report;
}




public function clear(): void
{
$this->isInitialized = false;
$this->currentId = null;
$this->data = [];
$this->tests = [];
$this->report = null;
}




public function filter(): Filter
{
return $this->filter;
}




public function getData(bool $raw = false): array
{
if (!$raw && $this->addUncoveredFilesFromWhitelist) {
$this->addUncoveredFilesFromWhitelist();
}

return $this->data;
}




public function setData(array $data): void
{
$this->data = $data;
$this->report = null;
}




public function getTests(): array
{
return $this->tests;
}




public function setTests(array $tests): void
{
$this->tests = $tests;
}








public function start($id, bool $clear = false): void
{
if ($clear) {
$this->clear();
}

if ($this->isInitialized === false) {
$this->initializeData();
}

$this->currentId = $id;

$this->driver->start($this->shouldCheckForDeadAndUnused);
}












public function stop(bool $append = true, $linesToBeCovered = [], array $linesToBeUsed = [], bool $ignoreForceCoversAnnotation = false): array
{
if (!\is_array($linesToBeCovered) && $linesToBeCovered !== false) {
throw InvalidArgumentException::create(
2,
'array or false'
);
}

$data = $this->driver->stop();
$this->append($data, null, $append, $linesToBeCovered, $linesToBeUsed, $ignoreForceCoversAnnotation);

$this->currentId = null;

return $data;
}














public function append(array $data, $id = null, bool $append = true, $linesToBeCovered = [], array $linesToBeUsed = [], bool $ignoreForceCoversAnnotation = false): void
{
if ($id === null) {
$id = $this->currentId;
}

if ($id === null) {
throw new RuntimeException;
}

$this->applyWhitelistFilter($data);
$this->applyIgnoredLinesFilter($data);
$this->initializeFilesThatAreSeenTheFirstTime($data);

if (!$append) {
return;
}

if ($id !== 'UNCOVERED_FILES_FROM_WHITELIST') {
$this->applyCoversAnnotationFilter(
$data,
$linesToBeCovered,
$linesToBeUsed,
$ignoreForceCoversAnnotation
);
}

if (empty($data)) {
return;
}

$size = 'unknown';
$status = -1;

if ($id instanceof TestCase) {
$_size = $id->getSize();

if ($_size === Test::SMALL) {
$size = 'small';
} elseif ($_size === Test::MEDIUM) {
$size = 'medium';
} elseif ($_size === Test::LARGE) {
$size = 'large';
}

$status = $id->getStatus();
$id = \get_class($id) . '::' . $id->getName();
} elseif ($id instanceof PhptTestCase) {
$size = 'large';
$id = $id->getName();
}

$this->tests[$id] = ['size' => $size, 'status' => $status];

foreach ($data as $file => $lines) {
if (!$this->filter->isFile($file)) {
continue;
}

foreach ($lines as $k => $v) {
if ($v === Driver::LINE_EXECUTED) {
if (empty($this->data[$file][$k]) || !\in_array($id, $this->data[$file][$k])) {
$this->data[$file][$k][] = $id;
}
}
}
}

$this->report = null;
}






public function merge(self $that): void
{
$this->filter->setWhitelistedFiles(
\array_merge($this->filter->getWhitelistedFiles(), $that->filter()->getWhitelistedFiles())
);

foreach ($that->data as $file => $lines) {
if (!isset($this->data[$file])) {
if (!$this->filter->isFiltered($file)) {
$this->data[$file] = $lines;
}

continue;
}


 $compareLineNumbers = \array_unique(
\array_merge(
\array_keys($this->data[$file]),
\array_keys($that->data[$file])
)
);

foreach ($compareLineNumbers as $line) {
$thatPriority = $this->getLinePriority($that->data[$file], $line);
$thisPriority = $this->getLinePriority($this->data[$file], $line);

if ($thatPriority > $thisPriority) {
$this->data[$file][$line] = $that->data[$file][$line];
} elseif ($thatPriority === $thisPriority && \is_array($this->data[$file][$line])) {
$this->data[$file][$line] = \array_unique(
\array_merge($this->data[$file][$line], $that->data[$file][$line])
);
}
}
}

$this->tests = \array_merge($this->tests, $that->getTests());
$this->report = null;
}

public function setCacheTokens(bool $flag): void
{
$this->cacheTokens = $flag;
}

public function getCacheTokens(): bool
{
return $this->cacheTokens;
}

public function setCheckForUnintentionallyCoveredCode(bool $flag): void
{
$this->checkForUnintentionallyCoveredCode = $flag;
}

public function setForceCoversAnnotation(bool $flag): void
{
$this->forceCoversAnnotation = $flag;
}

public function setCheckForMissingCoversAnnotation(bool $flag): void
{
$this->checkForMissingCoversAnnotation = $flag;
}

public function setCheckForUnexecutedCoveredCode(bool $flag): void
{
$this->checkForUnexecutedCoveredCode = $flag;
}

public function setAddUncoveredFilesFromWhitelist(bool $flag): void
{
$this->addUncoveredFilesFromWhitelist = $flag;
}

public function setProcessUncoveredFilesFromWhitelist(bool $flag): void
{
$this->processUncoveredFilesFromWhitelist = $flag;
}

public function setDisableIgnoredLines(bool $flag): void
{
$this->disableIgnoredLines = $flag;
}

public function setIgnoreDeprecatedCode(bool $flag): void
{
$this->ignoreDeprecatedCode = $flag;
}

public function setUnintentionallyCoveredSubclassesWhitelist(array $whitelist): void
{
$this->unintentionallyCoveredSubclassesWhitelist = $whitelist;
}
















private function getLinePriority($data, $line)
{
if (!\array_key_exists($line, $data)) {
return 1;
}

if (\is_array($data[$line]) && \count($data[$line]) === 0) {
return 2;
}

if ($data[$line] === null) {
return 3;
}

return 4;
}











private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, array $linesToBeUsed, bool $ignoreForceCoversAnnotation): void
{
if ($linesToBeCovered === false ||
($this->forceCoversAnnotation && empty($linesToBeCovered) && !$ignoreForceCoversAnnotation)) {
if ($this->checkForMissingCoversAnnotation) {
throw new MissingCoversAnnotationException;
}

$data = [];

return;
}

if (empty($linesToBeCovered)) {
return;
}

if ($this->checkForUnintentionallyCoveredCode &&
(!$this->currentId instanceof TestCase ||
(!$this->currentId->isMedium() && !$this->currentId->isLarge()))) {
$this->performUnintentionallyCoveredCodeCheck($data, $linesToBeCovered, $linesToBeUsed);
}

if ($this->checkForUnexecutedCoveredCode) {
$this->performUnexecutedCoveredCodeCheck($data, $linesToBeCovered, $linesToBeUsed);
}

$data = \array_intersect_key($data, $linesToBeCovered);

foreach (\array_keys($data) as $filename) {
$_linesToBeCovered = \array_flip($linesToBeCovered[$filename]);
$data[$filename] = \array_intersect_key($data[$filename], $_linesToBeCovered);
}
}

private function applyWhitelistFilter(array &$data): void
{
foreach (\array_keys($data) as $filename) {
if ($this->filter->isFiltered($filename)) {
unset($data[$filename]);
}
}
}




private function applyIgnoredLinesFilter(array &$data): void
{
foreach (\array_keys($data) as $filename) {
if (!$this->filter->isFile($filename)) {
continue;
}

foreach ($this->getLinesToBeIgnored($filename) as $line) {
unset($data[$filename][$line]);
}
}
}

private function initializeFilesThatAreSeenTheFirstTime(array $data): void
{
foreach ($data as $file => $lines) {
if (!isset($this->data[$file]) && $this->filter->isFile($file)) {
$this->data[$file] = [];

foreach ($lines as $k => $v) {
$this->data[$file][$k] = $v === -2 ? null : [];
}
}
}
}









private function addUncoveredFilesFromWhitelist(): void
{
$data = [];
$uncoveredFiles = \array_diff(
$this->filter->getWhitelist(),
\array_keys($this->data)
);

foreach ($uncoveredFiles as $uncoveredFile) {
if (!\file_exists($uncoveredFile)) {
continue;
}

$data[$uncoveredFile] = [];

$lines = \count(\file($uncoveredFile));

for ($i = 1; $i <= $lines; $i++) {
$data[$uncoveredFile][$i] = Driver::LINE_NOT_EXECUTED;
}
}

$this->append($data, 'UNCOVERED_FILES_FROM_WHITELIST');
}

private function getLinesToBeIgnored(string $fileName): array
{
if (isset($this->ignoredLines[$fileName])) {
return $this->ignoredLines[$fileName];
}

try {
return $this->getLinesToBeIgnoredInner($fileName);
} catch (\OutOfBoundsException $e) {

 
 return [];
}
}

private function getLinesToBeIgnoredInner(string $fileName): array
{
$this->ignoredLines[$fileName] = [];

$lines = \file($fileName);

foreach ($lines as $index => $line) {
if (!\trim($line)) {
$this->ignoredLines[$fileName][] = $index + 1;
}
}

if ($this->cacheTokens) {
$tokens = \PHP_Token_Stream_CachingFactory::get($fileName);
} else {
$tokens = new \PHP_Token_Stream($fileName);
}

foreach ($tokens->getInterfaces() as $interface) {
$interfaceStartLine = $interface['startLine'];
$interfaceEndLine = $interface['endLine'];

foreach (\range($interfaceStartLine, $interfaceEndLine) as $line) {
$this->ignoredLines[$fileName][] = $line;
}
}

foreach (\array_merge($tokens->getClasses(), $tokens->getTraits()) as $classOrTrait) {
$classOrTraitStartLine = $classOrTrait['startLine'];
$classOrTraitEndLine = $classOrTrait['endLine'];

if (empty($classOrTrait['methods'])) {
foreach (\range($classOrTraitStartLine, $classOrTraitEndLine) as $line) {
$this->ignoredLines[$fileName][] = $line;
}

continue;
}

$firstMethod = \array_shift($classOrTrait['methods']);
$firstMethodStartLine = $firstMethod['startLine'];
$lastMethodEndLine = $firstMethod['endLine'];

do {
$lastMethod = \array_pop($classOrTrait['methods']);
} while ($lastMethod !== null && 0 === \strpos($lastMethod['signature'], 'anonymousFunction'));

if ($lastMethod !== null) {
$lastMethodEndLine = $lastMethod['endLine'];
}

foreach (\range($classOrTraitStartLine, $firstMethodStartLine) as $line) {
$this->ignoredLines[$fileName][] = $line;
}

foreach (\range($lastMethodEndLine + 1, $classOrTraitEndLine) as $line) {
$this->ignoredLines[$fileName][] = $line;
}
}

if ($this->disableIgnoredLines) {
$this->ignoredLines[$fileName] = \array_unique($this->ignoredLines[$fileName]);
\sort($this->ignoredLines[$fileName]);

return $this->ignoredLines[$fileName];
}

$ignore = false;
$stop = false;

foreach ($tokens->tokens() as $token) {
switch (\get_class($token)) {
case \PHP_Token_COMMENT::class:
case \PHP_Token_DOC_COMMENT::class:
$_token = \trim((string) $token);
$_line = \trim($lines[$token->getLine() - 1]);

if ($_token === '// @codeCoverageIgnore' ||
$_token === '//@codeCoverageIgnore') {
$ignore = true;
$stop = true;
} elseif ($_token === '// @codeCoverageIgnoreStart' ||
$_token === '//@codeCoverageIgnoreStart') {
$ignore = true;
} elseif ($_token === '// @codeCoverageIgnoreEnd' ||
$_token === '//@codeCoverageIgnoreEnd') {
$stop = true;
}

if (!$ignore) {
$start = $token->getLine();
$end = $start + \substr_count((string) $token, "\n");


 
 if (0 !== \strpos($_token, $_line)) {
$start++;
}

for ($i = $start; $i < $end; $i++) {
$this->ignoredLines[$fileName][] = $i;
}


 
 if (isset($lines[$i - 1]) && 0 === \strpos($_token, '/*') && '*/' === \substr(\trim($lines[$i - 1]), -2)) {
$this->ignoredLines[$fileName][] = $i;
}
}

break;

case \PHP_Token_INTERFACE::class:
case \PHP_Token_TRAIT::class:
case \PHP_Token_CLASS::class:
case \PHP_Token_FUNCTION::class:


$docblock = (string) $token->getDocblock();

$this->ignoredLines[$fileName][] = $token->getLine();

if (\strpos($docblock, '@codeCoverageIgnore') || ($this->ignoreDeprecatedCode && \strpos($docblock, '@deprecated'))) {
$endLine = $token->getEndLine();

for ($i = $token->getLine(); $i <= $endLine; $i++) {
$this->ignoredLines[$fileName][] = $i;
}
}

break;


case \PHP_Token_NAMESPACE::class:
$this->ignoredLines[$fileName][] = $token->getEndLine();


 case \PHP_Token_DECLARE::class:
case \PHP_Token_OPEN_TAG::class:
case \PHP_Token_CLOSE_TAG::class:
case \PHP_Token_USE::class:
case \PHP_Token_USE_FUNCTION::class:
$this->ignoredLines[$fileName][] = $token->getLine();

break;
}

if ($ignore) {
$this->ignoredLines[$fileName][] = $token->getLine();

if ($stop) {
$ignore = false;
$stop = false;
}
}
}

$this->ignoredLines[$fileName][] = \count($lines) + 1;

$this->ignoredLines[$fileName] = \array_unique(
$this->ignoredLines[$fileName]
);

$this->ignoredLines[$fileName] = \array_unique($this->ignoredLines[$fileName]);
\sort($this->ignoredLines[$fileName]);

return $this->ignoredLines[$fileName];
}





private function performUnintentionallyCoveredCodeCheck(array &$data, array $linesToBeCovered, array $linesToBeUsed): void
{
$allowedLines = $this->getAllowedLines(
$linesToBeCovered,
$linesToBeUsed
);

$unintentionallyCoveredUnits = [];

foreach ($data as $file => $_data) {
foreach ($_data as $line => $flag) {
if ($flag === 1 && !isset($allowedLines[$file][$line])) {
$unintentionallyCoveredUnits[] = $this->wizard->lookup($file, $line);
}
}
}

$unintentionallyCoveredUnits = $this->processUnintentionallyCoveredUnits($unintentionallyCoveredUnits);

if (!empty($unintentionallyCoveredUnits)) {
throw new UnintentionallyCoveredCodeException(
$unintentionallyCoveredUnits
);
}
}




private function performUnexecutedCoveredCodeCheck(array &$data, array $linesToBeCovered, array $linesToBeUsed): void
{
$executedCodeUnits = $this->coverageToCodeUnits($data);
$message = '';

foreach ($this->linesToCodeUnits($linesToBeCovered) as $codeUnit) {
if (!\in_array($codeUnit, $executedCodeUnits)) {
$message .= \sprintf(
'- %s is expected to be executed (@covers) but was not executed' . "\n",
$codeUnit
);
}
}

foreach ($this->linesToCodeUnits($linesToBeUsed) as $codeUnit) {
if (!\in_array($codeUnit, $executedCodeUnits)) {
$message .= \sprintf(
'- %s is expected to be executed (@uses) but was not executed' . "\n",
$codeUnit
);
}
}

if (!empty($message)) {
throw new CoveredCodeNotExecutedException($message);
}
}

private function getAllowedLines(array $linesToBeCovered, array $linesToBeUsed): array
{
$allowedLines = [];

foreach (\array_keys($linesToBeCovered) as $file) {
if (!isset($allowedLines[$file])) {
$allowedLines[$file] = [];
}

$allowedLines[$file] = \array_merge(
$allowedLines[$file],
$linesToBeCovered[$file]
);
}

foreach (\array_keys($linesToBeUsed) as $file) {
if (!isset($allowedLines[$file])) {
$allowedLines[$file] = [];
}

$allowedLines[$file] = \array_merge(
$allowedLines[$file],
$linesToBeUsed[$file]
);
}

foreach (\array_keys($allowedLines) as $file) {
$allowedLines[$file] = \array_flip(
\array_unique($allowedLines[$file])
);
}

return $allowedLines;
}




private function selectDriver(Filter $filter): Driver
{
$runtime = new Runtime;

if ($runtime->hasPHPDBGCodeCoverage()) {
return new PHPDBG;
}

if ($runtime->hasPCOV()) {
return new PCOV;
}

if ($runtime->hasXdebug()) {
return new Xdebug($filter);
}

throw new RuntimeException('No code coverage driver available');
}

private function processUnintentionallyCoveredUnits(array $unintentionallyCoveredUnits): array
{
$unintentionallyCoveredUnits = \array_unique($unintentionallyCoveredUnits);
\sort($unintentionallyCoveredUnits);

foreach (\array_keys($unintentionallyCoveredUnits) as $k => $v) {
$unit = \explode('::', $unintentionallyCoveredUnits[$k]);

if (\count($unit) !== 2) {
continue;
}

$class = new \ReflectionClass($unit[0]);

foreach ($this->unintentionallyCoveredSubclassesWhitelist as $whitelisted) {
if ($class->isSubclassOf($whitelisted)) {
unset($unintentionallyCoveredUnits[$k]);

break;
}
}
}

return \array_values($unintentionallyCoveredUnits);
}









private function initializeData(): void
{
$this->isInitialized = true;

if ($this->processUncoveredFilesFromWhitelist) {
$this->shouldCheckForDeadAndUnused = false;

$this->driver->start();

foreach ($this->filter->getWhitelist() as $file) {
if ($this->filter->isFile($file)) {
include_once $file;
}
}

$data = [];

foreach ($this->driver->stop() as $file => $fileCoverage) {
if ($this->filter->isFiltered($file)) {
continue;
}

foreach (\array_keys($fileCoverage) as $key) {
if ($fileCoverage[$key] === Driver::LINE_EXECUTED) {
$fileCoverage[$key] = Driver::LINE_NOT_EXECUTED;
}
}

$data[$file] = $fileCoverage;
}

$this->append($data, 'UNCOVERED_FILES_FROM_WHITELIST');
}
}

private function coverageToCodeUnits(array $data): array
{
$codeUnits = [];

foreach ($data as $filename => $lines) {
foreach ($lines as $line => $flag) {
if ($flag === 1) {
$codeUnits[] = $this->wizard->lookup($filename, $line);
}
}
}

return \array_unique($codeUnits);
}

private function linesToCodeUnits(array $data): array
{
$codeUnits = [];

foreach ($data as $filename => $lines) {
foreach ($lines as $line) {
$codeUnits[] = $this->wizard->lookup($filename, $line);
}
}

return \array_unique($codeUnits);
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Node;

use SebastianBergmann\CodeCoverage\InvalidArgumentException;




final class Directory extends AbstractNode implements \IteratorAggregate
{



private $children = [];




private $directories = [];




private $files = [];




private $classes;




private $traits;




private $functions;




private $linesOfCode;




private $numFiles = -1;




private $numExecutableLines = -1;




private $numExecutedLines = -1;




private $numClasses = -1;




private $numTestedClasses = -1;




private $numTraits = -1;




private $numTestedTraits = -1;




private $numMethods = -1;




private $numTestedMethods = -1;




private $numFunctions = -1;




private $numTestedFunctions = -1;




public function count(): int
{
if ($this->numFiles === -1) {
$this->numFiles = 0;

foreach ($this->children as $child) {
$this->numFiles += \count($child);
}
}

return $this->numFiles;
}




public function getIterator(): \RecursiveIteratorIterator
{
return new \RecursiveIteratorIterator(
new Iterator($this),
\RecursiveIteratorIterator::SELF_FIRST
);
}




public function addDirectory(string $name): self
{
$directory = new self($name, $this);

$this->children[] = $directory;
$this->directories[] = &$this->children[\count($this->children) - 1];

return $directory;
}






public function addFile(string $name, array $coverageData, array $testData, bool $cacheTokens): File
{
$file = new File($name, $this, $coverageData, $testData, $cacheTokens);

$this->children[] = $file;
$this->files[] = &$this->children[\count($this->children) - 1];

$this->numExecutableLines = -1;
$this->numExecutedLines = -1;

return $file;
}




public function getDirectories(): array
{
return $this->directories;
}




public function getFiles(): array
{
return $this->files;
}




public function getChildNodes(): array
{
return $this->children;
}




public function getClasses(): array
{
if ($this->classes === null) {
$this->classes = [];

foreach ($this->children as $child) {
$this->classes = \array_merge(
$this->classes,
$child->getClasses()
);
}
}

return $this->classes;
}




public function getTraits(): array
{
if ($this->traits === null) {
$this->traits = [];

foreach ($this->children as $child) {
$this->traits = \array_merge(
$this->traits,
$child->getTraits()
);
}
}

return $this->traits;
}




public function getFunctions(): array
{
if ($this->functions === null) {
$this->functions = [];

foreach ($this->children as $child) {
$this->functions = \array_merge(
$this->functions,
$child->getFunctions()
);
}
}

return $this->functions;
}




public function getLinesOfCode(): array
{
if ($this->linesOfCode === null) {
$this->linesOfCode = ['loc' => 0, 'cloc' => 0, 'ncloc' => 0];

foreach ($this->children as $child) {
$linesOfCode = $child->getLinesOfCode();

$this->linesOfCode['loc'] += $linesOfCode['loc'];
$this->linesOfCode['cloc'] += $linesOfCode['cloc'];
$this->linesOfCode['ncloc'] += $linesOfCode['ncloc'];
}
}

return $this->linesOfCode;
}




public function getNumExecutableLines(): int
{
if ($this->numExecutableLines === -1) {
$this->numExecutableLines = 0;

foreach ($this->children as $child) {
$this->numExecutableLines += $child->getNumExecutableLines();
}
}

return $this->numExecutableLines;
}




public function getNumExecutedLines(): int
{
if ($this->numExecutedLines === -1) {
$this->numExecutedLines = 0;

foreach ($this->children as $child) {
$this->numExecutedLines += $child->getNumExecutedLines();
}
}

return $this->numExecutedLines;
}




public function getNumClasses(): int
{
if ($this->numClasses === -1) {
$this->numClasses = 0;

foreach ($this->children as $child) {
$this->numClasses += $child->getNumClasses();
}
}

return $this->numClasses;
}




public function getNumTestedClasses(): int
{
if ($this->numTestedClasses === -1) {
$this->numTestedClasses = 0;

foreach ($this->children as $child) {
$this->numTestedClasses += $child->getNumTestedClasses();
}
}

return $this->numTestedClasses;
}




public function getNumTraits(): int
{
if ($this->numTraits === -1) {
$this->numTraits = 0;

foreach ($this->children as $child) {
$this->numTraits += $child->getNumTraits();
}
}

return $this->numTraits;
}




public function getNumTestedTraits(): int
{
if ($this->numTestedTraits === -1) {
$this->numTestedTraits = 0;

foreach ($this->children as $child) {
$this->numTestedTraits += $child->getNumTestedTraits();
}
}

return $this->numTestedTraits;
}




public function getNumMethods(): int
{
if ($this->numMethods === -1) {
$this->numMethods = 0;

foreach ($this->children as $child) {
$this->numMethods += $child->getNumMethods();
}
}

return $this->numMethods;
}




public function getNumTestedMethods(): int
{
if ($this->numTestedMethods === -1) {
$this->numTestedMethods = 0;

foreach ($this->children as $child) {
$this->numTestedMethods += $child->getNumTestedMethods();
}
}

return $this->numTestedMethods;
}




public function getNumFunctions(): int
{
if ($this->numFunctions === -1) {
$this->numFunctions = 0;

foreach ($this->children as $child) {
$this->numFunctions += $child->getNumFunctions();
}
}

return $this->numFunctions;
}




public function getNumTestedFunctions(): int
{
if ($this->numTestedFunctions === -1) {
$this->numTestedFunctions = 0;

foreach ($this->children as $child) {
$this->numTestedFunctions += $child->getNumTestedFunctions();
}
}

return $this->numTestedFunctions;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Node;




final class Iterator implements \RecursiveIterator
{



private $position;




private $nodes;

public function __construct(Directory $node)
{
$this->nodes = $node->getChildNodes();
}




public function rewind(): void
{
$this->position = 0;
}




public function valid(): bool
{
return $this->position < \count($this->nodes);
}




public function key(): int
{
return $this->position;
}




public function current(): AbstractNode
{
return $this->valid() ? $this->nodes[$this->position] : null;
}




public function next(): void
{
$this->position++;
}






public function getChildren(): self
{
return new self($this->nodes[$this->position]);
}




public function hasChildren(): bool
{
return $this->nodes[$this->position] instanceof Directory;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Node;

use SebastianBergmann\CodeCoverage\CodeCoverage;

final class Builder
{
public function build(CodeCoverage $coverage): Directory
{
$files = $coverage->getData();
$commonPath = $this->reducePaths($files);
$root = new Directory(
$commonPath,
null
);

$this->addItems(
$root,
$this->buildDirectoryStructure($files),
$coverage->getTests(),
$coverage->getCacheTokens()
);

return $root;
}

private function addItems(Directory $root, array $items, array $tests, bool $cacheTokens): void
{
foreach ($items as $key => $value) {
$key = (string) $key;

if (\substr($key, -2) === '/f') {
$key = \substr($key, 0, -2);

if (\file_exists($root->getPath() . \DIRECTORY_SEPARATOR . $key)) {
$root->addFile($key, $value, $tests, $cacheTokens);
}
} else {
$child = $root->addDirectory($key);
$this->addItems($child, $value, $tests, $cacheTokens);
}
}
}









































private function buildDirectoryStructure(array $files): array
{
$result = [];

foreach ($files as $path => $file) {
$path = \explode(\DIRECTORY_SEPARATOR, $path);
$pointer = &$result;
$max = \count($path);

for ($i = 0; $i < $max; $i++) {
$type = '';

if ($i === ($max - 1)) {
$type = '/f';
}

$pointer = &$pointer[$path[$i] . $type];
}

$pointer = $file;
}

return $result;
}






































private function reducePaths(array &$files): string
{
if (empty($files)) {
return '.';
}

$commonPath = '';
$paths = \array_keys($files);

if (\count($files) === 1) {
$commonPath = \dirname($paths[0]) . \DIRECTORY_SEPARATOR;
$files[\basename($paths[0])] = $files[$paths[0]];

unset($files[$paths[0]]);

return $commonPath;
}

$max = \count($paths);

for ($i = 0; $i < $max; $i++) {

 if (\strpos($paths[$i], 'phar://') === 0) {
$paths[$i] = \substr($paths[$i], 7);
$paths[$i] = \str_replace('/', \DIRECTORY_SEPARATOR, $paths[$i]);
}
$paths[$i] = \explode(\DIRECTORY_SEPARATOR, $paths[$i]);

if (empty($paths[$i][0])) {
$paths[$i][0] = \DIRECTORY_SEPARATOR;
}
}

$done = false;
$max = \count($paths);

while (!$done) {
for ($i = 0; $i < $max - 1; $i++) {
if (!isset($paths[$i][0]) ||
!isset($paths[$i + 1][0]) ||
$paths[$i][0] !== $paths[$i + 1][0]) {
$done = true;

break;
}
}

if (!$done) {
$commonPath .= $paths[0][0];

if ($paths[0][0] !== \DIRECTORY_SEPARATOR) {
$commonPath .= \DIRECTORY_SEPARATOR;
}

for ($i = 0; $i < $max; $i++) {
\array_shift($paths[$i]);
}
}
}

$original = \array_keys($files);
$max = \count($original);

for ($i = 0; $i < $max; $i++) {
$files[\implode(\DIRECTORY_SEPARATOR, $paths[$i])] = $files[$original[$i]];
unset($files[$original[$i]]);
}

\ksort($files);

return \substr($commonPath, 0, -1);
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Node;

use SebastianBergmann\CodeCoverage\Util;




abstract class AbstractNode implements \Countable
{



private $name;




private $path;




private $pathArray;




private $parent;




private $id;

public function __construct(string $name, self $parent = null)
{
if (\substr($name, -1) == \DIRECTORY_SEPARATOR) {
$name = \substr($name, 0, -1);
}

$this->name = $name;
$this->parent = $parent;
}

public function getName(): string
{
return $this->name;
}

public function getId(): string
{
if ($this->id === null) {
$parent = $this->getParent();

if ($parent === null) {
$this->id = 'index';
} else {
$parentId = $parent->getId();

if ($parentId === 'index') {
$this->id = \str_replace(':', '_', $this->name);
} else {
$this->id = $parentId . '/' . $this->name;
}
}
}

return $this->id;
}

public function getPath(): string
{
if ($this->path === null) {
if ($this->parent === null || $this->parent->getPath() === null || $this->parent->getPath() === false) {
$this->path = $this->name;
} else {
$this->path = $this->parent->getPath() . \DIRECTORY_SEPARATOR . $this->name;
}
}

return $this->path;
}

public function getPathAsArray(): array
{
if ($this->pathArray === null) {
if ($this->parent === null) {
$this->pathArray = [];
} else {
$this->pathArray = $this->parent->getPathAsArray();
}

$this->pathArray[] = $this;
}

return $this->pathArray;
}

public function getParent(): ?self
{
return $this->parent;
}






public function getTestedClassesPercent(bool $asString = true)
{
return Util::percent(
$this->getNumTestedClasses(),
$this->getNumClasses(),
$asString
);
}






public function getTestedTraitsPercent(bool $asString = true)
{
return Util::percent(
$this->getNumTestedTraits(),
$this->getNumTraits(),
$asString
);
}






public function getTestedClassesAndTraitsPercent(bool $asString = true)
{
return Util::percent(
$this->getNumTestedClassesAndTraits(),
$this->getNumClassesAndTraits(),
$asString
);
}






public function getTestedFunctionsPercent(bool $asString = true)
{
return Util::percent(
$this->getNumTestedFunctions(),
$this->getNumFunctions(),
$asString
);
}






public function getTestedMethodsPercent(bool $asString = true)
{
return Util::percent(
$this->getNumTestedMethods(),
$this->getNumMethods(),
$asString
);
}






public function getTestedFunctionsAndMethodsPercent(bool $asString = true)
{
return Util::percent(
$this->getNumTestedFunctionsAndMethods(),
$this->getNumFunctionsAndMethods(),
$asString
);
}






public function getLineExecutedPercent(bool $asString = true)
{
return Util::percent(
$this->getNumExecutedLines(),
$this->getNumExecutableLines(),
$asString
);
}




public function getNumClassesAndTraits(): int
{
return $this->getNumClasses() + $this->getNumTraits();
}




public function getNumTestedClassesAndTraits(): int
{
return $this->getNumTestedClasses() + $this->getNumTestedTraits();
}




public function getClassesAndTraits(): array
{
return \array_merge($this->getClasses(), $this->getTraits());
}




public function getNumFunctionsAndMethods(): int
{
return $this->getNumFunctions() + $this->getNumMethods();
}




public function getNumTestedFunctionsAndMethods(): int
{
return $this->getNumTestedFunctions() + $this->getNumTestedMethods();
}




public function getFunctionsAndMethods(): array
{
return \array_merge($this->getFunctions(), $this->getMethods());
}




abstract public function getClasses(): array;




abstract public function getTraits(): array;




abstract public function getFunctions(): array;




abstract public function getLinesOfCode(): array;




abstract public function getNumExecutableLines(): int;




abstract public function getNumExecutedLines(): int;




abstract public function getNumClasses(): int;




abstract public function getNumTestedClasses(): int;




abstract public function getNumTraits(): int;




abstract public function getNumTestedTraits(): int;




abstract public function getNumMethods(): int;




abstract public function getNumTestedMethods(): int;




abstract public function getNumFunctions(): int;




abstract public function getNumTestedFunctions(): int;
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Node;




final class File extends AbstractNode
{



private $coverageData;




private $testData;




private $numExecutableLines = 0;




private $numExecutedLines = 0;




private $classes = [];




private $traits = [];




private $functions = [];




private $linesOfCode = [];




private $numClasses;




private $numTestedClasses = 0;




private $numTraits;




private $numTestedTraits = 0;




private $numMethods;




private $numTestedMethods;




private $numTestedFunctions;




private $cacheTokens;




private $codeUnitsByLine = [];

public function __construct(string $name, AbstractNode $parent, array $coverageData, array $testData, bool $cacheTokens)
{
parent::__construct($name, $parent);

$this->coverageData = $coverageData;
$this->testData = $testData;
$this->cacheTokens = $cacheTokens;

$this->calculateStatistics();
}




public function count(): int
{
return 1;
}




public function getCoverageData(): array
{
return $this->coverageData;
}




public function getTestData(): array
{
return $this->testData;
}




public function getClasses(): array
{
return $this->classes;
}




public function getTraits(): array
{
return $this->traits;
}




public function getFunctions(): array
{
return $this->functions;
}




public function getLinesOfCode(): array
{
return $this->linesOfCode;
}




public function getNumExecutableLines(): int
{
return $this->numExecutableLines;
}




public function getNumExecutedLines(): int
{
return $this->numExecutedLines;
}




public function getNumClasses(): int
{
if ($this->numClasses === null) {
$this->numClasses = 0;

foreach ($this->classes as $class) {
foreach ($class['methods'] as $method) {
if ($method['executableLines'] > 0) {
$this->numClasses++;

continue 2;
}
}
}
}

return $this->numClasses;
}




public function getNumTestedClasses(): int
{
return $this->numTestedClasses;
}




public function getNumTraits(): int
{
if ($this->numTraits === null) {
$this->numTraits = 0;

foreach ($this->traits as $trait) {
foreach ($trait['methods'] as $method) {
if ($method['executableLines'] > 0) {
$this->numTraits++;

continue 2;
}
}
}
}

return $this->numTraits;
}




public function getNumTestedTraits(): int
{
return $this->numTestedTraits;
}




public function getNumMethods(): int
{
if ($this->numMethods === null) {
$this->numMethods = 0;

foreach ($this->classes as $class) {
foreach ($class['methods'] as $method) {
if ($method['executableLines'] > 0) {
$this->numMethods++;
}
}
}

foreach ($this->traits as $trait) {
foreach ($trait['methods'] as $method) {
if ($method['executableLines'] > 0) {
$this->numMethods++;
}
}
}
}

return $this->numMethods;
}




public function getNumTestedMethods(): int
{
if ($this->numTestedMethods === null) {
$this->numTestedMethods = 0;

foreach ($this->classes as $class) {
foreach ($class['methods'] as $method) {
if ($method['executableLines'] > 0 &&
$method['coverage'] === 100) {
$this->numTestedMethods++;
}
}
}

foreach ($this->traits as $trait) {
foreach ($trait['methods'] as $method) {
if ($method['executableLines'] > 0 &&
$method['coverage'] === 100) {
$this->numTestedMethods++;
}
}
}
}

return $this->numTestedMethods;
}




public function getNumFunctions(): int
{
return \count($this->functions);
}




public function getNumTestedFunctions(): int
{
if ($this->numTestedFunctions === null) {
$this->numTestedFunctions = 0;

foreach ($this->functions as $function) {
if ($function['executableLines'] > 0 &&
$function['coverage'] === 100) {
$this->numTestedFunctions++;
}
}
}

return $this->numTestedFunctions;
}

private function calculateStatistics(): void
{
if ($this->cacheTokens) {
$tokens = \PHP_Token_Stream_CachingFactory::get($this->getPath());
} else {
$tokens = new \PHP_Token_Stream($this->getPath());
}

$this->linesOfCode = $tokens->getLinesOfCode();

foreach (\range(1, $this->linesOfCode['loc']) as $lineNumber) {
$this->codeUnitsByLine[$lineNumber] = [];
}

try {
$this->processClasses($tokens);
$this->processTraits($tokens);
$this->processFunctions($tokens);
} catch (\OutOfBoundsException $e) {

 
 }
unset($tokens);

foreach (\range(1, $this->linesOfCode['loc']) as $lineNumber) {
if (isset($this->coverageData[$lineNumber])) {
foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) {
$codeUnit['executableLines']++;
}

unset($codeUnit);

$this->numExecutableLines++;

if (\count($this->coverageData[$lineNumber]) > 0) {
foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) {
$codeUnit['executedLines']++;
}

unset($codeUnit);

$this->numExecutedLines++;
}
}
}

foreach ($this->traits as &$trait) {
foreach ($trait['methods'] as &$method) {
if ($method['executableLines'] > 0) {
$method['coverage'] = ($method['executedLines'] /
$method['executableLines']) * 100;
} else {
$method['coverage'] = 100;
}

$method['crap'] = $this->crap(
$method['ccn'],
$method['coverage']
);

$trait['ccn'] += $method['ccn'];
}

unset($method);

if ($trait['executableLines'] > 0) {
$trait['coverage'] = ($trait['executedLines'] /
$trait['executableLines']) * 100;

if ($trait['coverage'] === 100) {
$this->numTestedClasses++;
}
} else {
$trait['coverage'] = 100;
}

$trait['crap'] = $this->crap(
$trait['ccn'],
$trait['coverage']
);
}

unset($trait);

foreach ($this->classes as &$class) {
foreach ($class['methods'] as &$method) {
if ($method['executableLines'] > 0) {
$method['coverage'] = ($method['executedLines'] /
$method['executableLines']) * 100;
} else {
$method['coverage'] = 100;
}

$method['crap'] = $this->crap(
$method['ccn'],
$method['coverage']
);

$class['ccn'] += $method['ccn'];
}

unset($method);

if ($class['executableLines'] > 0) {
$class['coverage'] = ($class['executedLines'] /
$class['executableLines']) * 100;

if ($class['coverage'] === 100) {
$this->numTestedClasses++;
}
} else {
$class['coverage'] = 100;
}

$class['crap'] = $this->crap(
$class['ccn'],
$class['coverage']
);
}

unset($class);

foreach ($this->functions as &$function) {
if ($function['executableLines'] > 0) {
$function['coverage'] = ($function['executedLines'] /
$function['executableLines']) * 100;
} else {
$function['coverage'] = 100;
}

if ($function['coverage'] === 100) {
$this->numTestedFunctions++;
}

$function['crap'] = $this->crap(
$function['ccn'],
$function['coverage']
);
}
}

private function processClasses(\PHP_Token_Stream $tokens): void
{
$classes = $tokens->getClasses();
$link = $this->getId() . '.html#';

foreach ($classes as $className => $class) {
if (\strpos($className, 'anonymous') === 0) {
continue;
}

if (!empty($class['package']['namespace'])) {
$className = $class['package']['namespace'] . '\\' . $className;
}

$this->classes[$className] = [
'className' => $className,
'methods' => [],
'startLine' => $class['startLine'],
'executableLines' => 0,
'executedLines' => 0,
'ccn' => 0,
'coverage' => 0,
'crap' => 0,
'package' => $class['package'],
'link' => $link . $class['startLine'],
];

foreach ($class['methods'] as $methodName => $method) {
if (\strpos($methodName, 'anonymous') === 0) {
continue;
}

$this->classes[$className]['methods'][$methodName] = $this->newMethod($methodName, $method, $link);

foreach (\range($method['startLine'], $method['endLine']) as $lineNumber) {
$this->codeUnitsByLine[$lineNumber] = [
&$this->classes[$className],
&$this->classes[$className]['methods'][$methodName],
];
}
}
}
}

private function processTraits(\PHP_Token_Stream $tokens): void
{
$traits = $tokens->getTraits();
$link = $this->getId() . '.html#';

foreach ($traits as $traitName => $trait) {
$this->traits[$traitName] = [
'traitName' => $traitName,
'methods' => [],
'startLine' => $trait['startLine'],
'executableLines' => 0,
'executedLines' => 0,
'ccn' => 0,
'coverage' => 0,
'crap' => 0,
'package' => $trait['package'],
'link' => $link . $trait['startLine'],
];

foreach ($trait['methods'] as $methodName => $method) {
if (\strpos($methodName, 'anonymous') === 0) {
continue;
}

$this->traits[$traitName]['methods'][$methodName] = $this->newMethod($methodName, $method, $link);

foreach (\range($method['startLine'], $method['endLine']) as $lineNumber) {
$this->codeUnitsByLine[$lineNumber] = [
&$this->traits[$traitName],
&$this->traits[$traitName]['methods'][$methodName],
];
}
}
}
}

private function processFunctions(\PHP_Token_Stream $tokens): void
{
$functions = $tokens->getFunctions();
$link = $this->getId() . '.html#';

foreach ($functions as $functionName => $function) {
if (\strpos($functionName, 'anonymous') === 0) {
continue;
}

$this->functions[$functionName] = [
'functionName' => $functionName,
'signature' => $function['signature'],
'startLine' => $function['startLine'],
'executableLines' => 0,
'executedLines' => 0,
'ccn' => $function['ccn'],
'coverage' => 0,
'crap' => 0,
'link' => $link . $function['startLine'],
];

foreach (\range($function['startLine'], $function['endLine']) as $lineNumber) {
$this->codeUnitsByLine[$lineNumber] = [&$this->functions[$functionName]];
}
}
}

private function crap(int $ccn, float $coverage): string
{
if ($coverage === 0.0) {
return (string) ($ccn ** 2 + $ccn);
}

if ($coverage >= 95) {
return (string) $ccn;
}

return \sprintf(
'%01.2F',
$ccn ** 2 * (1 - $coverage / 100) ** 3 + $ccn
);
}

private function newMethod(string $methodName, array $method, string $link): array
{
return [
'methodName' => $methodName,
'visibility' => $method['visibility'],
'signature' => $method['signature'],
'startLine' => $method['startLine'],
'endLine' => $method['endLine'],
'executableLines' => 0,
'executedLines' => 0,
'ccn' => $method['ccn'],
'coverage' => 0,
'crap' => 0,
'link' => $link . $method['startLine'],
];
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage;

use SebastianBergmann\Version as VersionId;

final class Version
{



private static $version;

public static function id(): string
{
if (self::$version === null) {
$version = new VersionId('7.0.15', \dirname(__DIR__));
self::$version = $version->getVersion();
}

return self::$version;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage;

use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;




final class Filter
{





private $whitelistedFiles = [];






private $isFileCallsCache = [];




public function addDirectoryToWhitelist(string $directory, string $suffix = '.php', string $prefix = ''): void
{
$facade = new FileIteratorFacade;
$files = $facade->getFilesAsArray($directory, $suffix, $prefix);

foreach ($files as $file) {
$this->addFileToWhitelist($file);
}
}




public function addFileToWhitelist(string $filename): void
{
$filename = \realpath($filename);

if (!$filename) {
return;
}

$this->whitelistedFiles[$filename] = true;
}






public function addFilesToWhitelist(array $files): void
{
foreach ($files as $file) {
$this->addFileToWhitelist($file);
}
}




public function removeDirectoryFromWhitelist(string $directory, string $suffix = '.php', string $prefix = ''): void
{
$facade = new FileIteratorFacade;
$files = $facade->getFilesAsArray($directory, $suffix, $prefix);

foreach ($files as $file) {
$this->removeFileFromWhitelist($file);
}
}




public function removeFileFromWhitelist(string $filename): void
{
$filename = \realpath($filename);

if (!$filename || !isset($this->whitelistedFiles[$filename])) {
return;
}

unset($this->whitelistedFiles[$filename]);
}




public function isFile(string $filename): bool
{
if (isset($this->isFileCallsCache[$filename])) {
return $this->isFileCallsCache[$filename];
}

if ($filename === '-' ||
\strpos($filename, 'vfs://') === 0 ||
\strpos($filename, 'xdebug://debug-eval') !== false ||
\strpos($filename, 'eval()\'d code') !== false ||
\strpos($filename, 'runtime-created function') !== false ||
\strpos($filename, 'runkit created function') !== false ||
\strpos($filename, 'assert code') !== false ||
\strpos($filename, 'regexp code') !== false ||
\strpos($filename, 'Standard input code') !== false) {
$isFile = false;
} else {
$isFile = \file_exists($filename);
}

$this->isFileCallsCache[$filename] = $isFile;

return $isFile;
}




public function isFiltered(string $filename): bool
{
if (!$this->isFile($filename)) {
return true;
}

return !isset($this->whitelistedFiles[$filename]);
}






public function getWhitelist(): array
{
return \array_keys($this->whitelistedFiles);
}




public function hasWhitelist(): bool
{
return !empty($this->whitelistedFiles);
}






public function getWhitelistedFiles(): array
{
return $this->whitelistedFiles;
}




public function setWhitelistedFiles(array $whitelistedFiles): void
{
$this->whitelistedFiles = $whitelistedFiles;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report;

use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Node\File;
use SebastianBergmann\CodeCoverage\Util;






final class Text
{



private const COLOR_GREEN = "\x1b[30;42m";




private const COLOR_YELLOW = "\x1b[30;43m";




private const COLOR_RED = "\x1b[37;41m";




private const COLOR_HEADER = "\x1b[1;37;40m";




private const COLOR_RESET = "\x1b[0m";




private const COLOR_EOL = "\x1b[2K";




private $lowUpperBound;




private $highLowerBound;




private $showUncoveredFiles;




private $showOnlySummary;

public function __construct(int $lowUpperBound = 50, int $highLowerBound = 90, bool $showUncoveredFiles = false, bool $showOnlySummary = false)
{
$this->lowUpperBound = $lowUpperBound;
$this->highLowerBound = $highLowerBound;
$this->showUncoveredFiles = $showUncoveredFiles;
$this->showOnlySummary = $showOnlySummary;
}

public function process(CodeCoverage $coverage, bool $showColors = false): string
{
$output = \PHP_EOL . \PHP_EOL;
$report = $coverage->getReport();

$colors = [
'header' => '',
'classes' => '',
'methods' => '',
'lines' => '',
'reset' => '',
'eol' => '',
];

if ($showColors) {
$colors['classes'] = $this->getCoverageColor(
$report->getNumTestedClassesAndTraits(),
$report->getNumClassesAndTraits()
);

$colors['methods'] = $this->getCoverageColor(
$report->getNumTestedMethods(),
$report->getNumMethods()
);

$colors['lines'] = $this->getCoverageColor(
$report->getNumExecutedLines(),
$report->getNumExecutableLines()
);

$colors['reset'] = self::COLOR_RESET;
$colors['header'] = self::COLOR_HEADER;
$colors['eol'] = self::COLOR_EOL;
}

$classes = \sprintf(
'  Classes: %6s (%d/%d)',
Util::percent(
$report->getNumTestedClassesAndTraits(),
$report->getNumClassesAndTraits(),
true
),
$report->getNumTestedClassesAndTraits(),
$report->getNumClassesAndTraits()
);

$methods = \sprintf(
'  Methods: %6s (%d/%d)',
Util::percent(
$report->getNumTestedMethods(),
$report->getNumMethods(),
true
),
$report->getNumTestedMethods(),
$report->getNumMethods()
);

$lines = \sprintf(
'  Lines:   %6s (%d/%d)',
Util::percent(
$report->getNumExecutedLines(),
$report->getNumExecutableLines(),
true
),
$report->getNumExecutedLines(),
$report->getNumExecutableLines()
);

$padding = \max(\array_map('strlen', [$classes, $methods, $lines]));

if ($this->showOnlySummary) {
$title = 'Code Coverage Report Summary:';
$padding = \max($padding, \strlen($title));

$output .= $this->format($colors['header'], $padding, $title);
} else {
$date = \date('  Y-m-d H:i:s', $_SERVER['REQUEST_TIME']);
$title = 'Code Coverage Report:';

$output .= $this->format($colors['header'], $padding, $title);
$output .= $this->format($colors['header'], $padding, $date);
$output .= $this->format($colors['header'], $padding, '');
$output .= $this->format($colors['header'], $padding, ' Summary:');
}

$output .= $this->format($colors['classes'], $padding, $classes);
$output .= $this->format($colors['methods'], $padding, $methods);
$output .= $this->format($colors['lines'], $padding, $lines);

if ($this->showOnlySummary) {
return $output . \PHP_EOL;
}

$classCoverage = [];

foreach ($report as $item) {
if (!$item instanceof File) {
continue;
}

$classes = $item->getClassesAndTraits();

foreach ($classes as $className => $class) {
$classStatements = 0;
$coveredClassStatements = 0;
$coveredMethods = 0;
$classMethods = 0;

foreach ($class['methods'] as $method) {
if ($method['executableLines'] == 0) {
continue;
}

$classMethods++;
$classStatements += $method['executableLines'];
$coveredClassStatements += $method['executedLines'];

if ($method['coverage'] == 100) {
$coveredMethods++;
}
}

$namespace = '';

if (!empty($class['package']['namespace'])) {
$namespace = '\\' . $class['package']['namespace'] . '::';
} elseif (!empty($class['package']['fullPackage'])) {
$namespace = '@' . $class['package']['fullPackage'] . '::';
}

$classCoverage[$namespace . $className] = [
'namespace' => $namespace,
'className ' => $className,
'methodsCovered' => $coveredMethods,
'methodCount' => $classMethods,
'statementsCovered' => $coveredClassStatements,
'statementCount' => $classStatements,
];
}
}

\ksort($classCoverage);

$methodColor = '';
$linesColor = '';
$resetColor = '';

foreach ($classCoverage as $fullQualifiedPath => $classInfo) {
if ($this->showUncoveredFiles || $classInfo['statementsCovered'] != 0) {
if ($showColors) {
$methodColor = $this->getCoverageColor($classInfo['methodsCovered'], $classInfo['methodCount']);
$linesColor = $this->getCoverageColor($classInfo['statementsCovered'], $classInfo['statementCount']);
$resetColor = $colors['reset'];
}

$output .= \PHP_EOL . $fullQualifiedPath . \PHP_EOL
. '  ' . $methodColor . 'Methods: ' . $this->printCoverageCounts($classInfo['methodsCovered'], $classInfo['methodCount'], 2) . $resetColor . ' '
. '  ' . $linesColor . 'Lines: ' . $this->printCoverageCounts($classInfo['statementsCovered'], $classInfo['statementCount'], 3) . $resetColor;
}
}

return $output . \PHP_EOL;
}

private function getCoverageColor(int $numberOfCoveredElements, int $totalNumberOfElements): string
{
$coverage = Util::percent(
$numberOfCoveredElements,
$totalNumberOfElements
);

if ($coverage >= $this->highLowerBound) {
return self::COLOR_GREEN;
}

if ($coverage > $this->lowUpperBound) {
return self::COLOR_YELLOW;
}

return self::COLOR_RED;
}

private function printCoverageCounts(int $numberOfCoveredElements, int $totalNumberOfElements, int $precision): string
{
$format = '%' . $precision . 's';

return Util::percent(
$numberOfCoveredElements,
$totalNumberOfElements,
true,
true
) .
' (' . \sprintf($format, $numberOfCoveredElements) . '/' .
\sprintf($format, $totalNumberOfElements) . ')';
}

private function format($color, $padding, $string): string
{
$reset = $color ? self::COLOR_RESET : '';

return $color . \str_pad($string, $padding) . $reset . \PHP_EOL;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report;

use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\RuntimeException;




final class PHP
{



public function process(CodeCoverage $coverage, ?string $target = null): string
{
$filter = $coverage->filter();

$buffer = \sprintf(
'<?php
$coverage = new SebastianBergmann\CodeCoverage\CodeCoverage;
$coverage->setData(%s);
$coverage->setTests(%s);

$filter = $coverage->filter();
$filter->setWhitelistedFiles(%s);

return $coverage;',
\var_export($coverage->getData(true), true),
\var_export($coverage->getTests(), true),
\var_export($filter->getWhitelistedFiles(), true)
);

if ($target !== null) {
if (!$this->createDirectory(\dirname($target))) {
throw new \RuntimeException(\sprintf('Directory "%s" was not created', \dirname($target)));
}

if (@\file_put_contents($target, $buffer) === false) {
throw new RuntimeException(
\sprintf(
'Could not write to "%s',
$target
)
);
}
}

return $buffer;
}

private function createDirectory(string $directory): bool
{
return !(!\is_dir($directory) && !@\mkdir($directory, 0777, true) && !\is_dir($directory));
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Xml;

use TheSeer\Tokenizer\NamespaceUri;
use TheSeer\Tokenizer\Tokenizer;
use TheSeer\Tokenizer\XMLSerializer;

final class Source
{

private $context;

public function __construct(\DOMElement $context)
{
$this->context = $context;
}

public function setSourceCode(string $source): void
{
$context = $this->context;

$tokens = (new Tokenizer())->parse($source);
$srcDom = (new XMLSerializer(new NamespaceUri($context->namespaceURI)))->toDom($tokens);

$context->parentNode->replaceChild(
$context->ownerDocument->importNode($srcDom->documentElement, true),
$context
);
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Xml;

final class Directory extends Node
{
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Xml;

use SebastianBergmann\Environment\Runtime;

final class BuildInformation
{



private $contextNode;

public function __construct(\DOMElement $contextNode)
{
$this->contextNode = $contextNode;
}

public function setRuntimeInformation(Runtime $runtime): void
{
$runtimeNode = $this->getNodeByName('runtime');

$runtimeNode->setAttribute('name', $runtime->getName());
$runtimeNode->setAttribute('version', $runtime->getVersion());
$runtimeNode->setAttribute('url', $runtime->getVendorUrl());

$driverNode = $this->getNodeByName('driver');

if ($runtime->hasPHPDBGCodeCoverage()) {
$driverNode->setAttribute('name', 'phpdbg');
$driverNode->setAttribute('version', \constant('PHPDBG_VERSION'));
}

if ($runtime->hasXdebug()) {
$driverNode->setAttribute('name', 'xdebug');
$driverNode->setAttribute('version', \phpversion('xdebug'));
}

if ($runtime->hasPCOV()) {
$driverNode->setAttribute('name', 'pcov');
$driverNode->setAttribute('version', \phpversion('pcov'));
}
}

public function setBuildTime(\DateTime $date): void
{
$this->contextNode->setAttribute('time', $date->format('D M j G:i:s T Y'));
}

public function setGeneratorVersions(string $phpUnitVersion, string $coverageVersion): void
{
$this->contextNode->setAttribute('phpunit', $phpUnitVersion);
$this->contextNode->setAttribute('coverage', $coverageVersion);
}

private function getNodeByName(string $name): \DOMElement
{
$node = $this->contextNode->getElementsByTagNameNS(
'https://schema.phpunit.de/coverage/1.0',
$name
)->item(0);

if (!$node) {
$node = $this->contextNode->appendChild(
$this->contextNode->ownerDocument->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
$name
)
);
}

return $node;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Xml;

use SebastianBergmann\CodeCoverage\Util;

final class Totals
{



private $container;




private $linesNode;




private $methodsNode;




private $functionsNode;




private $classesNode;




private $traitsNode;

public function __construct(\DOMElement $container)
{
$this->container = $container;
$dom = $container->ownerDocument;

$this->linesNode = $dom->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'lines'
);

$this->methodsNode = $dom->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'methods'
);

$this->functionsNode = $dom->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'functions'
);

$this->classesNode = $dom->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'classes'
);

$this->traitsNode = $dom->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'traits'
);

$container->appendChild($this->linesNode);
$container->appendChild($this->methodsNode);
$container->appendChild($this->functionsNode);
$container->appendChild($this->classesNode);
$container->appendChild($this->traitsNode);
}

public function getContainer(): \DOMNode
{
return $this->container;
}

public function setNumLines(int $loc, int $cloc, int $ncloc, int $executable, int $executed): void
{
$this->linesNode->setAttribute('total', (string) $loc);
$this->linesNode->setAttribute('comments', (string) $cloc);
$this->linesNode->setAttribute('code', (string) $ncloc);
$this->linesNode->setAttribute('executable', (string) $executable);
$this->linesNode->setAttribute('executed', (string) $executed);
$this->linesNode->setAttribute(
'percent',
$executable === 0 ? '0' : \sprintf('%01.2F', Util::percent($executed, $executable))
);
}

public function setNumClasses(int $count, int $tested): void
{
$this->classesNode->setAttribute('count', (string) $count);
$this->classesNode->setAttribute('tested', (string) $tested);
$this->classesNode->setAttribute(
'percent',
$count === 0 ? '0' : \sprintf('%01.2F', Util::percent($tested, $count))
);
}

public function setNumTraits(int $count, int $tested): void
{
$this->traitsNode->setAttribute('count', (string) $count);
$this->traitsNode->setAttribute('tested', (string) $tested);
$this->traitsNode->setAttribute(
'percent',
$count === 0 ? '0' : \sprintf('%01.2F', Util::percent($tested, $count))
);
}

public function setNumMethods(int $count, int $tested): void
{
$this->methodsNode->setAttribute('count', (string) $count);
$this->methodsNode->setAttribute('tested', (string) $tested);
$this->methodsNode->setAttribute(
'percent',
$count === 0 ? '0' : \sprintf('%01.2F', Util::percent($tested, $count))
);
}

public function setNumFunctions(int $count, int $tested): void
{
$this->functionsNode->setAttribute('count', (string) $count);
$this->functionsNode->setAttribute('tested', (string) $tested);
$this->functionsNode->setAttribute(
'percent',
$count === 0 ? '0' : \sprintf('%01.2F', Util::percent($tested, $count))
);
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Xml;

abstract class Node
{



private $dom;




private $contextNode;

public function __construct(\DOMElement $context)
{
$this->setContextNode($context);
}

public function getDom(): \DOMDocument
{
return $this->dom;
}

public function getTotals(): Totals
{
$totalsContainer = $this->getContextNode()->firstChild;

if (!$totalsContainer) {
$totalsContainer = $this->getContextNode()->appendChild(
$this->dom->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'totals'
)
);
}

return new Totals($totalsContainer);
}

public function addDirectory(string $name): Directory
{
$dirNode = $this->getDom()->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'directory'
);

$dirNode->setAttribute('name', $name);
$this->getContextNode()->appendChild($dirNode);

return new Directory($dirNode);
}

public function addFile(string $name, string $href): File
{
$fileNode = $this->getDom()->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'file'
);

$fileNode->setAttribute('name', $name);
$fileNode->setAttribute('href', $href);
$this->getContextNode()->appendChild($fileNode);

return new File($fileNode);
}

protected function setContextNode(\DOMElement $context): void
{
$this->dom = $context->ownerDocument;
$this->contextNode = $context;
}

protected function getContextNode(): \DOMElement
{
return $this->contextNode;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Xml;

final class Report extends File
{
public function __construct(string $name)
{
$dom = new \DOMDocument();
$dom->loadXML('<?xml version="1.0" ?><phpunit xmlns="https://schema.phpunit.de/coverage/1.0"><file /></phpunit>');

$contextNode = $dom->getElementsByTagNameNS(
'https://schema.phpunit.de/coverage/1.0',
'file'
)->item(0);

parent::__construct($contextNode);

$this->setName($name);
}

public function asDom(): \DOMDocument
{
return $this->getDomDocument();
}

public function getFunctionObject($name): Method
{
$node = $this->getContextNode()->appendChild(
$this->getDomDocument()->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'function'
)
);

return new Method($node, $name);
}

public function getClassObject($name): Unit
{
return $this->getUnitObject('class', $name);
}

public function getTraitObject($name): Unit
{
return $this->getUnitObject('trait', $name);
}

public function getSource(): Source
{
$source = $this->getContextNode()->getElementsByTagNameNS(
'https://schema.phpunit.de/coverage/1.0',
'source'
)->item(0);

if (!$source) {
$source = $this->getContextNode()->appendChild(
$this->getDomDocument()->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'source'
)
);
}

return new Source($source);
}

private function setName($name): void
{
$this->getContextNode()->setAttribute('name', \basename($name));
$this->getContextNode()->setAttribute('path', \dirname($name));
}

private function getUnitObject($tagName, $name): Unit
{
$node = $this->getContextNode()->appendChild(
$this->getDomDocument()->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
$tagName
)
);

return new Unit($node, $name);
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Xml;

use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Node\AbstractNode;
use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode;
use SebastianBergmann\CodeCoverage\Node\File as FileNode;
use SebastianBergmann\CodeCoverage\RuntimeException;
use SebastianBergmann\CodeCoverage\Version;
use SebastianBergmann\Environment\Runtime;

final class Facade
{



private $target;




private $project;




private $phpUnitVersion;

public function __construct(string $version)
{
$this->phpUnitVersion = $version;
}




public function process(CodeCoverage $coverage, string $target): void
{
if (\substr($target, -1, 1) !== \DIRECTORY_SEPARATOR) {
$target .= \DIRECTORY_SEPARATOR;
}

$this->target = $target;
$this->initTargetDirectory($target);

$report = $coverage->getReport();

$this->project = new Project(
$coverage->getReport()->getName()
);

$this->setBuildInformation();
$this->processTests($coverage->getTests());
$this->processDirectory($report, $this->project);

$this->saveDocument($this->project->asDom(), 'index');
}

private function setBuildInformation(): void
{
$buildNode = $this->project->getBuildInformation();
$buildNode->setRuntimeInformation(new Runtime());
$buildNode->setBuildTime(\DateTime::createFromFormat('U', (string) $_SERVER['REQUEST_TIME']));
$buildNode->setGeneratorVersions($this->phpUnitVersion, Version::id());
}




private function initTargetDirectory(string $directory): void
{
if (\file_exists($directory)) {
if (!\is_dir($directory)) {
throw new RuntimeException(
"'$directory' exists but is not a directory."
);
}

if (!\is_writable($directory)) {
throw new RuntimeException(
"'$directory' exists but is not writable."
);
}
} elseif (!$this->createDirectory($directory)) {
throw new RuntimeException(
"'$directory' could not be created."
);
}
}

private function processDirectory(DirectoryNode $directory, Node $context): void
{
$directoryName = $directory->getName();

if ($this->project->getProjectSourceDirectory() === $directoryName) {
$directoryName = '/';
}

$directoryObject = $context->addDirectory($directoryName);

$this->setTotals($directory, $directoryObject->getTotals());

foreach ($directory->getDirectories() as $node) {
$this->processDirectory($node, $directoryObject);
}

foreach ($directory->getFiles() as $node) {
$this->processFile($node, $directoryObject);
}
}




private function processFile(FileNode $file, Directory $context): void
{
$fileObject = $context->addFile(
$file->getName(),
$file->getId() . '.xml'
);

$this->setTotals($file, $fileObject->getTotals());

$path = \substr(
$file->getPath(),
\strlen($this->project->getProjectSourceDirectory())
);

$fileReport = new Report($path);

$this->setTotals($file, $fileReport->getTotals());

foreach ($file->getClassesAndTraits() as $unit) {
$this->processUnit($unit, $fileReport);
}

foreach ($file->getFunctions() as $function) {
$this->processFunction($function, $fileReport);
}

foreach ($file->getCoverageData() as $line => $tests) {
if (!\is_array($tests) || \count($tests) === 0) {
continue;
}

$coverage = $fileReport->getLineCoverage((string) $line);

foreach ($tests as $test) {
$coverage->addTest($test);
}

$coverage->finalize();
}

$fileReport->getSource()->setSourceCode(
\file_get_contents($file->getPath())
);

$this->saveDocument($fileReport->asDom(), $file->getId());
}

private function processUnit(array $unit, Report $report): void
{
if (isset($unit['className'])) {
$unitObject = $report->getClassObject($unit['className']);
} else {
$unitObject = $report->getTraitObject($unit['traitName']);
}

$unitObject->setLines(
$unit['startLine'],
$unit['executableLines'],
$unit['executedLines']
);

$unitObject->setCrap((float) $unit['crap']);

$unitObject->setPackage(
$unit['package']['fullPackage'],
$unit['package']['package'],
$unit['package']['subpackage'],
$unit['package']['category']
);

$unitObject->setNamespace($unit['package']['namespace']);

foreach ($unit['methods'] as $method) {
$methodObject = $unitObject->addMethod($method['methodName']);
$methodObject->setSignature($method['signature']);
$methodObject->setLines((string) $method['startLine'], (string) $method['endLine']);
$methodObject->setCrap($method['crap']);
$methodObject->setTotals(
(string) $method['executableLines'],
(string) $method['executedLines'],
(string) $method['coverage']
);
}
}

private function processFunction(array $function, Report $report): void
{
$functionObject = $report->getFunctionObject($function['functionName']);

$functionObject->setSignature($function['signature']);
$functionObject->setLines((string) $function['startLine']);
$functionObject->setCrap($function['crap']);
$functionObject->setTotals((string) $function['executableLines'], (string) $function['executedLines'], (string) $function['coverage']);
}

private function processTests(array $tests): void
{
$testsObject = $this->project->getTests();

foreach ($tests as $test => $result) {
if ($test === 'UNCOVERED_FILES_FROM_WHITELIST') {
continue;
}

$testsObject->addTest($test, $result);
}
}

private function setTotals(AbstractNode $node, Totals $totals): void
{
$loc = $node->getLinesOfCode();

$totals->setNumLines(
$loc['loc'],
$loc['cloc'],
$loc['ncloc'],
$node->getNumExecutableLines(),
$node->getNumExecutedLines()
);

$totals->setNumClasses(
$node->getNumClasses(),
$node->getNumTestedClasses()
);

$totals->setNumTraits(
$node->getNumTraits(),
$node->getNumTestedTraits()
);

$totals->setNumMethods(
$node->getNumMethods(),
$node->getNumTestedMethods()
);

$totals->setNumFunctions(
$node->getNumFunctions(),
$node->getNumTestedFunctions()
);
}

private function getTargetDirectory(): string
{
return $this->target;
}




private function saveDocument(\DOMDocument $document, string $name): void
{
$filename = \sprintf('%s/%s.xml', $this->getTargetDirectory(), $name);

$document->formatOutput = true;
$document->preserveWhiteSpace = false;
$this->initTargetDirectory(\dirname($filename));

$document->save($filename);
}

private function createDirectory(string $directory): bool
{
return !(!\is_dir($directory) && !@\mkdir($directory, 0777, true) && !\is_dir($directory));
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Xml;

use SebastianBergmann\CodeCoverage\RuntimeException;

final class Coverage
{



private $writer;




private $contextNode;




private $finalized = false;

public function __construct(\DOMElement $context, string $line)
{
$this->contextNode = $context;

$this->writer = new \XMLWriter();
$this->writer->openMemory();
$this->writer->startElementNS(null, $context->nodeName, 'https://schema.phpunit.de/coverage/1.0');
$this->writer->writeAttribute('nr', $line);
}




public function addTest(string $test): void
{
if ($this->finalized) {
throw new RuntimeException('Coverage Report already finalized');
}

$this->writer->startElement('covered');
$this->writer->writeAttribute('by', $test);
$this->writer->endElement();
}

public function finalize(): void
{
$this->writer->endElement();

$fragment = $this->contextNode->ownerDocument->createDocumentFragment();
$fragment->appendXML($this->writer->outputMemory());

$this->contextNode->parentNode->replaceChild(
$fragment,
$this->contextNode
);

$this->finalized = true;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Xml;

final class Unit
{



private $contextNode;

public function __construct(\DOMElement $context, string $name)
{
$this->contextNode = $context;

$this->setName($name);
}

public function setLines(int $start, int $executable, int $executed): void
{
$this->contextNode->setAttribute('start', (string) $start);
$this->contextNode->setAttribute('executable', (string) $executable);
$this->contextNode->setAttribute('executed', (string) $executed);
}

public function setCrap(float $crap): void
{
$this->contextNode->setAttribute('crap', (string) $crap);
}

public function setPackage(string $full, string $package, string $sub, string $category): void
{
$node = $this->contextNode->getElementsByTagNameNS(
'https://schema.phpunit.de/coverage/1.0',
'package'
)->item(0);

if (!$node) {
$node = $this->contextNode->appendChild(
$this->contextNode->ownerDocument->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'package'
)
);
}

$node->setAttribute('full', $full);
$node->setAttribute('name', $package);
$node->setAttribute('sub', $sub);
$node->setAttribute('category', $category);
}

public function setNamespace(string $namespace): void
{
$node = $this->contextNode->getElementsByTagNameNS(
'https://schema.phpunit.de/coverage/1.0',
'namespace'
)->item(0);

if (!$node) {
$node = $this->contextNode->appendChild(
$this->contextNode->ownerDocument->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'namespace'
)
);
}

$node->setAttribute('name', $namespace);
}

public function addMethod(string $name): Method
{
$node = $this->contextNode->appendChild(
$this->contextNode->ownerDocument->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'method'
)
);

return new Method($node, $name);
}

private function setName(string $name): void
{
$this->contextNode->setAttribute('name', $name);
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Xml;

final class Method
{



private $contextNode;

public function __construct(\DOMElement $context, string $name)
{
$this->contextNode = $context;

$this->setName($name);
}

public function setSignature(string $signature): void
{
$this->contextNode->setAttribute('signature', $signature);
}

public function setLines(string $start, ?string $end = null): void
{
$this->contextNode->setAttribute('start', $start);

if ($end !== null) {
$this->contextNode->setAttribute('end', $end);
}
}

public function setTotals(string $executable, string $executed, string $coverage): void
{
$this->contextNode->setAttribute('executable', $executable);
$this->contextNode->setAttribute('executed', $executed);
$this->contextNode->setAttribute('coverage', $coverage);
}

public function setCrap(string $crap): void
{
$this->contextNode->setAttribute('crap', $crap);
}

private function setName(string $name): void
{
$this->contextNode->setAttribute('name', $name);
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Xml;

class File
{



private $dom;




private $contextNode;

public function __construct(\DOMElement $context)
{
$this->dom = $context->ownerDocument;
$this->contextNode = $context;
}

public function getTotals(): Totals
{
$totalsContainer = $this->contextNode->firstChild;

if (!$totalsContainer) {
$totalsContainer = $this->contextNode->appendChild(
$this->dom->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'totals'
)
);
}

return new Totals($totalsContainer);
}

public function getLineCoverage(string $line): Coverage
{
$coverage = $this->contextNode->getElementsByTagNameNS(
'https://schema.phpunit.de/coverage/1.0',
'coverage'
)->item(0);

if (!$coverage) {
$coverage = $this->contextNode->appendChild(
$this->dom->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'coverage'
)
);
}

$lineNode = $coverage->appendChild(
$this->dom->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'line'
)
);

return new Coverage($lineNode, $line);
}

protected function getContextNode(): \DOMElement
{
return $this->contextNode;
}

protected function getDomDocument(): \DOMDocument
{
return $this->dom;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Xml;

final class Tests
{
private $contextNode;

private $codeMap = [
-1 => 'UNKNOWN', 
 0 => 'PASSED', 
 1 => 'SKIPPED', 
 2 => 'INCOMPLETE', 
 3 => 'FAILURE', 
 4 => 'ERROR', 
 5 => 'RISKY', 
 6 => 'WARNING', 
 ];

public function __construct(\DOMElement $context)
{
$this->contextNode = $context;
}

public function addTest(string $test, array $result): void
{
$node = $this->contextNode->appendChild(
$this->contextNode->ownerDocument->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'test'
)
);

$node->setAttribute('name', $test);
$node->setAttribute('size', $result['size']);
$node->setAttribute('result', (string) $result['status']);
$node->setAttribute('status', $this->codeMap[(int) $result['status']]);
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Xml;

final class Project extends Node
{
public function __construct(string $directory)
{
$this->init();
$this->setProjectSourceDirectory($directory);
}

public function getProjectSourceDirectory(): string
{
return $this->getContextNode()->getAttribute('source');
}

public function getBuildInformation(): BuildInformation
{
$buildNode = $this->getDom()->getElementsByTagNameNS(
'https://schema.phpunit.de/coverage/1.0',
'build'
)->item(0);

if (!$buildNode) {
$buildNode = $this->getDom()->documentElement->appendChild(
$this->getDom()->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'build'
)
);
}

return new BuildInformation($buildNode);
}

public function getTests(): Tests
{
$testsNode = $this->getContextNode()->getElementsByTagNameNS(
'https://schema.phpunit.de/coverage/1.0',
'tests'
)->item(0);

if (!$testsNode) {
$testsNode = $this->getContextNode()->appendChild(
$this->getDom()->createElementNS(
'https://schema.phpunit.de/coverage/1.0',
'tests'
)
);
}

return new Tests($testsNode);
}

public function asDom(): \DOMDocument
{
return $this->getDom();
}

private function init(): void
{
$dom = new \DOMDocument;
$dom->loadXML('<?xml version="1.0" ?><phpunit xmlns="https://schema.phpunit.de/coverage/1.0"><build/><project/></phpunit>');

$this->setContextNode(
$dom->getElementsByTagNameNS(
'https://schema.phpunit.de/coverage/1.0',
'project'
)->item(0)
);
}

private function setProjectSourceDirectory(string $name): void
{
$this->getContextNode()->setAttribute('source', $name);
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Html;

use SebastianBergmann\CodeCoverage\Node\AbstractNode;
use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode;
use SebastianBergmann\CodeCoverage\Node\File as FileNode;
use SebastianBergmann\CodeCoverage\Version;
use SebastianBergmann\Environment\Runtime;




abstract class Renderer
{



protected $templatePath;




protected $generator;




protected $date;




protected $lowUpperBound;




protected $highLowerBound;




protected $version;

public function __construct(string $templatePath, string $generator, string $date, int $lowUpperBound, int $highLowerBound)
{
$this->templatePath = $templatePath;
$this->generator = $generator;
$this->date = $date;
$this->lowUpperBound = $lowUpperBound;
$this->highLowerBound = $highLowerBound;
$this->version = Version::id();
}

protected function renderItemTemplate(\Text_Template $template, array $data): string
{
$numSeparator = '&nbsp;/&nbsp;';

if (isset($data['numClasses']) && $data['numClasses'] > 0) {
$classesLevel = $this->getColorLevel($data['testedClassesPercent']);

$classesNumber = $data['numTestedClasses'] . $numSeparator .
$data['numClasses'];

$classesBar = $this->getCoverageBar(
$data['testedClassesPercent']
);
} else {
$classesLevel = '';
$classesNumber = '0' . $numSeparator . '0';
$classesBar = '';
$data['testedClassesPercentAsString'] = 'n/a';
}

if ($data['numMethods'] > 0) {
$methodsLevel = $this->getColorLevel($data['testedMethodsPercent']);

$methodsNumber = $data['numTestedMethods'] . $numSeparator .
$data['numMethods'];

$methodsBar = $this->getCoverageBar(
$data['testedMethodsPercent']
);
} else {
$methodsLevel = '';
$methodsNumber = '0' . $numSeparator . '0';
$methodsBar = '';
$data['testedMethodsPercentAsString'] = 'n/a';
}

if ($data['numExecutableLines'] > 0) {
$linesLevel = $this->getColorLevel($data['linesExecutedPercent']);

$linesNumber = $data['numExecutedLines'] . $numSeparator .
$data['numExecutableLines'];

$linesBar = $this->getCoverageBar(
$data['linesExecutedPercent']
);
} else {
$linesLevel = '';
$linesNumber = '0' . $numSeparator . '0';
$linesBar = '';
$data['linesExecutedPercentAsString'] = 'n/a';
}

$template->setVar(
[
'icon' => $data['icon'] ?? '',
'crap' => $data['crap'] ?? '',
'name' => $data['name'],
'lines_bar' => $linesBar,
'lines_executed_percent' => $data['linesExecutedPercentAsString'],
'lines_level' => $linesLevel,
'lines_number' => $linesNumber,
'methods_bar' => $methodsBar,
'methods_tested_percent' => $data['testedMethodsPercentAsString'],
'methods_level' => $methodsLevel,
'methods_number' => $methodsNumber,
'classes_bar' => $classesBar,
'classes_tested_percent' => $data['testedClassesPercentAsString'] ?? '',
'classes_level' => $classesLevel,
'classes_number' => $classesNumber,
]
);

return $template->render();
}

protected function setCommonTemplateVariables(\Text_Template $template, AbstractNode $node): void
{
$template->setVar(
[
'id' => $node->getId(),
'full_path' => $node->getPath(),
'path_to_root' => $this->getPathToRoot($node),
'breadcrumbs' => $this->getBreadcrumbs($node),
'date' => $this->date,
'version' => $this->version,
'runtime' => $this->getRuntimeString(),
'generator' => $this->generator,
'low_upper_bound' => $this->lowUpperBound,
'high_lower_bound' => $this->highLowerBound,
]
);
}

protected function getBreadcrumbs(AbstractNode $node): string
{
$breadcrumbs = '';
$path = $node->getPathAsArray();
$pathToRoot = [];
$max = \count($path);

if ($node instanceof FileNode) {
$max--;
}

for ($i = 0; $i < $max; $i++) {
$pathToRoot[] = \str_repeat('../', $i);
}

foreach ($path as $step) {
if ($step !== $node) {
$breadcrumbs .= $this->getInactiveBreadcrumb(
$step,
\array_pop($pathToRoot)
);
} else {
$breadcrumbs .= $this->getActiveBreadcrumb($step);
}
}

return $breadcrumbs;
}

protected function getActiveBreadcrumb(AbstractNode $node): string
{
$buffer = \sprintf(
'         <li class="breadcrumb-item active">%s</li>' . "\n",
$node->getName()
);

if ($node instanceof DirectoryNode) {
$buffer .= '         <li class="breadcrumb-item">(<a href="dashboard.html">Dashboard</a>)</li>' . "\n";
}

return $buffer;
}

protected function getInactiveBreadcrumb(AbstractNode $node, string $pathToRoot): string
{
return \sprintf(
'         <li class="breadcrumb-item"><a href="%sindex.html">%s</a></li>' . "\n",
$pathToRoot,
$node->getName()
);
}

protected function getPathToRoot(AbstractNode $node): string
{
$id = $node->getId();
$depth = \substr_count($id, '/');

if ($id !== 'index' &&
$node instanceof DirectoryNode) {
$depth++;
}

return \str_repeat('../', $depth);
}

protected function getCoverageBar(float $percent): string
{
$level = $this->getColorLevel($percent);

$template = new \Text_Template(
$this->templatePath . 'coverage_bar.html',
'{{',
'}}'
);

$template->setVar(['level' => $level, 'percent' => \sprintf('%.2F', $percent)]);

return $template->render();
}

protected function getColorLevel(float $percent): string
{
if ($percent <= $this->lowUpperBound) {
return 'danger';
}

if ($percent > $this->lowUpperBound &&
$percent < $this->highLowerBound) {
return 'warning';
}

return 'success';
}

private function getRuntimeString(): string
{
$runtime = new Runtime;

$buffer = \sprintf(
'<a href="%s" target="_top">%s %s</a>',
$runtime->getVendorUrl(),
$runtime->getName(),
$runtime->getVersion()
);

if ($runtime->hasXdebug() && !$runtime->hasPHPDBGCodeCoverage()) {
$buffer .= \sprintf(
' with <a href="https://xdebug.org/">Xdebug %s</a>',
\phpversion('xdebug')
);
}

if ($runtime->hasPCOV() && !$runtime->hasPHPDBGCodeCoverage()) {
$buffer .= \sprintf(
' with <a href="https://github.com/krakjoe/pcov">PCOV %s</a>',
\phpversion('pcov')
);
}

return $buffer;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Html;

use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode;
use SebastianBergmann\CodeCoverage\RuntimeException;




final class Facade
{



private $templatePath;




private $generator;




private $lowUpperBound;




private $highLowerBound;

public function __construct(int $lowUpperBound = 50, int $highLowerBound = 90, string $generator = '')
{
$this->generator = $generator;
$this->highLowerBound = $highLowerBound;
$this->lowUpperBound = $lowUpperBound;
$this->templatePath = __DIR__ . '/Renderer/Template/';
}






public function process(CodeCoverage $coverage, string $target): void
{
$target = $this->getDirectory($target);
$report = $coverage->getReport();

if (!isset($_SERVER['REQUEST_TIME'])) {
$_SERVER['REQUEST_TIME'] = \time();
}

$date = \date('D M j G:i:s T Y', $_SERVER['REQUEST_TIME']);

$dashboard = new Dashboard(
$this->templatePath,
$this->generator,
$date,
$this->lowUpperBound,
$this->highLowerBound
);

$directory = new Directory(
$this->templatePath,
$this->generator,
$date,
$this->lowUpperBound,
$this->highLowerBound
);

$file = new File(
$this->templatePath,
$this->generator,
$date,
$this->lowUpperBound,
$this->highLowerBound
);

$directory->render($report, $target . 'index.html');
$dashboard->render($report, $target . 'dashboard.html');

foreach ($report as $node) {
$id = $node->getId();

if ($node instanceof DirectoryNode) {
if (!$this->createDirectory($target . $id)) {
throw new \RuntimeException(\sprintf('Directory "%s" was not created', $target . $id));
}

$directory->render($node, $target . $id . '/index.html');
$dashboard->render($node, $target . $id . '/dashboard.html');
} else {
$dir = \dirname($target . $id);

if (!$this->createDirectory($dir)) {
throw new \RuntimeException(\sprintf('Directory "%s" was not created', $dir));
}

$file->render($node, $target . $id . '.html');
}
}

$this->copyFiles($target);
}




private function copyFiles(string $target): void
{
$dir = $this->getDirectory($target . '_css');

\copy($this->templatePath . 'css/bootstrap.min.css', $dir . 'bootstrap.min.css');
\copy($this->templatePath . 'css/nv.d3.min.css', $dir . 'nv.d3.min.css');
\copy($this->templatePath . 'css/style.css', $dir . 'style.css');
\copy($this->templatePath . 'css/custom.css', $dir . 'custom.css');
\copy($this->templatePath . 'css/octicons.css', $dir . 'octicons.css');

$dir = $this->getDirectory($target . '_icons');
\copy($this->templatePath . 'icons/file-code.svg', $dir . 'file-code.svg');
\copy($this->templatePath . 'icons/file-directory.svg', $dir . 'file-directory.svg');

$dir = $this->getDirectory($target . '_js');
\copy($this->templatePath . 'js/bootstrap.min.js', $dir . 'bootstrap.min.js');
\copy($this->templatePath . 'js/popper.min.js', $dir . 'popper.min.js');
\copy($this->templatePath . 'js/d3.min.js', $dir . 'd3.min.js');
\copy($this->templatePath . 'js/jquery.min.js', $dir . 'jquery.min.js');
\copy($this->templatePath . 'js/nv.d3.min.js', $dir . 'nv.d3.min.js');
\copy($this->templatePath . 'js/file.js', $dir . 'file.js');
}




private function getDirectory(string $directory): string
{
if (\substr($directory, -1, 1) != \DIRECTORY_SEPARATOR) {
$directory .= \DIRECTORY_SEPARATOR;
}

if (!$this->createDirectory($directory)) {
throw new RuntimeException(
\sprintf(
'Directory "%s" does not exist.',
$directory
)
);
}

return $directory;
}

private function createDirectory(string $directory): bool
{
return !(!\is_dir($directory) && !@\mkdir($directory, 0777, true) && !\is_dir($directory));
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Html;

use SebastianBergmann\CodeCoverage\Node\AbstractNode as Node;
use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode;




final class Directory extends Renderer
{




public function render(DirectoryNode $node, string $file): void
{
$template = new \Text_Template($this->templatePath . 'directory.html', '{{', '}}');

$this->setCommonTemplateVariables($template, $node);

$items = $this->renderItem($node, true);

foreach ($node->getDirectories() as $item) {
$items .= $this->renderItem($item);
}

foreach ($node->getFiles() as $item) {
$items .= $this->renderItem($item);
}

$template->setVar(
[
'id' => $node->getId(),
'items' => $items,
]
);

$template->renderTo($file);
}

protected function renderItem(Node $node, bool $total = false): string
{
$data = [
'numClasses' => $node->getNumClassesAndTraits(),
'numTestedClasses' => $node->getNumTestedClassesAndTraits(),
'numMethods' => $node->getNumFunctionsAndMethods(),
'numTestedMethods' => $node->getNumTestedFunctionsAndMethods(),
'linesExecutedPercent' => $node->getLineExecutedPercent(false),
'linesExecutedPercentAsString' => $node->getLineExecutedPercent(),
'numExecutedLines' => $node->getNumExecutedLines(),
'numExecutableLines' => $node->getNumExecutableLines(),
'testedMethodsPercent' => $node->getTestedFunctionsAndMethodsPercent(false),
'testedMethodsPercentAsString' => $node->getTestedFunctionsAndMethodsPercent(),
'testedClassesPercent' => $node->getTestedClassesAndTraitsPercent(false),
'testedClassesPercentAsString' => $node->getTestedClassesAndTraitsPercent(),
];

if ($total) {
$data['name'] = 'Total';
} else {
if ($node instanceof DirectoryNode) {
$data['name'] = \sprintf(
'<a href="%s/index.html">%s</a>',
$node->getName(),
$node->getName()
);

$up = \str_repeat('../', \count($node->getPathAsArray()) - 2);

$data['icon'] = \sprintf('<img src="%s_icons/file-directory.svg" class="octicon" />', $up);
} else {
$data['name'] = \sprintf(
'<a href="%s.html">%s</a>',
$node->getName(),
$node->getName()
);

$up = \str_repeat('../', \count($node->getPathAsArray()) - 2);

$data['icon'] = \sprintf('<img src="%s_icons/file-code.svg" class="octicon" />', $up);
}
}

return $this->renderItemTemplate(
new \Text_Template($this->templatePath . 'directory_item.html', '{{', '}}'),
$data
);
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Html;

use SebastianBergmann\CodeCoverage\Node\AbstractNode;
use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode;




final class Dashboard extends Renderer
{




public function render(DirectoryNode $node, string $file): void
{
$classes = $node->getClassesAndTraits();
$template = new \Text_Template(
$this->templatePath . 'dashboard.html',
'{{',
'}}'
);

$this->setCommonTemplateVariables($template, $node);

$baseLink = $node->getId() . '/';
$complexity = $this->complexity($classes, $baseLink);
$coverageDistribution = $this->coverageDistribution($classes);
$insufficientCoverage = $this->insufficientCoverage($classes, $baseLink);
$projectRisks = $this->projectRisks($classes, $baseLink);

$template->setVar(
[
'insufficient_coverage_classes' => $insufficientCoverage['class'],
'insufficient_coverage_methods' => $insufficientCoverage['method'],
'project_risks_classes' => $projectRisks['class'],
'project_risks_methods' => $projectRisks['method'],
'complexity_class' => $complexity['class'],
'complexity_method' => $complexity['method'],
'class_coverage_distribution' => $coverageDistribution['class'],
'method_coverage_distribution' => $coverageDistribution['method'],
]
);

$template->renderTo($file);
}




protected function complexity(array $classes, string $baseLink): array
{
$result = ['class' => [], 'method' => []];

foreach ($classes as $className => $class) {
foreach ($class['methods'] as $methodName => $method) {
if ($className !== '*') {
$methodName = $className . '::' . $methodName;
}

$result['method'][] = [
$method['coverage'],
$method['ccn'],
\sprintf(
'<a href="%s">%s</a>',
\str_replace($baseLink, '', $method['link']),
$methodName
),
];
}

$result['class'][] = [
$class['coverage'],
$class['ccn'],
\sprintf(
'<a href="%s">%s</a>',
\str_replace($baseLink, '', $class['link']),
$className
),
];
}

return [
'class' => \json_encode($result['class']),
'method' => \json_encode($result['method']),
];
}




protected function coverageDistribution(array $classes): array
{
$result = [
'class' => [
'0%' => 0,
'0-10%' => 0,
'10-20%' => 0,
'20-30%' => 0,
'30-40%' => 0,
'40-50%' => 0,
'50-60%' => 0,
'60-70%' => 0,
'70-80%' => 0,
'80-90%' => 0,
'90-100%' => 0,
'100%' => 0,
],
'method' => [
'0%' => 0,
'0-10%' => 0,
'10-20%' => 0,
'20-30%' => 0,
'30-40%' => 0,
'40-50%' => 0,
'50-60%' => 0,
'60-70%' => 0,
'70-80%' => 0,
'80-90%' => 0,
'90-100%' => 0,
'100%' => 0,
],
];

foreach ($classes as $class) {
foreach ($class['methods'] as $methodName => $method) {
if ($method['coverage'] === 0) {
$result['method']['0%']++;
} elseif ($method['coverage'] === 100) {
$result['method']['100%']++;
} else {
$key = \floor($method['coverage'] / 10) * 10;
$key = $key . '-' . ($key + 10) . '%';
$result['method'][$key]++;
}
}

if ($class['coverage'] === 0) {
$result['class']['0%']++;
} elseif ($class['coverage'] === 100) {
$result['class']['100%']++;
} else {
$key = \floor($class['coverage'] / 10) * 10;
$key = $key . '-' . ($key + 10) . '%';
$result['class'][$key]++;
}
}

return [
'class' => \json_encode(\array_values($result['class'])),
'method' => \json_encode(\array_values($result['method'])),
];
}




protected function insufficientCoverage(array $classes, string $baseLink): array
{
$leastTestedClasses = [];
$leastTestedMethods = [];
$result = ['class' => '', 'method' => ''];

foreach ($classes as $className => $class) {
foreach ($class['methods'] as $methodName => $method) {
if ($method['coverage'] < $this->highLowerBound) {
$key = $methodName;

if ($className !== '*') {
$key = $className . '::' . $methodName;
}

$leastTestedMethods[$key] = $method['coverage'];
}
}

if ($class['coverage'] < $this->highLowerBound) {
$leastTestedClasses[$className] = $class['coverage'];
}
}

\asort($leastTestedClasses);
\asort($leastTestedMethods);

foreach ($leastTestedClasses as $className => $coverage) {
$result['class'] .= \sprintf(
'       <tr><td><a href="%s">%s</a></td><td class="text-right">%d%%</td></tr>' . "\n",
\str_replace($baseLink, '', $classes[$className]['link']),
$className,
$coverage
);
}

foreach ($leastTestedMethods as $methodName => $coverage) {
[$class, $method] = \explode('::', $methodName);

$result['method'] .= \sprintf(
'       <tr><td><a href="%s"><abbr title="%s">%s</abbr></a></td><td class="text-right">%d%%</td></tr>' . "\n",
\str_replace($baseLink, '', $classes[$class]['methods'][$method]['link']),
$methodName,
$method,
$coverage
);
}

return $result;
}




protected function projectRisks(array $classes, string $baseLink): array
{
$classRisks = [];
$methodRisks = [];
$result = ['class' => '', 'method' => ''];

foreach ($classes as $className => $class) {
foreach ($class['methods'] as $methodName => $method) {
if ($method['coverage'] < $this->highLowerBound && $method['ccn'] > 1) {
$key = $methodName;

if ($className !== '*') {
$key = $className . '::' . $methodName;
}

$methodRisks[$key] = $method['crap'];
}
}

if ($class['coverage'] < $this->highLowerBound &&
$class['ccn'] > \count($class['methods'])) {
$classRisks[$className] = $class['crap'];
}
}

\arsort($classRisks);
\arsort($methodRisks);

foreach ($classRisks as $className => $crap) {
$result['class'] .= \sprintf(
'       <tr><td><a href="%s">%s</a></td><td class="text-right">%d</td></tr>' . "\n",
\str_replace($baseLink, '', $classes[$className]['link']),
$className,
$crap
);
}

foreach ($methodRisks as $methodName => $crap) {
[$class, $method] = \explode('::', $methodName);

$result['method'] .= \sprintf(
'       <tr><td><a href="%s"><abbr title="%s">%s</abbr></a></td><td class="text-right">%d</td></tr>' . "\n",
\str_replace($baseLink, '', $classes[$class]['methods'][$method]['link']),
$methodName,
$method,
$crap
);
}

return $result;
}

protected function getActiveBreadcrumb(AbstractNode $node): string
{
return \sprintf(
'         <li class="breadcrumb-item"><a href="index.html">%s</a></li>' . "\n" .
'         <li class="breadcrumb-item active">(Dashboard)</li>' . "\n",
$node->getName()
);
}
}
<!DOCTYPE html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <title>Code Coverage for {{full_path}}</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="{{path_to_root}}_css/bootstrap.min.css" rel="stylesheet" type="text/css">
  <link href="{{path_to_root}}_css/octicons.css" rel="stylesheet" type="text/css">
  <link href="{{path_to_root}}_css/style.css" rel="stylesheet" type="text/css">
  <link href="{{path_to_root}}_css/custom.css" rel="stylesheet" type="text/css">
 </head>
 <body>
  <header>
   <div class="container-fluid">
    <div class="row">
     <div class="col-md-12">
      <nav aria-label="breadcrumb">
       <ol class="breadcrumb">
{{breadcrumbs}}
       </ol>
      </nav>
     </div>
    </div>
   </div>
  </header>
  <div class="container-fluid">
   <div class="table-responsive">
    <table class="table table-bordered">
     <thead>
      <tr>
       <td>&nbsp;</td>
       <td colspan="10"><div align="center"><strong>Code Coverage</strong></div></td>
      </tr>
      <tr>
       <td>&nbsp;</td>
       <td colspan="3"><div align="center"><strong>Classes and Traits</strong></div></td>
       <td colspan="4"><div align="center"><strong>Functions and Methods</strong></div></td>
       <td colspan="3"><div align="center"><strong>Lines</strong></div></td>
      </tr>
     </thead>
     <tbody>
{{items}}
     </tbody>
    </table>
   </div>
   <table id="code" class="table table-borderless table-condensed">
    <tbody>
{{lines}}
    </tbody>
   </table>
   <footer>
    <hr/>
    <h4>Legend</h4>
    <p>
     <span class="success"><strong>Executed</strong></span>
     <span class="danger"><strong>Not Executed</strong></span>
     <span class="warning"><strong>Dead Code</strong></span>
    </p>
    <p>
     <small>Generated by <a href="https://github.com/sebastianbergmann/php-code-coverage" target="_top">php-code-coverage {{version}}</a> using {{runtime}}{{generator}} at {{date}}.</small>
    </p>
    <a title="Back to the top" id="toplink" href="#">
        <svg xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 12 16"><path fill-rule="evenodd" d="M12 11L6 5l-6 6h12z"/></svg>
    </a>
   </footer>
  </div>
  <script src="{{path_to_root}}_js/jquery.min.js" type="text/javascript"></script>
  <script src="{{path_to_root}}_js/popper.min.js" type="text/javascript"></script>
  <script src="{{path_to_root}}_js/bootstrap.min.js" type="text/javascript"></script>
  <script src="{{path_to_root}}_js/file.js" type="text/javascript"></script>
 </body>
</html>
<!DOCTYPE html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <title>Dashboard for {{full_path}}</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="{{path_to_root}}_css/bootstrap.min.css" rel="stylesheet" type="text/css">
  <link href="{{path_to_root}}_css/nv.d3.min.css" rel="stylesheet" type="text/css">
  <link href="{{path_to_root}}_css/style.css" rel="stylesheet" type="text/css">
  <link href="{{path_to_root}}_css/custom.css" rel="stylesheet" type="text/css">
 </head>
 <body>
  <header>
   <div class="container-fluid">
    <div class="row">
     <div class="col-md-12">
      <nav aria-label="breadcrumb">
       <ol class="breadcrumb">
{{breadcrumbs}}
       </ol>
      </nav>
     </div>
    </div>
   </div>
  </header>
  <div class="container-fluid">
   <div class="row">
    <div class="col-md-12">
     <h2>Classes</h2>
    </div>
   </div>
   <div class="row">
    <div class="col-md-6">
     <h3>Coverage Distribution</h3>
     <div id="classCoverageDistribution" style="height: 300px;">
       <svg></svg>
     </div>
    </div>
    <div class="col-md-6">
     <h3>Complexity</h3>
     <div id="classComplexity" style="height: 300px;">
       <svg></svg>
     </div>
    </div>
   </div>
   <div class="row">
    <div class="col-md-6">
     <h3>Insufficient Coverage</h3>
     <div class="scrollbox">
      <table class="table">
       <thead>
        <tr>
         <th>Class</th>
         <th class="text-right">Coverage</th>
        </tr>
       </thead>
       <tbody>
{{insufficient_coverage_classes}}
       </tbody>
      </table>
     </div>
    </div>
    <div class="col-md-6">
     <h3>Project Risks</h3>
     <div class="scrollbox">
      <table class="table">
       <thead>
        <tr>
         <th>Class</th>
         <th class="text-right"><abbr title="Change Risk Anti-Patterns (CRAP) Index">CRAP</abbr></th>
        </tr>
       </thead>
       <tbody>
{{project_risks_classes}}
       </tbody>
      </table>
     </div>
    </div>
   </div>
   <div class="row">
    <div class="col-md-12">
     <h2>Methods</h2>
    </div>
   </div>
   <div class="row">
    <div class="col-md-6">
     <h3>Coverage Distribution</h3>
     <div id="methodCoverageDistribution" style="height: 300px;">
       <svg></svg>
     </div>
    </div>
    <div class="col-md-6">
     <h3>Complexity</h3>
     <div id="methodComplexity" style="height: 300px;">
       <svg></svg>
     </div>
    </div>
   </div>
   <div class="row">
    <div class="col-md-6">
     <h3>Insufficient Coverage</h3>
     <div class="scrollbox">
      <table class="table">
       <thead>
        <tr>
         <th>Method</th>
         <th class="text-right">Coverage</th>
        </tr>
       </thead>
       <tbody>
{{insufficient_coverage_methods}}
       </tbody>
      </table>
     </div>
    </div>
    <div class="col-md-6">
     <h3>Project Risks</h3>
     <div class="scrollbox">
      <table class="table">
       <thead>
        <tr>
         <th>Method</th>
         <th class="text-right"><abbr title="Change Risk Anti-Patterns (CRAP) Index">CRAP</abbr></th>
        </tr>
       </thead>
       <tbody>
{{project_risks_methods}}
       </tbody>
      </table>
     </div>
    </div>
   </div>
   <footer>
    <hr/>
    <p>
     <small>Generated by <a href="https://github.com/sebastianbergmann/php-code-coverage" target="_top">php-code-coverage {{version}}</a> using {{runtime}}{{generator}} at {{date}}.</small>
    </p>
   </footer>
  </div>
  <script src="{{path_to_root}}_js/jquery.min.js" type="text/javascript"></script>
  <script src="{{path_to_root}}_js/d3.min.js" type="text/javascript"></script>
  <script src="{{path_to_root}}_js/nv.d3.min.js" type="text/javascript"></script>
  <script type="text/javascript">
$(document).ready(function() {
  nv.addGraph(function() {
    var chart = nv.models.multiBarChart();
    chart.tooltips(false)
      .showControls(false)
      .showLegend(false)
      .reduceXTicks(false)
      .staggerLabels(true)
      .yAxis.tickFormat(d3.format('d'));

    d3.select('#classCoverageDistribution svg')
      .datum(getCoverageDistributionData({{class_coverage_distribution}}, "Class Coverage"))
      .transition().duration(500).call(chart);

    nv.utils.windowResize(chart.update);

    return chart;
  });

  nv.addGraph(function() {
    var chart = nv.models.multiBarChart();
    chart.tooltips(false)
      .showControls(false)
      .showLegend(false)
      .reduceXTicks(false)
      .staggerLabels(true)
      .yAxis.tickFormat(d3.format('d'));

    d3.select('#methodCoverageDistribution svg')
      .datum(getCoverageDistributionData({{method_coverage_distribution}}, "Method Coverage"))
      .transition().duration(500).call(chart);

    nv.utils.windowResize(chart.update);

    return chart;
  });

  function getCoverageDistributionData(data, label) {
    var labels = [
      '0%',
      '0-10%',
      '10-20%',
      '20-30%',
      '30-40%',
      '40-50%',
      '50-60%',
      '60-70%',
      '70-80%',
      '80-90%',
      '90-100%',
      '100%'
    ];
    var values = [];
    $.each(labels, function(key) {
      values.push({x: labels[key], y: data[key]});
    });

    return [
      {
        key: label,
        values: values,
        color: "#4572A7"
      }
    ];
  }
  nv.addGraph(function() {
    var chart = nv.models.scatterChart()
      .showDistX(true)
      .showDistY(true)
      .showLegend(false)
      .forceX([0, 100]);
    chart.tooltipContent(function(graph) {
      return '<p>' + graph.point.class + '</p>';
    });

    chart.xAxis.axisLabel('Code Coverage (in percent)');
    chart.yAxis.axisLabel('Cyclomatic Complexity');

    d3.select('#classComplexity svg')
      .datum(getComplexityData({{complexity_class}}, 'Class Complexity'))
      .transition()
      .duration(500)
      .call(chart);

    nv.utils.windowResize(chart.update);

    return chart;
  });

  nv.addGraph(function() {
    var chart = nv.models.scatterChart()
      .showDistX(true)
      .showDistY(true)
      .showLegend(false)
      .forceX([0, 100]);
    chart.tooltipContent(function(graph) {
      return '<p>' + graph.point.class + '</p>';
    });

    chart.xAxis.axisLabel('Code Coverage (in percent)');
    chart.yAxis.axisLabel('Method Complexity');

    d3.select('#methodComplexity svg')
      .datum(getComplexityData({{complexity_method}}, 'Method Complexity'))
      .transition()
      .duration(500)
      .call(chart);

    nv.utils.windowResize(chart.update);

    return chart;
  });

  function getComplexityData(data, label) {
    var values = [];
    $.each(data, function(key) {
      var value = Math.round(data[key][0]*100) / 100;
      values.push({
        x: value,
        y: data[key][1],
        class: data[key][2],
        size: 0.05,
        shape: 'diamond'
      });
    });

    return [
      {
        key: label,
        values: values,
        color: "#4572A7"
      }
    ];
  }
});
  </script>
 </body>
</html>
      <tr>
       <td class="{{methods_level}}" colspan="4">{{name}}</td>
       <td class="{{methods_level}} big">{{methods_bar}}</td>
       <td class="{{methods_level}} small"><div align="right">{{methods_tested_percent}}</div></td>
       <td class="{{methods_level}} small"><div align="right">{{methods_number}}</div></td>
       <td class="{{methods_level}} small">{{crap}}</td>
       <td class="{{lines_level}} big">{{lines_bar}}</td>
       <td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
       <td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>
      </tr>

<svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M13 4H7V3c0-.66-.31-1-1-1H1c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1V5c0-.55-.45-1-1-1zM6 4H1V3h5v1z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 12 16"><path fill-rule="evenodd" d="M8.5 1H1c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h10c.55 0 1-.45 1-1V4.5L8.5 1zM11 14H1V2h7l3 3v9zM5 6.98L3.5 8.5 5 10l-.5 1L2 8.5 4.5 6l.5.98zM7.5 6L10 8.5 7.5 11l-.5-.98L8.5 8.5 7 7l.5-1z"/></svg><!DOCTYPE html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <title>Code Coverage for {{full_path}}</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="{{path_to_root}}_css/bootstrap.min.css" rel="stylesheet" type="text/css">
  <link href="{{path_to_root}}_css/octicons.css" rel="stylesheet" type="text/css">
  <link href="{{path_to_root}}_css/style.css" rel="stylesheet" type="text/css">
  <link href="{{path_to_root}}_css/custom.css" rel="stylesheet" type="text/css">
 </head>
 <body>
  <header>
   <div class="container-fluid">
    <div class="row">
     <div class="col-md-12">
      <nav aria-label="breadcrumb">
       <ol class="breadcrumb">
{{breadcrumbs}}
       </ol>
      </nav>
     </div>
    </div>
   </div>
  </header>
  <div class="container-fluid">
   <div class="table-responsive">
    <table class="table table-bordered">
     <thead>
      <tr>
       <td>&nbsp;</td>
       <td colspan="9"><div align="center"><strong>Code Coverage</strong></div></td>
      </tr>
      <tr>
       <td>&nbsp;</td>
       <td colspan="3"><div align="center"><strong>Lines</strong></div></td>
       <td colspan="3"><div align="center"><strong>Functions and Methods</strong></div></td>
       <td colspan="3"><div align="center"><strong>Classes and Traits</strong></div></td>
      </tr>
     </thead>
     <tbody>
{{items}}
     </tbody>
    </table>
   </div>
   <footer>
    <hr/>
    <h4>Legend</h4>
    <p>
     <span class="danger"><strong>Low</strong>: 0% to {{low_upper_bound}}%</span>
     <span class="warning"><strong>Medium</strong>: {{low_upper_bound}}% to {{high_lower_bound}}%</span>
     <span class="success"><strong>High</strong>: {{high_lower_bound}}% to 100%</span>
    </p>
    <p>
     <small>Generated by <a href="https://github.com/sebastianbergmann/php-code-coverage" target="_top">php-code-coverage {{version}}</a> using {{runtime}}{{generator}} at {{date}}.</small>
    </p>
   </footer>
  </div>
 </body>
</html>
      <tr>
       <td class="{{classes_level}}">{{name}}</td>
       <td class="{{classes_level}} big">{{classes_bar}}</td>
       <td class="{{classes_level}} small"><div align="right">{{classes_tested_percent}}</div></td>
       <td class="{{classes_level}} small"><div align="right">{{classes_number}}</div></td>
       <td class="{{methods_level}} big">{{methods_bar}}</td>
       <td class="{{methods_level}} small"><div align="right">{{methods_tested_percent}}</div></td>
       <td class="{{methods_level}} small"><div align="right">{{methods_number}}</div></td>
       <td class="{{methods_level}} small">{{crap}}</td>
       <td class="{{lines_level}} big">{{lines_bar}}</td>
       <td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
       <td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>
      </tr>

/*!
 * Bootstrap v4.3.1 (https://getbootstrap.com/)
 * Copyright 2011-2019 The Bootstrap Authors
 * Copyright 2011-2019 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014\00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code{font-size:87.5%;color:#e83e8c;word-break:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-ms-flex-order:-1;order:-1}.order-last{-ms-flex-order:13;order:13}.order-0{-ms-flex-order:0;order:0}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-ms-flex-order:-1;order:-1}.order-sm-last{-ms-flex-order:13;order:13}.order-sm-0{-ms-flex-order:0;order:0}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-md-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-ms-flex-order:-1;order:-1}.order-md-last{-ms-flex-order:13;order:13}.order-md-0{-ms-flex-order:0;order:0}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-lg-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-ms-flex-order:-1;order:-1}.order-lg-last{-ms-flex-order:13;order:13}.order-lg-0{-ms-flex-order:0;order:0}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-xl-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-ms-flex-order:-1;order:-1}.order-xl-last{-ms-flex-order:13;order:13}.order-xl-0{-ms-flex-order:0;order:0}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;margin-bottom:1rem;color:#212529}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{color:#212529;background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-primary tbody+tbody,.table-primary td,.table-primary th,.table-primary thead th{border-color:#7abaff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-secondary tbody+tbody,.table-secondary td,.table-secondary th,.table-secondary thead th{border-color:#b3b7bb}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-success tbody+tbody,.table-success td,.table-success th,.table-success thead th{border-color:#8fd19e}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-info tbody+tbody,.table-info td,.table-info th,.table-info thead th{border-color:#86cfda}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-warning tbody+tbody,.table-warning td,.table-warning th,.table-warning thead th{border-color:#ffdf7e}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-danger tbody+tbody,.table-danger td,.table-danger th,.table-danger thead th{border-color:#ed969e}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-light tbody+tbody,.table-light td,.table-light th,.table-light thead th{border-color:#fbfcfc}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#95999c}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#343a40;border-color:#454d55}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#343a40}.table-dark td,.table-dark th,.table-dark thead th{border-color:#454d55}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{color:#fff;background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.form-control-lg{height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}select.form-control[multiple],select.form-control[size]{height:auto}textarea.form-control{height:auto}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(40,167,69,.9);border-radius:.25rem}.form-control.is-valid,.was-validated .form-control:valid{border-color:#28a745;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:center right calc(.375em + .1875rem);background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.form-control.is-valid~.valid-feedback,.form-control.is-valid~.valid-tooltip,.was-validated .form-control:valid~.valid-feedback,.was-validated .form-control:valid~.valid-tooltip{display:block}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-valid,.was-validated .custom-select:valid{border-color:#28a745;padding-right:calc((1em + .75rem) * 3 / 4 + 1.75rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-valid:focus,.was-validated .custom-select:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.valid-feedback,.custom-select.is-valid~.valid-tooltip,.was-validated .custom-select:valid~.valid-feedback,.was-validated .custom-select:valid~.valid-tooltip{display:block}.form-control-file.is-valid~.valid-feedback,.form-control-file.is-valid~.valid-tooltip,.was-validated .form-control-file:valid~.valid-feedback,.was-validated .form-control-file:valid~.valid-tooltip{display:block}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{border-color:#28a745}.custom-control-input.is-valid~.valid-feedback,.custom-control-input.is-valid~.valid-tooltip,.was-validated .custom-control-input:valid~.valid-feedback,.was-validated .custom-control-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{border-color:#34ce57;background-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label::before{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid~.valid-feedback,.custom-file-input.is-valid~.valid-tooltip,.was-validated .custom-file-input:valid~.valid-feedback,.was-validated .custom-file-input:valid~.valid-tooltip{display:block}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E");background-repeat:no-repeat;background-position:center right calc(.375em + .1875rem);background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-invalid,.was-validated .custom-select:invalid{border-color:#dc3545;padding-right:calc((1em + .75rem) * 3 / 4 + 1.75rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E") #fff no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-invalid:focus,.was-validated .custom-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip{display:block}.form-control-file.is-invalid~.invalid-feedback,.form-control-file.is-invalid~.invalid-tooltip,.was-validated .form-control-file:invalid~.invalid-feedback,.was-validated .form-control-file:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{border-color:#dc3545}.custom-control-input.is-invalid~.invalid-feedback,.custom-control-input.is-invalid~.invalid-tooltip,.was-validated .custom-control-input:invalid~.invalid-feedback,.was-validated .custom-control-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{border-color:#e4606d;background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label::before{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid~.invalid-feedback,.custom-file-input.is-invalid~.invalid-tooltip,.was-validated .custom-file-input:invalid~.invalid-feedback,.was-validated .custom-file-input:invalid~.invalid-tooltip{display:block}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;-ms-flex-negative:0;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;color:#212529;text-align:center;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529;text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(38,143,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(38,143,255,.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 .2rem rgba(130,138,145,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(130,138,145,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(72,180,97,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(72,180,97,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(58,176,195,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(58,176,195,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(222,170,12,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(222,170,12,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 .2rem rgba(216,217,219,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(216,217,219,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(82,88,93,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(82,88,93,.5)}.btn-outline-primary{color:#007bff;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#6c757d;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-success{color:#28a745;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;text-decoration:none}.btn-link:hover{color:#0056b3;text-decoration:underline}.btn-link.focus,.btn-link:focus{text-decoration:underline;box-shadow:none}.btn-link.disabled,.btn-link:disabled{color:#6c757d;pointer-events:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu-left{right:auto;left:0}.dropdown-menu-right{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-left{right:auto;left:0}.dropdown-menu-sm-right{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-left{right:auto;left:0}.dropdown-menu-md-right{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-left{right:auto;left:0}.dropdown-menu-lg-right{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-left{right:auto;left:0}.dropdown-menu-xl-right{right:0;left:auto}}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#212529}.btn-group,.btn-group-vertical{position:relative;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-ms-flex:1 1 auto;flex:1 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-toolbar{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:center;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control,.input-group>.form-control-plaintext{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control,.input-group>.form-control-plaintext+.custom-file,.input-group>.form-control-plaintext+.custom-select,.input-group>.form-control-plaintext+.form-control{margin-left:-1px}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file .custom-file-input:focus{z-index:4}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn:focus,.input-group-prepend .btn:focus{z-index:3}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group-lg>.custom-select,.input-group-lg>.form-control:not(textarea){height:calc(1.5em + 1rem + 2px)}.input-group-lg>.custom-select,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-sm>.custom-select,.input-group-sm>.form-control:not(textarea){height:calc(1.5em + .5rem + 2px)}.input-group-sm>.custom-select,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-lg>.custom-select,.input-group-sm>.custom-select{padding-right:1.75rem}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;border-color:#007bff;background-color:#007bff}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:focus:not(:checked)~.custom-control-label::before{border-color:#80bdff}.custom-control-input:not(:disabled):active~.custom-control-label::before{color:#fff;background-color:#b3d7ff;border-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label{color:#6c757d}.custom-control-input:disabled~.custom-control-label::before{background-color:#e9ecef}.custom-control-label{position:relative;margin-bottom:0;vertical-align:top}.custom-control-label::before{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;pointer-events:none;content:"";background-color:#fff;border:#adb5bd solid 1px}.custom-control-label::after{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:"";background:no-repeat 50%/50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{border-color:#007bff;background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-switch{padding-left:2.25rem}.custom-switch .custom-control-label::before{left:-2.25rem;width:1.75rem;pointer-events:all;border-radius:.5rem}.custom-switch .custom-control-label::after{top:calc(.25rem + 2px);left:calc(-2.25rem + 2px);width:calc(1rem - 4px);height:calc(1rem - 4px);background-color:#adb5bd;border-radius:.5rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-switch .custom-control-label::after{transition:none}}.custom-switch .custom-control-input:checked~.custom-control-label::after{background-color:#fff;-webkit-transform:translateX(.75rem);transform:translateX(.75rem)}.custom-switch .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem 1.75rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;vertical-align:middle;background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{display:none}.custom-select-sm{height:calc(1.5em + .5rem + 2px);padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem}.custom-select-lg{height:calc(1.5em + 1rem + 2px);padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.custom-file{position:relative;display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(1.5em + .75rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:disabled~.custom-file-label{background-color:#e9ecef}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-input~.custom-file-label[data-browse]::after{content:attr(data-browse)}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(1.5em + .75rem);padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:inherit;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;height:calc(1rem + .4rem);padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-range:focus{outline:0}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{transition:none}}.custom-range::-webkit-slider-thumb:active{background-color:#b3d7ff}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{transition:none}}.custom-range::-moz-range-thumb:active{background-color:#b3d7ff}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-ms-thumb{width:1rem;height:1rem;margin-top:0;margin-right:.2rem;margin-left:.2rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-ms-thumb{transition:none}}.custom-range::-ms-thumb:active{background-color:#b3d7ff}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px;background-color:#dee2e6;border-radius:1rem}.custom-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.custom-range:disabled::-webkit-slider-runnable-track{cursor:default}.custom-range:disabled::-moz-range-thumb{background-color:#adb5bd}.custom-range:disabled::-moz-range-track{cursor:default}.custom-range:disabled::-ms-thumb{background-color:#adb5bd}.custom-control-label::before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-control-label::before,.custom-file-label,.custom-select{transition:none}}.nav{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:-ms-flexbox;display:flex;-ms-flex:1 0 0%;flex:1 0 0%;-ms-flex-direction:column;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion>.card{overflow:hidden}.accordion>.card:not(:first-of-type) .card-header:first-child{border-radius:0}.accordion>.card:not(:first-of-type):not(:last-of-type){border-bottom:0;border-radius:0}.accordion>.card:first-of-type{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion>.card:last-of-type{border-top-left-radius:0;border-top-right-radius:0}.accordion>.card .card-header{margin-bottom:-1px}.breadcrumb{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:1;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.badge{transition:none}}a.badge:focus,a.badge:hover{text-decoration:none}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}a.badge-primary:focus,a.badge-primary:hover{color:#fff;background-color:#0062cc}a.badge-primary.focus,a.badge-primary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.badge-secondary{color:#fff;background-color:#6c757d}a.badge-secondary:focus,a.badge-secondary:hover{color:#fff;background-color:#545b62}a.badge-secondary.focus,a.badge-secondary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.badge-success{color:#fff;background-color:#28a745}a.badge-success:focus,a.badge-success:hover{color:#fff;background-color:#1e7e34}a.badge-success.focus,a.badge-success:focus{outline:0;box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.badge-info{color:#fff;background-color:#17a2b8}a.badge-info:focus,a.badge-info:hover{color:#fff;background-color:#117a8b}a.badge-info.focus,a.badge-info:focus{outline:0;box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.badge-warning{color:#212529;background-color:#ffc107}a.badge-warning:focus,a.badge-warning:hover{color:#212529;background-color:#d39e00}a.badge-warning.focus,a.badge-warning:focus{outline:0;box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.badge-danger{color:#fff;background-color:#dc3545}a.badge-danger:focus,a.badge-danger:hover{color:#fff;background-color:#bd2130}a.badge-danger.focus,a.badge-danger:focus{outline:0;box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.badge-light{color:#212529;background-color:#f8f9fa}a.badge-light:focus,a.badge-light:hover{color:#212529;background-color:#dae0e5}a.badge-light.focus,a.badge-light:focus{outline:0;box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.badge-dark{color:#fff;background-color:#343a40}a.badge-dark:focus,a.badge-dark:hover{color:#fff;background-color:#1d2124}a.badge-dark.focus,a.badge-dark:focus{outline:0;box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;color:#fff;text-align:center;white-space:nowrap;background-color:#007bff;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.media{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start}.media-body{-ms-flex:1;flex:1}.list-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-horizontal{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}@media (min-width:576px){.list-group-horizontal-sm{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-sm .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal-sm .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}}@media (min-width:768px){.list-group-horizontal-md{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-md .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal-md .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}}@media (min-width:992px){.list-group-horizontal-lg{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-lg .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal-lg .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}}@media (min-width:1200px){.list-group-horizontal-xl{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-xl .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal-xl .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush .list-group-item:last-child{margin-bottom:-1px}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{margin-bottom:0;border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:hover{color:#000;text-decoration:none}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{opacity:.75}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}a.close.disabled{pointer-events:none}.toast{max-width:350px;overflow:hidden;font-size:.875rem;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .25rem .75rem rgba(0,0,0,.1);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);opacity:0;border-radius:.25rem}.toast:not(:last-child){margin-bottom:.75rem}.toast.showing{opacity:1}.toast.show{display:block;opacity:1}.toast.hide{display:none}.toast-header{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.25rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05)}.toast-body{padding:.75rem}.modal-open{overflow:hidden}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;top:0;left:0;z-index:1050;display:none;width:100%;height:100%;overflow:hidden;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-50px);transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{-webkit-transform:none;transform:none}.modal-dialog-scrollable{display:-ms-flexbox;display:flex;max-height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 1rem);overflow:hidden}.modal-dialog-scrollable .modal-footer,.modal-dialog-scrollable .modal-header{-ms-flex-negative:0;flex-shrink:0}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;min-height:calc(100% - 1rem)}.modal-dialog-centered::before{display:block;height:calc(100vh - 1rem);content:""}.modal-dialog-centered.modal-dialog-scrollable{-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;height:100%}.modal-dialog-centered.modal-dialog-scrollable .modal-content{max-height:none}.modal-dialog-centered.modal-dialog-scrollable::before{content:none}.modal-content{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:justify;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:.3rem;border-top-right-radius:.3rem}.modal-header .close{padding:1rem 1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end;padding:1rem;border-top:1px solid #dee2e6;border-bottom-right-radius:.3rem;border-bottom-left-radius:.3rem}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{max-height:calc(100% - 3.5rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-dialog-centered::before{height:calc(100vh - 3.5rem)}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top]>.arrow,.bs-popover-top>.arrow{bottom:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=top]>.arrow::before,.bs-popover-top>.arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top]>.arrow::after,.bs-popover-top>.arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right]>.arrow,.bs-popover-right>.arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right]>.arrow::before,.bs-popover-right>.arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right]>.arrow::after,.bs-popover-right>.arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom]>.arrow,.bs-popover-bottom>.arrow{top:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=bottom]>.arrow::before,.bs-popover-bottom>.arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom]>.arrow::after,.bs-popover-bottom>.arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left]>.arrow,.bs-popover-left>.arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left]>.arrow::before,.bs-popover-left>.arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left]>.arrow::after,.bs-popover-left>.arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{-ms-touch-action:pan-y;touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out;transition:transform .6s ease-in-out,-webkit-transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-right,.carousel-item-next:not(.carousel-item-left){-webkit-transform:translateX(100%);transform:translateX(100%)}.active.carousel-item-left,.carousel-item-prev:not(.carousel-item-right){-webkit-transform:translateX(-100%);transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;-webkit-transform:none;transform:none}.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{z-index:0;opacity:0;transition:0s .6s opacity}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:no-repeat 50%/100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:15;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{box-sizing:content-box;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators li{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}@-webkit-keyframes spinner-border{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spinner-border{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;-webkit-animation:spinner-border .75s linear infinite;animation:spinner-border .75s linear infinite}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1}}@keyframes spinner-grow{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:spinner-grow .75s linear infinite;animation:spinner-grow .75s linear infinite}.spinner-grow-sm{width:1rem;height:1rem}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded-sm{border-radius:.2rem!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-lg{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-sm-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-sm-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-sm-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-sm-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-sm-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-md-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-md-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-md-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-md-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-md-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-lg-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-lg-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-lg-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-lg-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-lg-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-xl-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-xl-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-xl-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-xl-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-xl-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.min-vw-100{min-width:100vw!important}.min-vh-100{min-height:100vh!important}.vw-100{width:100vw!important}.vh-100{height:100vh!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:auto;content:"";background-color:rgba(0,0,0,0)}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-n1{margin:-.25rem!important}.mt-n1,.my-n1{margin-top:-.25rem!important}.mr-n1,.mx-n1{margin-right:-.25rem!important}.mb-n1,.my-n1{margin-bottom:-.25rem!important}.ml-n1,.mx-n1{margin-left:-.25rem!important}.m-n2{margin:-.5rem!important}.mt-n2,.my-n2{margin-top:-.5rem!important}.mr-n2,.mx-n2{margin-right:-.5rem!important}.mb-n2,.my-n2{margin-bottom:-.5rem!important}.ml-n2,.mx-n2{margin-left:-.5rem!important}.m-n3{margin:-1rem!important}.mt-n3,.my-n3{margin-top:-1rem!important}.mr-n3,.mx-n3{margin-right:-1rem!important}.mb-n3,.my-n3{margin-bottom:-1rem!important}.ml-n3,.mx-n3{margin-left:-1rem!important}.m-n4{margin:-1.5rem!important}.mt-n4,.my-n4{margin-top:-1.5rem!important}.mr-n4,.mx-n4{margin-right:-1.5rem!important}.mb-n4,.my-n4{margin-bottom:-1.5rem!important}.ml-n4,.mx-n4{margin-left:-1.5rem!important}.m-n5{margin:-3rem!important}.mt-n5,.my-n5{margin-top:-3rem!important}.mr-n5,.mx-n5{margin-right:-3rem!important}.mb-n5,.my-n5{margin-bottom:-3rem!important}.ml-n5,.mx-n5{margin-left:-3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-n1{margin:-.25rem!important}.mt-sm-n1,.my-sm-n1{margin-top:-.25rem!important}.mr-sm-n1,.mx-sm-n1{margin-right:-.25rem!important}.mb-sm-n1,.my-sm-n1{margin-bottom:-.25rem!important}.ml-sm-n1,.mx-sm-n1{margin-left:-.25rem!important}.m-sm-n2{margin:-.5rem!important}.mt-sm-n2,.my-sm-n2{margin-top:-.5rem!important}.mr-sm-n2,.mx-sm-n2{margin-right:-.5rem!important}.mb-sm-n2,.my-sm-n2{margin-bottom:-.5rem!important}.ml-sm-n2,.mx-sm-n2{margin-left:-.5rem!important}.m-sm-n3{margin:-1rem!important}.mt-sm-n3,.my-sm-n3{margin-top:-1rem!important}.mr-sm-n3,.mx-sm-n3{margin-right:-1rem!important}.mb-sm-n3,.my-sm-n3{margin-bottom:-1rem!important}.ml-sm-n3,.mx-sm-n3{margin-left:-1rem!important}.m-sm-n4{margin:-1.5rem!important}.mt-sm-n4,.my-sm-n4{margin-top:-1.5rem!important}.mr-sm-n4,.mx-sm-n4{margin-right:-1.5rem!important}.mb-sm-n4,.my-sm-n4{margin-bottom:-1.5rem!important}.ml-sm-n4,.mx-sm-n4{margin-left:-1.5rem!important}.m-sm-n5{margin:-3rem!important}.mt-sm-n5,.my-sm-n5{margin-top:-3rem!important}.mr-sm-n5,.mx-sm-n5{margin-right:-3rem!important}.mb-sm-n5,.my-sm-n5{margin-bottom:-3rem!important}.ml-sm-n5,.mx-sm-n5{margin-left:-3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-n1{margin:-.25rem!important}.mt-md-n1,.my-md-n1{margin-top:-.25rem!important}.mr-md-n1,.mx-md-n1{margin-right:-.25rem!important}.mb-md-n1,.my-md-n1{margin-bottom:-.25rem!important}.ml-md-n1,.mx-md-n1{margin-left:-.25rem!important}.m-md-n2{margin:-.5rem!important}.mt-md-n2,.my-md-n2{margin-top:-.5rem!important}.mr-md-n2,.mx-md-n2{margin-right:-.5rem!important}.mb-md-n2,.my-md-n2{margin-bottom:-.5rem!important}.ml-md-n2,.mx-md-n2{margin-left:-.5rem!important}.m-md-n3{margin:-1rem!important}.mt-md-n3,.my-md-n3{margin-top:-1rem!important}.mr-md-n3,.mx-md-n3{margin-right:-1rem!important}.mb-md-n3,.my-md-n3{margin-bottom:-1rem!important}.ml-md-n3,.mx-md-n3{margin-left:-1rem!important}.m-md-n4{margin:-1.5rem!important}.mt-md-n4,.my-md-n4{margin-top:-1.5rem!important}.mr-md-n4,.mx-md-n4{margin-right:-1.5rem!important}.mb-md-n4,.my-md-n4{margin-bottom:-1.5rem!important}.ml-md-n4,.mx-md-n4{margin-left:-1.5rem!important}.m-md-n5{margin:-3rem!important}.mt-md-n5,.my-md-n5{margin-top:-3rem!important}.mr-md-n5,.mx-md-n5{margin-right:-3rem!important}.mb-md-n5,.my-md-n5{margin-bottom:-3rem!important}.ml-md-n5,.mx-md-n5{margin-left:-3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-n1{margin:-.25rem!important}.mt-lg-n1,.my-lg-n1{margin-top:-.25rem!important}.mr-lg-n1,.mx-lg-n1{margin-right:-.25rem!important}.mb-lg-n1,.my-lg-n1{margin-bottom:-.25rem!important}.ml-lg-n1,.mx-lg-n1{margin-left:-.25rem!important}.m-lg-n2{margin:-.5rem!important}.mt-lg-n2,.my-lg-n2{margin-top:-.5rem!important}.mr-lg-n2,.mx-lg-n2{margin-right:-.5rem!important}.mb-lg-n2,.my-lg-n2{margin-bottom:-.5rem!important}.ml-lg-n2,.mx-lg-n2{margin-left:-.5rem!important}.m-lg-n3{margin:-1rem!important}.mt-lg-n3,.my-lg-n3{margin-top:-1rem!important}.mr-lg-n3,.mx-lg-n3{margin-right:-1rem!important}.mb-lg-n3,.my-lg-n3{margin-bottom:-1rem!important}.ml-lg-n3,.mx-lg-n3{margin-left:-1rem!important}.m-lg-n4{margin:-1.5rem!important}.mt-lg-n4,.my-lg-n4{margin-top:-1.5rem!important}.mr-lg-n4,.mx-lg-n4{margin-right:-1.5rem!important}.mb-lg-n4,.my-lg-n4{margin-bottom:-1.5rem!important}.ml-lg-n4,.mx-lg-n4{margin-left:-1.5rem!important}.m-lg-n5{margin:-3rem!important}.mt-lg-n5,.my-lg-n5{margin-top:-3rem!important}.mr-lg-n5,.mx-lg-n5{margin-right:-3rem!important}.mb-lg-n5,.my-lg-n5{margin-bottom:-3rem!important}.ml-lg-n5,.mx-lg-n5{margin-left:-3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-n1{margin:-.25rem!important}.mt-xl-n1,.my-xl-n1{margin-top:-.25rem!important}.mr-xl-n1,.mx-xl-n1{margin-right:-.25rem!important}.mb-xl-n1,.my-xl-n1{margin-bottom:-.25rem!important}.ml-xl-n1,.mx-xl-n1{margin-left:-.25rem!important}.m-xl-n2{margin:-.5rem!important}.mt-xl-n2,.my-xl-n2{margin-top:-.5rem!important}.mr-xl-n2,.mx-xl-n2{margin-right:-.5rem!important}.mb-xl-n2,.my-xl-n2{margin-bottom:-.5rem!important}.ml-xl-n2,.mx-xl-n2{margin-left:-.5rem!important}.m-xl-n3{margin:-1rem!important}.mt-xl-n3,.my-xl-n3{margin-top:-1rem!important}.mr-xl-n3,.mx-xl-n3{margin-right:-1rem!important}.mb-xl-n3,.my-xl-n3{margin-bottom:-1rem!important}.ml-xl-n3,.mx-xl-n3{margin-left:-1rem!important}.m-xl-n4{margin:-1.5rem!important}.mt-xl-n4,.my-xl-n4{margin-top:-1.5rem!important}.mr-xl-n4,.mx-xl-n4{margin-right:-1.5rem!important}.mb-xl-n4,.my-xl-n4{margin-bottom:-1.5rem!important}.ml-xl-n4,.mx-xl-n4{margin-left:-1.5rem!important}.m-xl-n5{margin:-3rem!important}.mt-xl-n5,.my-xl-n5{margin-top:-3rem!important}.mr-xl-n5,.mx-xl-n5{margin-right:-3rem!important}.mb-xl-n5,.my-xl-n5{margin-bottom:-3rem!important}.ml-xl-n5,.mx-xl-n5{margin-left:-3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace!important}.text-justify{text-align:justify!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-lighter{font-weight:lighter!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-weight-bolder{font-weight:bolder!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0056b3!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#494f54!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#19692c!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#0f6674!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#ba8b00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#a71d2a!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#cbd3da!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#121416!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.text-decoration-none{text-decoration:none!important}.text-break{word-break:break-word!important;overflow-wrap:break-word!important}.text-reset{color:inherit!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#dee2e6}.table .thead-dark th{color:inherit;border-color:#dee2e6}}
/*# sourceMappingURL=bootstrap.min.css.map */.octicon {
  display: inline-block;
  vertical-align: text-top;
  fill: currentColor;
}
body {
 padding-top: 10px;
}

.popover {
 max-width: none;
}

.octicon {
 margin-right:.25em;
}

.table-bordered>thead>tr>td {
 border-bottom-width: 1px;
}

.table tbody>tr>td, .table thead>tr>td {
 padding-top: 3px;
 padding-bottom: 3px;
}

.table-condensed tbody>tr>td {
 padding-top: 0;
 padding-bottom: 0;
}

.table .progress {
 margin-bottom: inherit;
}

.table-borderless th, .table-borderless td {
 border: 0 !important;
}

.table tbody tr.covered-by-large-tests, li.covered-by-large-tests, tr.success, td.success, li.success, span.success {
 background-color: #dff0d8;
}

.table tbody tr.covered-by-medium-tests, li.covered-by-medium-tests {
 background-color: #c3e3b5;
}

.table tbody tr.covered-by-small-tests, li.covered-by-small-tests {
 background-color: #99cb84;
}

.table tbody tr.danger, .table tbody td.danger, li.danger, span.danger {
 background-color: #f2dede;
}

.table tbody td.warning, li.warning, span.warning {
 background-color: #fcf8e3;
}

.table tbody td.info {
 background-color: #d9edf7;
}

td.big {
 width: 117px;
}

td.small {
}

td.codeLine {
 font-family: "Source Code Pro", "SFMono-Regular", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
 white-space: pre;
}

td span.comment {
 color: #888a85;
}

td span.default {
 color: #2e3436;
}

td span.html {
 color: #888a85;
}

td span.keyword {
 color: #2e3436;
 font-weight: bold;
}

pre span.string {
 color: #2e3436;
}

span.success, span.warning, span.danger {
 margin-right: 2px;
 padding-left: 10px;
 padding-right: 10px;
 text-align: center;
}

#classCoverageDistribution, #classComplexity {
 height: 200px;
 width: 475px;
}

#toplink {
 position: fixed;
 left: 5px;
 bottom: 5px;
 outline: 0;
}

svg text {
 font-family: "Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, Helvetica, sans-serif;
 font-size: 11px;
 color: #666;
 fill: #666;
}

.scrollbox {
 height:245px;
 overflow-x:hidden;
 overflow-y:scroll;
}
.nvd3 .nv-axis{pointer-events:none;opacity:1}.nvd3 .nv-axis path{fill:none;stroke:#000;stroke-opacity:.75;shape-rendering:crispEdges}.nvd3 .nv-axis path.domain{stroke-opacity:.75}.nvd3 .nv-axis.nv-x path.domain{stroke-opacity:0}.nvd3 .nv-axis line{fill:none;stroke:#e5e5e5;shape-rendering:crispEdges}.nvd3 .nv-axis .zero line,.nvd3 .nv-axis line.zero{stroke-opacity:.75}.nvd3 .nv-axis .nv-axisMaxMin text{font-weight:700}.nvd3 .x .nv-axis .nv-axisMaxMin text,.nvd3 .x2 .nv-axis .nv-axisMaxMin text,.nvd3 .x3 .nv-axis .nv-axisMaxMin text{text-anchor:middle}.nvd3 .nv-axis.nv-disabled{opacity:0}.nvd3 .nv-bars rect{fill-opacity:.75;transition:fill-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear}.nvd3 .nv-bars rect.hover{fill-opacity:1}.nvd3 .nv-bars .hover rect{fill:#add8e6}.nvd3 .nv-bars text{fill:rgba(0,0,0,0)}.nvd3 .nv-bars .hover text{fill:rgba(0,0,0,1)}.nvd3 .nv-multibar .nv-groups rect,.nvd3 .nv-multibarHorizontal .nv-groups rect,.nvd3 .nv-discretebar .nv-groups rect{stroke-opacity:0;transition:fill-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear}.nvd3 .nv-multibar .nv-groups rect:hover,.nvd3 .nv-multibarHorizontal .nv-groups rect:hover,.nvd3 .nv-candlestickBar .nv-ticks rect:hover,.nvd3 .nv-discretebar .nv-groups rect:hover{fill-opacity:1}.nvd3 .nv-discretebar .nv-groups text,.nvd3 .nv-multibarHorizontal .nv-groups text{font-weight:700;fill:rgba(0,0,0,1);stroke:rgba(0,0,0,0)}.nvd3 .nv-boxplot circle{fill-opacity:.5}.nvd3 .nv-boxplot circle:hover{fill-opacity:1}.nvd3 .nv-boxplot rect:hover{fill-opacity:1}.nvd3 line.nv-boxplot-median{stroke:#000}.nv-boxplot-tick:hover{stroke-width:2.5px}.nvd3.nv-bullet{font:10px sans-serif}.nvd3.nv-bullet .nv-measure{fill-opacity:.8}.nvd3.nv-bullet .nv-measure:hover{fill-opacity:1}.nvd3.nv-bullet .nv-marker{stroke:#000;stroke-width:2px}.nvd3.nv-bullet .nv-markerTriangle{stroke:#000;fill:#fff;stroke-width:1.5px}.nvd3.nv-bullet .nv-tick line{stroke:#666;stroke-width:.5px}.nvd3.nv-bullet .nv-range.nv-s0{fill:#eee}.nvd3.nv-bullet .nv-range.nv-s1{fill:#ddd}.nvd3.nv-bullet .nv-range.nv-s2{fill:#ccc}.nvd3.nv-bullet .nv-title{font-size:14px;font-weight:700}.nvd3.nv-bullet .nv-subtitle{fill:#999}.nvd3.nv-bullet .nv-range{fill:#bababa;fill-opacity:.4}.nvd3.nv-bullet .nv-range:hover{fill-opacity:.7}.nvd3.nv-candlestickBar .nv-ticks .nv-tick{stroke-width:1px}.nvd3.nv-candlestickBar .nv-ticks .nv-tick.hover{stroke-width:2px}.nvd3.nv-candlestickBar .nv-ticks .nv-tick.positive rect{stroke:#2ca02c;fill:#2ca02c}.nvd3.nv-candlestickBar .nv-ticks .nv-tick.negative rect{stroke:#d62728;fill:#d62728}.with-transitions .nv-candlestickBar .nv-ticks .nv-tick{transition:stroke-width 250ms linear,stroke-opacity 250ms linear;-moz-transition:stroke-width 250ms linear,stroke-opacity 250ms linear;-webkit-transition:stroke-width 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-candlestickBar .nv-ticks line{stroke:#333}.nvd3 .nv-legend .nv-disabled rect{}.nvd3 .nv-check-box .nv-box{fill-opacity:0;stroke-width:2}.nvd3 .nv-check-box .nv-check{fill-opacity:0;stroke-width:4}.nvd3 .nv-series.nv-disabled .nv-check-box .nv-check{fill-opacity:0;stroke-opacity:0}.nvd3 .nv-controlsWrap .nv-legend .nv-check-box .nv-check{opacity:0}.nvd3.nv-linePlusBar .nv-bar rect{fill-opacity:.75}.nvd3.nv-linePlusBar .nv-bar rect:hover{fill-opacity:1}.nvd3 .nv-groups path.nv-line{fill:none}.nvd3 .nv-groups path.nv-area{stroke:none}.nvd3.nv-line .nvd3.nv-scatter .nv-groups .nv-point{fill-opacity:0;stroke-opacity:0}.nvd3.nv-scatter.nv-single-point .nv-groups .nv-point{fill-opacity:.5!important;stroke-opacity:.5!important}.with-transitions .nvd3 .nv-groups .nv-point{transition:stroke-width 250ms linear,stroke-opacity 250ms linear;-moz-transition:stroke-width 250ms linear,stroke-opacity 250ms linear;-webkit-transition:stroke-width 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-scatter .nv-groups .nv-point.hover,.nvd3 .nv-groups .nv-point.hover{stroke-width:7px;fill-opacity:.95!important;stroke-opacity:.95!important}.nvd3 .nv-point-paths path{stroke:#aaa;stroke-opacity:0;fill:#eee;fill-opacity:0}.nvd3 .nv-indexLine{cursor:ew-resize}svg.nvd3-svg{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-ms-user-select:none;-moz-user-select:none;user-select:none;display:block;width:100%;height:100%}.nvtooltip.with-3d-shadow,.with-3d-shadow .nvtooltip{-moz-box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nvd3 text{font:400 12px Arial}.nvd3 .title{font:700 14px Arial}.nvd3 .nv-background{fill:#fff;fill-opacity:0}.nvd3.nv-noData{font-size:18px;font-weight:700}.nv-brush .extent{fill-opacity:.125;shape-rendering:crispEdges}.nv-brush .resize path{fill:#eee;stroke:#666}.nvd3 .nv-legend .nv-series{cursor:pointer}.nvd3 .nv-legend .nv-disabled circle{fill-opacity:0}.nvd3 .nv-brush .extent{fill-opacity:0!important}.nvd3 .nv-brushBackground rect{stroke:#000;stroke-width:.4;fill:#fff;fill-opacity:.7}.nvd3.nv-ohlcBar .nv-ticks .nv-tick{stroke-width:1px}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.hover{stroke-width:2px}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.positive{stroke:#2ca02c}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.negative{stroke:#d62728}.nvd3 .background path{fill:none;stroke:#EEE;stroke-opacity:.4;shape-rendering:crispEdges}.nvd3 .foreground path{fill:none;stroke-opacity:.7}.nvd3 .nv-parallelCoordinates-brush .extent{fill:#fff;fill-opacity:.6;stroke:gray;shape-rendering:crispEdges}.nvd3 .nv-parallelCoordinates .hover{fill-opacity:1;stroke-width:3px}.nvd3 .missingValuesline line{fill:none;stroke:#000;stroke-width:1;stroke-opacity:1;stroke-dasharray:5,5}.nvd3.nv-pie path{stroke-opacity:0;transition:fill-opacity 250ms linear,stroke-width 250ms linear,stroke-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear,stroke-width 250ms linear,stroke-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear,stroke-width 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-pie .nv-pie-title{font-size:24px;fill:rgba(19,196,249,.59)}.nvd3.nv-pie .nv-slice text{stroke:#000;stroke-width:0}.nvd3.nv-pie path{stroke:#fff;stroke-width:1px;stroke-opacity:1}.nvd3.nv-pie .hover path{fill-opacity:.7}.nvd3.nv-pie .nv-label{pointer-events:none}.nvd3.nv-pie .nv-label rect{fill-opacity:0;stroke-opacity:0}.nvd3 .nv-groups .nv-point.hover{stroke-width:20px;stroke-opacity:.5}.nvd3 .nv-scatter .nv-point.hover{fill-opacity:1}.nv-noninteractive{pointer-events:none}.nv-distx,.nv-disty{pointer-events:none}.nvd3.nv-sparkline path{fill:none}.nvd3.nv-sparklineplus g.nv-hoverValue{pointer-events:none}.nvd3.nv-sparklineplus .nv-hoverValue line{stroke:#333;stroke-width:1.5px}.nvd3.nv-sparklineplus,.nvd3.nv-sparklineplus g{pointer-events:all}.nvd3 .nv-hoverArea{fill-opacity:0;stroke-opacity:0}.nvd3.nv-sparklineplus .nv-xValue,.nvd3.nv-sparklineplus .nv-yValue{stroke-width:0;font-size:.9em;font-weight:400}.nvd3.nv-sparklineplus .nv-yValue{stroke:#f66}.nvd3.nv-sparklineplus .nv-maxValue{stroke:#2ca02c;fill:#2ca02c}.nvd3.nv-sparklineplus .nv-minValue{stroke:#d62728;fill:#d62728}.nvd3.nv-sparklineplus .nv-currentValue{font-weight:700;font-size:1.1em}.nvd3.nv-stackedarea path.nv-area{fill-opacity:.7;stroke-opacity:0;transition:fill-opacity 250ms linear,stroke-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear,stroke-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-stackedarea path.nv-area.hover{fill-opacity:.9}.nvd3.nv-stackedarea .nv-groups .nv-point{stroke-opacity:0;fill-opacity:0}.nvtooltip{position:absolute;background-color:rgba(255,255,255,1);color:rgba(0,0,0,1);padding:1px;border:1px solid rgba(0,0,0,.2);z-index:10000;display:block;font-family:Arial;font-size:13px;text-align:left;pointer-events:none;white-space:nowrap;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.nvtooltip{background:rgba(255,255,255,.8);border:1px solid rgba(0,0,0,.5);border-radius:4px}.nvtooltip.with-transitions,.with-transitions .nvtooltip{transition:opacity 50ms linear;-moz-transition:opacity 50ms linear;-webkit-transition:opacity 50ms linear;transition-delay:200ms;-moz-transition-delay:200ms;-webkit-transition-delay:200ms}.nvtooltip.x-nvtooltip,.nvtooltip.y-nvtooltip{padding:8px}.nvtooltip h3{margin:0;padding:4px 14px;line-height:18px;font-weight:400;background-color:rgba(247,247,247,.75);color:rgba(0,0,0,1);text-align:center;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.nvtooltip p{margin:0;padding:5px 14px;text-align:center}.nvtooltip span{display:inline-block;margin:2px 0}.nvtooltip table{margin:6px;border-spacing:0}.nvtooltip table td{padding:2px 9px 2px 0;vertical-align:middle}.nvtooltip table td.key{font-weight:400}.nvtooltip table td.value{text-align:right;font-weight:700}.nvtooltip table tr.highlight td{padding:1px 9px 1px 0;border-bottom-style:solid;border-bottom-width:1px;border-top-style:solid;border-top-width:1px}.nvtooltip table td.legend-color-guide div{width:8px;height:8px;vertical-align:middle}.nvtooltip table td.legend-color-guide div{width:12px;height:12px;border:1px solid #999}.nvtooltip .footer{padding:3px;text-align:center}.nvtooltip-pending-removal{pointer-events:none;display:none}.nvd3 .nv-interactiveGuideLine{pointer-events:none}.nvd3 line.nv-guideline{stroke:#ccc}      <tr>
       <td class="{{lines_level}}">{{icon}}{{name}}</td>
       <td class="{{lines_level}} big">{{lines_bar}}</td>
       <td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
       <td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>
       <td class="{{methods_level}} big">{{methods_bar}}</td>
       <td class="{{methods_level}} small"><div align="right">{{methods_tested_percent}}</div></td>
       <td class="{{methods_level}} small"><div align="right">{{methods_number}}</div></td>
       <td class="{{classes_level}} big">{{classes_bar}}</td>
       <td class="{{classes_level}} small"><div align="right">{{classes_tested_percent}}</div></td>
       <td class="{{classes_level}} small"><div align="right">{{classes_number}}</div></td>
      </tr>

/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */
!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}k.fn=k.prototype={jquery:f,constructor:k,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=k.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return k.each(this,e)},map:function(n){return this.pushStack(k.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},k.extend=k.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(k.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||k.isPlainObject(n)?n:{},i=!1,a[t]=k.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},k.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t){b(e,{nonce:t&&t.nonce})},each:function(e,t){var n,r=0;if(d(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?"":(e+"").replace(p,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(d(Object(e))?k.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(d(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g.apply([],a)},guid:1,support:y}),"function"==typeof Symbol&&(k.fn[Symbol.iterator]=t[Symbol.iterator]),k.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var h=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,k="sizzle"+1*new Date,m=n.document,S=0,r=0,p=ue(),x=ue(),N=ue(),A=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",$=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",F=new RegExp(M+"+","g"),B=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="<a id='"+k+"'></a><select id='"+k+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!==C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!==C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(F," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),x="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[S,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[S,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[k]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace(B,"$1"));return s[k]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[S,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[k]||(e[k]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===S&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[k]&&(v=Ce(v)),y&&!y[k]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[k]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(B,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace(B," ")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=N[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[k]?i.push(a):o.push(a);(a=N(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=S+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t===C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument===C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(S=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(S=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=k.split("").sort(D).join("")===k,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);k.find=h,k.expr=h.selectors,k.expr[":"]=k.expr.pseudos,k.uniqueSort=k.unique=h.uniqueSort,k.text=h.getText,k.isXMLDoc=h.isXML,k.contains=h.contains,k.escapeSelector=h.escape;var T=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&k(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},N=k.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var D=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1<i.call(n,e)!==r}):k.filter(n,e,r)}k.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?k.find.matchesSelector(r,e)?[r]:[]:k.find.matches(e,k.grep(t,function(e){return 1===e.nodeType}))},k.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(k(e).filter(function(){for(t=0;t<r;t++)if(k.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)k.find(e,i[t],n);return 1<r?k.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&N.test(e)?k(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(k.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&k(e);if(!N.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&k.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?k.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(k(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(k.uniqueSort(k.merge(this.get(),k(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),k.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return T(e,"parentNode")},parentsUntil:function(e,t,n){return T(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return T(e,"nextSibling")},prevAll:function(e){return T(e,"previousSibling")},nextUntil:function(e,t,n){return T(e,"nextSibling",n)},prevUntil:function(e,t,n){return T(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return"undefined"!=typeof e.contentDocument?e.contentDocument:(A(e,"template")&&(e=e.content||e),k.merge([],e.childNodes))}},function(r,i){k.fn[r]=function(e,t){var n=k.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=k.filter(t,n)),1<this.length&&(O[r]||k.uniqueSort(n),H.test(r)&&n.reverse()),this.pushStack(n)}});var R=/[^\x20\t\r\n\f]+/g;function M(e){return e}function I(e){throw e}function W(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}k.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},k.each(e.match(R)||[],function(e,t){n[t]=!0}),n):k.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){k.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return k.each(arguments,function(e,t){var n;while(-1<(n=k.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<k.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},k.extend({Deferred:function(e){var o=[["notify","progress",k.Callbacks("memory"),k.Callbacks("memory"),2],["resolve","done",k.Callbacks("once memory"),k.Callbacks("once memory"),0,"resolved"],["reject","fail",k.Callbacks("once memory"),k.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return k.Deferred(function(r){k.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,M,s),l(u,o,I,s)):(u++,t.call(e,l(u,o,M,s),l(u,o,I,s),l(u,o,M,o.notifyWith))):(a!==M&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){k.Deferred.exceptionHook&&k.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==I&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(k.Deferred.getStackHook&&(t.stackTrace=k.Deferred.getStackHook()),C.setTimeout(t))}}return k.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:M,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:M)),o[2][3].add(l(0,e,m(n)?n:I))}).promise()},promise:function(e){return null!=e?k.extend(e,a):a}},s={};return k.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=k.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(W(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)W(i[t],a(t),o.reject);return o.promise()}});var $=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;k.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&$.test(e.name)&&C.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},k.readyException=function(e){C.setTimeout(function(){throw e})};var F=k.Deferred();function B(){E.removeEventListener("DOMContentLoaded",B),C.removeEventListener("load",B),k.ready()}k.fn.ready=function(e){return F.then(e)["catch"](function(e){k.readyException(e)}),this},k.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--k.readyWait:k.isReady)||(k.isReady=!0)!==e&&0<--k.readyWait||F.resolveWith(E,[k])}}),k.ready.then=F.then,"complete"===E.readyState||"loading"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(k.ready):(E.addEventListener("DOMContentLoaded",B),C.addEventListener("load",B));var _=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===w(n))for(s in i=!0,n)_(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(k(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},z=/^-ms-/,U=/-([a-z])/g;function X(e,t){return t.toUpperCase()}function V(e){return e.replace(z,"ms-").replace(U,X)}var G=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function Y(){this.expando=k.expando+Y.uid++}Y.uid=1,Y.prototype={cache:function(e){var t=e[this.expando];return t||(t={},G(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[V(t)]=n;else for(r in t)i[V(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][V(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(V):(t=V(t))in r?[t]:t.match(R)||[]).length;while(n--)delete r[t[n]]}(void 0===t||k.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!k.isEmptyObject(t)}};var Q=new Y,J=new Y,K=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Z=/[A-Z]/g;function ee(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(Z,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:K.test(i)?JSON.parse(i):i)}catch(e){}J.set(e,t,n)}else n=void 0;return n}k.extend({hasData:function(e){return J.hasData(e)||Q.hasData(e)},data:function(e,t,n){return J.access(e,t,n)},removeData:function(e,t){J.remove(e,t)},_data:function(e,t,n){return Q.access(e,t,n)},_removeData:function(e,t){Q.remove(e,t)}}),k.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=J.get(o),1===o.nodeType&&!Q.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=V(r.slice(5)),ee(o,r,i[r]));Q.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){J.set(this,n)}):_(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=J.get(o,n))?t:void 0!==(t=ee(o,n))?t:void 0;this.each(function(){J.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){J.remove(this,e)})}}),k.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Q.get(e,t),n&&(!r||Array.isArray(n)?r=Q.access(e,t,k.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=k.queue(e,t),r=n.length,i=n.shift(),o=k._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){k.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Q.get(e,n)||Q.access(e,n,{empty:k.Callbacks("once memory").add(function(){Q.remove(e,[t+"queue",n])})})}}),k.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?k.queue(this[0],t):void 0===n?this:this.each(function(){var e=k.queue(this,t,n);k._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&k.dequeue(this,t)})},dequeue:function(e){return this.each(function(){k.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=k.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=Q.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var te=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,ne=new RegExp("^(?:([+-])=|)("+te+")([a-z%]*)$","i"),re=["Top","Right","Bottom","Left"],ie=E.documentElement,oe=function(e){return k.contains(e.ownerDocument,e)},ae={composed:!0};ie.getRootNode&&(oe=function(e){return k.contains(e.ownerDocument,e)||e.getRootNode(ae)===e.ownerDocument});var se=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&oe(e)&&"none"===k.css(e,"display")},ue=function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];for(o in i=n.apply(e,r||[]),t)e.style[o]=a[o];return i};function le(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return k.css(e,t,"")},u=s(),l=n&&n[3]||(k.cssNumber[t]?"":"px"),c=e.nodeType&&(k.cssNumber[t]||"px"!==l&&+u)&&ne.exec(k.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)k.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,k.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ce={};function fe(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Q.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&se(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ce[s])||(o=a.body.appendChild(a.createElement(s)),u=k.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ce[s]=u)))):"none"!==n&&(l[c]="none",Q.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}k.fn.extend({show:function(){return fe(this,!0)},hide:function(){return fe(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){se(this)?k(this).show():k(this).hide()})}});var pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Q.set(e[n],"globalEval",!t||Q.get(t[n],"globalEval"))}ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;var me,xe,be=/<|&#?\w+;/;function we(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===w(o))k.merge(p,o.nodeType?[o]:o);else if(be.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+k.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;k.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<k.inArray(o,r))i&&i.push(o);else if(l=oe(o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}me=E.createDocumentFragment().appendChild(E.createElement("div")),(xe=E.createElement("input")).setAttribute("type","radio"),xe.setAttribute("checked","checked"),xe.setAttribute("name","t"),me.appendChild(xe),y.checkClone=me.cloneNode(!0).cloneNode(!0).lastChild.checked,me.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t<arguments.length;t++)u[t]=arguments[t];if(s.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,s)){a=k.event.handlers.call(this,s,l),t=0;while((i=a[t++])&&!s.isPropagationStopped()){s.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!s.isImmediatePropagationStopped())s.rnamespace&&!1!==o.namespace&&!s.rnamespace.test(o.namespace)||(s.handleObj=o,s.data=o.data,void 0!==(r=((k.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,u))&&!1===(s.result=r)&&(s.preventDefault(),s.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,s),s.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<k(i,this).index(l):k.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(k.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[k.expando]?e:new k.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&De(t,"click",ke),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&De(t,"click"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,"input")&&Q.get(t,"click")||A(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},k.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},k.Event=function(e,t){if(!(this instanceof k.Event))return new k.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?ke:Se,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&k.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[k.expando]=!0},k.Event.prototype={constructor:k.Event,isDefaultPrevented:Se,isPropagationStopped:Se,isImmediatePropagationStopped:Se,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=ke,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=ke,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=ke,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},k.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&Te.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&Ce.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},k.event.addProp),k.each({focus:"focusin",blur:"focusout"},function(e,t){k.event.special[e]={setup:function(){return De(this,e,Ne),!1},trigger:function(){return De(this,e),!0},delegateType:t}}),k.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){k.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||k.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),k.fn.extend({on:function(e,t,n,r){return Ae(this,e,t,n,r)},one:function(e,t,n,r){return Ae(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,k(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=Se),this.each(function(){k.event.remove(this,e,n,t)})}});var je=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/<script|<style|<link/i,Le=/checked\s*(?:[^=]|=\s*.checked.)/i,He=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n<r;n++)k.event.add(t,i,l[i][n]);J.hasData(e)&&(s=J.access(e),u=k.extend({},s),J.set(t,u))}}function Ie(n,r,i,o){r=g.apply([],r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&"string"==typeof d&&!y.checkClone&&Le.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Ie(t,r,i,o)});if(f&&(t=(e=we(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=k.map(ve(e,"script"),Pe)).length;c<f;c++)u=e,c!==p&&(u=k.clone(u,!0,!0),s&&k.merge(a,ve(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,k.map(a,Re),c=0;c<s;c++)u=a[c],he.test(u.type||"")&&!Q.access(u,"globalEval")&&k.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?k._evalUrl&&!u.noModule&&k._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")}):b(u.textContent.replace(He,""),u,l))}return n}function We(e,t,n){for(var r,i=t?k.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||k.cleanData(ve(r)),r.parentNode&&(n&&oe(r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}k.extend({htmlPrefilter:function(e){return e.replace(je,"<$1></$2>")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Me(o[r],a[r]);else Me(e,c);return 0<(a=ve(c,"script")).length&&ye(a,!f&&ve(e,"script")),c},cleanData:function(e){for(var t,n,r,i=k.event.special,o=0;void 0!==(n=e[o]);o++)if(G(n)){if(t=n[Q.expando]){if(t.events)for(r in t.events)i[r]?k.event.remove(n,r):k.removeEvent(n,r,t.handle);n[Q.expando]=void 0}n[J.expando]&&(n[J.expando]=void 0)}}}),k.fn.extend({detach:function(e){return We(this,e,!0)},remove:function(e){return We(this,e)},text:function(e){return _(this,function(e){return void 0===e?k.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Ie(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Oe(this,e).appendChild(e)})},prepend:function(){return Ie(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Oe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(k.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return k.clone(this,e,t)})},html:function(e){return _(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!qe.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=k.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(k.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Ie(this,arguments,function(e){var t=this.parentNode;k.inArray(this,n)<0&&(k.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),k.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){k.fn[e]=function(e){for(var t,n=[],r=k(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),k(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var $e=new RegExp("^("+te+")(?!px)[a-z%]+$","i"),Fe=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},Be=new RegExp(re.join("|"),"i");function _e(e,t,n){var r,i,o,a,s=e.style;return(n=n||Fe(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||oe(e)||(a=k.style(e,t)),!y.pixelBoxStyles()&&$e.test(a)&&Be.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function ze(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(u){s.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",u.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",ie.appendChild(s).appendChild(u);var e=C.getComputedStyle(u);n="1%"!==e.top,a=12===t(e.marginLeft),u.style.right="60%",o=36===t(e.right),r=36===t(e.width),u.style.position="absolute",i=12===t(u.offsetWidth/3),ie.removeChild(s),u=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s=E.createElement("div"),u=E.createElement("div");u.style&&(u.style.backgroundClip="content-box",u.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===u.style.backgroundClip,k.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),a},scrollboxSize:function(){return e(),i}}))}();var Ue=["Webkit","Moz","ms"],Xe=E.createElement("div").style,Ve={};function Ge(e){var t=k.cssProps[e]||Ve[e];return t||(e in Xe?e:Ve[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Ue.length;while(n--)if((e=Ue[n]+t)in Xe)return e}(e)||e)}var Ye=/^(none|table(?!-c[ea]).+)/,Qe=/^--/,Je={position:"absolute",visibility:"hidden",display:"block"},Ke={letterSpacing:"0",fontWeight:"400"};function Ze(e,t,n){var r=ne.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function et(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=k.css(e,n+re[a],!0,i)),r?("content"===n&&(u-=k.css(e,"padding"+re[a],!0,i)),"margin"!==n&&(u-=k.css(e,"border"+re[a]+"Width",!0,i))):(u+=k.css(e,"padding"+re[a],!0,i),"padding"!==n?u+=k.css(e,"border"+re[a]+"Width",!0,i):s+=k.css(e,"border"+re[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function tt(e,t,n){var r=Fe(e),i=(!y.boxSizingReliable()||n)&&"border-box"===k.css(e,"boxSizing",!1,r),o=i,a=_e(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if($e.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||"auto"===a||!parseFloat(a)&&"inline"===k.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===k.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+et(e,t,n||(i?"border":"content"),o,r,a)+"px"}function nt(e,t,n,r,i){return new nt.prototype.init(e,t,n,r,i)}k.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=_e(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=V(t),u=Qe.test(t),l=e.style;if(u||(t=Ge(s)),a=k.cssHooks[t]||k.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=ne.exec(n))&&i[1]&&(n=le(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(k.cssNumber[s]?"":"px")),y.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=V(t);return Qe.test(t)||(t=Ge(s)),(a=k.cssHooks[t]||k.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=_e(e,t,r)),"normal"===i&&t in Ke&&(i=Ke[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),k.each(["height","width"],function(e,u){k.cssHooks[u]={get:function(e,t,n){if(t)return!Ye.test(k.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?tt(e,u,n):ue(e,Je,function(){return tt(e,u,n)})},set:function(e,t,n){var r,i=Fe(e),o=!y.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===k.css(e,"boxSizing",!1,i),s=n?et(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-et(e,u,"border",!1,i)-.5)),s&&(r=ne.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=k.css(e,u)),Ze(0,t,s)}}}),k.cssHooks.marginLeft=ze(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(_e(e,"marginLeft"))||e.getBoundingClientRect().left-ue(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),k.each({margin:"",padding:"",border:"Width"},function(i,o){k.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+re[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(k.cssHooks[i+o].set=Ze)}),k.fn.extend({css:function(e,t){return _(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Fe(e),i=t.length;a<i;a++)o[t[a]]=k.css(e,t[a],!1,r);return o}return void 0!==n?k.style(e,t,n):k.css(e,t)},e,t,1<arguments.length)}}),((k.Tween=nt).prototype={constructor:nt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||k.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(k.cssNumber[n]?"":"px")},cur:function(){var e=nt.propHooks[this.prop];return e&&e.get?e.get(this):nt.propHooks._default.get(this)},run:function(e){var t,n=nt.propHooks[this.prop];return this.options.duration?this.pos=t=k.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):nt.propHooks._default.set(this),this}}).init.prototype=nt.prototype,(nt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=k.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){k.fx.step[e.prop]?k.fx.step[e.prop](e):1!==e.elem.nodeType||!k.cssHooks[e.prop]&&null==e.elem.style[Ge(e.prop)]?e.elem[e.prop]=e.now:k.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=nt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},k.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},k.fx=nt.prototype.init,k.fx.step={};var rt,it,ot,at,st=/^(?:toggle|show|hide)$/,ut=/queueHooks$/;function lt(){it&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(lt):C.setTimeout(lt,k.fx.interval),k.fx.tick())}function ct(){return C.setTimeout(function(){rt=void 0}),rt=Date.now()}function ft(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=re[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function pt(e,t,n){for(var r,i=(dt.tweeners[t]||[]).concat(dt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function dt(o,e,t){var n,a,r=0,i=dt.prefilters.length,s=k.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=rt||ct(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:k.extend({},e),opts:k.extend(!0,{specialEasing:{},easing:k.easing._default},t),originalProperties:e,originalOptions:t,startTime:rt||ct(),duration:t.duration,tweens:[],createTween:function(e,t){var n=k.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=V(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=k.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=dt.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(k._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return k.map(c,pt,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),k.fx.timer(k.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}k.Animation=k.extend(dt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return le(n.elem,e,ne.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(R);for(var n,r=0,i=e.length;r<i;r++)n=e[r],dt.tweeners[n]=dt.tweeners[n]||[],dt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&se(e),v=Q.get(e,"fxshow");for(r in n.queue||(null==(a=k._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,k.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],st.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||k.style(e,r)}if((u=!k.isEmptyObject(t))||!k.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Q.get(e,"display")),"none"===(c=k.css(e,"display"))&&(l?c=l:(fe([e],!0),l=e.style.display||l,c=k.css(e,"display"),fe([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===k.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=Q.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&fe([e],!0),p.done(function(){for(r in g||fe([e]),Q.remove(e,"fxshow"),d)k.style(e,r,d[r])})),u=pt(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?dt.prefilters.unshift(e):dt.prefilters.push(e)}}),k.speed=function(e,t,n){var r=e&&"object"==typeof e?k.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return k.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in k.fx.speeds?r.duration=k.fx.speeds[r.duration]:r.duration=k.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&k.dequeue(this,r.queue)},r},k.fn.extend({fadeTo:function(e,t,n,r){return this.filter(se).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=k.isEmptyObject(t),o=k.speed(e,n,r),a=function(){var e=dt(this,k.extend({},t),o);(i||Q.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&!1!==i&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=k.timers,r=Q.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&ut.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||k.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=Q.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=k.timers,o=n?n.length:0;for(t.finish=!0,k.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),k.each(["toggle","show","hide"],function(e,r){var i=k.fn[r];k.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(ft(r,!0),e,t,n)}}),k.each({slideDown:ft("show"),slideUp:ft("hide"),slideToggle:ft("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){k.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),k.timers=[],k.fx.tick=function(){var e,t=0,n=k.timers;for(rt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||k.fx.stop(),rt=void 0},k.fx.timer=function(e){k.timers.push(e),k.fx.start()},k.fx.interval=13,k.fx.start=function(){it||(it=!0,lt())},k.fx.stop=function(){it=null},k.fx.speeds={slow:600,fast:200,_default:400},k.fn.delay=function(r,e){return r=k.fx&&k.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},ot=E.createElement("input"),at=E.createElement("select").appendChild(E.createElement("option")),ot.type="checkbox",y.checkOn=""!==ot.value,y.optSelected=at.selected,(ot=E.createElement("input")).value="t",ot.type="radio",y.radioValue="t"===ot.value;var ht,gt=k.expr.attrHandle;k.fn.extend({attr:function(e,t){return _(this,k.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){k.removeAttr(this,e)})}}),k.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?k.prop(e,t,n):(1===o&&k.isXMLDoc(e)||(i=k.attrHooks[t.toLowerCase()]||(k.expr.match.bool.test(t)?ht:void 0)),void 0!==n?null===n?void k.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=k.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(R);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),ht={set:function(e,t,n){return!1===t?k.removeAttr(e,n):e.setAttribute(n,n),n}},k.each(k.expr.match.bool.source.match(/\w+/g),function(e,t){var a=gt[t]||k.find.attr;gt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=gt[o],gt[o]=r,r=null!=a(e,t,n)?o:null,gt[o]=i),r}});var vt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;function mt(e){return(e.match(R)||[]).join(" ")}function xt(e){return e.getAttribute&&e.getAttribute("class")||""}function bt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(R)||[]}k.fn.extend({prop:function(e,t){return _(this,k.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[k.propFix[e]||e]})}}),k.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&k.isXMLDoc(e)||(t=k.propFix[t]||t,i=k.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=k.find.attr(e,"tabindex");return t?parseInt(t,10):vt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),y.optSelected||(k.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),k.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){k.propFix[this.toLowerCase()]=this}),k.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).addClass(t.call(this,e,xt(this)))});if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&" "+mt(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=mt(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).removeClass(t.call(this,e,xt(this)))});if(!arguments.length)return this.attr("class","");if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&" "+mt(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=mt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){k(this).toggleClass(i.call(this,e,xt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=k(this),r=bt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=xt(this))&&Q.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Q.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+mt(xt(n))+" ").indexOf(t))return!0;return!1}});var wt=/\r/g;k.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,k(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=k.map(t,function(e){return null==e?"":e+""})),(r=k.valHooks[this.type]||k.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=k.valHooks[t.type]||k.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(wt,""):null==e?"":e:void 0}}),k.extend({valHooks:{option:{get:function(e){var t=k.find.attr(e,"value");return null!=t?t:mt(k.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,"optgroup"))){if(t=k(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=k.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<k.inArray(k.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),k.each(["radio","checkbox"],function(){k.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<k.inArray(k(e).val(),t)}},y.checkOn||(k.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in C;var Tt=/^(?:focusinfocus|focusoutblur)$/,Ct=function(e){e.stopPropagation()};k.extend(k.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,"type")?e.type:e,h=v.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!Tt.test(d+k.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[k.expando]?e:new k.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:k.makeArray(t,[e]),c=k.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,Tt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Q.get(o,"events")||{})[e.type]&&Q.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&G(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!G(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),k.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,Ct),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,Ct),k.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=k.extend(new k.Event,n,{type:e,isSimulated:!0});k.event.trigger(r,null,t)}}),k.fn.extend({trigger:function(e,t){return this.each(function(){k.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return k.event.trigger(e,t,n,!0)}}),y.focusin||k.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){k.event.simulate(r,e.target,k.event.fix(e))};k.event.special[r]={setup:function(){var e=this.ownerDocument||this,t=Q.access(e,r);t||e.addEventListener(n,i,!0),Q.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this,t=Q.access(e,r)-1;t?Q.access(e,r,t):(e.removeEventListener(n,i,!0),Q.remove(e,r))}}});var Et=C.location,kt=Date.now(),St=/\?/;k.parseXML=function(e){var t;if(!e||"string"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||k.error("Invalid XML: "+e),t};var Nt=/\[\]$/,At=/\r?\n/g,Dt=/^(?:submit|button|image|reset|file)$/i,jt=/^(?:input|select|textarea|keygen)/i;function qt(n,e,r,i){var t;if(Array.isArray(e))k.each(e,function(e,t){r||Nt.test(n)?i(n,t):qt(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==w(e))i(n,e);else for(t in e)qt(n+"["+t+"]",e[t],r,i)}k.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!k.isPlainObject(e))k.each(e,function(){i(this.name,this.value)});else for(n in e)qt(n,e[n],t,i);return r.join("&")},k.fn.extend({serialize:function(){return k.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=k.prop(this,"elements");return e?k.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!k(this).is(":disabled")&&jt.test(this.nodeName)&&!Dt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=k(this).val();return null==n?null:Array.isArray(n)?k.map(n,function(e){return{name:t.name,value:e.replace(At,"\r\n")}}):{name:t.name,value:n.replace(At,"\r\n")}}).get()}});var Lt=/%20/g,Ht=/#.*$/,Ot=/([?&])_=[^&]*/,Pt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Rt=/^(?:GET|HEAD)$/,Mt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Ft=E.createElement("a");function Bt(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(R)||[];if(m(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function _t(t,i,o,a){var s={},u=t===Wt;function l(e){var r;return s[e]=!0,k.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function zt(e,t){var n,r,i=k.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&k.extend(!0,e,r),e}Ft.href=Et.href,k.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Et.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Et.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":k.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,k.ajaxSettings),t):zt(k.ajaxSettings,e)},ajaxPrefilter:Bt(It),ajaxTransport:Bt(Wt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=k.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?k(y):k.event,x=k.Deferred(),b=k.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Pt.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Et.href)+"").replace(Mt,Et.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(R)||[""],null==v.crossDomain){r=E.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Ft.protocol+"//"+Ft.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=k.param(v.data,v.traditional)),_t(It,v,t,T),h)return T;for(i in(g=k.event&&v.global)&&0==k.active++&&k.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Rt.test(v.type),f=v.url.replace(Ht,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(Lt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(St.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Ot,"$1"),o=(St.test(f)?"&":"?")+"_="+kt+++o),v.url=f+o),v.ifModified&&(k.lastModified[f]&&T.setRequestHeader("If-Modified-Since",k.lastModified[f]),k.etag[f]&&T.setRequestHeader("If-None-Match",k.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+$t+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=_t(Wt,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(k.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(k.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--k.active||k.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return k.get(e,t,n,"json")},getScript:function(e,t){return k.get(e,void 0,t,"script")}}),k.each(["get","post"],function(e,i){k[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),k.ajax(k.extend({url:e,type:i,dataType:r,data:t,success:n},k.isPlainObject(e)&&e))}}),k._evalUrl=function(e,t){return k.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){k.globalEval(e,t)}})},k.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=k(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){k(this).wrapInner(n.call(this,e))}):this.each(function(){var e=k(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){k(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){k(this).replaceWith(this.childNodes)}),this}}),k.expr.pseudos.hidden=function(e){return!k.expr.pseudos.visible(e)},k.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},k.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var Ut={0:200,1223:204},Xt=k.ajaxSettings.xhr();y.cors=!!Xt&&"withCredentials"in Xt,y.ajax=Xt=!!Xt,k.ajaxTransport(function(i){var o,a;if(y.cors||Xt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(Ut[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),k.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),k.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return k.globalEval(e),e}}}),k.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),k.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=k("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=mt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&k.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?k("<div>").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}}),k.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),k.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}}),k.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||k.guid++,i},k.holdReady=function(e){e?k.readyWait++:k.ready(!0)},k.isArray=Array.isArray,k.parseJSON=JSON.parse,k.nodeName=A,k.isFunction=m,k.isWindow=x,k.camelCase=V,k.type=w,k.now=Date.now,k.isNumeric=function(e){var t=k.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},"function"==typeof define&&define.amd&&define("jquery",[],function(){return k});var Qt=C.jQuery,Jt=C.$;return k.noConflict=function(e){return C.$===k&&(C.$=Jt),e&&C.jQuery===k&&(C.jQuery=Qt),k},e||(C.jQuery=C.$=k),k});
/*!
  * Bootstrap v4.3.1 (https://getbootstrap.com/)
  * Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
  */
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e((t=t||self).bootstrap={},t.jQuery,t.Popper)}(this,function(t,g,u){"use strict";function i(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function s(t,e,n){return e&&i(t.prototype,e),n&&i(t,n),t}function l(o){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{},e=Object.keys(r);"function"==typeof Object.getOwnPropertySymbols&&(e=e.concat(Object.getOwnPropertySymbols(r).filter(function(t){return Object.getOwnPropertyDescriptor(r,t).enumerable}))),e.forEach(function(t){var e,n,i;e=o,i=r[n=t],n in e?Object.defineProperty(e,n,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[n]=i})}return o}g=g&&g.hasOwnProperty("default")?g.default:g,u=u&&u.hasOwnProperty("default")?u.default:u;var e="transitionend";function n(t){var e=this,n=!1;return g(this).one(_.TRANSITION_END,function(){n=!0}),setTimeout(function(){n||_.triggerTransitionEnd(e)},t),this}var _={TRANSITION_END:"bsTransitionEnd",getUID:function(t){for(;t+=~~(1e6*Math.random()),document.getElementById(t););return t},getSelectorFromElement:function(t){var e=t.getAttribute("data-target");if(!e||"#"===e){var n=t.getAttribute("href");e=n&&"#"!==n?n.trim():""}try{return document.querySelector(e)?e:null}catch(t){return null}},getTransitionDurationFromElement:function(t){if(!t)return 0;var e=g(t).css("transition-duration"),n=g(t).css("transition-delay"),i=parseFloat(e),o=parseFloat(n);return i||o?(e=e.split(",")[0],n=n.split(",")[0],1e3*(parseFloat(e)+parseFloat(n))):0},reflow:function(t){return t.offsetHeight},triggerTransitionEnd:function(t){g(t).trigger(e)},supportsTransitionEnd:function(){return Boolean(e)},isElement:function(t){return(t[0]||t).nodeType},typeCheckConfig:function(t,e,n){for(var i in n)if(Object.prototype.hasOwnProperty.call(n,i)){var o=n[i],r=e[i],s=r&&_.isElement(r)?"element":(a=r,{}.toString.call(a).match(/\s([a-z]+)/i)[1].toLowerCase());if(!new RegExp(o).test(s))throw new Error(t.toUpperCase()+': Option "'+i+'" provided type "'+s+'" but expected type "'+o+'".')}var a},findShadowRoot:function(t){if(!document.documentElement.attachShadow)return null;if("function"!=typeof t.getRootNode)return t instanceof ShadowRoot?t:t.parentNode?_.findShadowRoot(t.parentNode):null;var e=t.getRootNode();return e instanceof ShadowRoot?e:null}};g.fn.emulateTransitionEnd=n,g.event.special[_.TRANSITION_END]={bindType:e,delegateType:e,handle:function(t){if(g(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}};var o="alert",r="bs.alert",a="."+r,c=g.fn[o],h={CLOSE:"close"+a,CLOSED:"closed"+a,CLICK_DATA_API:"click"+a+".data-api"},f="alert",d="fade",m="show",p=function(){function i(t){this._element=t}var t=i.prototype;return t.close=function(t){var e=this._element;t&&(e=this._getRootElement(t)),this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},t.dispose=function(){g.removeData(this._element,r),this._element=null},t._getRootElement=function(t){var e=_.getSelectorFromElement(t),n=!1;return e&&(n=document.querySelector(e)),n||(n=g(t).closest("."+f)[0]),n},t._triggerCloseEvent=function(t){var e=g.Event(h.CLOSE);return g(t).trigger(e),e},t._removeElement=function(e){var n=this;if(g(e).removeClass(m),g(e).hasClass(d)){var t=_.getTransitionDurationFromElement(e);g(e).one(_.TRANSITION_END,function(t){return n._destroyElement(e,t)}).emulateTransitionEnd(t)}else this._destroyElement(e)},t._destroyElement=function(t){g(t).detach().trigger(h.CLOSED).remove()},i._jQueryInterface=function(n){return this.each(function(){var t=g(this),e=t.data(r);e||(e=new i(this),t.data(r,e)),"close"===n&&e[n](this)})},i._handleDismiss=function(e){return function(t){t&&t.preventDefault(),e.close(this)}},s(i,null,[{key:"VERSION",get:function(){return"4.3.1"}}]),i}();g(document).on(h.CLICK_DATA_API,'[data-dismiss="alert"]',p._handleDismiss(new p)),g.fn[o]=p._jQueryInterface,g.fn[o].Constructor=p,g.fn[o].noConflict=function(){return g.fn[o]=c,p._jQueryInterface};var v="button",y="bs.button",E="."+y,C=".data-api",T=g.fn[v],S="active",b="btn",I="focus",D='[data-toggle^="button"]',w='[data-toggle="buttons"]',A='input:not([type="hidden"])',N=".active",O=".btn",k={CLICK_DATA_API:"click"+E+C,FOCUS_BLUR_DATA_API:"focus"+E+C+" blur"+E+C},P=function(){function n(t){this._element=t}var t=n.prototype;return t.toggle=function(){var t=!0,e=!0,n=g(this._element).closest(w)[0];if(n){var i=this._element.querySelector(A);if(i){if("radio"===i.type)if(i.checked&&this._element.classList.contains(S))t=!1;else{var o=n.querySelector(N);o&&g(o).removeClass(S)}if(t){if(i.hasAttribute("disabled")||n.hasAttribute("disabled")||i.classList.contains("disabled")||n.classList.contains("disabled"))return;i.checked=!this._element.classList.contains(S),g(i).trigger("change")}i.focus(),e=!1}}e&&this._element.setAttribute("aria-pressed",!this._element.classList.contains(S)),t&&g(this._element).toggleClass(S)},t.dispose=function(){g.removeData(this._element,y),this._element=null},n._jQueryInterface=function(e){return this.each(function(){var t=g(this).data(y);t||(t=new n(this),g(this).data(y,t)),"toggle"===e&&t[e]()})},s(n,null,[{key:"VERSION",get:function(){return"4.3.1"}}]),n}();g(document).on(k.CLICK_DATA_API,D,function(t){t.preventDefault();var e=t.target;g(e).hasClass(b)||(e=g(e).closest(O)),P._jQueryInterface.call(g(e),"toggle")}).on(k.FOCUS_BLUR_DATA_API,D,function(t){var e=g(t.target).closest(O)[0];g(e).toggleClass(I,/^focus(in)?$/.test(t.type))}),g.fn[v]=P._jQueryInterface,g.fn[v].Constructor=P,g.fn[v].noConflict=function(){return g.fn[v]=T,P._jQueryInterface};var L="carousel",j="bs.carousel",H="."+j,R=".data-api",x=g.fn[L],F={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},U={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},W="next",q="prev",M="left",K="right",Q={SLIDE:"slide"+H,SLID:"slid"+H,KEYDOWN:"keydown"+H,MOUSEENTER:"mouseenter"+H,MOUSELEAVE:"mouseleave"+H,TOUCHSTART:"touchstart"+H,TOUCHMOVE:"touchmove"+H,TOUCHEND:"touchend"+H,POINTERDOWN:"pointerdown"+H,POINTERUP:"pointerup"+H,DRAG_START:"dragstart"+H,LOAD_DATA_API:"load"+H+R,CLICK_DATA_API:"click"+H+R},B="carousel",V="active",Y="slide",z="carousel-item-right",X="carousel-item-left",$="carousel-item-next",G="carousel-item-prev",J="pointer-event",Z=".active",tt=".active.carousel-item",et=".carousel-item",nt=".carousel-item img",it=".carousel-item-next, .carousel-item-prev",ot=".carousel-indicators",rt="[data-slide], [data-slide-to]",st='[data-ride="carousel"]',at={TOUCH:"touch",PEN:"pen"},lt=function(){function r(t,e){this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._element=t,this._indicatorsElement=this._element.querySelector(ot),this._touchSupported="ontouchstart"in document.documentElement||0<navigator.maxTouchPoints,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}var t=r.prototype;return t.next=function(){this._isSliding||this._slide(W)},t.nextWhenVisible=function(){!document.hidden&&g(this._element).is(":visible")&&"hidden"!==g(this._element).css("visibility")&&this.next()},t.prev=function(){this._isSliding||this._slide(q)},t.pause=function(t){t||(this._isPaused=!0),this._element.querySelector(it)&&(_.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},t.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},t.to=function(t){var e=this;this._activeElement=this._element.querySelector(tt);var n=this._getItemIndex(this._activeElement);if(!(t>this._items.length-1||t<0))if(this._isSliding)g(this._element).one(Q.SLID,function(){return e.to(t)});else{if(n===t)return this.pause(),void this.cycle();var i=n<t?W:q;this._slide(i,this._items[t])}},t.dispose=function(){g(this._element).off(H),g.removeData(this._element,j),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},t._getConfig=function(t){return t=l({},F,t),_.typeCheckConfig(L,t,U),t},t._handleSwipe=function(){var t=Math.abs(this.touchDeltaX);if(!(t<=40)){var e=t/this.touchDeltaX;0<e&&this.prev(),e<0&&this.next()}},t._addEventListeners=function(){var e=this;this._config.keyboard&&g(this._element).on(Q.KEYDOWN,function(t){return e._keydown(t)}),"hover"===this._config.pause&&g(this._element).on(Q.MOUSEENTER,function(t){return e.pause(t)}).on(Q.MOUSELEAVE,function(t){return e.cycle(t)}),this._config.touch&&this._addTouchEventListeners()},t._addTouchEventListeners=function(){var n=this;if(this._touchSupported){var e=function(t){n._pointerEvent&&at[t.originalEvent.pointerType.toUpperCase()]?n.touchStartX=t.originalEvent.clientX:n._pointerEvent||(n.touchStartX=t.originalEvent.touches[0].clientX)},i=function(t){n._pointerEvent&&at[t.originalEvent.pointerType.toUpperCase()]&&(n.touchDeltaX=t.originalEvent.clientX-n.touchStartX),n._handleSwipe(),"hover"===n._config.pause&&(n.pause(),n.touchTimeout&&clearTimeout(n.touchTimeout),n.touchTimeout=setTimeout(function(t){return n.cycle(t)},500+n._config.interval))};g(this._element.querySelectorAll(nt)).on(Q.DRAG_START,function(t){return t.preventDefault()}),this._pointerEvent?(g(this._element).on(Q.POINTERDOWN,function(t){return e(t)}),g(this._element).on(Q.POINTERUP,function(t){return i(t)}),this._element.classList.add(J)):(g(this._element).on(Q.TOUCHSTART,function(t){return e(t)}),g(this._element).on(Q.TOUCHMOVE,function(t){var e;(e=t).originalEvent.touches&&1<e.originalEvent.touches.length?n.touchDeltaX=0:n.touchDeltaX=e.originalEvent.touches[0].clientX-n.touchStartX}),g(this._element).on(Q.TOUCHEND,function(t){return i(t)}))}},t._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},t._getItemIndex=function(t){return this._items=t&&t.parentNode?[].slice.call(t.parentNode.querySelectorAll(et)):[],this._items.indexOf(t)},t._getItemByDirection=function(t,e){var n=t===W,i=t===q,o=this._getItemIndex(e),r=this._items.length-1;if((i&&0===o||n&&o===r)&&!this._config.wrap)return e;var s=(o+(t===q?-1:1))%this._items.length;return-1===s?this._items[this._items.length-1]:this._items[s]},t._triggerSlideEvent=function(t,e){var n=this._getItemIndex(t),i=this._getItemIndex(this._element.querySelector(tt)),o=g.Event(Q.SLIDE,{relatedTarget:t,direction:e,from:i,to:n});return g(this._element).trigger(o),o},t._setActiveIndicatorElement=function(t){if(this._indicatorsElement){var e=[].slice.call(this._indicatorsElement.querySelectorAll(Z));g(e).removeClass(V);var n=this._indicatorsElement.children[this._getItemIndex(t)];n&&g(n).addClass(V)}},t._slide=function(t,e){var n,i,o,r=this,s=this._element.querySelector(tt),a=this._getItemIndex(s),l=e||s&&this._getItemByDirection(t,s),c=this._getItemIndex(l),h=Boolean(this._interval);if(o=t===W?(n=X,i=$,M):(n=z,i=G,K),l&&g(l).hasClass(V))this._isSliding=!1;else if(!this._triggerSlideEvent(l,o).isDefaultPrevented()&&s&&l){this._isSliding=!0,h&&this.pause(),this._setActiveIndicatorElement(l);var u=g.Event(Q.SLID,{relatedTarget:l,direction:o,from:a,to:c});if(g(this._element).hasClass(Y)){g(l).addClass(i),_.reflow(l),g(s).addClass(n),g(l).addClass(n);var f=parseInt(l.getAttribute("data-interval"),10);this._config.interval=f?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,f):this._config.defaultInterval||this._config.interval;var d=_.getTransitionDurationFromElement(s);g(s).one(_.TRANSITION_END,function(){g(l).removeClass(n+" "+i).addClass(V),g(s).removeClass(V+" "+i+" "+n),r._isSliding=!1,setTimeout(function(){return g(r._element).trigger(u)},0)}).emulateTransitionEnd(d)}else g(s).removeClass(V),g(l).addClass(V),this._isSliding=!1,g(this._element).trigger(u);h&&this.cycle()}},r._jQueryInterface=function(i){return this.each(function(){var t=g(this).data(j),e=l({},F,g(this).data());"object"==typeof i&&(e=l({},e,i));var n="string"==typeof i?i:e.slide;if(t||(t=new r(this,e),g(this).data(j,t)),"number"==typeof i)t.to(i);else if("string"==typeof n){if("undefined"==typeof t[n])throw new TypeError('No method named "'+n+'"');t[n]()}else e.interval&&e.ride&&(t.pause(),t.cycle())})},r._dataApiClickHandler=function(t){var e=_.getSelectorFromElement(this);if(e){var n=g(e)[0];if(n&&g(n).hasClass(B)){var i=l({},g(n).data(),g(this).data()),o=this.getAttribute("data-slide-to");o&&(i.interval=!1),r._jQueryInterface.call(g(n),i),o&&g(n).data(j).to(o),t.preventDefault()}}},s(r,null,[{key:"VERSION",get:function(){return"4.3.1"}},{key:"Default",get:function(){return F}}]),r}();g(document).on(Q.CLICK_DATA_API,rt,lt._dataApiClickHandler),g(window).on(Q.LOAD_DATA_API,function(){for(var t=[].slice.call(document.querySelectorAll(st)),e=0,n=t.length;e<n;e++){var i=g(t[e]);lt._jQueryInterface.call(i,i.data())}}),g.fn[L]=lt._jQueryInterface,g.fn[L].Constructor=lt,g.fn[L].noConflict=function(){return g.fn[L]=x,lt._jQueryInterface};var ct="collapse",ht="bs.collapse",ut="."+ht,ft=g.fn[ct],dt={toggle:!0,parent:""},gt={toggle:"boolean",parent:"(string|element)"},_t={SHOW:"show"+ut,SHOWN:"shown"+ut,HIDE:"hide"+ut,HIDDEN:"hidden"+ut,CLICK_DATA_API:"click"+ut+".data-api"},mt="show",pt="collapse",vt="collapsing",yt="collapsed",Et="width",Ct="height",Tt=".show, .collapsing",St='[data-toggle="collapse"]',bt=function(){function a(e,t){this._isTransitioning=!1,this._element=e,this._config=this._getConfig(t),this._triggerArray=[].slice.call(document.querySelectorAll('[data-toggle="collapse"][href="#'+e.id+'"],[data-toggle="collapse"][data-target="#'+e.id+'"]'));for(var n=[].slice.call(document.querySelectorAll(St)),i=0,o=n.length;i<o;i++){var r=n[i],s=_.getSelectorFromElement(r),a=[].slice.call(document.querySelectorAll(s)).filter(function(t){return t===e});null!==s&&0<a.length&&(this._selector=s,this._triggerArray.push(r))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var t=a.prototype;return t.toggle=function(){g(this._element).hasClass(mt)?this.hide():this.show()},t.show=function(){var t,e,n=this;if(!this._isTransitioning&&!g(this._element).hasClass(mt)&&(this._parent&&0===(t=[].slice.call(this._parent.querySelectorAll(Tt)).filter(function(t){return"string"==typeof n._config.parent?t.getAttribute("data-parent")===n._config.parent:t.classList.contains(pt)})).length&&(t=null),!(t&&(e=g(t).not(this._selector).data(ht))&&e._isTransitioning))){var i=g.Event(_t.SHOW);if(g(this._element).trigger(i),!i.isDefaultPrevented()){t&&(a._jQueryInterface.call(g(t).not(this._selector),"hide"),e||g(t).data(ht,null));var o=this._getDimension();g(this._element).removeClass(pt).addClass(vt),this._element.style[o]=0,this._triggerArray.length&&g(this._triggerArray).removeClass(yt).attr("aria-expanded",!0),this.setTransitioning(!0);var r="scroll"+(o[0].toUpperCase()+o.slice(1)),s=_.getTransitionDurationFromElement(this._element);g(this._element).one(_.TRANSITION_END,function(){g(n._element).removeClass(vt).addClass(pt).addClass(mt),n._element.style[o]="",n.setTransitioning(!1),g(n._element).trigger(_t.SHOWN)}).emulateTransitionEnd(s),this._element.style[o]=this._element[r]+"px"}}},t.hide=function(){var t=this;if(!this._isTransitioning&&g(this._element).hasClass(mt)){var e=g.Event(_t.HIDE);if(g(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",_.reflow(this._element),g(this._element).addClass(vt).removeClass(pt).removeClass(mt);var i=this._triggerArray.length;if(0<i)for(var o=0;o<i;o++){var r=this._triggerArray[o],s=_.getSelectorFromElement(r);if(null!==s)g([].slice.call(document.querySelectorAll(s))).hasClass(mt)||g(r).addClass(yt).attr("aria-expanded",!1)}this.setTransitioning(!0);this._element.style[n]="";var a=_.getTransitionDurationFromElement(this._element);g(this._element).one(_.TRANSITION_END,function(){t.setTransitioning(!1),g(t._element).removeClass(vt).addClass(pt).trigger(_t.HIDDEN)}).emulateTransitionEnd(a)}}},t.setTransitioning=function(t){this._isTransitioning=t},t.dispose=function(){g.removeData(this._element,ht),this._config=null,this._parent=null,this._element=null,this._triggerArray=null,this._isTransitioning=null},t._getConfig=function(t){return(t=l({},dt,t)).toggle=Boolean(t.toggle),_.typeCheckConfig(ct,t,gt),t},t._getDimension=function(){return g(this._element).hasClass(Et)?Et:Ct},t._getParent=function(){var t,n=this;_.isElement(this._config.parent)?(t=this._config.parent,"undefined"!=typeof this._config.parent.jquery&&(t=this._config.parent[0])):t=document.querySelector(this._config.parent);var e='[data-toggle="collapse"][data-parent="'+this._config.parent+'"]',i=[].slice.call(t.querySelectorAll(e));return g(i).each(function(t,e){n._addAriaAndCollapsedClass(a._getTargetFromElement(e),[e])}),t},t._addAriaAndCollapsedClass=function(t,e){var n=g(t).hasClass(mt);e.length&&g(e).toggleClass(yt,!n).attr("aria-expanded",n)},a._getTargetFromElement=function(t){var e=_.getSelectorFromElement(t);return e?document.querySelector(e):null},a._jQueryInterface=function(i){return this.each(function(){var t=g(this),e=t.data(ht),n=l({},dt,t.data(),"object"==typeof i&&i?i:{});if(!e&&n.toggle&&/show|hide/.test(i)&&(n.toggle=!1),e||(e=new a(this,n),t.data(ht,e)),"string"==typeof i){if("undefined"==typeof e[i])throw new TypeError('No method named "'+i+'"');e[i]()}})},s(a,null,[{key:"VERSION",get:function(){return"4.3.1"}},{key:"Default",get:function(){return dt}}]),a}();g(document).on(_t.CLICK_DATA_API,St,function(t){"A"===t.currentTarget.tagName&&t.preventDefault();var n=g(this),e=_.getSelectorFromElement(this),i=[].slice.call(document.querySelectorAll(e));g(i).each(function(){var t=g(this),e=t.data(ht)?"toggle":n.data();bt._jQueryInterface.call(t,e)})}),g.fn[ct]=bt._jQueryInterface,g.fn[ct].Constructor=bt,g.fn[ct].noConflict=function(){return g.fn[ct]=ft,bt._jQueryInterface};var It="dropdown",Dt="bs.dropdown",wt="."+Dt,At=".data-api",Nt=g.fn[It],Ot=new RegExp("38|40|27"),kt={HIDE:"hide"+wt,HIDDEN:"hidden"+wt,SHOW:"show"+wt,SHOWN:"shown"+wt,CLICK:"click"+wt,CLICK_DATA_API:"click"+wt+At,KEYDOWN_DATA_API:"keydown"+wt+At,KEYUP_DATA_API:"keyup"+wt+At},Pt="disabled",Lt="show",jt="dropup",Ht="dropright",Rt="dropleft",xt="dropdown-menu-right",Ft="position-static",Ut='[data-toggle="dropdown"]',Wt=".dropdown form",qt=".dropdown-menu",Mt=".navbar-nav",Kt=".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",Qt="top-start",Bt="top-end",Vt="bottom-start",Yt="bottom-end",zt="right-start",Xt="left-start",$t={offset:0,flip:!0,boundary:"scrollParent",reference:"toggle",display:"dynamic"},Gt={offset:"(number|string|function)",flip:"boolean",boundary:"(string|element)",reference:"(string|element)",display:"string"},Jt=function(){function c(t,e){this._element=t,this._popper=null,this._config=this._getConfig(e),this._menu=this._getMenuElement(),this._inNavbar=this._detectNavbar(),this._addEventListeners()}var t=c.prototype;return t.toggle=function(){if(!this._element.disabled&&!g(this._element).hasClass(Pt)){var t=c._getParentFromElement(this._element),e=g(this._menu).hasClass(Lt);if(c._clearMenus(),!e){var n={relatedTarget:this._element},i=g.Event(kt.SHOW,n);if(g(t).trigger(i),!i.isDefaultPrevented()){if(!this._inNavbar){if("undefined"==typeof u)throw new TypeError("Bootstrap's dropdowns require Popper.js (https://popper.js.org/)");var o=this._element;"parent"===this._config.reference?o=t:_.isElement(this._config.reference)&&(o=this._config.reference,"undefined"!=typeof this._config.reference.jquery&&(o=this._config.reference[0])),"scrollParent"!==this._config.boundary&&g(t).addClass(Ft),this._popper=new u(o,this._menu,this._getPopperConfig())}"ontouchstart"in document.documentElement&&0===g(t).closest(Mt).length&&g(document.body).children().on("mouseover",null,g.noop),this._element.focus(),this._element.setAttribute("aria-expanded",!0),g(this._menu).toggleClass(Lt),g(t).toggleClass(Lt).trigger(g.Event(kt.SHOWN,n))}}}},t.show=function(){if(!(this._element.disabled||g(this._element).hasClass(Pt)||g(this._menu).hasClass(Lt))){var t={relatedTarget:this._element},e=g.Event(kt.SHOW,t),n=c._getParentFromElement(this._element);g(n).trigger(e),e.isDefaultPrevented()||(g(this._menu).toggleClass(Lt),g(n).toggleClass(Lt).trigger(g.Event(kt.SHOWN,t)))}},t.hide=function(){if(!this._element.disabled&&!g(this._element).hasClass(Pt)&&g(this._menu).hasClass(Lt)){var t={relatedTarget:this._element},e=g.Event(kt.HIDE,t),n=c._getParentFromElement(this._element);g(n).trigger(e),e.isDefaultPrevented()||(g(this._menu).toggleClass(Lt),g(n).toggleClass(Lt).trigger(g.Event(kt.HIDDEN,t)))}},t.dispose=function(){g.removeData(this._element,Dt),g(this._element).off(wt),this._element=null,(this._menu=null)!==this._popper&&(this._popper.destroy(),this._popper=null)},t.update=function(){this._inNavbar=this._detectNavbar(),null!==this._popper&&this._popper.scheduleUpdate()},t._addEventListeners=function(){var e=this;g(this._element).on(kt.CLICK,function(t){t.preventDefault(),t.stopPropagation(),e.toggle()})},t._getConfig=function(t){return t=l({},this.constructor.Default,g(this._element).data(),t),_.typeCheckConfig(It,t,this.constructor.DefaultType),t},t._getMenuElement=function(){if(!this._menu){var t=c._getParentFromElement(this._element);t&&(this._menu=t.querySelector(qt))}return this._menu},t._getPlacement=function(){var t=g(this._element.parentNode),e=Vt;return t.hasClass(jt)?(e=Qt,g(this._menu).hasClass(xt)&&(e=Bt)):t.hasClass(Ht)?e=zt:t.hasClass(Rt)?e=Xt:g(this._menu).hasClass(xt)&&(e=Yt),e},t._detectNavbar=function(){return 0<g(this._element).closest(".navbar").length},t._getOffset=function(){var e=this,t={};return"function"==typeof this._config.offset?t.fn=function(t){return t.offsets=l({},t.offsets,e._config.offset(t.offsets,e._element)||{}),t}:t.offset=this._config.offset,t},t._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};return"static"===this._config.display&&(t.modifiers.applyStyle={enabled:!1}),t},c._jQueryInterface=function(e){return this.each(function(){var t=g(this).data(Dt);if(t||(t=new c(this,"object"==typeof e?e:null),g(this).data(Dt,t)),"string"==typeof e){if("undefined"==typeof t[e])throw new TypeError('No method named "'+e+'"');t[e]()}})},c._clearMenus=function(t){if(!t||3!==t.which&&("keyup"!==t.type||9===t.which))for(var e=[].slice.call(document.querySelectorAll(Ut)),n=0,i=e.length;n<i;n++){var o=c._getParentFromElement(e[n]),r=g(e[n]).data(Dt),s={relatedTarget:e[n]};if(t&&"click"===t.type&&(s.clickEvent=t),r){var a=r._menu;if(g(o).hasClass(Lt)&&!(t&&("click"===t.type&&/input|textarea/i.test(t.target.tagName)||"keyup"===t.type&&9===t.which)&&g.contains(o,t.target))){var l=g.Event(kt.HIDE,s);g(o).trigger(l),l.isDefaultPrevented()||("ontouchstart"in document.documentElement&&g(document.body).children().off("mouseover",null,g.noop),e[n].setAttribute("aria-expanded","false"),g(a).removeClass(Lt),g(o).removeClass(Lt).trigger(g.Event(kt.HIDDEN,s)))}}}},c._getParentFromElement=function(t){var e,n=_.getSelectorFromElement(t);return n&&(e=document.querySelector(n)),e||t.parentNode},c._dataApiKeydownHandler=function(t){if((/input|textarea/i.test(t.target.tagName)?!(32===t.which||27!==t.which&&(40!==t.which&&38!==t.which||g(t.target).closest(qt).length)):Ot.test(t.which))&&(t.preventDefault(),t.stopPropagation(),!this.disabled&&!g(this).hasClass(Pt))){var e=c._getParentFromElement(this),n=g(e).hasClass(Lt);if(n&&(!n||27!==t.which&&32!==t.which)){var i=[].slice.call(e.querySelectorAll(Kt));if(0!==i.length){var o=i.indexOf(t.target);38===t.which&&0<o&&o--,40===t.which&&o<i.length-1&&o++,o<0&&(o=0),i[o].focus()}}else{if(27===t.which){var r=e.querySelector(Ut);g(r).trigger("focus")}g(this).trigger("click")}}},s(c,null,[{key:"VERSION",get:function(){return"4.3.1"}},{key:"Default",get:function(){return $t}},{key:"DefaultType",get:function(){return Gt}}]),c}();g(document).on(kt.KEYDOWN_DATA_API,Ut,Jt._dataApiKeydownHandler).on(kt.KEYDOWN_DATA_API,qt,Jt._dataApiKeydownHandler).on(kt.CLICK_DATA_API+" "+kt.KEYUP_DATA_API,Jt._clearMenus).on(kt.CLICK_DATA_API,Ut,function(t){t.preventDefault(),t.stopPropagation(),Jt._jQueryInterface.call(g(this),"toggle")}).on(kt.CLICK_DATA_API,Wt,function(t){t.stopPropagation()}),g.fn[It]=Jt._jQueryInterface,g.fn[It].Constructor=Jt,g.fn[It].noConflict=function(){return g.fn[It]=Nt,Jt._jQueryInterface};var Zt="modal",te="bs.modal",ee="."+te,ne=g.fn[Zt],ie={backdrop:!0,keyboard:!0,focus:!0,show:!0},oe={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean",show:"boolean"},re={HIDE:"hide"+ee,HIDDEN:"hidden"+ee,SHOW:"show"+ee,SHOWN:"shown"+ee,FOCUSIN:"focusin"+ee,RESIZE:"resize"+ee,CLICK_DISMISS:"click.dismiss"+ee,KEYDOWN_DISMISS:"keydown.dismiss"+ee,MOUSEUP_DISMISS:"mouseup.dismiss"+ee,MOUSEDOWN_DISMISS:"mousedown.dismiss"+ee,CLICK_DATA_API:"click"+ee+".data-api"},se="modal-dialog-scrollable",ae="modal-scrollbar-measure",le="modal-backdrop",ce="modal-open",he="fade",ue="show",fe=".modal-dialog",de=".modal-body",ge='[data-toggle="modal"]',_e='[data-dismiss="modal"]',me=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",pe=".sticky-top",ve=function(){function o(t,e){this._config=this._getConfig(e),this._element=t,this._dialog=t.querySelector(fe),this._backdrop=null,this._isShown=!1,this._isBodyOverflowing=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollbarWidth=0}var t=o.prototype;return t.toggle=function(t){return this._isShown?this.hide():this.show(t)},t.show=function(t){var e=this;if(!this._isShown&&!this._isTransitioning){g(this._element).hasClass(he)&&(this._isTransitioning=!0);var n=g.Event(re.SHOW,{relatedTarget:t});g(this._element).trigger(n),this._isShown||n.isDefaultPrevented()||(this._isShown=!0,this._checkScrollbar(),this._setScrollbar(),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),g(this._element).on(re.CLICK_DISMISS,_e,function(t){return e.hide(t)}),g(this._dialog).on(re.MOUSEDOWN_DISMISS,function(){g(e._element).one(re.MOUSEUP_DISMISS,function(t){g(t.target).is(e._element)&&(e._ignoreBackdropClick=!0)})}),this._showBackdrop(function(){return e._showElement(t)}))}},t.hide=function(t){var e=this;if(t&&t.preventDefault(),this._isShown&&!this._isTransitioning){var n=g.Event(re.HIDE);if(g(this._element).trigger(n),this._isShown&&!n.isDefaultPrevented()){this._isShown=!1;var i=g(this._element).hasClass(he);if(i&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),g(document).off(re.FOCUSIN),g(this._element).removeClass(ue),g(this._element).off(re.CLICK_DISMISS),g(this._dialog).off(re.MOUSEDOWN_DISMISS),i){var o=_.getTransitionDurationFromElement(this._element);g(this._element).one(_.TRANSITION_END,function(t){return e._hideModal(t)}).emulateTransitionEnd(o)}else this._hideModal()}}},t.dispose=function(){[window,this._element,this._dialog].forEach(function(t){return g(t).off(ee)}),g(document).off(re.FOCUSIN),g.removeData(this._element,te),this._config=null,this._element=null,this._dialog=null,this._backdrop=null,this._isShown=null,this._isBodyOverflowing=null,this._ignoreBackdropClick=null,this._isTransitioning=null,this._scrollbarWidth=null},t.handleUpdate=function(){this._adjustDialog()},t._getConfig=function(t){return t=l({},ie,t),_.typeCheckConfig(Zt,t,oe),t},t._showElement=function(t){var e=this,n=g(this._element).hasClass(he);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),g(this._dialog).hasClass(se)?this._dialog.querySelector(de).scrollTop=0:this._element.scrollTop=0,n&&_.reflow(this._element),g(this._element).addClass(ue),this._config.focus&&this._enforceFocus();var i=g.Event(re.SHOWN,{relatedTarget:t}),o=function(){e._config.focus&&e._element.focus(),e._isTransitioning=!1,g(e._element).trigger(i)};if(n){var r=_.getTransitionDurationFromElement(this._dialog);g(this._dialog).one(_.TRANSITION_END,o).emulateTransitionEnd(r)}else o()},t._enforceFocus=function(){var e=this;g(document).off(re.FOCUSIN).on(re.FOCUSIN,function(t){document!==t.target&&e._element!==t.target&&0===g(e._element).has(t.target).length&&e._element.focus()})},t._setEscapeEvent=function(){var e=this;this._isShown&&this._config.keyboard?g(this._element).on(re.KEYDOWN_DISMISS,function(t){27===t.which&&(t.preventDefault(),e.hide())}):this._isShown||g(this._element).off(re.KEYDOWN_DISMISS)},t._setResizeEvent=function(){var e=this;this._isShown?g(window).on(re.RESIZE,function(t){return e.handleUpdate(t)}):g(window).off(re.RESIZE)},t._hideModal=function(){var t=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._isTransitioning=!1,this._showBackdrop(function(){g(document.body).removeClass(ce),t._resetAdjustments(),t._resetScrollbar(),g(t._element).trigger(re.HIDDEN)})},t._removeBackdrop=function(){this._backdrop&&(g(this._backdrop).remove(),this._backdrop=null)},t._showBackdrop=function(t){var e=this,n=g(this._element).hasClass(he)?he:"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className=le,n&&this._backdrop.classList.add(n),g(this._backdrop).appendTo(document.body),g(this._element).on(re.CLICK_DISMISS,function(t){e._ignoreBackdropClick?e._ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"===e._config.backdrop?e._element.focus():e.hide())}),n&&_.reflow(this._backdrop),g(this._backdrop).addClass(ue),!t)return;if(!n)return void t();var i=_.getTransitionDurationFromElement(this._backdrop);g(this._backdrop).one(_.TRANSITION_END,t).emulateTransitionEnd(i)}else if(!this._isShown&&this._backdrop){g(this._backdrop).removeClass(ue);var o=function(){e._removeBackdrop(),t&&t()};if(g(this._element).hasClass(he)){var r=_.getTransitionDurationFromElement(this._backdrop);g(this._backdrop).one(_.TRANSITION_END,o).emulateTransitionEnd(r)}else o()}else t&&t()},t._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},t._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},t._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=t.left+t.right<window.innerWidth,this._scrollbarWidth=this._getScrollbarWidth()},t._setScrollbar=function(){var o=this;if(this._isBodyOverflowing){var t=[].slice.call(document.querySelectorAll(me)),e=[].slice.call(document.querySelectorAll(pe));g(t).each(function(t,e){var n=e.style.paddingRight,i=g(e).css("padding-right");g(e).data("padding-right",n).css("padding-right",parseFloat(i)+o._scrollbarWidth+"px")}),g(e).each(function(t,e){var n=e.style.marginRight,i=g(e).css("margin-right");g(e).data("margin-right",n).css("margin-right",parseFloat(i)-o._scrollbarWidth+"px")});var n=document.body.style.paddingRight,i=g(document.body).css("padding-right");g(document.body).data("padding-right",n).css("padding-right",parseFloat(i)+this._scrollbarWidth+"px")}g(document.body).addClass(ce)},t._resetScrollbar=function(){var t=[].slice.call(document.querySelectorAll(me));g(t).each(function(t,e){var n=g(e).data("padding-right");g(e).removeData("padding-right"),e.style.paddingRight=n||""});var e=[].slice.call(document.querySelectorAll(""+pe));g(e).each(function(t,e){var n=g(e).data("margin-right");"undefined"!=typeof n&&g(e).css("margin-right",n).removeData("margin-right")});var n=g(document.body).data("padding-right");g(document.body).removeData("padding-right"),document.body.style.paddingRight=n||""},t._getScrollbarWidth=function(){var t=document.createElement("div");t.className=ae,document.body.appendChild(t);var e=t.getBoundingClientRect().width-t.clientWidth;return document.body.removeChild(t),e},o._jQueryInterface=function(n,i){return this.each(function(){var t=g(this).data(te),e=l({},ie,g(this).data(),"object"==typeof n&&n?n:{});if(t||(t=new o(this,e),g(this).data(te,t)),"string"==typeof n){if("undefined"==typeof t[n])throw new TypeError('No method named "'+n+'"');t[n](i)}else e.show&&t.show(i)})},s(o,null,[{key:"VERSION",get:function(){return"4.3.1"}},{key:"Default",get:function(){return ie}}]),o}();g(document).on(re.CLICK_DATA_API,ge,function(t){var e,n=this,i=_.getSelectorFromElement(this);i&&(e=document.querySelector(i));var o=g(e).data(te)?"toggle":l({},g(e).data(),g(this).data());"A"!==this.tagName&&"AREA"!==this.tagName||t.preventDefault();var r=g(e).one(re.SHOW,function(t){t.isDefaultPrevented()||r.one(re.HIDDEN,function(){g(n).is(":visible")&&n.focus()})});ve._jQueryInterface.call(g(e),o,this)}),g.fn[Zt]=ve._jQueryInterface,g.fn[Zt].Constructor=ve,g.fn[Zt].noConflict=function(){return g.fn[Zt]=ne,ve._jQueryInterface};var ye=["background","cite","href","itemtype","longdesc","poster","src","xlink:href"],Ee={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Ce=/^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi,Te=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;function Se(t,s,e){if(0===t.length)return t;if(e&&"function"==typeof e)return e(t);for(var n=(new window.DOMParser).parseFromString(t,"text/html"),a=Object.keys(s),l=[].slice.call(n.body.querySelectorAll("*")),i=function(t,e){var n=l[t],i=n.nodeName.toLowerCase();if(-1===a.indexOf(n.nodeName.toLowerCase()))return n.parentNode.removeChild(n),"continue";var o=[].slice.call(n.attributes),r=[].concat(s["*"]||[],s[i]||[]);o.forEach(function(t){(function(t,e){var n=t.nodeName.toLowerCase();if(-1!==e.indexOf(n))return-1===ye.indexOf(n)||Boolean(t.nodeValue.match(Ce)||t.nodeValue.match(Te));for(var i=e.filter(function(t){return t instanceof RegExp}),o=0,r=i.length;o<r;o++)if(n.match(i[o]))return!0;return!1})(t,r)||n.removeAttribute(t.nodeName)})},o=0,r=l.length;o<r;o++)i(o);return n.body.innerHTML}var be="tooltip",Ie="bs.tooltip",De="."+Ie,we=g.fn[be],Ae="bs-tooltip",Ne=new RegExp("(^|\\s)"+Ae+"\\S+","g"),Oe=["sanitize","whiteList","sanitizeFn"],ke={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string|function)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)",sanitize:"boolean",sanitizeFn:"(null|function)",whiteList:"object"},Pe={AUTO:"auto",TOP:"top",RIGHT:"right",BOTTOM:"bottom",LEFT:"left"},Le={animation:!0,template:'<div class="tooltip" role="tooltip"><div class="arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",sanitize:!0,sanitizeFn:null,whiteList:Ee},je="show",He="out",Re={HIDE:"hide"+De,HIDDEN:"hidden"+De,SHOW:"show"+De,SHOWN:"shown"+De,INSERTED:"inserted"+De,CLICK:"click"+De,FOCUSIN:"focusin"+De,FOCUSOUT:"focusout"+De,MOUSEENTER:"mouseenter"+De,MOUSELEAVE:"mouseleave"+De},xe="fade",Fe="show",Ue=".tooltip-inner",We=".arrow",qe="hover",Me="focus",Ke="click",Qe="manual",Be=function(){function i(t,e){if("undefined"==typeof u)throw new TypeError("Bootstrap's tooltips require Popper.js (https://popper.js.org/)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var t=i.prototype;return t.enable=function(){this._isEnabled=!0},t.disable=function(){this._isEnabled=!1},t.toggleEnabled=function(){this._isEnabled=!this._isEnabled},t.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=g(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(g(this.getTipElement()).hasClass(Fe))return void this._leave(null,this);this._enter(null,this)}},t.dispose=function(){clearTimeout(this._timeout),g.removeData(this.element,this.constructor.DATA_KEY),g(this.element).off(this.constructor.EVENT_KEY),g(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&g(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,(this._activeTrigger=null)!==this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},t.show=function(){var e=this;if("none"===g(this.element).css("display"))throw new Error("Please use show on visible elements");var t=g.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){g(this.element).trigger(t);var n=_.findShadowRoot(this.element),i=g.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(t.isDefaultPrevented()||!i)return;var o=this.getTipElement(),r=_.getUID(this.constructor.NAME);o.setAttribute("id",r),this.element.setAttribute("aria-describedby",r),this.setContent(),this.config.animation&&g(o).addClass(xe);var s="function"==typeof this.config.placement?this.config.placement.call(this,o,this.element):this.config.placement,a=this._getAttachment(s);this.addAttachmentClass(a);var l=this._getContainer();g(o).data(this.constructor.DATA_KEY,this),g.contains(this.element.ownerDocument.documentElement,this.tip)||g(o).appendTo(l),g(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new u(this.element,o,{placement:a,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:We},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}}),g(o).addClass(Fe),"ontouchstart"in document.documentElement&&g(document.body).children().on("mouseover",null,g.noop);var c=function(){e.config.animation&&e._fixTransition();var t=e._hoverState;e._hoverState=null,g(e.element).trigger(e.constructor.Event.SHOWN),t===He&&e._leave(null,e)};if(g(this.tip).hasClass(xe)){var h=_.getTransitionDurationFromElement(this.tip);g(this.tip).one(_.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},t.hide=function(t){var e=this,n=this.getTipElement(),i=g.Event(this.constructor.Event.HIDE),o=function(){e._hoverState!==je&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),g(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(g(this.element).trigger(i),!i.isDefaultPrevented()){if(g(n).removeClass(Fe),"ontouchstart"in document.documentElement&&g(document.body).children().off("mouseover",null,g.noop),this._activeTrigger[Ke]=!1,this._activeTrigger[Me]=!1,this._activeTrigger[qe]=!1,g(this.tip).hasClass(xe)){var r=_.getTransitionDurationFromElement(n);g(n).one(_.TRANSITION_END,o).emulateTransitionEnd(r)}else o();this._hoverState=""}},t.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},t.isWithContent=function(){return Boolean(this.getTitle())},t.addAttachmentClass=function(t){g(this.getTipElement()).addClass(Ae+"-"+t)},t.getTipElement=function(){return this.tip=this.tip||g(this.config.template)[0],this.tip},t.setContent=function(){var t=this.getTipElement();this.setElementContent(g(t.querySelectorAll(Ue)),this.getTitle()),g(t).removeClass(xe+" "+Fe)},t.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=Se(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?g(e).parent().is(t)||t.empty().append(e):t.text(g(e).text())},t.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},t._getOffset=function(){var e=this,t={};return"function"==typeof this.config.offset?t.fn=function(t){return t.offsets=l({},t.offsets,e.config.offset(t.offsets,e.element)||{}),t}:t.offset=this.config.offset,t},t._getContainer=function(){return!1===this.config.container?document.body:_.isElement(this.config.container)?g(this.config.container):g(document).find(this.config.container)},t._getAttachment=function(t){return Pe[t.toUpperCase()]},t._setListeners=function(){var i=this;this.config.trigger.split(" ").forEach(function(t){if("click"===t)g(i.element).on(i.constructor.Event.CLICK,i.config.selector,function(t){return i.toggle(t)});else if(t!==Qe){var e=t===qe?i.constructor.Event.MOUSEENTER:i.constructor.Event.FOCUSIN,n=t===qe?i.constructor.Event.MOUSELEAVE:i.constructor.Event.FOCUSOUT;g(i.element).on(e,i.config.selector,function(t){return i._enter(t)}).on(n,i.config.selector,function(t){return i._leave(t)})}}),g(this.element).closest(".modal").on("hide.bs.modal",function(){i.element&&i.hide()}),this.config.selector?this.config=l({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},t._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},t._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||g(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Me:qe]=!0),g(e.getTipElement()).hasClass(Fe)||e._hoverState===je?e._hoverState=je:(clearTimeout(e._timeout),e._hoverState=je,e.config.delay&&e.config.delay.show?e._timeout=setTimeout(function(){e._hoverState===je&&e.show()},e.config.delay.show):e.show())},t._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||g(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Me:qe]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=He,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout(function(){e._hoverState===He&&e.hide()},e.config.delay.hide):e.hide())},t._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},t._getConfig=function(t){var e=g(this.element).data();return Object.keys(e).forEach(function(t){-1!==Oe.indexOf(t)&&delete e[t]}),"number"==typeof(t=l({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),_.typeCheckConfig(be,t,this.constructor.DefaultType),t.sanitize&&(t.template=Se(t.template,t.whiteList,t.sanitizeFn)),t},t._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},t._cleanTipClass=function(){var t=g(this.getTipElement()),e=t.attr("class").match(Ne);null!==e&&e.length&&t.removeClass(e.join(""))},t._handlePopperPlacementChange=function(t){var e=t.instance;this.tip=e.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},t._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(g(t).removeClass(xe),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},i._jQueryInterface=function(n){return this.each(function(){var t=g(this).data(Ie),e="object"==typeof n&&n;if((t||!/dispose|hide/.test(n))&&(t||(t=new i(this,e),g(this).data(Ie,t)),"string"==typeof n)){if("undefined"==typeof t[n])throw new TypeError('No method named "'+n+'"');t[n]()}})},s(i,null,[{key:"VERSION",get:function(){return"4.3.1"}},{key:"Default",get:function(){return Le}},{key:"NAME",get:function(){return be}},{key:"DATA_KEY",get:function(){return Ie}},{key:"Event",get:function(){return Re}},{key:"EVENT_KEY",get:function(){return De}},{key:"DefaultType",get:function(){return ke}}]),i}();g.fn[be]=Be._jQueryInterface,g.fn[be].Constructor=Be,g.fn[be].noConflict=function(){return g.fn[be]=we,Be._jQueryInterface};var Ve="popover",Ye="bs.popover",ze="."+Ye,Xe=g.fn[Ve],$e="bs-popover",Ge=new RegExp("(^|\\s)"+$e+"\\S+","g"),Je=l({},Be.Default,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>'}),Ze=l({},Be.DefaultType,{content:"(string|element|function)"}),tn="fade",en="show",nn=".popover-header",on=".popover-body",rn={HIDE:"hide"+ze,HIDDEN:"hidden"+ze,SHOW:"show"+ze,SHOWN:"shown"+ze,INSERTED:"inserted"+ze,CLICK:"click"+ze,FOCUSIN:"focusin"+ze,FOCUSOUT:"focusout"+ze,MOUSEENTER:"mouseenter"+ze,MOUSELEAVE:"mouseleave"+ze},sn=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),(e.prototype.constructor=e).__proto__=n;var o=i.prototype;return o.isWithContent=function(){return this.getTitle()||this._getContent()},o.addAttachmentClass=function(t){g(this.getTipElement()).addClass($e+"-"+t)},o.getTipElement=function(){return this.tip=this.tip||g(this.config.template)[0],this.tip},o.setContent=function(){var t=g(this.getTipElement());this.setElementContent(t.find(nn),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(on),e),t.removeClass(tn+" "+en)},o._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},o._cleanTipClass=function(){var t=g(this.getTipElement()),e=t.attr("class").match(Ge);null!==e&&0<e.length&&t.removeClass(e.join(""))},i._jQueryInterface=function(n){return this.each(function(){var t=g(this).data(Ye),e="object"==typeof n?n:null;if((t||!/dispose|hide/.test(n))&&(t||(t=new i(this,e),g(this).data(Ye,t)),"string"==typeof n)){if("undefined"==typeof t[n])throw new TypeError('No method named "'+n+'"');t[n]()}})},s(i,null,[{key:"VERSION",get:function(){return"4.3.1"}},{key:"Default",get:function(){return Je}},{key:"NAME",get:function(){return Ve}},{key:"DATA_KEY",get:function(){return Ye}},{key:"Event",get:function(){return rn}},{key:"EVENT_KEY",get:function(){return ze}},{key:"DefaultType",get:function(){return Ze}}]),i}(Be);g.fn[Ve]=sn._jQueryInterface,g.fn[Ve].Constructor=sn,g.fn[Ve].noConflict=function(){return g.fn[Ve]=Xe,sn._jQueryInterface};var an="scrollspy",ln="bs.scrollspy",cn="."+ln,hn=g.fn[an],un={offset:10,method:"auto",target:""},fn={offset:"number",method:"string",target:"(string|element)"},dn={ACTIVATE:"activate"+cn,SCROLL:"scroll"+cn,LOAD_DATA_API:"load"+cn+".data-api"},gn="dropdown-item",_n="active",mn='[data-spy="scroll"]',pn=".nav, .list-group",vn=".nav-link",yn=".nav-item",En=".list-group-item",Cn=".dropdown",Tn=".dropdown-item",Sn=".dropdown-toggle",bn="offset",In="position",Dn=function(){function n(t,e){var n=this;this._element=t,this._scrollElement="BODY"===t.tagName?window:t,this._config=this._getConfig(e),this._selector=this._config.target+" "+vn+","+this._config.target+" "+En+","+this._config.target+" "+Tn,this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,g(this._scrollElement).on(dn.SCROLL,function(t){return n._process(t)}),this.refresh(),this._process()}var t=n.prototype;return t.refresh=function(){var e=this,t=this._scrollElement===this._scrollElement.window?bn:In,o="auto"===this._config.method?t:this._config.method,r=o===In?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map(function(t){var e,n=_.getSelectorFromElement(t);if(n&&(e=document.querySelector(n)),e){var i=e.getBoundingClientRect();if(i.width||i.height)return[g(e)[o]().top+r,n]}return null}).filter(function(t){return t}).sort(function(t,e){return t[0]-e[0]}).forEach(function(t){e._offsets.push(t[0]),e._targets.push(t[1])})},t.dispose=function(){g.removeData(this._element,ln),g(this._scrollElement).off(cn),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},t._getConfig=function(t){if("string"!=typeof(t=l({},un,"object"==typeof t&&t?t:{})).target){var e=g(t.target).attr("id");e||(e=_.getUID(an),g(t.target).attr("id",e)),t.target="#"+e}return _.typeCheckConfig(an,t,fn),t},t._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},t._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},t._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},t._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),n<=t){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t<this._offsets[0]&&0<this._offsets[0])return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;){this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t<this._offsets[o+1])&&this._activate(this._targets[o])}}},t._activate=function(e){this._activeTarget=e,this._clear();var t=this._selector.split(",").map(function(t){return t+'[data-target="'+e+'"],'+t+'[href="'+e+'"]'}),n=g([].slice.call(document.querySelectorAll(t.join(","))));n.hasClass(gn)?(n.closest(Cn).find(Sn).addClass(_n),n.addClass(_n)):(n.addClass(_n),n.parents(pn).prev(vn+", "+En).addClass(_n),n.parents(pn).prev(yn).children(vn).addClass(_n)),g(this._scrollElement).trigger(dn.ACTIVATE,{relatedTarget:e})},t._clear=function(){[].slice.call(document.querySelectorAll(this._selector)).filter(function(t){return t.classList.contains(_n)}).forEach(function(t){return t.classList.remove(_n)})},n._jQueryInterface=function(e){return this.each(function(){var t=g(this).data(ln);if(t||(t=new n(this,"object"==typeof e&&e),g(this).data(ln,t)),"string"==typeof e){if("undefined"==typeof t[e])throw new TypeError('No method named "'+e+'"');t[e]()}})},s(n,null,[{key:"VERSION",get:function(){return"4.3.1"}},{key:"Default",get:function(){return un}}]),n}();g(window).on(dn.LOAD_DATA_API,function(){for(var t=[].slice.call(document.querySelectorAll(mn)),e=t.length;e--;){var n=g(t[e]);Dn._jQueryInterface.call(n,n.data())}}),g.fn[an]=Dn._jQueryInterface,g.fn[an].Constructor=Dn,g.fn[an].noConflict=function(){return g.fn[an]=hn,Dn._jQueryInterface};var wn="bs.tab",An="."+wn,Nn=g.fn.tab,On={HIDE:"hide"+An,HIDDEN:"hidden"+An,SHOW:"show"+An,SHOWN:"shown"+An,CLICK_DATA_API:"click"+An+".data-api"},kn="dropdown-menu",Pn="active",Ln="disabled",jn="fade",Hn="show",Rn=".dropdown",xn=".nav, .list-group",Fn=".active",Un="> li > .active",Wn='[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',qn=".dropdown-toggle",Mn="> .dropdown-menu .active",Kn=function(){function i(t){this._element=t}var t=i.prototype;return t.show=function(){var n=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&g(this._element).hasClass(Pn)||g(this._element).hasClass(Ln))){var t,i,e=g(this._element).closest(xn)[0],o=_.getSelectorFromElement(this._element);if(e){var r="UL"===e.nodeName||"OL"===e.nodeName?Un:Fn;i=(i=g.makeArray(g(e).find(r)))[i.length-1]}var s=g.Event(On.HIDE,{relatedTarget:this._element}),a=g.Event(On.SHOW,{relatedTarget:i});if(i&&g(i).trigger(s),g(this._element).trigger(a),!a.isDefaultPrevented()&&!s.isDefaultPrevented()){o&&(t=document.querySelector(o)),this._activate(this._element,e);var l=function(){var t=g.Event(On.HIDDEN,{relatedTarget:n._element}),e=g.Event(On.SHOWN,{relatedTarget:i});g(i).trigger(t),g(n._element).trigger(e)};t?this._activate(t,t.parentNode,l):l()}}},t.dispose=function(){g.removeData(this._element,wn),this._element=null},t._activate=function(t,e,n){var i=this,o=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?g(e).children(Fn):g(e).find(Un))[0],r=n&&o&&g(o).hasClass(jn),s=function(){return i._transitionComplete(t,o,n)};if(o&&r){var a=_.getTransitionDurationFromElement(o);g(o).removeClass(Hn).one(_.TRANSITION_END,s).emulateTransitionEnd(a)}else s()},t._transitionComplete=function(t,e,n){if(e){g(e).removeClass(Pn);var i=g(e.parentNode).find(Mn)[0];i&&g(i).removeClass(Pn),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}if(g(t).addClass(Pn),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),_.reflow(t),t.classList.contains(jn)&&t.classList.add(Hn),t.parentNode&&g(t.parentNode).hasClass(kn)){var o=g(t).closest(Rn)[0];if(o){var r=[].slice.call(o.querySelectorAll(qn));g(r).addClass(Pn)}t.setAttribute("aria-expanded",!0)}n&&n()},i._jQueryInterface=function(n){return this.each(function(){var t=g(this),e=t.data(wn);if(e||(e=new i(this),t.data(wn,e)),"string"==typeof n){if("undefined"==typeof e[n])throw new TypeError('No method named "'+n+'"');e[n]()}})},s(i,null,[{key:"VERSION",get:function(){return"4.3.1"}}]),i}();g(document).on(On.CLICK_DATA_API,Wn,function(t){t.preventDefault(),Kn._jQueryInterface.call(g(this),"show")}),g.fn.tab=Kn._jQueryInterface,g.fn.tab.Constructor=Kn,g.fn.tab.noConflict=function(){return g.fn.tab=Nn,Kn._jQueryInterface};var Qn="toast",Bn="bs.toast",Vn="."+Bn,Yn=g.fn[Qn],zn={CLICK_DISMISS:"click.dismiss"+Vn,HIDE:"hide"+Vn,HIDDEN:"hidden"+Vn,SHOW:"show"+Vn,SHOWN:"shown"+Vn},Xn="fade",$n="hide",Gn="show",Jn="showing",Zn={animation:"boolean",autohide:"boolean",delay:"number"},ti={animation:!0,autohide:!0,delay:500},ei='[data-dismiss="toast"]',ni=function(){function i(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}var t=i.prototype;return t.show=function(){var t=this;g(this._element).trigger(zn.SHOW),this._config.animation&&this._element.classList.add(Xn);var e=function(){t._element.classList.remove(Jn),t._element.classList.add(Gn),g(t._element).trigger(zn.SHOWN),t._config.autohide&&t.hide()};if(this._element.classList.remove($n),this._element.classList.add(Jn),this._config.animation){var n=_.getTransitionDurationFromElement(this._element);g(this._element).one(_.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},t.hide=function(t){var e=this;this._element.classList.contains(Gn)&&(g(this._element).trigger(zn.HIDE),t?this._close():this._timeout=setTimeout(function(){e._close()},this._config.delay))},t.dispose=function(){clearTimeout(this._timeout),this._timeout=null,this._element.classList.contains(Gn)&&this._element.classList.remove(Gn),g(this._element).off(zn.CLICK_DISMISS),g.removeData(this._element,Bn),this._element=null,this._config=null},t._getConfig=function(t){return t=l({},ti,g(this._element).data(),"object"==typeof t&&t?t:{}),_.typeCheckConfig(Qn,t,this.constructor.DefaultType),t},t._setListeners=function(){var t=this;g(this._element).on(zn.CLICK_DISMISS,ei,function(){return t.hide(!0)})},t._close=function(){var t=this,e=function(){t._element.classList.add($n),g(t._element).trigger(zn.HIDDEN)};if(this._element.classList.remove(Gn),this._config.animation){var n=_.getTransitionDurationFromElement(this._element);g(this._element).one(_.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},i._jQueryInterface=function(n){return this.each(function(){var t=g(this),e=t.data(Bn);if(e||(e=new i(this,"object"==typeof n&&n),t.data(Bn,e)),"string"==typeof n){if("undefined"==typeof e[n])throw new TypeError('No method named "'+n+'"');e[n](this)}})},s(i,null,[{key:"VERSION",get:function(){return"4.3.1"}},{key:"DefaultType",get:function(){return Zn}},{key:"Default",get:function(){return ti}}]),i}();g.fn[Qn]=ni._jQueryInterface,g.fn[Qn].Constructor=ni,g.fn[Qn].noConflict=function(){return g.fn[Qn]=Yn,ni._jQueryInterface},function(){if("undefined"==typeof g)throw new TypeError("Bootstrap's JavaScript requires jQuery. jQuery must be included before Bootstrap's JavaScript.");var t=g.fn.jquery.split(" ")[0].split(".");if(t[0]<2&&t[1]<9||1===t[0]&&9===t[1]&&t[2]<1||4<=t[0])throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}(),t.Util=_,t.Alert=p,t.Button=P,t.Carousel=lt,t.Collapse=bt,t.Dropdown=Jt,t.Modal=ve,t.Popover=sn,t.Scrollspy=Dn,t.Tab=Kn,t.Toast=ni,t.Tooltip=Be,Object.defineProperty(t,"__esModule",{value:!0})});
//# sourceMappingURL=bootstrap.min.js.map/* nvd3 version 1.8.1 (https://github.com/novus/nvd3) 2015-06-15 */
!function(){var a={};a.dev=!1,a.tooltip=a.tooltip||{},a.utils=a.utils||{},a.models=a.models||{},a.charts={},a.logs={},a.dom={},a.dispatch=d3.dispatch("render_start","render_end"),Function.prototype.bind||(Function.prototype.bind=function(a){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var b=Array.prototype.slice.call(arguments,1),c=this,d=function(){},e=function(){return c.apply(this instanceof d&&a?this:a,b.concat(Array.prototype.slice.call(arguments)))};return d.prototype=this.prototype,e.prototype=new d,e}),a.dev&&(a.dispatch.on("render_start",function(){a.logs.startTime=+new Date}),a.dispatch.on("render_end",function(){a.logs.endTime=+new Date,a.logs.totalTime=a.logs.endTime-a.logs.startTime,a.log("total",a.logs.totalTime)})),a.log=function(){if(a.dev&&window.console&&console.log&&console.log.apply)console.log.apply(console,arguments);else if(a.dev&&window.console&&"function"==typeof console.log&&Function.prototype.bind){var b=Function.prototype.bind.call(console.log,console);b.apply(console,arguments)}return arguments[arguments.length-1]},a.deprecated=function(a,b){console&&console.warn&&console.warn("nvd3 warning: `"+a+"` has been deprecated. ",b||"")},a.render=function(b){b=b||1,a.render.active=!0,a.dispatch.render_start();var c=function(){for(var d,e,f=0;b>f&&(e=a.render.queue[f]);f++)d=e.generate(),typeof e.callback==typeof Function&&e.callback(d);a.render.queue.splice(0,f),a.render.queue.length?setTimeout(c):(a.dispatch.render_end(),a.render.active=!1)};setTimeout(c)},a.render.active=!1,a.render.queue=[],a.addGraph=function(b){typeof arguments[0]==typeof Function&&(b={generate:arguments[0],callback:arguments[1]}),a.render.queue.push(b),a.render.active||a.render()},"undefined"!=typeof module&&"undefined"!=typeof exports&&(module.exports=a),"undefined"!=typeof window&&(window.nv=a),a.dom.write=function(a){return void 0!==window.fastdom?fastdom.write(a):a()},a.dom.read=function(a){return void 0!==window.fastdom?fastdom.read(a):a()},a.interactiveGuideline=function(){"use strict";function b(l){l.each(function(l){function m(){var a=d3.mouse(this),d=a[0],e=a[1],i=!0,j=!1;if(k&&(d=d3.event.offsetX,e=d3.event.offsetY,"svg"!==d3.event.target.tagName&&(i=!1),d3.event.target.className.baseVal.match("nv-legend")&&(j=!0)),i&&(d-=f.left,e-=f.top),0>d||0>e||d>o||e>p||d3.event.relatedTarget&&void 0===d3.event.relatedTarget.ownerSVGElement||j){if(k&&d3.event.relatedTarget&&void 0===d3.event.relatedTarget.ownerSVGElement&&(void 0===d3.event.relatedTarget.className||d3.event.relatedTarget.className.match(c.nvPointerEventsClass)))return;return h.elementMouseout({mouseX:d,mouseY:e}),b.renderGuideLine(null),void c.hidden(!0)}c.hidden(!1);var l=g.invert(d);h.elementMousemove({mouseX:d,mouseY:e,pointXValue:l}),"dblclick"===d3.event.type&&h.elementDblclick({mouseX:d,mouseY:e,pointXValue:l}),"click"===d3.event.type&&h.elementClick({mouseX:d,mouseY:e,pointXValue:l})}var n=d3.select(this),o=d||960,p=e||400,q=n.selectAll("g.nv-wrap.nv-interactiveLineLayer").data([l]),r=q.enter().append("g").attr("class"," nv-wrap nv-interactiveLineLayer");r.append("g").attr("class","nv-interactiveGuideLine"),j&&(j.on("touchmove",m).on("mousemove",m,!0).on("mouseout",m,!0).on("dblclick",m).on("click",m),b.guideLine=null,b.renderGuideLine=function(c){i&&(b.guideLine&&b.guideLine.attr("x1")===c||a.dom.write(function(){var b=q.select(".nv-interactiveGuideLine").selectAll("line").data(null!=c?[a.utils.NaNtoZero(c)]:[],String);b.enter().append("line").attr("class","nv-guideline").attr("x1",function(a){return a}).attr("x2",function(a){return a}).attr("y1",p).attr("y2",0),b.exit().remove()}))})})}var c=a.models.tooltip();c.duration(0).hideDelay(0)._isInteractiveLayer(!0).hidden(!1);var d=null,e=null,f={left:0,top:0},g=d3.scale.linear(),h=d3.dispatch("elementMousemove","elementMouseout","elementClick","elementDblclick"),i=!0,j=null,k="ActiveXObject"in window;return b.dispatch=h,b.tooltip=c,b.margin=function(a){return arguments.length?(f.top="undefined"!=typeof a.top?a.top:f.top,f.left="undefined"!=typeof a.left?a.left:f.left,b):f},b.width=function(a){return arguments.length?(d=a,b):d},b.height=function(a){return arguments.length?(e=a,b):e},b.xScale=function(a){return arguments.length?(g=a,b):g},b.showGuideLine=function(a){return arguments.length?(i=a,b):i},b.svgContainer=function(a){return arguments.length?(j=a,b):j},b},a.interactiveBisect=function(a,b,c){"use strict";if(!(a instanceof Array))return null;var d;d="function"!=typeof c?function(a){return a.x}:c;var e=function(a,b){return d(a)-b},f=d3.bisector(e).left,g=d3.max([0,f(a,b)-1]),h=d(a[g]);if("undefined"==typeof h&&(h=g),h===b)return g;var i=d3.min([g+1,a.length-1]),j=d(a[i]);return"undefined"==typeof j&&(j=i),Math.abs(j-b)>=Math.abs(h-b)?g:i},a.nearestValueIndex=function(a,b,c){"use strict";var d=1/0,e=null;return a.forEach(function(a,f){var g=Math.abs(b-a);null!=a&&d>=g&&c>g&&(d=g,e=f)}),e},function(){"use strict";a.models.tooltip=function(){function b(){if(k){var a=d3.select(k);"svg"!==a.node().tagName&&(a=a.select("svg"));var b=a.node()?a.attr("viewBox"):null;if(b){b=b.split(" ");var c=parseInt(a.style("width"),10)/b[2];p.left=p.left*c,p.top=p.top*c}}}function c(){if(!n){var a;a=k?k:document.body,n=d3.select(a).append("div").attr("class","nvtooltip "+(j?j:"xy-tooltip")).attr("id",v),n.style("top",0).style("left",0),n.style("opacity",0),n.selectAll("div, table, td, tr").classed(w,!0),n.classed(w,!0),o=n.node()}}function d(){if(r&&B(e)){b();var f=p.left,g=null!==i?i:p.top;return a.dom.write(function(){c();var b=A(e);b&&(o.innerHTML=b),k&&u?a.dom.read(function(){var a=k.getElementsByTagName("svg")[0],b={left:0,top:0};if(a){var c=a.getBoundingClientRect(),d=k.getBoundingClientRect(),e=c.top;if(0>e){var i=k.getBoundingClientRect();e=Math.abs(e)>i.height?0:e}b.top=Math.abs(e-d.top),b.left=Math.abs(c.left-d.left)}f+=k.offsetLeft+b.left-2*k.scrollLeft,g+=k.offsetTop+b.top-2*k.scrollTop,h&&h>0&&(g=Math.floor(g/h)*h),C([f,g])}):C([f,g])}),d}}var e=null,f="w",g=25,h=0,i=null,j=null,k=null,l=!0,m=400,n=null,o=null,p={left:null,top:null},q={left:0,top:0},r=!0,s=100,t=!0,u=!1,v="nvtooltip-"+Math.floor(1e5*Math.random()),w="nv-pointer-events-none",x=function(a){return a},y=function(a){return a},z=function(a){return a},A=function(a){if(null===a)return"";var b=d3.select(document.createElement("table"));if(t){var c=b.selectAll("thead").data([a]).enter().append("thead");c.append("tr").append("td").attr("colspan",3).append("strong").classed("x-value",!0).html(y(a.value))}var d=b.selectAll("tbody").data([a]).enter().append("tbody"),e=d.selectAll("tr").data(function(a){return a.series}).enter().append("tr").classed("highlight",function(a){return a.highlight});e.append("td").classed("legend-color-guide",!0).append("div").style("background-color",function(a){return a.color}),e.append("td").classed("key",!0).html(function(a,b){return z(a.key,b)}),e.append("td").classed("value",!0).html(function(a,b){return x(a.value,b)}),e.selectAll("td").each(function(a){if(a.highlight){var b=d3.scale.linear().domain([0,1]).range(["#fff",a.color]),c=.6;d3.select(this).style("border-bottom-color",b(c)).style("border-top-color",b(c))}});var f=b.node().outerHTML;return void 0!==a.footer&&(f+="<div class='footer'>"+a.footer+"</div>"),f},B=function(a){if(a&&a.series){if(a.series instanceof Array)return!!a.series.length;if(a.series instanceof Object)return a.series=[a.series],!0}return!1},C=function(b){o&&a.dom.read(function(){var c,d,e=parseInt(o.offsetHeight,10),h=parseInt(o.offsetWidth,10),i=a.utils.windowSize().width,j=a.utils.windowSize().height,k=window.pageYOffset,p=window.pageXOffset;j=window.innerWidth>=document.body.scrollWidth?j:j-16,i=window.innerHeight>=document.body.scrollHeight?i:i-16;var r,t,u=function(a){var b=d;do isNaN(a.offsetTop)||(b+=a.offsetTop),a=a.offsetParent;while(a);return b},v=function(a){var b=c;do isNaN(a.offsetLeft)||(b+=a.offsetLeft),a=a.offsetParent;while(a);return b};switch(f){case"e":c=b[0]-h-g,d=b[1]-e/2,r=v(o),t=u(o),p>r&&(c=b[0]+g>p?b[0]+g:p-r+c),k>t&&(d=k-t+d),t+e>k+j&&(d=k+j-t+d-e);break;case"w":c=b[0]+g,d=b[1]-e/2,r=v(o),t=u(o),r+h>i&&(c=b[0]-h-g),k>t&&(d=k+5),t+e>k+j&&(d=k+j-t+d-e);break;case"n":c=b[0]-h/2-5,d=b[1]+g,r=v(o),t=u(o),p>r&&(c=p+5),r+h>i&&(c=c-h/2+5),t+e>k+j&&(d=k+j-t+d-e);break;case"s":c=b[0]-h/2,d=b[1]-e-g,r=v(o),t=u(o),p>r&&(c=p+5),r+h>i&&(c=c-h/2+5),k>t&&(d=k);break;case"none":c=b[0],d=b[1]-g,r=v(o),t=u(o)}c-=q.left,d-=q.top;var w=o.getBoundingClientRect(),k=window.pageYOffset||document.documentElement.scrollTop,p=window.pageXOffset||document.documentElement.scrollLeft,x="translate("+(w.left+p)+"px, "+(w.top+k)+"px)",y="translate("+c+"px, "+d+"px)",z=d3.interpolateString(x,y),A=n.style("opacity")<.1;l?n.transition().delay(m).duration(0).style("opacity",0):n.interrupt().transition().duration(A?0:s).styleTween("transform",function(){return z},"important").style("-webkit-transform",y).style("opacity",1)})};return d.nvPointerEventsClass=w,d.options=a.utils.optionsFunc.bind(d),d._options=Object.create({},{duration:{get:function(){return s},set:function(a){s=a}},gravity:{get:function(){return f},set:function(a){f=a}},distance:{get:function(){return g},set:function(a){g=a}},snapDistance:{get:function(){return h},set:function(a){h=a}},classes:{get:function(){return j},set:function(a){j=a}},chartContainer:{get:function(){return k},set:function(a){k=a}},fixedTop:{get:function(){return i},set:function(a){i=a}},enabled:{get:function(){return r},set:function(a){r=a}},hideDelay:{get:function(){return m},set:function(a){m=a}},contentGenerator:{get:function(){return A},set:function(a){A=a}},valueFormatter:{get:function(){return x},set:function(a){x=a}},headerFormatter:{get:function(){return y},set:function(a){y=a}},keyFormatter:{get:function(){return z},set:function(a){z=a}},headerEnabled:{get:function(){return t},set:function(a){t=a}},_isInteractiveLayer:{get:function(){return u},set:function(a){u=!!a}},position:{get:function(){return p},set:function(a){p.left=void 0!==a.left?a.left:p.left,p.top=void 0!==a.top?a.top:p.top}},offset:{get:function(){return q},set:function(a){q.left=void 0!==a.left?a.left:q.left,q.top=void 0!==a.top?a.top:q.top}},hidden:{get:function(){return l},set:function(a){l!=a&&(l=!!a,d())}},data:{get:function(){return e},set:function(a){a.point&&(a.value=a.point.x,a.series=a.series||{},a.series.value=a.point.y,a.series.color=a.point.color||a.series.color),e=a}},tooltipElem:{get:function(){return o},set:function(){}},id:{get:function(){return v},set:function(){}}}),a.utils.initOptions(d),d}}(),a.utils.windowSize=function(){var a={width:640,height:480};return window.innerWidth&&window.innerHeight?(a.width=window.innerWidth,a.height=window.innerHeight,a):"CSS1Compat"==document.compatMode&&document.documentElement&&document.documentElement.offsetWidth?(a.width=document.documentElement.offsetWidth,a.height=document.documentElement.offsetHeight,a):document.body&&document.body.offsetWidth?(a.width=document.body.offsetWidth,a.height=document.body.offsetHeight,a):a},a.utils.windowResize=function(b){return window.addEventListener?window.addEventListener("resize",b):a.log("ERROR: Failed to bind to window.resize with: ",b),{callback:b,clear:function(){window.removeEventListener("resize",b)}}},a.utils.getColor=function(b){if(void 0===b)return a.utils.defaultColor();if(Array.isArray(b)){var c=d3.scale.ordinal().range(b);return function(a,b){var d=void 0===b?a:b;return a.color||c(d)}}return b},a.utils.defaultColor=function(){return a.utils.getColor(d3.scale.category20().range())},a.utils.customTheme=function(a,b,c){b=b||function(a){return a.key},c=c||d3.scale.category20().range();var d=c.length;return function(e){var f=b(e);return"function"==typeof a[f]?a[f]():void 0!==a[f]?a[f]:(d||(d=c.length),d-=1,c[d])}},a.utils.pjax=function(b,c){var d=function(d){d3.html(d,function(d){var e=d3.select(c).node();e.parentNode.replaceChild(d3.select(d).select(c).node(),e),a.utils.pjax(b,c)})};d3.selectAll(b).on("click",function(){history.pushState(this.href,this.textContent,this.href),d(this.href),d3.event.preventDefault()}),d3.select(window).on("popstate",function(){d3.event.state&&d(d3.event.state)})},a.utils.calcApproxTextWidth=function(a){if("function"==typeof a.style&&"function"==typeof a.text){var b=parseInt(a.style("font-size").replace("px",""),10),c=a.text().length;return c*b*.5}return 0},a.utils.NaNtoZero=function(a){return"number"!=typeof a||isNaN(a)||null===a||1/0===a||a===-1/0?0:a},d3.selection.prototype.watchTransition=function(a){var b=[this].concat([].slice.call(arguments,1));return a.transition.apply(a,b)},a.utils.renderWatch=function(b,c){if(!(this instanceof a.utils.renderWatch))return new a.utils.renderWatch(b,c);var d=void 0!==c?c:250,e=[],f=this;this.models=function(a){return a=[].slice.call(arguments,0),a.forEach(function(a){a.__rendered=!1,function(a){a.dispatch.on("renderEnd",function(){a.__rendered=!0,f.renderEnd("model")})}(a),e.indexOf(a)<0&&e.push(a)}),this},this.reset=function(a){void 0!==a&&(d=a),e=[]},this.transition=function(a,b,c){if(b=arguments.length>1?[].slice.call(arguments,1):[],c=b.length>1?b.pop():void 0!==d?d:250,a.__rendered=!1,e.indexOf(a)<0&&e.push(a),0===c)return a.__rendered=!0,a.delay=function(){return this},a.duration=function(){return this},a;a.__rendered=0===a.length?!0:a.every(function(a){return!a.length})?!0:!1;var g=0;return a.transition().duration(c).each(function(){++g}).each("end",function(){0===--g&&(a.__rendered=!0,f.renderEnd.apply(this,b))})},this.renderEnd=function(){e.every(function(a){return a.__rendered})&&(e.forEach(function(a){a.__rendered=!1}),b.renderEnd.apply(this,arguments))}},a.utils.deepExtend=function(b){var c=arguments.length>1?[].slice.call(arguments,1):[];c.forEach(function(c){for(var d in c){var e=b[d]instanceof Array,f="object"==typeof b[d],g="object"==typeof c[d];f&&!e&&g?a.utils.deepExtend(b[d],c[d]):b[d]=c[d]}})},a.utils.state=function(){if(!(this instanceof a.utils.state))return new a.utils.state;var b={},c=function(){},d=function(){return{}},e=null,f=null;this.dispatch=d3.dispatch("change","set"),this.dispatch.on("set",function(a){c(a,!0)}),this.getter=function(a){return d=a,this},this.setter=function(a,b){return b||(b=function(){}),c=function(c,d){a(c),d&&b()},this},this.init=function(b){e=e||{},a.utils.deepExtend(e,b)};var g=function(){var a=d();if(JSON.stringify(a)===JSON.stringify(b))return!1;for(var c in a)void 0===b[c]&&(b[c]={}),b[c]=a[c],f=!0;return!0};this.update=function(){e&&(c(e,!1),e=null),g.call(this)&&this.dispatch.change(b)}},a.utils.optionsFunc=function(a){return a&&d3.map(a).forEach(function(a,b){"function"==typeof this[a]&&this[a](b)}.bind(this)),this},a.utils.calcTicksX=function(b,c){var d=1,e=0;for(e;e<c.length;e+=1){var f=c[e]&&c[e].values?c[e].values.length:0;d=f>d?f:d}return a.log("Requested number of ticks: ",b),a.log("Calculated max values to be: ",d),b=b>d?b=d-1:b,b=1>b?1:b,b=Math.floor(b),a.log("Calculating tick count as: ",b),b},a.utils.calcTicksY=function(b,c){return a.utils.calcTicksX(b,c)},a.utils.initOption=function(a,b){a._calls&&a._calls[b]?a[b]=a._calls[b]:(a[b]=function(c){return arguments.length?(a._overrides[b]=!0,a._options[b]=c,a):a._options[b]},a["_"+b]=function(c){return arguments.length?(a._overrides[b]||(a._options[b]=c),a):a._options[b]})},a.utils.initOptions=function(b){b._overrides=b._overrides||{};var c=Object.getOwnPropertyNames(b._options||{}),d=Object.getOwnPropertyNames(b._calls||{});c=c.concat(d);for(var e in c)a.utils.initOption(b,c[e])},a.utils.inheritOptionsD3=function(a,b,c){a._d3options=c.concat(a._d3options||[]),c.unshift(b),c.unshift(a),d3.rebind.apply(this,c)},a.utils.arrayUnique=function(a){return a.sort().filter(function(b,c){return!c||b!=a[c-1]})},a.utils.symbolMap=d3.map(),a.utils.symbol=function(){function b(b,e){var f=c.call(this,b,e),g=d.call(this,b,e);return-1!==d3.svg.symbolTypes.indexOf(f)?d3.svg.symbol().type(f).size(g)():a.utils.symbolMap.get(f)(g)}var c,d=64;return b.type=function(a){return arguments.length?(c=d3.functor(a),b):c},b.size=function(a){return arguments.length?(d=d3.functor(a),b):d},b},a.utils.inheritOptions=function(b,c){var d=Object.getOwnPropertyNames(c._options||{}),e=Object.getOwnPropertyNames(c._calls||{}),f=c._inherited||[],g=c._d3options||[],h=d.concat(e).concat(f).concat(g);h.unshift(c),h.unshift(b),d3.rebind.apply(this,h),b._inherited=a.utils.arrayUnique(d.concat(e).concat(f).concat(d).concat(b._inherited||[])),b._d3options=a.utils.arrayUnique(g.concat(b._d3options||[]))},a.utils.initSVG=function(a){a.classed({"nvd3-svg":!0})},a.utils.sanitizeHeight=function(a,b){return a||parseInt(b.style("height"),10)||400},a.utils.sanitizeWidth=function(a,b){return a||parseInt(b.style("width"),10)||960},a.utils.availableHeight=function(b,c,d){return a.utils.sanitizeHeight(b,c)-d.top-d.bottom},a.utils.availableWidth=function(b,c,d){return a.utils.sanitizeWidth(b,c)-d.left-d.right},a.utils.noData=function(b,c){var d=b.options(),e=d.margin(),f=d.noData(),g=null==f?["No Data Available."]:[f],h=a.utils.availableHeight(d.height(),c,e),i=a.utils.availableWidth(d.width(),c,e),j=e.left+i/2,k=e.top+h/2;c.selectAll("g").remove();var l=c.selectAll(".nv-noData").data(g);l.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),l.attr("x",j).attr("y",k).text(function(a){return a})},a.models.axis=function(){"use strict";function b(g){return s.reset(),g.each(function(b){var g=d3.select(this);a.utils.initSVG(g);var p=g.selectAll("g.nv-wrap.nv-axis").data([b]),q=p.enter().append("g").attr("class","nvd3 nv-wrap nv-axis"),t=(q.append("g"),p.select("g"));null!==n?c.ticks(n):("top"==c.orient()||"bottom"==c.orient())&&c.ticks(Math.abs(d.range()[1]-d.range()[0])/100),t.watchTransition(s,"axis").call(c),r=r||c.scale();var u=c.tickFormat();null==u&&(u=r.tickFormat());var v=t.selectAll("text.nv-axislabel").data([h||null]);v.exit().remove();var w,x,y;switch(c.orient()){case"top":v.enter().append("text").attr("class","nv-axislabel"),y=d.range().length<2?0:2===d.range().length?d.range()[1]:d.range()[d.range().length-1]+(d.range()[1]-d.range()[0]),v.attr("text-anchor","middle").attr("y",0).attr("x",y/2),i&&(x=p.selectAll("g.nv-axisMaxMin").data(d.domain()),x.enter().append("g").attr("class",function(a,b){return["nv-axisMaxMin","nv-axisMaxMin-x",0==b?"nv-axisMin-x":"nv-axisMax-x"].join(" ")}).append("text"),x.exit().remove(),x.attr("transform",function(b){return"translate("+a.utils.NaNtoZero(d(b))+",0)"}).select("text").attr("dy","-0.5em").attr("y",-c.tickPadding()).attr("text-anchor","middle").text(function(a){var b=u(a);return(""+b).match("NaN")?"":b}),x.watchTransition(s,"min-max top").attr("transform",function(b,c){return"translate("+a.utils.NaNtoZero(d.range()[c])+",0)"}));break;case"bottom":w=o+36;var z=30,A=0,B=t.selectAll("g").select("text"),C="";if(j%360){B.each(function(){var a=this.getBoundingClientRect(),b=a.width;A=a.height,b>z&&(z=b)}),C="rotate("+j+" 0,"+(A/2+c.tickPadding())+")";var D=Math.abs(Math.sin(j*Math.PI/180));w=(D?D*z:z)+30,B.attr("transform",C).style("text-anchor",j%360>0?"start":"end")}v.enter().append("text").attr("class","nv-axislabel"),y=d.range().length<2?0:2===d.range().length?d.range()[1]:d.range()[d.range().length-1]+(d.range()[1]-d.range()[0]),v.attr("text-anchor","middle").attr("y",w).attr("x",y/2),i&&(x=p.selectAll("g.nv-axisMaxMin").data([d.domain()[0],d.domain()[d.domain().length-1]]),x.enter().append("g").attr("class",function(a,b){return["nv-axisMaxMin","nv-axisMaxMin-x",0==b?"nv-axisMin-x":"nv-axisMax-x"].join(" ")}).append("text"),x.exit().remove(),x.attr("transform",function(b){return"translate("+a.utils.NaNtoZero(d(b)+(m?d.rangeBand()/2:0))+",0)"}).select("text").attr("dy",".71em").attr("y",c.tickPadding()).attr("transform",C).style("text-anchor",j?j%360>0?"start":"end":"middle").text(function(a){var b=u(a);return(""+b).match("NaN")?"":b}),x.watchTransition(s,"min-max bottom").attr("transform",function(b){return"translate("+a.utils.NaNtoZero(d(b)+(m?d.rangeBand()/2:0))+",0)"})),l&&B.attr("transform",function(a,b){return"translate(0,"+(b%2==0?"0":"12")+")"});break;case"right":v.enter().append("text").attr("class","nv-axislabel"),v.style("text-anchor",k?"middle":"begin").attr("transform",k?"rotate(90)":"").attr("y",k?-Math.max(e.right,f)+12:-10).attr("x",k?d3.max(d.range())/2:c.tickPadding()),i&&(x=p.selectAll("g.nv-axisMaxMin").data(d.domain()),x.enter().append("g").attr("class",function(a,b){return["nv-axisMaxMin","nv-axisMaxMin-y",0==b?"nv-axisMin-y":"nv-axisMax-y"].join(" ")}).append("text").style("opacity",0),x.exit().remove(),x.attr("transform",function(b){return"translate(0,"+a.utils.NaNtoZero(d(b))+")"}).select("text").attr("dy",".32em").attr("y",0).attr("x",c.tickPadding()).style("text-anchor","start").text(function(a){var b=u(a);return(""+b).match("NaN")?"":b}),x.watchTransition(s,"min-max right").attr("transform",function(b,c){return"translate(0,"+a.utils.NaNtoZero(d.range()[c])+")"}).select("text").style("opacity",1));break;case"left":v.enter().append("text").attr("class","nv-axislabel"),v.style("text-anchor",k?"middle":"end").attr("transform",k?"rotate(-90)":"").attr("y",k?-Math.max(e.left,f)+25-(o||0):-10).attr("x",k?-d3.max(d.range())/2:-c.tickPadding()),i&&(x=p.selectAll("g.nv-axisMaxMin").data(d.domain()),x.enter().append("g").attr("class",function(a,b){return["nv-axisMaxMin","nv-axisMaxMin-y",0==b?"nv-axisMin-y":"nv-axisMax-y"].join(" ")}).append("text").style("opacity",0),x.exit().remove(),x.attr("transform",function(b){return"translate(0,"+a.utils.NaNtoZero(r(b))+")"}).select("text").attr("dy",".32em").attr("y",0).attr("x",-c.tickPadding()).attr("text-anchor","end").text(function(a){var b=u(a);return(""+b).match("NaN")?"":b}),x.watchTransition(s,"min-max right").attr("transform",function(b,c){return"translate(0,"+a.utils.NaNtoZero(d.range()[c])+")"}).select("text").style("opacity",1))}if(v.text(function(a){return a}),!i||"left"!==c.orient()&&"right"!==c.orient()||(t.selectAll("g").each(function(a){d3.select(this).select("text").attr("opacity",1),(d(a)<d.range()[1]+10||d(a)>d.range()[0]-10)&&((a>1e-10||-1e-10>a)&&d3.select(this).attr("opacity",0),d3.select(this).select("text").attr("opacity",0))}),d.domain()[0]==d.domain()[1]&&0==d.domain()[0]&&p.selectAll("g.nv-axisMaxMin").style("opacity",function(a,b){return b?0:1})),i&&("top"===c.orient()||"bottom"===c.orient())){var E=[];p.selectAll("g.nv-axisMaxMin").each(function(a,b){try{E.push(b?d(a)-this.getBoundingClientRect().width-4:d(a)+this.getBoundingClientRect().width+4)}catch(c){E.push(b?d(a)-4:d(a)+4)}}),t.selectAll("g").each(function(a){(d(a)<E[0]||d(a)>E[1])&&(a>1e-10||-1e-10>a?d3.select(this).remove():d3.select(this).select("text").remove())})}t.selectAll(".tick").filter(function(a){return!parseFloat(Math.round(1e5*a)/1e6)&&void 0!==a}).classed("zero",!0),r=d.copy()}),s.renderEnd("axis immediate"),b}var c=d3.svg.axis(),d=d3.scale.linear(),e={top:0,right:0,bottom:0,left:0},f=75,g=60,h=null,i=!0,j=0,k=!0,l=!1,m=!1,n=null,o=0,p=250,q=d3.dispatch("renderEnd");c.scale(d).orient("bottom").tickFormat(function(a){return a});var r,s=a.utils.renderWatch(q,p);return b.axis=c,b.dispatch=q,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{axisLabelDistance:{get:function(){return o},set:function(a){o=a}},staggerLabels:{get:function(){return l},set:function(a){l=a}},rotateLabels:{get:function(){return j},set:function(a){j=a}},rotateYLabel:{get:function(){return k},set:function(a){k=a}},showMaxMin:{get:function(){return i},set:function(a){i=a}},axisLabel:{get:function(){return h},set:function(a){h=a}},height:{get:function(){return g},set:function(a){g=a}},ticks:{get:function(){return n},set:function(a){n=a}},width:{get:function(){return f},set:function(a){f=a}},margin:{get:function(){return e},set:function(a){e.top=void 0!==a.top?a.top:e.top,e.right=void 0!==a.right?a.right:e.right,e.bottom=void 0!==a.bottom?a.bottom:e.bottom,e.left=void 0!==a.left?a.left:e.left}},duration:{get:function(){return p},set:function(a){p=a,s.reset(p)}},scale:{get:function(){return d},set:function(e){d=e,c.scale(d),m="function"==typeof d.rangeBands,a.utils.inheritOptionsD3(b,d,["domain","range","rangeBand","rangeBands"])}}}),a.utils.initOptions(b),a.utils.inheritOptionsD3(b,c,["orient","tickValues","tickSubdivide","tickSize","tickPadding","tickFormat"]),a.utils.inheritOptionsD3(b,d,["domain","range","rangeBand","rangeBands"]),b},a.models.boxPlot=function(){"use strict";function b(l){return v.reset(),l.each(function(b){var l=j-i.left-i.right,p=k-i.top-i.bottom;r=d3.select(this),a.utils.initSVG(r),m.domain(c||b.map(function(a,b){return o(a,b)})).rangeBands(e||[0,l],.1);var w=[];if(!d){var x=d3.min(b.map(function(a){var b=[];return b.push(a.values.Q1),a.values.hasOwnProperty("whisker_low")&&null!==a.values.whisker_low&&b.push(a.values.whisker_low),a.values.hasOwnProperty("outliers")&&null!==a.values.outliers&&(b=b.concat(a.values.outliers)),d3.min(b)})),y=d3.max(b.map(function(a){var b=[];return b.push(a.values.Q3),a.values.hasOwnProperty("whisker_high")&&null!==a.values.whisker_high&&b.push(a.values.whisker_high),a.values.hasOwnProperty("outliers")&&null!==a.values.outliers&&(b=b.concat(a.values.outliers)),d3.max(b)}));w=[x,y]}n.domain(d||w),n.range(f||[p,0]),g=g||m,h=h||n.copy().range([n(0),n(0)]);{var z=r.selectAll("g.nv-wrap").data([b]);z.enter().append("g").attr("class","nvd3 nv-wrap")}z.attr("transform","translate("+i.left+","+i.top+")");var A=z.selectAll(".nv-boxplot").data(function(a){return a}),B=A.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6);A.attr("class","nv-boxplot").attr("transform",function(a,b){return"translate("+(m(o(a,b))+.05*m.rangeBand())+", 0)"}).classed("hover",function(a){return a.hover}),A.watchTransition(v,"nv-boxplot: boxplots").style("stroke-opacity",1).style("fill-opacity",.75).delay(function(a,c){return c*t/b.length}).attr("transform",function(a,b){return"translate("+(m(o(a,b))+.05*m.rangeBand())+", 0)"}),A.exit().remove(),B.each(function(a,b){var c=d3.select(this);["low","high"].forEach(function(d){a.values.hasOwnProperty("whisker_"+d)&&null!==a.values["whisker_"+d]&&(c.append("line").style("stroke",a.color?a.color:q(a,b)).attr("class","nv-boxplot-whisker nv-boxplot-"+d),c.append("line").style("stroke",a.color?a.color:q(a,b)).attr("class","nv-boxplot-tick nv-boxplot-"+d))})});var C=A.selectAll(".nv-boxplot-outlier").data(function(a){return a.values.hasOwnProperty("outliers")&&null!==a.values.outliers?a.values.outliers:[]});C.enter().append("circle").style("fill",function(a,b,c){return q(a,c)}).style("stroke",function(a,b,c){return q(a,c)}).on("mouseover",function(a,b,c){d3.select(this).classed("hover",!0),s.elementMouseover({series:{key:a,color:q(a,c)},e:d3.event})}).on("mouseout",function(a,b,c){d3.select(this).classed("hover",!1),s.elementMouseout({series:{key:a,color:q(a,c)},e:d3.event})}).on("mousemove",function(){s.elementMousemove({e:d3.event})}),C.attr("class","nv-boxplot-outlier"),C.watchTransition(v,"nv-boxplot: nv-boxplot-outlier").attr("cx",.45*m.rangeBand()).attr("cy",function(a){return n(a)}).attr("r","3"),C.exit().remove();var D=function(){return null===u?.9*m.rangeBand():Math.min(75,.9*m.rangeBand())},E=function(){return.45*m.rangeBand()-D()/2},F=function(){return.45*m.rangeBand()+D()/2};["low","high"].forEach(function(a){var b="low"===a?"Q1":"Q3";A.select("line.nv-boxplot-whisker.nv-boxplot-"+a).watchTransition(v,"nv-boxplot: boxplots").attr("x1",.45*m.rangeBand()).attr("y1",function(b){return n(b.values["whisker_"+a])}).attr("x2",.45*m.rangeBand()).attr("y2",function(a){return n(a.values[b])}),A.select("line.nv-boxplot-tick.nv-boxplot-"+a).watchTransition(v,"nv-boxplot: boxplots").attr("x1",E).attr("y1",function(b){return n(b.values["whisker_"+a])}).attr("x2",F).attr("y2",function(b){return n(b.values["whisker_"+a])})}),["low","high"].forEach(function(a){B.selectAll(".nv-boxplot-"+a).on("mouseover",function(b,c,d){d3.select(this).classed("hover",!0),s.elementMouseover({series:{key:b.values["whisker_"+a],color:q(b,d)},e:d3.event})}).on("mouseout",function(b,c,d){d3.select(this).classed("hover",!1),s.elementMouseout({series:{key:b.values["whisker_"+a],color:q(b,d)},e:d3.event})}).on("mousemove",function(){s.elementMousemove({e:d3.event})})}),B.append("rect").attr("class","nv-boxplot-box").on("mouseover",function(a,b){d3.select(this).classed("hover",!0),s.elementMouseover({key:a.label,value:a.label,series:[{key:"Q3",value:a.values.Q3,color:a.color||q(a,b)},{key:"Q2",value:a.values.Q2,color:a.color||q(a,b)},{key:"Q1",value:a.values.Q1,color:a.color||q(a,b)}],data:a,index:b,e:d3.event})}).on("mouseout",function(a,b){d3.select(this).classed("hover",!1),s.elementMouseout({key:a.label,value:a.label,series:[{key:"Q3",value:a.values.Q3,color:a.color||q(a,b)},{key:"Q2",value:a.values.Q2,color:a.color||q(a,b)},{key:"Q1",value:a.values.Q1,color:a.color||q(a,b)}],data:a,index:b,e:d3.event})}).on("mousemove",function(){s.elementMousemove({e:d3.event})}),A.select("rect.nv-boxplot-box").watchTransition(v,"nv-boxplot: boxes").attr("y",function(a){return n(a.values.Q3)}).attr("width",D).attr("x",E).attr("height",function(a){return Math.abs(n(a.values.Q3)-n(a.values.Q1))||1}).style("fill",function(a,b){return a.color||q(a,b)}).style("stroke",function(a,b){return a.color||q(a,b)}),B.append("line").attr("class","nv-boxplot-median"),A.select("line.nv-boxplot-median").watchTransition(v,"nv-boxplot: boxplots line").attr("x1",E).attr("y1",function(a){return n(a.values.Q2)}).attr("x2",F).attr("y2",function(a){return n(a.values.Q2)}),g=m.copy(),h=n.copy()}),v.renderEnd("nv-boxplot immediate"),b}var c,d,e,f,g,h,i={top:0,right:0,bottom:0,left:0},j=960,k=500,l=Math.floor(1e4*Math.random()),m=d3.scale.ordinal(),n=d3.scale.linear(),o=function(a){return a.x},p=function(a){return a.y},q=a.utils.defaultColor(),r=null,s=d3.dispatch("elementMouseover","elementMouseout","elementMousemove","renderEnd"),t=250,u=null,v=a.utils.renderWatch(s,t);return b.dispatch=s,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return j},set:function(a){j=a}},height:{get:function(){return k},set:function(a){k=a}},maxBoxWidth:{get:function(){return u},set:function(a){u=a}},x:{get:function(){return o},set:function(a){o=a}},y:{get:function(){return p},set:function(a){p=a}},xScale:{get:function(){return m},set:function(a){m=a}},yScale:{get:function(){return n},set:function(a){n=a}},xDomain:{get:function(){return c},set:function(a){c=a}},yDomain:{get:function(){return d},set:function(a){d=a}},xRange:{get:function(){return e},set:function(a){e=a}},yRange:{get:function(){return f},set:function(a){f=a}},id:{get:function(){return l},set:function(a){l=a}},margin:{get:function(){return i},set:function(a){i.top=void 0!==a.top?a.top:i.top,i.right=void 0!==a.right?a.right:i.right,i.bottom=void 0!==a.bottom?a.bottom:i.bottom,i.left=void 0!==a.left?a.left:i.left}},color:{get:function(){return q},set:function(b){q=a.utils.getColor(b)}},duration:{get:function(){return t},set:function(a){t=a,v.reset(t)}}}),a.utils.initOptions(b),b},a.models.boxPlotChart=function(){"use strict";function b(k){return t.reset(),t.models(e),l&&t.models(f),m&&t.models(g),k.each(function(k){var p=d3.select(this);a.utils.initSVG(p);var t=(i||parseInt(p.style("width"))||960)-h.left-h.right,u=(j||parseInt(p.style("height"))||400)-h.top-h.bottom;if(b.update=function(){r.beforeUpdate(),p.transition().duration(s).call(b)},b.container=this,!(k&&k.length&&k.filter(function(a){return a.values.hasOwnProperty("Q1")&&a.values.hasOwnProperty("Q2")&&a.values.hasOwnProperty("Q3")}).length)){var v=p.selectAll(".nv-noData").data([q]);return v.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),v.attr("x",h.left+t/2).attr("y",h.top+u/2).text(function(a){return a}),b}p.selectAll(".nv-noData").remove(),c=e.xScale(),d=e.yScale().clamp(!0);var w=p.selectAll("g.nv-wrap.nv-boxPlotWithAxes").data([k]),x=w.enter().append("g").attr("class","nvd3 nv-wrap nv-boxPlotWithAxes").append("g"),y=x.append("defs"),z=w.select("g");
x.append("g").attr("class","nv-x nv-axis"),x.append("g").attr("class","nv-y nv-axis").append("g").attr("class","nv-zeroLine").append("line"),x.append("g").attr("class","nv-barsWrap"),z.attr("transform","translate("+h.left+","+h.top+")"),n&&z.select(".nv-y.nv-axis").attr("transform","translate("+t+",0)"),e.width(t).height(u);var A=z.select(".nv-barsWrap").datum(k.filter(function(a){return!a.disabled}));if(A.transition().call(e),y.append("clipPath").attr("id","nv-x-label-clip-"+e.id()).append("rect"),z.select("#nv-x-label-clip-"+e.id()+" rect").attr("width",c.rangeBand()*(o?2:1)).attr("height",16).attr("x",-c.rangeBand()/(o?1:2)),l){f.scale(c).ticks(a.utils.calcTicksX(t/100,k)).tickSize(-u,0),z.select(".nv-x.nv-axis").attr("transform","translate(0,"+d.range()[0]+")"),z.select(".nv-x.nv-axis").call(f);var B=z.select(".nv-x.nv-axis").selectAll("g");o&&B.selectAll("text").attr("transform",function(a,b,c){return"translate(0,"+(c%2==0?"5":"17")+")"})}m&&(g.scale(d).ticks(Math.floor(u/36)).tickSize(-t,0),z.select(".nv-y.nv-axis").call(g)),z.select(".nv-zeroLine line").attr("x1",0).attr("x2",t).attr("y1",d(0)).attr("y2",d(0))}),t.renderEnd("nv-boxplot chart immediate"),b}var c,d,e=a.models.boxPlot(),f=a.models.axis(),g=a.models.axis(),h={top:15,right:10,bottom:50,left:60},i=null,j=null,k=a.utils.getColor(),l=!0,m=!0,n=!1,o=!1,p=a.models.tooltip(),q="No Data Available.",r=d3.dispatch("tooltipShow","tooltipHide","beforeUpdate","renderEnd"),s=250;f.orient("bottom").showMaxMin(!1).tickFormat(function(a){return a}),g.orient(n?"right":"left").tickFormat(d3.format(",.1f")),p.duration(0);var t=a.utils.renderWatch(r,s);return e.dispatch.on("elementMouseover.tooltip",function(a){p.data(a).hidden(!1)}),e.dispatch.on("elementMouseout.tooltip",function(a){p.data(a).hidden(!0)}),e.dispatch.on("elementMousemove.tooltip",function(){p.position({top:d3.event.pageY,left:d3.event.pageX})()}),b.dispatch=r,b.boxplot=e,b.xAxis=f,b.yAxis=g,b.tooltip=p,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return i},set:function(a){i=a}},height:{get:function(){return j},set:function(a){j=a}},staggerLabels:{get:function(){return o},set:function(a){o=a}},showXAxis:{get:function(){return l},set:function(a){l=a}},showYAxis:{get:function(){return m},set:function(a){m=a}},tooltips:{get:function(){return tooltips},set:function(a){tooltips=a}},tooltipContent:{get:function(){return p},set:function(a){p=a}},noData:{get:function(){return q},set:function(a){q=a}},margin:{get:function(){return h},set:function(a){h.top=void 0!==a.top?a.top:h.top,h.right=void 0!==a.right?a.right:h.right,h.bottom=void 0!==a.bottom?a.bottom:h.bottom,h.left=void 0!==a.left?a.left:h.left}},duration:{get:function(){return s},set:function(a){s=a,t.reset(s),e.duration(s),f.duration(s),g.duration(s)}},color:{get:function(){return k},set:function(b){k=a.utils.getColor(b),e.color(k)}},rightAlignYAxis:{get:function(){return n},set:function(a){n=a,g.orient(a?"right":"left")}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.bullet=function(){"use strict";function b(d){return d.each(function(b,d){var p=m-c.left-c.right,s=n-c.top-c.bottom;o=d3.select(this),a.utils.initSVG(o);{var t=f.call(this,b,d).slice().sort(d3.descending),u=g.call(this,b,d).slice().sort(d3.descending),v=h.call(this,b,d).slice().sort(d3.descending),w=i.call(this,b,d).slice(),x=j.call(this,b,d).slice(),y=k.call(this,b,d).slice(),z=d3.scale.linear().domain(d3.extent(d3.merge([l,t]))).range(e?[p,0]:[0,p]);this.__chart__||d3.scale.linear().domain([0,1/0]).range(z.range())}this.__chart__=z;var A=d3.min(t),B=d3.max(t),C=t[1],D=o.selectAll("g.nv-wrap.nv-bullet").data([b]),E=D.enter().append("g").attr("class","nvd3 nv-wrap nv-bullet"),F=E.append("g"),G=D.select("g");F.append("rect").attr("class","nv-range nv-rangeMax"),F.append("rect").attr("class","nv-range nv-rangeAvg"),F.append("rect").attr("class","nv-range nv-rangeMin"),F.append("rect").attr("class","nv-measure"),D.attr("transform","translate("+c.left+","+c.top+")");var H=function(a){return Math.abs(z(a)-z(0))},I=function(a){return z(0>a?a:0)};G.select("rect.nv-rangeMax").attr("height",s).attr("width",H(B>0?B:A)).attr("x",I(B>0?B:A)).datum(B>0?B:A),G.select("rect.nv-rangeAvg").attr("height",s).attr("width",H(C)).attr("x",I(C)).datum(C),G.select("rect.nv-rangeMin").attr("height",s).attr("width",H(B)).attr("x",I(B)).attr("width",H(B>0?A:B)).attr("x",I(B>0?A:B)).datum(B>0?A:B),G.select("rect.nv-measure").style("fill",q).attr("height",s/3).attr("y",s/3).attr("width",0>v?z(0)-z(v[0]):z(v[0])-z(0)).attr("x",I(v)).on("mouseover",function(){r.elementMouseover({value:v[0],label:y[0]||"Current",color:d3.select(this).style("fill")})}).on("mousemove",function(){r.elementMousemove({value:v[0],label:y[0]||"Current",color:d3.select(this).style("fill")})}).on("mouseout",function(){r.elementMouseout({value:v[0],label:y[0]||"Current",color:d3.select(this).style("fill")})});var J=s/6,K=u.map(function(a,b){return{value:a,label:x[b]}});F.selectAll("path.nv-markerTriangle").data(K).enter().append("path").attr("class","nv-markerTriangle").attr("transform",function(a){return"translate("+z(a.value)+","+s/2+")"}).attr("d","M0,"+J+"L"+J+","+-J+" "+-J+","+-J+"Z").on("mouseover",function(a){r.elementMouseover({value:a.value,label:a.label||"Previous",color:d3.select(this).style("fill"),pos:[z(a.value),s/2]})}).on("mousemove",function(a){r.elementMousemove({value:a.value,label:a.label||"Previous",color:d3.select(this).style("fill")})}).on("mouseout",function(a){r.elementMouseout({value:a.value,label:a.label||"Previous",color:d3.select(this).style("fill")})}),D.selectAll(".nv-range").on("mouseover",function(a,b){var c=w[b]||(b?1==b?"Mean":"Minimum":"Maximum");r.elementMouseover({value:a,label:c,color:d3.select(this).style("fill")})}).on("mousemove",function(){r.elementMousemove({value:v[0],label:y[0]||"Previous",color:d3.select(this).style("fill")})}).on("mouseout",function(a,b){var c=w[b]||(b?1==b?"Mean":"Minimum":"Maximum");r.elementMouseout({value:a,label:c,color:d3.select(this).style("fill")})})}),b}var c={top:0,right:0,bottom:0,left:0},d="left",e=!1,f=function(a){return a.ranges},g=function(a){return a.markers?a.markers:[0]},h=function(a){return a.measures},i=function(a){return a.rangeLabels?a.rangeLabels:[]},j=function(a){return a.markerLabels?a.markerLabels:[]},k=function(a){return a.measureLabels?a.measureLabels:[]},l=[0],m=380,n=30,o=null,p=null,q=a.utils.getColor(["#1f77b4"]),r=d3.dispatch("elementMouseover","elementMouseout","elementMousemove");return b.dispatch=r,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{ranges:{get:function(){return f},set:function(a){f=a}},markers:{get:function(){return g},set:function(a){g=a}},measures:{get:function(){return h},set:function(a){h=a}},forceX:{get:function(){return l},set:function(a){l=a}},width:{get:function(){return m},set:function(a){m=a}},height:{get:function(){return n},set:function(a){n=a}},tickFormat:{get:function(){return p},set:function(a){p=a}},margin:{get:function(){return c},set:function(a){c.top=void 0!==a.top?a.top:c.top,c.right=void 0!==a.right?a.right:c.right,c.bottom=void 0!==a.bottom?a.bottom:c.bottom,c.left=void 0!==a.left?a.left:c.left}},orient:{get:function(){return d},set:function(a){d=a,e="right"==d||"bottom"==d}},color:{get:function(){return q},set:function(b){q=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.bulletChart=function(){"use strict";function b(d){return d.each(function(e,o){var p=d3.select(this);a.utils.initSVG(p);var q=a.utils.availableWidth(k,p,g),r=l-g.top-g.bottom;if(b.update=function(){b(d)},b.container=this,!e||!h.call(this,e,o))return a.utils.noData(b,p),b;p.selectAll(".nv-noData").remove();var s=h.call(this,e,o).slice().sort(d3.descending),t=i.call(this,e,o).slice().sort(d3.descending),u=j.call(this,e,o).slice().sort(d3.descending),v=p.selectAll("g.nv-wrap.nv-bulletChart").data([e]),w=v.enter().append("g").attr("class","nvd3 nv-wrap nv-bulletChart"),x=w.append("g"),y=v.select("g");x.append("g").attr("class","nv-bulletWrap"),x.append("g").attr("class","nv-titles"),v.attr("transform","translate("+g.left+","+g.top+")");var z=d3.scale.linear().domain([0,Math.max(s[0],t[0],u[0])]).range(f?[q,0]:[0,q]),A=this.__chart__||d3.scale.linear().domain([0,1/0]).range(z.range());this.__chart__=z;var B=x.select(".nv-titles").append("g").attr("text-anchor","end").attr("transform","translate(-6,"+(l-g.top-g.bottom)/2+")");B.append("text").attr("class","nv-title").text(function(a){return a.title}),B.append("text").attr("class","nv-subtitle").attr("dy","1em").text(function(a){return a.subtitle}),c.width(q).height(r);var C=y.select(".nv-bulletWrap");d3.transition(C).call(c);var D=m||z.tickFormat(q/100),E=y.selectAll("g.nv-tick").data(z.ticks(n?n:q/50),function(a){return this.textContent||D(a)}),F=E.enter().append("g").attr("class","nv-tick").attr("transform",function(a){return"translate("+A(a)+",0)"}).style("opacity",1e-6);F.append("line").attr("y1",r).attr("y2",7*r/6),F.append("text").attr("text-anchor","middle").attr("dy","1em").attr("y",7*r/6).text(D);var G=d3.transition(E).attr("transform",function(a){return"translate("+z(a)+",0)"}).style("opacity",1);G.select("line").attr("y1",r).attr("y2",7*r/6),G.select("text").attr("y",7*r/6),d3.transition(E.exit()).attr("transform",function(a){return"translate("+z(a)+",0)"}).style("opacity",1e-6).remove()}),d3.timer.flush(),b}var c=a.models.bullet(),d=a.models.tooltip(),e="left",f=!1,g={top:5,right:40,bottom:20,left:120},h=function(a){return a.ranges},i=function(a){return a.markers?a.markers:[0]},j=function(a){return a.measures},k=null,l=55,m=null,n=null,o=null,p=d3.dispatch("tooltipShow","tooltipHide");return d.duration(0).headerEnabled(!1),c.dispatch.on("elementMouseover.tooltip",function(a){a.series={key:a.label,value:a.value,color:a.color},d.data(a).hidden(!1)}),c.dispatch.on("elementMouseout.tooltip",function(){d.hidden(!0)}),c.dispatch.on("elementMousemove.tooltip",function(){d.position({top:d3.event.pageY,left:d3.event.pageX})()}),b.bullet=c,b.dispatch=p,b.tooltip=d,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{ranges:{get:function(){return h},set:function(a){h=a}},markers:{get:function(){return i},set:function(a){i=a}},measures:{get:function(){return j},set:function(a){j=a}},width:{get:function(){return k},set:function(a){k=a}},height:{get:function(){return l},set:function(a){l=a}},tickFormat:{get:function(){return m},set:function(a){m=a}},ticks:{get:function(){return n},set:function(a){n=a}},noData:{get:function(){return o},set:function(a){o=a}},tooltips:{get:function(){return d.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),d.enabled(!!b)}},tooltipContent:{get:function(){return d.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),d.contentGenerator(b)}},margin:{get:function(){return g},set:function(a){g.top=void 0!==a.top?a.top:g.top,g.right=void 0!==a.right?a.right:g.right,g.bottom=void 0!==a.bottom?a.bottom:g.bottom,g.left=void 0!==a.left?a.left:g.left}},orient:{get:function(){return e},set:function(a){e=a,f="right"==e||"bottom"==e}}}),a.utils.inheritOptions(b,c),a.utils.initOptions(b),b},a.models.candlestickBar=function(){"use strict";function b(x){return x.each(function(b){c=d3.select(this);var x=a.utils.availableWidth(i,c,h),y=a.utils.availableHeight(j,c,h);a.utils.initSVG(c);var A=x/b[0].values.length*.45;l.domain(d||d3.extent(b[0].values.map(n).concat(t))),l.range(v?f||[.5*x/b[0].values.length,x*(b[0].values.length-.5)/b[0].values.length]:f||[5+A/2,x-A/2-5]),m.domain(e||[d3.min(b[0].values.map(s).concat(u)),d3.max(b[0].values.map(r).concat(u))]).range(g||[y,0]),l.domain()[0]===l.domain()[1]&&l.domain(l.domain()[0]?[l.domain()[0]-.01*l.domain()[0],l.domain()[1]+.01*l.domain()[1]]:[-1,1]),m.domain()[0]===m.domain()[1]&&m.domain(m.domain()[0]?[m.domain()[0]+.01*m.domain()[0],m.domain()[1]-.01*m.domain()[1]]:[-1,1]);var B=d3.select(this).selectAll("g.nv-wrap.nv-candlestickBar").data([b[0].values]),C=B.enter().append("g").attr("class","nvd3 nv-wrap nv-candlestickBar"),D=C.append("defs"),E=C.append("g"),F=B.select("g");E.append("g").attr("class","nv-ticks"),B.attr("transform","translate("+h.left+","+h.top+")"),c.on("click",function(a,b){z.chartClick({data:a,index:b,pos:d3.event,id:k})}),D.append("clipPath").attr("id","nv-chart-clip-path-"+k).append("rect"),B.select("#nv-chart-clip-path-"+k+" rect").attr("width",x).attr("height",y),F.attr("clip-path",w?"url(#nv-chart-clip-path-"+k+")":"");var G=B.select(".nv-ticks").selectAll(".nv-tick").data(function(a){return a});G.exit().remove();{var H=G.enter().append("g").attr("class",function(a,b,c){return(p(a,b)>q(a,b)?"nv-tick negative":"nv-tick positive")+" nv-tick-"+c+"-"+b});H.append("line").attr("class","nv-candlestick-lines").attr("transform",function(a,b){return"translate("+l(n(a,b))+",0)"}).attr("x1",0).attr("y1",function(a,b){return m(r(a,b))}).attr("x2",0).attr("y2",function(a,b){return m(s(a,b))}),H.append("rect").attr("class","nv-candlestick-rects nv-bars").attr("transform",function(a,b){return"translate("+(l(n(a,b))-A/2)+","+(m(o(a,b))-(p(a,b)>q(a,b)?m(q(a,b))-m(p(a,b)):0))+")"}).attr("x",0).attr("y",0).attr("width",A).attr("height",function(a,b){var c=p(a,b),d=q(a,b);return c>d?m(d)-m(c):m(c)-m(d)})}c.selectAll(".nv-candlestick-lines").transition().attr("transform",function(a,b){return"translate("+l(n(a,b))+",0)"}).attr("x1",0).attr("y1",function(a,b){return m(r(a,b))}).attr("x2",0).attr("y2",function(a,b){return m(s(a,b))}),c.selectAll(".nv-candlestick-rects").transition().attr("transform",function(a,b){return"translate("+(l(n(a,b))-A/2)+","+(m(o(a,b))-(p(a,b)>q(a,b)?m(q(a,b))-m(p(a,b)):0))+")"}).attr("x",0).attr("y",0).attr("width",A).attr("height",function(a,b){var c=p(a,b),d=q(a,b);return c>d?m(d)-m(c):m(c)-m(d)})}),b}var c,d,e,f,g,h={top:0,right:0,bottom:0,left:0},i=null,j=null,k=Math.floor(1e4*Math.random()),l=d3.scale.linear(),m=d3.scale.linear(),n=function(a){return a.x},o=function(a){return a.y},p=function(a){return a.open},q=function(a){return a.close},r=function(a){return a.high},s=function(a){return a.low},t=[],u=[],v=!1,w=!0,x=a.utils.defaultColor(),y=!1,z=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd","chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove");return b.highlightPoint=function(a,d){b.clearHighlights(),c.select(".nv-candlestickBar .nv-tick-0-"+a).classed("hover",d)},b.clearHighlights=function(){c.select(".nv-candlestickBar .nv-tick.hover").classed("hover",!1)},b.dispatch=z,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return i},set:function(a){i=a}},height:{get:function(){return j},set:function(a){j=a}},xScale:{get:function(){return l},set:function(a){l=a}},yScale:{get:function(){return m},set:function(a){m=a}},xDomain:{get:function(){return d},set:function(a){d=a}},yDomain:{get:function(){return e},set:function(a){e=a}},xRange:{get:function(){return f},set:function(a){f=a}},yRange:{get:function(){return g},set:function(a){g=a}},forceX:{get:function(){return t},set:function(a){t=a}},forceY:{get:function(){return u},set:function(a){u=a}},padData:{get:function(){return v},set:function(a){v=a}},clipEdge:{get:function(){return w},set:function(a){w=a}},id:{get:function(){return k},set:function(a){k=a}},interactive:{get:function(){return y},set:function(a){y=a}},x:{get:function(){return n},set:function(a){n=a}},y:{get:function(){return o},set:function(a){o=a}},open:{get:function(){return p()},set:function(a){p=a}},close:{get:function(){return q()},set:function(a){q=a}},high:{get:function(){return r},set:function(a){r=a}},low:{get:function(){return s},set:function(a){s=a}},margin:{get:function(){return h},set:function(a){h.top=void 0!=a.top?a.top:h.top,h.right=void 0!=a.right?a.right:h.right,h.bottom=void 0!=a.bottom?a.bottom:h.bottom,h.left=void 0!=a.left?a.left:h.left}},color:{get:function(){return x},set:function(b){x=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.cumulativeLineChart=function(){"use strict";function b(l){return H.reset(),H.models(f),r&&H.models(g),s&&H.models(h),l.each(function(l){function A(){d3.select(b.container).style("cursor","ew-resize")}function E(){G.x=d3.event.x,G.i=Math.round(F.invert(G.x)),K()}function H(){d3.select(b.container).style("cursor","auto"),y.index=G.i,C.stateChange(y)}function K(){bb.data([G]);var a=b.duration();b.duration(0),b.update(),b.duration(a)}var L=d3.select(this);a.utils.initSVG(L),L.classed("nv-chart-"+x,!0);var M=this,N=a.utils.availableWidth(o,L,m),O=a.utils.availableHeight(p,L,m);if(b.update=function(){0===D?L.call(b):L.transition().duration(D).call(b)},b.container=this,y.setter(J(l),b.update).getter(I(l)).update(),y.disabled=l.map(function(a){return!!a.disabled}),!z){var P;z={};for(P in y)z[P]=y[P]instanceof Array?y[P].slice(0):y[P]}var Q=d3.behavior.drag().on("dragstart",A).on("drag",E).on("dragend",H);if(!(l&&l.length&&l.filter(function(a){return a.values.length}).length))return a.utils.noData(b,L),b;if(L.selectAll(".nv-noData").remove(),d=f.xScale(),e=f.yScale(),w)f.yDomain(null);else{var R=l.filter(function(a){return!a.disabled}).map(function(a){var b=d3.extent(a.values,f.y());return b[0]<-.95&&(b[0]=-.95),[(b[0]-b[1])/(1+b[1]),(b[1]-b[0])/(1+b[0])]}),S=[d3.min(R,function(a){return a[0]}),d3.max(R,function(a){return a[1]})];f.yDomain(S)}F.domain([0,l[0].values.length-1]).range([0,N]).clamp(!0);var l=c(G.i,l),T=v?"none":"all",U=L.selectAll("g.nv-wrap.nv-cumulativeLine").data([l]),V=U.enter().append("g").attr("class","nvd3 nv-wrap nv-cumulativeLine").append("g"),W=U.select("g");if(V.append("g").attr("class","nv-interactive"),V.append("g").attr("class","nv-x nv-axis").style("pointer-events","none"),V.append("g").attr("class","nv-y nv-axis"),V.append("g").attr("class","nv-background"),V.append("g").attr("class","nv-linesWrap").style("pointer-events",T),V.append("g").attr("class","nv-avgLinesWrap").style("pointer-events","none"),V.append("g").attr("class","nv-legendWrap"),V.append("g").attr("class","nv-controlsWrap"),q&&(i.width(N),W.select(".nv-legendWrap").datum(l).call(i),m.top!=i.height()&&(m.top=i.height(),O=a.utils.availableHeight(p,L,m)),W.select(".nv-legendWrap").attr("transform","translate(0,"+-m.top+")")),u){var X=[{key:"Re-scale y-axis",disabled:!w}];j.width(140).color(["#444","#444","#444"]).rightAlign(!1).margin({top:5,right:0,bottom:5,left:20}),W.select(".nv-controlsWrap").datum(X).attr("transform","translate(0,"+-m.top+")").call(j)}U.attr("transform","translate("+m.left+","+m.top+")"),t&&W.select(".nv-y.nv-axis").attr("transform","translate("+N+",0)");var Y=l.filter(function(a){return a.tempDisabled});U.select(".tempDisabled").remove(),Y.length&&U.append("text").attr("class","tempDisabled").attr("x",N/2).attr("y","-.71em").style("text-anchor","end").text(Y.map(function(a){return a.key}).join(", ")+" values cannot be calculated for this time period."),v&&(k.width(N).height(O).margin({left:m.left,top:m.top}).svgContainer(L).xScale(d),U.select(".nv-interactive").call(k)),V.select(".nv-background").append("rect"),W.select(".nv-background rect").attr("width",N).attr("height",O),f.y(function(a){return a.display.y}).width(N).height(O).color(l.map(function(a,b){return a.color||n(a,b)}).filter(function(a,b){return!l[b].disabled&&!l[b].tempDisabled}));var Z=W.select(".nv-linesWrap").datum(l.filter(function(a){return!a.disabled&&!a.tempDisabled}));Z.call(f),l.forEach(function(a,b){a.seriesIndex=b});var $=l.filter(function(a){return!a.disabled&&!!B(a)}),_=W.select(".nv-avgLinesWrap").selectAll("line").data($,function(a){return a.key}),ab=function(a){var b=e(B(a));return 0>b?0:b>O?O:b};_.enter().append("line").style("stroke-width",2).style("stroke-dasharray","10,10").style("stroke",function(a){return f.color()(a,a.seriesIndex)}).attr("x1",0).attr("x2",N).attr("y1",ab).attr("y2",ab),_.style("stroke-opacity",function(a){var b=e(B(a));return 0>b||b>O?0:1}).attr("x1",0).attr("x2",N).attr("y1",ab).attr("y2",ab),_.exit().remove();var bb=Z.selectAll(".nv-indexLine").data([G]);bb.enter().append("rect").attr("class","nv-indexLine").attr("width",3).attr("x",-2).attr("fill","red").attr("fill-opacity",.5).style("pointer-events","all").call(Q),bb.attr("transform",function(a){return"translate("+F(a.i)+",0)"}).attr("height",O),r&&(g.scale(d)._ticks(a.utils.calcTicksX(N/70,l)).tickSize(-O,0),W.select(".nv-x.nv-axis").attr("transform","translate(0,"+e.range()[0]+")"),W.select(".nv-x.nv-axis").call(g)),s&&(h.scale(e)._ticks(a.utils.calcTicksY(O/36,l)).tickSize(-N,0),W.select(".nv-y.nv-axis").call(h)),W.select(".nv-background rect").on("click",function(){G.x=d3.mouse(this)[0],G.i=Math.round(F.invert(G.x)),y.index=G.i,C.stateChange(y),K()}),f.dispatch.on("elementClick",function(a){G.i=a.pointIndex,G.x=F(G.i),y.index=G.i,C.stateChange(y),K()}),j.dispatch.on("legendClick",function(a){a.disabled=!a.disabled,w=!a.disabled,y.rescaleY=w,C.stateChange(y),b.update()}),i.dispatch.on("stateChange",function(a){for(var c in a)y[c]=a[c];C.stateChange(y),b.update()}),k.dispatch.on("elementMousemove",function(c){f.clearHighlights();var d,e,i,j=[];if(l.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(g,h){e=a.interactiveBisect(g.values,c.pointXValue,b.x()),f.highlightPoint(h,e,!0);var k=g.values[e];"undefined"!=typeof k&&("undefined"==typeof d&&(d=k),"undefined"==typeof i&&(i=b.xScale()(b.x()(k,e))),j.push({key:g.key,value:b.y()(k,e),color:n(g,g.seriesIndex)}))}),j.length>2){var o=b.yScale().invert(c.mouseY),p=Math.abs(b.yScale().domain()[0]-b.yScale().domain()[1]),q=.03*p,r=a.nearestValueIndex(j.map(function(a){return a.value}),o,q);null!==r&&(j[r].highlight=!0)}var s=g.tickFormat()(b.x()(d,e),e);k.tooltip.position({left:i+m.left,top:c.mouseY+m.top}).chartContainer(M.parentNode).valueFormatter(function(a){return h.tickFormat()(a)}).data({value:s,series:j})(),k.renderGuideLine(i)}),k.dispatch.on("elementMouseout",function(){f.clearHighlights()}),C.on("changeState",function(a){"undefined"!=typeof a.disabled&&(l.forEach(function(b,c){b.disabled=a.disabled[c]}),y.disabled=a.disabled),"undefined"!=typeof a.index&&(G.i=a.index,G.x=F(G.i),y.index=a.index,bb.data([G])),"undefined"!=typeof a.rescaleY&&(w=a.rescaleY),b.update()})}),H.renderEnd("cumulativeLineChart immediate"),b}function c(a,b){return K||(K=f.y()),b.map(function(b){if(!b.values)return b;var c=b.values[a];if(null==c)return b;var d=K(c,a);return-.95>d&&!E?(b.tempDisabled=!0,b):(b.tempDisabled=!1,b.values=b.values.map(function(a,b){return a.display={y:(K(a,b)-d)/(1+d)},a}),b)})}var d,e,f=a.models.line(),g=a.models.axis(),h=a.models.axis(),i=a.models.legend(),j=a.models.legend(),k=a.interactiveGuideline(),l=a.models.tooltip(),m={top:30,right:30,bottom:50,left:60},n=a.utils.defaultColor(),o=null,p=null,q=!0,r=!0,s=!0,t=!1,u=!0,v=!1,w=!0,x=f.id(),y=a.utils.state(),z=null,A=null,B=function(a){return a.average},C=d3.dispatch("stateChange","changeState","renderEnd"),D=250,E=!1;y.index=0,y.rescaleY=w,g.orient("bottom").tickPadding(7),h.orient(t?"right":"left"),l.valueFormatter(function(a,b){return h.tickFormat()(a,b)}).headerFormatter(function(a,b){return g.tickFormat()(a,b)}),j.updateState(!1);var F=d3.scale.linear(),G={i:0,x:0},H=a.utils.renderWatch(C,D),I=function(a){return function(){return{active:a.map(function(a){return!a.disabled}),index:G.i,rescaleY:w}}},J=function(a){return function(b){void 0!==b.index&&(G.i=b.index),void 0!==b.rescaleY&&(w=b.rescaleY),void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};f.dispatch.on("elementMouseover.tooltip",function(a){var c={x:b.x()(a.point),y:b.y()(a.point),color:a.point.color};a.point=c,l.data(a).position(a.pos).hidden(!1)}),f.dispatch.on("elementMouseout.tooltip",function(){l.hidden(!0)});var K=null;return b.dispatch=C,b.lines=f,b.legend=i,b.controls=j,b.xAxis=g,b.yAxis=h,b.interactiveLayer=k,b.state=y,b.tooltip=l,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return o},set:function(a){o=a}},height:{get:function(){return p},set:function(a){p=a}},rescaleY:{get:function(){return w},set:function(a){w=a}},showControls:{get:function(){return u},set:function(a){u=a}},showLegend:{get:function(){return q},set:function(a){q=a}},average:{get:function(){return B},set:function(a){B=a}},defaultState:{get:function(){return z},set:function(a){z=a}},noData:{get:function(){return A},set:function(a){A=a}},showXAxis:{get:function(){return r},set:function(a){r=a}},showYAxis:{get:function(){return s},set:function(a){s=a}},noErrorCheck:{get:function(){return E},set:function(a){E=a}},tooltips:{get:function(){return l.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),l.enabled(!!b)}},tooltipContent:{get:function(){return l.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),l.contentGenerator(b)}},margin:{get:function(){return m},set:function(a){m.top=void 0!==a.top?a.top:m.top,m.right=void 0!==a.right?a.right:m.right,m.bottom=void 0!==a.bottom?a.bottom:m.bottom,m.left=void 0!==a.left?a.left:m.left}},color:{get:function(){return n},set:function(b){n=a.utils.getColor(b),i.color(n)}},useInteractiveGuideline:{get:function(){return v},set:function(a){v=a,a===!0&&(b.interactive(!1),b.useVoronoi(!1))}},rightAlignYAxis:{get:function(){return t},set:function(a){t=a,h.orient(a?"right":"left")}},duration:{get:function(){return D},set:function(a){D=a,f.duration(D),g.duration(D),h.duration(D),H.reset(D)}}}),a.utils.inheritOptions(b,f),a.utils.initOptions(b),b},a.models.discreteBar=function(){"use strict";function b(m){return y.reset(),m.each(function(b){var m=k-j.left-j.right,x=l-j.top-j.bottom;c=d3.select(this),a.utils.initSVG(c),b.forEach(function(a,b){a.values.forEach(function(a){a.series=b})});var z=d&&e?[]:b.map(function(a){return a.values.map(function(a,b){return{x:p(a,b),y:q(a,b),y0:a.y0}})});n.domain(d||d3.merge(z).map(function(a){return a.x})).rangeBands(f||[0,m],.1),o.domain(e||d3.extent(d3.merge(z).map(function(a){return a.y}).concat(r))),o.range(t?g||[x-(o.domain()[0]<0?12:0),o.domain()[1]>0?12:0]:g||[x,0]),h=h||n,i=i||o.copy().range([o(0),o(0)]);{var A=c.selectAll("g.nv-wrap.nv-discretebar").data([b]),B=A.enter().append("g").attr("class","nvd3 nv-wrap nv-discretebar"),C=B.append("g");A.select("g")}C.append("g").attr("class","nv-groups"),A.attr("transform","translate("+j.left+","+j.top+")");var D=A.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a){return a.key});D.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6),D.exit().watchTransition(y,"discreteBar: exit groups").style("stroke-opacity",1e-6).style("fill-opacity",1e-6).remove(),D.attr("class",function(a,b){return"nv-group nv-series-"+b}).classed("hover",function(a){return a.hover}),D.watchTransition(y,"discreteBar: groups").style("stroke-opacity",1).style("fill-opacity",.75);var E=D.selectAll("g.nv-bar").data(function(a){return a.values});E.exit().remove();var F=E.enter().append("g").attr("transform",function(a,b){return"translate("+(n(p(a,b))+.05*n.rangeBand())+", "+o(0)+")"}).on("mouseover",function(a,b){d3.select(this).classed("hover",!0),v.elementMouseover({data:a,index:b,color:d3.select(this).style("fill")})}).on("mouseout",function(a,b){d3.select(this).classed("hover",!1),v.elementMouseout({data:a,index:b,color:d3.select(this).style("fill")})}).on("mousemove",function(a,b){v.elementMousemove({data:a,index:b,color:d3.select(this).style("fill")})}).on("click",function(a,b){v.elementClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation()}).on("dblclick",function(a,b){v.elementDblClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation()});F.append("rect").attr("height",0).attr("width",.9*n.rangeBand()/b.length),t?(F.append("text").attr("text-anchor","middle"),E.select("text").text(function(a,b){return u(q(a,b))}).watchTransition(y,"discreteBar: bars text").attr("x",.9*n.rangeBand()/2).attr("y",function(a,b){return q(a,b)<0?o(q(a,b))-o(0)+12:-4})):E.selectAll("text").remove(),E.attr("class",function(a,b){return q(a,b)<0?"nv-bar negative":"nv-bar positive"}).style("fill",function(a,b){return a.color||s(a,b)}).style("stroke",function(a,b){return a.color||s(a,b)}).select("rect").attr("class",w).watchTransition(y,"discreteBar: bars rect").attr("width",.9*n.rangeBand()/b.length),E.watchTransition(y,"discreteBar: bars").attr("transform",function(a,b){var c=n(p(a,b))+.05*n.rangeBand(),d=q(a,b)<0?o(0):o(0)-o(q(a,b))<1?o(0)-1:o(q(a,b));return"translate("+c+", "+d+")"}).select("rect").attr("height",function(a,b){return Math.max(Math.abs(o(q(a,b))-o(e&&e[0]||0))||1)}),h=n.copy(),i=o.copy()}),y.renderEnd("discreteBar immediate"),b}var c,d,e,f,g,h,i,j={top:0,right:0,bottom:0,left:0},k=960,l=500,m=Math.floor(1e4*Math.random()),n=d3.scale.ordinal(),o=d3.scale.linear(),p=function(a){return a.x},q=function(a){return a.y},r=[0],s=a.utils.defaultColor(),t=!1,u=d3.format(",.2f"),v=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove","renderEnd"),w="discreteBar",x=250,y=a.utils.renderWatch(v,x);return b.dispatch=v,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return k},set:function(a){k=a}},height:{get:function(){return l},set:function(a){l=a}},forceY:{get:function(){return r},set:function(a){r=a}},showValues:{get:function(){return t},set:function(a){t=a}},x:{get:function(){return p},set:function(a){p=a}},y:{get:function(){return q},set:function(a){q=a}},xScale:{get:function(){return n},set:function(a){n=a}},yScale:{get:function(){return o},set:function(a){o=a}},xDomain:{get:function(){return d},set:function(a){d=a}},yDomain:{get:function(){return e},set:function(a){e=a}},xRange:{get:function(){return f},set:function(a){f=a}},yRange:{get:function(){return g},set:function(a){g=a}},valueFormat:{get:function(){return u},set:function(a){u=a}},id:{get:function(){return m},set:function(a){m=a}},rectClass:{get:function(){return w},set:function(a){w=a}},margin:{get:function(){return j},set:function(a){j.top=void 0!==a.top?a.top:j.top,j.right=void 0!==a.right?a.right:j.right,j.bottom=void 0!==a.bottom?a.bottom:j.bottom,j.left=void 0!==a.left?a.left:j.left}},color:{get:function(){return s},set:function(b){s=a.utils.getColor(b)}},duration:{get:function(){return x},set:function(a){x=a,y.reset(x)}}}),a.utils.initOptions(b),b},a.models.discreteBarChart=function(){"use strict";function b(h){return t.reset(),t.models(e),m&&t.models(f),n&&t.models(g),h.each(function(h){var l=d3.select(this);a.utils.initSVG(l);var q=a.utils.availableWidth(j,l,i),t=a.utils.availableHeight(k,l,i);if(b.update=function(){r.beforeUpdate(),l.transition().duration(s).call(b)},b.container=this,!(h&&h.length&&h.filter(function(a){return a.values.length}).length))return a.utils.noData(b,l),b;l.selectAll(".nv-noData").remove(),c=e.xScale(),d=e.yScale().clamp(!0);var u=l.selectAll("g.nv-wrap.nv-discreteBarWithAxes").data([h]),v=u.enter().append("g").attr("class","nvd3 nv-wrap nv-discreteBarWithAxes").append("g"),w=v.append("defs"),x=u.select("g");v.append("g").attr("class","nv-x nv-axis"),v.append("g").attr("class","nv-y nv-axis").append("g").attr("class","nv-zeroLine").append("line"),v.append("g").attr("class","nv-barsWrap"),x.attr("transform","translate("+i.left+","+i.top+")"),o&&x.select(".nv-y.nv-axis").attr("transform","translate("+q+",0)"),e.width(q).height(t);var y=x.select(".nv-barsWrap").datum(h.filter(function(a){return!a.disabled}));if(y.transition().call(e),w.append("clipPath").attr("id","nv-x-label-clip-"+e.id()).append("rect"),x.select("#nv-x-label-clip-"+e.id()+" rect").attr("width",c.rangeBand()*(p?2:1)).attr("height",16).attr("x",-c.rangeBand()/(p?1:2)),m){f.scale(c)._ticks(a.utils.calcTicksX(q/100,h)).tickSize(-t,0),x.select(".nv-x.nv-axis").attr("transform","translate(0,"+(d.range()[0]+(e.showValues()&&d.domain()[0]<0?16:0))+")"),x.select(".nv-x.nv-axis").call(f);
var z=x.select(".nv-x.nv-axis").selectAll("g");p&&z.selectAll("text").attr("transform",function(a,b,c){return"translate(0,"+(c%2==0?"5":"17")+")"})}n&&(g.scale(d)._ticks(a.utils.calcTicksY(t/36,h)).tickSize(-q,0),x.select(".nv-y.nv-axis").call(g)),x.select(".nv-zeroLine line").attr("x1",0).attr("x2",q).attr("y1",d(0)).attr("y2",d(0))}),t.renderEnd("discreteBar chart immediate"),b}var c,d,e=a.models.discreteBar(),f=a.models.axis(),g=a.models.axis(),h=a.models.tooltip(),i={top:15,right:10,bottom:50,left:60},j=null,k=null,l=a.utils.getColor(),m=!0,n=!0,o=!1,p=!1,q=null,r=d3.dispatch("beforeUpdate","renderEnd"),s=250;f.orient("bottom").showMaxMin(!1).tickFormat(function(a){return a}),g.orient(o?"right":"left").tickFormat(d3.format(",.1f")),h.duration(0).headerEnabled(!1).valueFormatter(function(a,b){return g.tickFormat()(a,b)}).keyFormatter(function(a,b){return f.tickFormat()(a,b)});var t=a.utils.renderWatch(r,s);return e.dispatch.on("elementMouseover.tooltip",function(a){a.series={key:b.x()(a.data),value:b.y()(a.data),color:a.color},h.data(a).hidden(!1)}),e.dispatch.on("elementMouseout.tooltip",function(){h.hidden(!0)}),e.dispatch.on("elementMousemove.tooltip",function(){h.position({top:d3.event.pageY,left:d3.event.pageX})()}),b.dispatch=r,b.discretebar=e,b.xAxis=f,b.yAxis=g,b.tooltip=h,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return j},set:function(a){j=a}},height:{get:function(){return k},set:function(a){k=a}},staggerLabels:{get:function(){return p},set:function(a){p=a}},showXAxis:{get:function(){return m},set:function(a){m=a}},showYAxis:{get:function(){return n},set:function(a){n=a}},noData:{get:function(){return q},set:function(a){q=a}},tooltips:{get:function(){return h.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),h.enabled(!!b)}},tooltipContent:{get:function(){return h.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),h.contentGenerator(b)}},margin:{get:function(){return i},set:function(a){i.top=void 0!==a.top?a.top:i.top,i.right=void 0!==a.right?a.right:i.right,i.bottom=void 0!==a.bottom?a.bottom:i.bottom,i.left=void 0!==a.left?a.left:i.left}},duration:{get:function(){return s},set:function(a){s=a,t.reset(s),e.duration(s),f.duration(s),g.duration(s)}},color:{get:function(){return l},set:function(b){l=a.utils.getColor(b),e.color(l)}},rightAlignYAxis:{get:function(){return o},set:function(a){o=a,g.orient(a?"right":"left")}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.distribution=function(){"use strict";function b(k){return m.reset(),k.each(function(b){var k=(e-("x"===g?d.left+d.right:d.top+d.bottom),"x"==g?"y":"x"),l=d3.select(this);a.utils.initSVG(l),c=c||j;var n=l.selectAll("g.nv-distribution").data([b]),o=n.enter().append("g").attr("class","nvd3 nv-distribution"),p=(o.append("g"),n.select("g"));n.attr("transform","translate("+d.left+","+d.top+")");var q=p.selectAll("g.nv-dist").data(function(a){return a},function(a){return a.key});q.enter().append("g"),q.attr("class",function(a,b){return"nv-dist nv-series-"+b}).style("stroke",function(a,b){return i(a,b)});var r=q.selectAll("line.nv-dist"+g).data(function(a){return a.values});r.enter().append("line").attr(g+"1",function(a,b){return c(h(a,b))}).attr(g+"2",function(a,b){return c(h(a,b))}),m.transition(q.exit().selectAll("line.nv-dist"+g),"dist exit").attr(g+"1",function(a,b){return j(h(a,b))}).attr(g+"2",function(a,b){return j(h(a,b))}).style("stroke-opacity",0).remove(),r.attr("class",function(a,b){return"nv-dist"+g+" nv-dist"+g+"-"+b}).attr(k+"1",0).attr(k+"2",f),m.transition(r,"dist").attr(g+"1",function(a,b){return j(h(a,b))}).attr(g+"2",function(a,b){return j(h(a,b))}),c=j.copy()}),m.renderEnd("distribution immediate"),b}var c,d={top:0,right:0,bottom:0,left:0},e=400,f=8,g="x",h=function(a){return a[g]},i=a.utils.defaultColor(),j=d3.scale.linear(),k=250,l=d3.dispatch("renderEnd"),m=a.utils.renderWatch(l,k);return b.options=a.utils.optionsFunc.bind(b),b.dispatch=l,b.margin=function(a){return arguments.length?(d.top="undefined"!=typeof a.top?a.top:d.top,d.right="undefined"!=typeof a.right?a.right:d.right,d.bottom="undefined"!=typeof a.bottom?a.bottom:d.bottom,d.left="undefined"!=typeof a.left?a.left:d.left,b):d},b.width=function(a){return arguments.length?(e=a,b):e},b.axis=function(a){return arguments.length?(g=a,b):g},b.size=function(a){return arguments.length?(f=a,b):f},b.getData=function(a){return arguments.length?(h=d3.functor(a),b):h},b.scale=function(a){return arguments.length?(j=a,b):j},b.color=function(c){return arguments.length?(i=a.utils.getColor(c),b):i},b.duration=function(a){return arguments.length?(k=a,m.reset(k),b):k},b},a.models.furiousLegend=function(){"use strict";function b(p){function q(a,b){return"furious"!=o?"#000":m?a.disengaged?g(a,b):"#fff":m?void 0:a.disabled?g(a,b):"#fff"}function r(a,b){return m&&"furious"==o?a.disengaged?"#fff":g(a,b):a.disabled?"#fff":g(a,b)}return p.each(function(b){var p=d-c.left-c.right,s=d3.select(this);a.utils.initSVG(s);var t=s.selectAll("g.nv-legend").data([b]),u=(t.enter().append("g").attr("class","nvd3 nv-legend").append("g"),t.select("g"));t.attr("transform","translate("+c.left+","+c.top+")");var v,w=u.selectAll(".nv-series").data(function(a){return"furious"!=o?a:a.filter(function(a){return m?!0:!a.disengaged})}),x=w.enter().append("g").attr("class","nv-series");if("classic"==o)x.append("circle").style("stroke-width",2).attr("class","nv-legend-symbol").attr("r",5),v=w.select("circle");else if("furious"==o){x.append("rect").style("stroke-width",2).attr("class","nv-legend-symbol").attr("rx",3).attr("ry",3),v=w.select("rect"),x.append("g").attr("class","nv-check-box").property("innerHTML",'<path d="M0.5,5 L22.5,5 L22.5,26.5 L0.5,26.5 L0.5,5 Z" class="nv-box"></path><path d="M5.5,12.8618467 L11.9185089,19.2803556 L31,0.198864511" class="nv-check"></path>').attr("transform","translate(-10,-8)scale(0.5)");var y=w.select(".nv-check-box");y.each(function(a,b){d3.select(this).selectAll("path").attr("stroke",q(a,b))})}x.append("text").attr("text-anchor","start").attr("class","nv-legend-text").attr("dy",".32em").attr("dx","8");var z=w.select("text.nv-legend-text");w.on("mouseover",function(a,b){n.legendMouseover(a,b)}).on("mouseout",function(a,b){n.legendMouseout(a,b)}).on("click",function(a,b){n.legendClick(a,b);var c=w.data();if(k){if("classic"==o)l?(c.forEach(function(a){a.disabled=!0}),a.disabled=!1):(a.disabled=!a.disabled,c.every(function(a){return a.disabled})&&c.forEach(function(a){a.disabled=!1}));else if("furious"==o)if(m)a.disengaged=!a.disengaged,a.userDisabled=void 0==a.userDisabled?!!a.disabled:a.userDisabled,a.disabled=a.disengaged||a.userDisabled;else if(!m){a.disabled=!a.disabled,a.userDisabled=a.disabled;var d=c.filter(function(a){return!a.disengaged});d.every(function(a){return a.userDisabled})&&c.forEach(function(a){a.disabled=a.userDisabled=!1})}n.stateChange({disabled:c.map(function(a){return!!a.disabled}),disengaged:c.map(function(a){return!!a.disengaged})})}}).on("dblclick",function(a,b){if(("furious"!=o||!m)&&(n.legendDblclick(a,b),k)){var c=w.data();c.forEach(function(a){a.disabled=!0,"furious"==o&&(a.userDisabled=a.disabled)}),a.disabled=!1,"furious"==o&&(a.userDisabled=a.disabled),n.stateChange({disabled:c.map(function(a){return!!a.disabled})})}}),w.classed("nv-disabled",function(a){return a.userDisabled}),w.exit().remove(),z.attr("fill",q).text(f);var A;switch(o){case"furious":A=23;break;case"classic":A=20}if(h){var B=[];w.each(function(){var b,c=d3.select(this).select("text");try{if(b=c.node().getComputedTextLength(),0>=b)throw Error()}catch(d){b=a.utils.calcApproxTextWidth(c)}B.push(b+i)});for(var C=0,D=0,E=[];p>D&&C<B.length;)E[C]=B[C],D+=B[C++];for(0===C&&(C=1);D>p&&C>1;){E=[],C--;for(var F=0;F<B.length;F++)B[F]>(E[F%C]||0)&&(E[F%C]=B[F]);D=E.reduce(function(a,b){return a+b})}for(var G=[],H=0,I=0;C>H;H++)G[H]=I,I+=E[H];w.attr("transform",function(a,b){return"translate("+G[b%C]+","+(5+Math.floor(b/C)*A)+")"}),j?u.attr("transform","translate("+(d-c.right-D)+","+c.top+")"):u.attr("transform","translate(0,"+c.top+")"),e=c.top+c.bottom+Math.ceil(B.length/C)*A}else{var J,K=5,L=5,M=0;w.attr("transform",function(){var a=d3.select(this).select("text").node().getComputedTextLength()+i;return J=L,d<c.left+c.right+J+a&&(L=J=5,K+=A),L+=a,L>M&&(M=L),"translate("+J+","+K+")"}),u.attr("transform","translate("+(d-c.right-M)+","+c.top+")"),e=c.top+c.bottom+K+15}"furious"==o&&v.attr("width",function(a,b){return z[0][b].getComputedTextLength()+27}).attr("height",18).attr("y",-9).attr("x",-15),v.style("fill",r).style("stroke",function(a,b){return a.color||g(a,b)})}),b}var c={top:5,right:0,bottom:5,left:0},d=400,e=20,f=function(a){return a.key},g=a.utils.getColor(),h=!0,i=28,j=!0,k=!0,l=!1,m=!1,n=d3.dispatch("legendClick","legendDblclick","legendMouseover","legendMouseout","stateChange"),o="classic";return b.dispatch=n,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return d},set:function(a){d=a}},height:{get:function(){return e},set:function(a){e=a}},key:{get:function(){return f},set:function(a){f=a}},align:{get:function(){return h},set:function(a){h=a}},rightAlign:{get:function(){return j},set:function(a){j=a}},padding:{get:function(){return i},set:function(a){i=a}},updateState:{get:function(){return k},set:function(a){k=a}},radioButtonMode:{get:function(){return l},set:function(a){l=a}},expanded:{get:function(){return m},set:function(a){m=a}},vers:{get:function(){return o},set:function(a){o=a}},margin:{get:function(){return c},set:function(a){c.top=void 0!==a.top?a.top:c.top,c.right=void 0!==a.right?a.right:c.right,c.bottom=void 0!==a.bottom?a.bottom:c.bottom,c.left=void 0!==a.left?a.left:c.left}},color:{get:function(){return g},set:function(b){g=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.historicalBar=function(){"use strict";function b(x){return x.each(function(b){w.reset(),k=d3.select(this);var x=a.utils.availableWidth(h,k,g),y=a.utils.availableHeight(i,k,g);a.utils.initSVG(k),l.domain(c||d3.extent(b[0].values.map(n).concat(p))),l.range(r?e||[.5*x/b[0].values.length,x*(b[0].values.length-.5)/b[0].values.length]:e||[0,x]),m.domain(d||d3.extent(b[0].values.map(o).concat(q))).range(f||[y,0]),l.domain()[0]===l.domain()[1]&&l.domain(l.domain()[0]?[l.domain()[0]-.01*l.domain()[0],l.domain()[1]+.01*l.domain()[1]]:[-1,1]),m.domain()[0]===m.domain()[1]&&m.domain(m.domain()[0]?[m.domain()[0]+.01*m.domain()[0],m.domain()[1]-.01*m.domain()[1]]:[-1,1]);var z=k.selectAll("g.nv-wrap.nv-historicalBar-"+j).data([b[0].values]),A=z.enter().append("g").attr("class","nvd3 nv-wrap nv-historicalBar-"+j),B=A.append("defs"),C=A.append("g"),D=z.select("g");C.append("g").attr("class","nv-bars"),z.attr("transform","translate("+g.left+","+g.top+")"),k.on("click",function(a,b){u.chartClick({data:a,index:b,pos:d3.event,id:j})}),B.append("clipPath").attr("id","nv-chart-clip-path-"+j).append("rect"),z.select("#nv-chart-clip-path-"+j+" rect").attr("width",x).attr("height",y),D.attr("clip-path",s?"url(#nv-chart-clip-path-"+j+")":"");var E=z.select(".nv-bars").selectAll(".nv-bar").data(function(a){return a},function(a,b){return n(a,b)});E.exit().remove(),E.enter().append("rect").attr("x",0).attr("y",function(b,c){return a.utils.NaNtoZero(m(Math.max(0,o(b,c))))}).attr("height",function(b,c){return a.utils.NaNtoZero(Math.abs(m(o(b,c))-m(0)))}).attr("transform",function(a,c){return"translate("+(l(n(a,c))-x/b[0].values.length*.45)+",0)"}).on("mouseover",function(a,b){v&&(d3.select(this).classed("hover",!0),u.elementMouseover({data:a,index:b,color:d3.select(this).style("fill")}))}).on("mouseout",function(a,b){v&&(d3.select(this).classed("hover",!1),u.elementMouseout({data:a,index:b,color:d3.select(this).style("fill")}))}).on("mousemove",function(a,b){v&&u.elementMousemove({data:a,index:b,color:d3.select(this).style("fill")})}).on("click",function(a,b){v&&(u.elementClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation())}).on("dblclick",function(a,b){v&&(u.elementDblClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation())}),E.attr("fill",function(a,b){return t(a,b)}).attr("class",function(a,b,c){return(o(a,b)<0?"nv-bar negative":"nv-bar positive")+" nv-bar-"+c+"-"+b}).watchTransition(w,"bars").attr("transform",function(a,c){return"translate("+(l(n(a,c))-x/b[0].values.length*.45)+",0)"}).attr("width",x/b[0].values.length*.9),E.watchTransition(w,"bars").attr("y",function(b,c){var d=o(b,c)<0?m(0):m(0)-m(o(b,c))<1?m(0)-1:m(o(b,c));return a.utils.NaNtoZero(d)}).attr("height",function(b,c){return a.utils.NaNtoZero(Math.max(Math.abs(m(o(b,c))-m(0)),1))})}),w.renderEnd("historicalBar immediate"),b}var c,d,e,f,g={top:0,right:0,bottom:0,left:0},h=null,i=null,j=Math.floor(1e4*Math.random()),k=null,l=d3.scale.linear(),m=d3.scale.linear(),n=function(a){return a.x},o=function(a){return a.y},p=[],q=[0],r=!1,s=!0,t=a.utils.defaultColor(),u=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove","renderEnd"),v=!0,w=a.utils.renderWatch(u,0);return b.highlightPoint=function(a,b){k.select(".nv-bars .nv-bar-0-"+a).classed("hover",b)},b.clearHighlights=function(){k.select(".nv-bars .nv-bar.hover").classed("hover",!1)},b.dispatch=u,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return h},set:function(a){h=a}},height:{get:function(){return i},set:function(a){i=a}},forceX:{get:function(){return p},set:function(a){p=a}},forceY:{get:function(){return q},set:function(a){q=a}},padData:{get:function(){return r},set:function(a){r=a}},x:{get:function(){return n},set:function(a){n=a}},y:{get:function(){return o},set:function(a){o=a}},xScale:{get:function(){return l},set:function(a){l=a}},yScale:{get:function(){return m},set:function(a){m=a}},xDomain:{get:function(){return c},set:function(a){c=a}},yDomain:{get:function(){return d},set:function(a){d=a}},xRange:{get:function(){return e},set:function(a){e=a}},yRange:{get:function(){return f},set:function(a){f=a}},clipEdge:{get:function(){return s},set:function(a){s=a}},id:{get:function(){return j},set:function(a){j=a}},interactive:{get:function(){return v},set:function(a){v=a}},margin:{get:function(){return g},set:function(a){g.top=void 0!==a.top?a.top:g.top,g.right=void 0!==a.right?a.right:g.right,g.bottom=void 0!==a.bottom?a.bottom:g.bottom,g.left=void 0!==a.left?a.left:g.left}},color:{get:function(){return t},set:function(b){t=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.historicalBarChart=function(b){"use strict";function c(b){return b.each(function(k){z.reset(),z.models(f),q&&z.models(g),r&&z.models(h);var w=d3.select(this),A=this;a.utils.initSVG(w);var B=a.utils.availableWidth(n,w,l),C=a.utils.availableHeight(o,w,l);if(c.update=function(){w.transition().duration(y).call(c)},c.container=this,u.disabled=k.map(function(a){return!!a.disabled}),!v){var D;v={};for(D in u)v[D]=u[D]instanceof Array?u[D].slice(0):u[D]}if(!(k&&k.length&&k.filter(function(a){return a.values.length}).length))return a.utils.noData(c,w),c;w.selectAll(".nv-noData").remove(),d=f.xScale(),e=f.yScale();var E=w.selectAll("g.nv-wrap.nv-historicalBarChart").data([k]),F=E.enter().append("g").attr("class","nvd3 nv-wrap nv-historicalBarChart").append("g"),G=E.select("g");F.append("g").attr("class","nv-x nv-axis"),F.append("g").attr("class","nv-y nv-axis"),F.append("g").attr("class","nv-barsWrap"),F.append("g").attr("class","nv-legendWrap"),F.append("g").attr("class","nv-interactive"),p&&(i.width(B),G.select(".nv-legendWrap").datum(k).call(i),l.top!=i.height()&&(l.top=i.height(),C=a.utils.availableHeight(o,w,l)),E.select(".nv-legendWrap").attr("transform","translate(0,"+-l.top+")")),E.attr("transform","translate("+l.left+","+l.top+")"),s&&G.select(".nv-y.nv-axis").attr("transform","translate("+B+",0)"),t&&(j.width(B).height(C).margin({left:l.left,top:l.top}).svgContainer(w).xScale(d),E.select(".nv-interactive").call(j)),f.width(B).height(C).color(k.map(function(a,b){return a.color||m(a,b)}).filter(function(a,b){return!k[b].disabled}));var H=G.select(".nv-barsWrap").datum(k.filter(function(a){return!a.disabled}));H.transition().call(f),q&&(g.scale(d)._ticks(a.utils.calcTicksX(B/100,k)).tickSize(-C,0),G.select(".nv-x.nv-axis").attr("transform","translate(0,"+e.range()[0]+")"),G.select(".nv-x.nv-axis").transition().call(g)),r&&(h.scale(e)._ticks(a.utils.calcTicksY(C/36,k)).tickSize(-B,0),G.select(".nv-y.nv-axis").transition().call(h)),j.dispatch.on("elementMousemove",function(b){f.clearHighlights();var d,e,i,n=[];k.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(g){e=a.interactiveBisect(g.values,b.pointXValue,c.x()),f.highlightPoint(e,!0);var h=g.values[e];void 0!==h&&(void 0===d&&(d=h),void 0===i&&(i=c.xScale()(c.x()(h,e))),n.push({key:g.key,value:c.y()(h,e),color:m(g,g.seriesIndex),data:g.values[e]}))});var o=g.tickFormat()(c.x()(d,e));j.tooltip.position({left:i+l.left,top:b.mouseY+l.top}).chartContainer(A.parentNode).valueFormatter(function(a){return h.tickFormat()(a)}).data({value:o,index:e,series:n})(),j.renderGuideLine(i)}),j.dispatch.on("elementMouseout",function(){x.tooltipHide(),f.clearHighlights()}),i.dispatch.on("legendClick",function(a){a.disabled=!a.disabled,k.filter(function(a){return!a.disabled}).length||k.map(function(a){return a.disabled=!1,E.selectAll(".nv-series").classed("disabled",!1),a}),u.disabled=k.map(function(a){return!!a.disabled}),x.stateChange(u),b.transition().call(c)}),i.dispatch.on("legendDblclick",function(a){k.forEach(function(a){a.disabled=!0}),a.disabled=!1,u.disabled=k.map(function(a){return!!a.disabled}),x.stateChange(u),c.update()}),x.on("changeState",function(a){"undefined"!=typeof a.disabled&&(k.forEach(function(b,c){b.disabled=a.disabled[c]}),u.disabled=a.disabled),c.update()})}),z.renderEnd("historicalBarChart immediate"),c}var d,e,f=b||a.models.historicalBar(),g=a.models.axis(),h=a.models.axis(),i=a.models.legend(),j=a.interactiveGuideline(),k=a.models.tooltip(),l={top:30,right:90,bottom:50,left:90},m=a.utils.defaultColor(),n=null,o=null,p=!1,q=!0,r=!0,s=!1,t=!1,u={},v=null,w=null,x=d3.dispatch("tooltipHide","stateChange","changeState","renderEnd"),y=250;g.orient("bottom").tickPadding(7),h.orient(s?"right":"left"),k.duration(0).headerEnabled(!1).valueFormatter(function(a,b){return h.tickFormat()(a,b)}).headerFormatter(function(a,b){return g.tickFormat()(a,b)});var z=a.utils.renderWatch(x,0);return f.dispatch.on("elementMouseover.tooltip",function(a){a.series={key:c.x()(a.data),value:c.y()(a.data),color:a.color},k.data(a).hidden(!1)}),f.dispatch.on("elementMouseout.tooltip",function(){k.hidden(!0)}),f.dispatch.on("elementMousemove.tooltip",function(){k.position({top:d3.event.pageY,left:d3.event.pageX})()}),c.dispatch=x,c.bars=f,c.legend=i,c.xAxis=g,c.yAxis=h,c.interactiveLayer=j,c.tooltip=k,c.options=a.utils.optionsFunc.bind(c),c._options=Object.create({},{width:{get:function(){return n},set:function(a){n=a}},height:{get:function(){return o},set:function(a){o=a}},showLegend:{get:function(){return p},set:function(a){p=a}},showXAxis:{get:function(){return q},set:function(a){q=a}},showYAxis:{get:function(){return r},set:function(a){r=a}},defaultState:{get:function(){return v},set:function(a){v=a}},noData:{get:function(){return w},set:function(a){w=a}},tooltips:{get:function(){return k.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),k.enabled(!!b)}},tooltipContent:{get:function(){return k.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),k.contentGenerator(b)}},margin:{get:function(){return l},set:function(a){l.top=void 0!==a.top?a.top:l.top,l.right=void 0!==a.right?a.right:l.right,l.bottom=void 0!==a.bottom?a.bottom:l.bottom,l.left=void 0!==a.left?a.left:l.left}},color:{get:function(){return m},set:function(b){m=a.utils.getColor(b),i.color(m),f.color(m)}},duration:{get:function(){return y},set:function(a){y=a,z.reset(y),h.duration(y),g.duration(y)}},rightAlignYAxis:{get:function(){return s},set:function(a){s=a,h.orient(a?"right":"left")}},useInteractiveGuideline:{get:function(){return t},set:function(a){t=a,a===!0&&c.interactive(!1)}}}),a.utils.inheritOptions(c,f),a.utils.initOptions(c),c},a.models.ohlcBarChart=function(){var b=a.models.historicalBarChart(a.models.ohlcBar());return b.useInteractiveGuideline(!0),b.interactiveLayer.tooltip.contentGenerator(function(a){var c=a.series[0].data,d=c.open<c.close?"2ca02c":"d62728";return'<h3 style="color: #'+d+'">'+a.value+"</h3><table><tr><td>open:</td><td>"+b.yAxis.tickFormat()(c.open)+"</td></tr><tr><td>close:</td><td>"+b.yAxis.tickFormat()(c.close)+"</td></tr><tr><td>high</td><td>"+b.yAxis.tickFormat()(c.high)+"</td></tr><tr><td>low:</td><td>"+b.yAxis.tickFormat()(c.low)+"</td></tr></table>"}),b},a.models.candlestickBarChart=function(){var b=a.models.historicalBarChart(a.models.candlestickBar());return b.useInteractiveGuideline(!0),b.interactiveLayer.tooltip.contentGenerator(function(a){var c=a.series[0].data,d=c.open<c.close?"2ca02c":"d62728";return'<h3 style="color: #'+d+'">'+a.value+"</h3><table><tr><td>open:</td><td>"+b.yAxis.tickFormat()(c.open)+"</td></tr><tr><td>close:</td><td>"+b.yAxis.tickFormat()(c.close)+"</td></tr><tr><td>high</td><td>"+b.yAxis.tickFormat()(c.high)+"</td></tr><tr><td>low:</td><td>"+b.yAxis.tickFormat()(c.low)+"</td></tr></table>"}),b},a.models.legend=function(){"use strict";function b(p){function q(a,b){return"furious"!=o?"#000":m?a.disengaged?"#000":"#fff":m?void 0:(a.color||(a.color=g(a,b)),a.disabled?a.color:"#fff")}function r(a,b){return m&&"furious"==o&&a.disengaged?"#eee":a.color||g(a,b)}function s(a){return m&&"furious"==o?1:a.disabled?0:1}return p.each(function(b){var g=d-c.left-c.right,p=d3.select(this);a.utils.initSVG(p);var t=p.selectAll("g.nv-legend").data([b]),u=t.enter().append("g").attr("class","nvd3 nv-legend").append("g"),v=t.select("g");t.attr("transform","translate("+c.left+","+c.top+")");var w,x,y=v.selectAll(".nv-series").data(function(a){return"furious"!=o?a:a.filter(function(a){return m?!0:!a.disengaged})}),z=y.enter().append("g").attr("class","nv-series");switch(o){case"furious":x=23;break;case"classic":x=20}if("classic"==o)z.append("circle").style("stroke-width",2).attr("class","nv-legend-symbol").attr("r",5),w=y.select("circle");else if("furious"==o){z.append("rect").style("stroke-width",2).attr("class","nv-legend-symbol").attr("rx",3).attr("ry",3),w=y.select(".nv-legend-symbol"),z.append("g").attr("class","nv-check-box").property("innerHTML",'<path d="M0.5,5 L22.5,5 L22.5,26.5 L0.5,26.5 L0.5,5 Z" class="nv-box"></path><path d="M5.5,12.8618467 L11.9185089,19.2803556 L31,0.198864511" class="nv-check"></path>').attr("transform","translate(-10,-8)scale(0.5)");var A=y.select(".nv-check-box");A.each(function(a,b){d3.select(this).selectAll("path").attr("stroke",q(a,b))})}z.append("text").attr("text-anchor","start").attr("class","nv-legend-text").attr("dy",".32em").attr("dx","8");var B=y.select("text.nv-legend-text");y.on("mouseover",function(a,b){n.legendMouseover(a,b)}).on("mouseout",function(a,b){n.legendMouseout(a,b)}).on("click",function(a,b){n.legendClick(a,b);var c=y.data();if(k){if("classic"==o)l?(c.forEach(function(a){a.disabled=!0}),a.disabled=!1):(a.disabled=!a.disabled,c.every(function(a){return a.disabled})&&c.forEach(function(a){a.disabled=!1}));else if("furious"==o)if(m)a.disengaged=!a.disengaged,a.userDisabled=void 0==a.userDisabled?!!a.disabled:a.userDisabled,a.disabled=a.disengaged||a.userDisabled;else if(!m){a.disabled=!a.disabled,a.userDisabled=a.disabled;var d=c.filter(function(a){return!a.disengaged});d.every(function(a){return a.userDisabled})&&c.forEach(function(a){a.disabled=a.userDisabled=!1})}n.stateChange({disabled:c.map(function(a){return!!a.disabled}),disengaged:c.map(function(a){return!!a.disengaged})})}}).on("dblclick",function(a,b){if(("furious"!=o||!m)&&(n.legendDblclick(a,b),k)){var c=y.data();c.forEach(function(a){a.disabled=!0,"furious"==o&&(a.userDisabled=a.disabled)}),a.disabled=!1,"furious"==o&&(a.userDisabled=a.disabled),n.stateChange({disabled:c.map(function(a){return!!a.disabled})})}}),y.classed("nv-disabled",function(a){return a.userDisabled}),y.exit().remove(),B.attr("fill",q).text(f);var C=0;if(h){var D=[];y.each(function(){var b,c=d3.select(this).select("text");try{if(b=c.node().getComputedTextLength(),0>=b)throw Error()}catch(d){b=a.utils.calcApproxTextWidth(c)}D.push(b+i)});var E=0,F=[];for(C=0;g>C&&E<D.length;)F[E]=D[E],C+=D[E++];for(0===E&&(E=1);C>g&&E>1;){F=[],E--;for(var G=0;G<D.length;G++)D[G]>(F[G%E]||0)&&(F[G%E]=D[G]);C=F.reduce(function(a,b){return a+b})}for(var H=[],I=0,J=0;E>I;I++)H[I]=J,J+=F[I];y.attr("transform",function(a,b){return"translate("+H[b%E]+","+(5+Math.floor(b/E)*x)+")"}),j?v.attr("transform","translate("+(d-c.right-C)+","+c.top+")"):v.attr("transform","translate(0,"+c.top+")"),e=c.top+c.bottom+Math.ceil(D.length/E)*x}else{var K,L=5,M=5,N=0;y.attr("transform",function(){var a=d3.select(this).select("text").node().getComputedTextLength()+i;return K=M,d<c.left+c.right+K+a&&(M=K=5,L+=x),M+=a,M>N&&(N=M),K+N>C&&(C=K+N),"translate("+K+","+L+")"}),v.attr("transform","translate("+(d-c.right-N)+","+c.top+")"),e=c.top+c.bottom+L+15}if("furious"==o){w.attr("width",function(a,b){return B[0][b].getComputedTextLength()+27}).attr("height",18).attr("y",-9).attr("x",-15),u.insert("rect",":first-child").attr("class","nv-legend-bg").attr("fill","#eee").attr("opacity",0);var O=v.select(".nv-legend-bg");O.transition().duration(300).attr("x",-x).attr("width",C+x-12).attr("height",e+10).attr("y",-c.top-10).attr("opacity",m?1:0)}w.style("fill",r).style("fill-opacity",s).style("stroke",r)}),b}var c={top:5,right:0,bottom:5,left:0},d=400,e=20,f=function(a){return a.key},g=a.utils.getColor(),h=!0,i=32,j=!0,k=!0,l=!1,m=!1,n=d3.dispatch("legendClick","legendDblclick","legendMouseover","legendMouseout","stateChange"),o="classic";return b.dispatch=n,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return d},set:function(a){d=a}},height:{get:function(){return e},set:function(a){e=a}},key:{get:function(){return f},set:function(a){f=a}},align:{get:function(){return h},set:function(a){h=a}},rightAlign:{get:function(){return j},set:function(a){j=a}},padding:{get:function(){return i},set:function(a){i=a}},updateState:{get:function(){return k},set:function(a){k=a}},radioButtonMode:{get:function(){return l},set:function(a){l=a}},expanded:{get:function(){return m},set:function(a){m=a}},vers:{get:function(){return o},set:function(a){o=a}},margin:{get:function(){return c},set:function(a){c.top=void 0!==a.top?a.top:c.top,c.right=void 0!==a.right?a.right:c.right,c.bottom=void 0!==a.bottom?a.bottom:c.bottom,c.left=void 0!==a.left?a.left:c.left}},color:{get:function(){return g},set:function(b){g=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.line=function(){"use strict";function b(r){return v.reset(),v.models(e),r.each(function(b){i=d3.select(this);var r=a.utils.availableWidth(g,i,f),s=a.utils.availableHeight(h,i,f);a.utils.initSVG(i),c=e.xScale(),d=e.yScale(),t=t||c,u=u||d;var w=i.selectAll("g.nv-wrap.nv-line").data([b]),x=w.enter().append("g").attr("class","nvd3 nv-wrap nv-line"),y=x.append("defs"),z=x.append("g"),A=w.select("g");z.append("g").attr("class","nv-groups"),z.append("g").attr("class","nv-scatterWrap"),w.attr("transform","translate("+f.left+","+f.top+")"),e.width(r).height(s);var B=w.select(".nv-scatterWrap");B.call(e),y.append("clipPath").attr("id","nv-edge-clip-"+e.id()).append("rect"),w.select("#nv-edge-clip-"+e.id()+" rect").attr("width",r).attr("height",s>0?s:0),A.attr("clip-path",p?"url(#nv-edge-clip-"+e.id()+")":""),B.attr("clip-path",p?"url(#nv-edge-clip-"+e.id()+")":"");var C=w.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a){return a.key});C.enter().append("g").style("stroke-opacity",1e-6).style("stroke-width",function(a){return a.strokeWidth||j}).style("fill-opacity",1e-6),C.exit().remove(),C.attr("class",function(a,b){return(a.classed||"")+" nv-group nv-series-"+b}).classed("hover",function(a){return a.hover}).style("fill",function(a,b){return k(a,b)}).style("stroke",function(a,b){return k(a,b)}),C.watchTransition(v,"line: groups").style("stroke-opacity",1).style("fill-opacity",function(a){return a.fillOpacity||.5});var D=C.selectAll("path.nv-area").data(function(a){return o(a)?[a]:[]});D.enter().append("path").attr("class","nv-area").attr("d",function(b){return d3.svg.area().interpolate(q).defined(n).x(function(b,c){return a.utils.NaNtoZero(t(l(b,c)))}).y0(function(b,c){return a.utils.NaNtoZero(u(m(b,c)))}).y1(function(){return u(d.domain()[0]<=0?d.domain()[1]>=0?0:d.domain()[1]:d.domain()[0])}).apply(this,[b.values])}),C.exit().selectAll("path.nv-area").remove(),D.watchTransition(v,"line: areaPaths").attr("d",function(b){return d3.svg.area().interpolate(q).defined(n).x(function(b,d){return a.utils.NaNtoZero(c(l(b,d)))}).y0(function(b,c){return a.utils.NaNtoZero(d(m(b,c)))}).y1(function(){return d(d.domain()[0]<=0?d.domain()[1]>=0?0:d.domain()[1]:d.domain()[0])}).apply(this,[b.values])});var E=C.selectAll("path.nv-line").data(function(a){return[a.values]});E.enter().append("path").attr("class","nv-line").attr("d",d3.svg.line().interpolate(q).defined(n).x(function(b,c){return a.utils.NaNtoZero(t(l(b,c)))}).y(function(b,c){return a.utils.NaNtoZero(u(m(b,c)))})),E.watchTransition(v,"line: linePaths").attr("d",d3.svg.line().interpolate(q).defined(n).x(function(b,d){return a.utils.NaNtoZero(c(l(b,d)))}).y(function(b,c){return a.utils.NaNtoZero(d(m(b,c)))})),t=c.copy(),u=d.copy()}),v.renderEnd("line immediate"),b}var c,d,e=a.models.scatter(),f={top:0,right:0,bottom:0,left:0},g=960,h=500,i=null,j=1.5,k=a.utils.defaultColor(),l=function(a){return a.x},m=function(a){return a.y},n=function(a,b){return!isNaN(m(a,b))&&null!==m(a,b)},o=function(a){return a.area},p=!1,q="linear",r=250,s=d3.dispatch("elementClick","elementMouseover","elementMouseout","renderEnd");e.pointSize(16).pointDomain([16,256]);var t,u,v=a.utils.renderWatch(s,r);return b.dispatch=s,b.scatter=e,e.dispatch.on("elementClick",function(){s.elementClick.apply(this,arguments)}),e.dispatch.on("elementMouseover",function(){s.elementMouseover.apply(this,arguments)}),e.dispatch.on("elementMouseout",function(){s.elementMouseout.apply(this,arguments)}),b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return g},set:function(a){g=a}},height:{get:function(){return h},set:function(a){h=a}},defined:{get:function(){return n},set:function(a){n=a}},interpolate:{get:function(){return q},set:function(a){q=a}},clipEdge:{get:function(){return p},set:function(a){p=a}},margin:{get:function(){return f},set:function(a){f.top=void 0!==a.top?a.top:f.top,f.right=void 0!==a.right?a.right:f.right,f.bottom=void 0!==a.bottom?a.bottom:f.bottom,f.left=void 0!==a.left?a.left:f.left}},duration:{get:function(){return r},set:function(a){r=a,v.reset(r),e.duration(r)}},isArea:{get:function(){return o},set:function(a){o=d3.functor(a)}},x:{get:function(){return l},set:function(a){l=a,e.x(a)}},y:{get:function(){return m},set:function(a){m=a,e.y(a)}},color:{get:function(){return k},set:function(b){k=a.utils.getColor(b),e.color(k)}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.lineChart=function(){"use strict";function b(j){return y.reset(),y.models(e),p&&y.models(f),q&&y.models(g),j.each(function(j){var v=d3.select(this),y=this;a.utils.initSVG(v);var B=a.utils.availableWidth(m,v,k),C=a.utils.availableHeight(n,v,k);if(b.update=function(){0===x?v.call(b):v.transition().duration(x).call(b)},b.container=this,t.setter(A(j),b.update).getter(z(j)).update(),t.disabled=j.map(function(a){return!!a.disabled}),!u){var D;u={};for(D in t)u[D]=t[D]instanceof Array?t[D].slice(0):t[D]
}if(!(j&&j.length&&j.filter(function(a){return a.values.length}).length))return a.utils.noData(b,v),b;v.selectAll(".nv-noData").remove(),c=e.xScale(),d=e.yScale();var E=v.selectAll("g.nv-wrap.nv-lineChart").data([j]),F=E.enter().append("g").attr("class","nvd3 nv-wrap nv-lineChart").append("g"),G=E.select("g");F.append("rect").style("opacity",0),F.append("g").attr("class","nv-x nv-axis"),F.append("g").attr("class","nv-y nv-axis"),F.append("g").attr("class","nv-linesWrap"),F.append("g").attr("class","nv-legendWrap"),F.append("g").attr("class","nv-interactive"),G.select("rect").attr("width",B).attr("height",C>0?C:0),o&&(h.width(B),G.select(".nv-legendWrap").datum(j).call(h),k.top!=h.height()&&(k.top=h.height(),C=a.utils.availableHeight(n,v,k)),E.select(".nv-legendWrap").attr("transform","translate(0,"+-k.top+")")),E.attr("transform","translate("+k.left+","+k.top+")"),r&&G.select(".nv-y.nv-axis").attr("transform","translate("+B+",0)"),s&&(i.width(B).height(C).margin({left:k.left,top:k.top}).svgContainer(v).xScale(c),E.select(".nv-interactive").call(i)),e.width(B).height(C).color(j.map(function(a,b){return a.color||l(a,b)}).filter(function(a,b){return!j[b].disabled}));var H=G.select(".nv-linesWrap").datum(j.filter(function(a){return!a.disabled}));H.call(e),p&&(f.scale(c)._ticks(a.utils.calcTicksX(B/100,j)).tickSize(-C,0),G.select(".nv-x.nv-axis").attr("transform","translate(0,"+d.range()[0]+")"),G.select(".nv-x.nv-axis").call(f)),q&&(g.scale(d)._ticks(a.utils.calcTicksY(C/36,j)).tickSize(-B,0),G.select(".nv-y.nv-axis").call(g)),h.dispatch.on("stateChange",function(a){for(var c in a)t[c]=a[c];w.stateChange(t),b.update()}),i.dispatch.on("elementMousemove",function(c){e.clearHighlights();var d,h,m,n=[];if(j.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(f,g){h=a.interactiveBisect(f.values,c.pointXValue,b.x());var i=f.values[h],j=b.y()(i,h);null!=j&&e.highlightPoint(g,h,!0),void 0!==i&&(void 0===d&&(d=i),void 0===m&&(m=b.xScale()(b.x()(i,h))),n.push({key:f.key,value:j,color:l(f,f.seriesIndex)}))}),n.length>2){var o=b.yScale().invert(c.mouseY),p=Math.abs(b.yScale().domain()[0]-b.yScale().domain()[1]),q=.03*p,r=a.nearestValueIndex(n.map(function(a){return a.value}),o,q);null!==r&&(n[r].highlight=!0)}var s=f.tickFormat()(b.x()(d,h));i.tooltip.position({left:c.mouseX+k.left,top:c.mouseY+k.top}).chartContainer(y.parentNode).valueFormatter(function(a){return null==a?"N/A":g.tickFormat()(a)}).data({value:s,index:h,series:n})(),i.renderGuideLine(m)}),i.dispatch.on("elementClick",function(c){var d,f=[];j.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(e){var g=a.interactiveBisect(e.values,c.pointXValue,b.x()),h=e.values[g];if("undefined"!=typeof h){"undefined"==typeof d&&(d=b.xScale()(b.x()(h,g)));var i=b.yScale()(b.y()(h,g));f.push({point:h,pointIndex:g,pos:[d,i],seriesIndex:e.seriesIndex,series:e})}}),e.dispatch.elementClick(f)}),i.dispatch.on("elementMouseout",function(){e.clearHighlights()}),w.on("changeState",function(a){"undefined"!=typeof a.disabled&&j.length===a.disabled.length&&(j.forEach(function(b,c){b.disabled=a.disabled[c]}),t.disabled=a.disabled),b.update()})}),y.renderEnd("lineChart immediate"),b}var c,d,e=a.models.line(),f=a.models.axis(),g=a.models.axis(),h=a.models.legend(),i=a.interactiveGuideline(),j=a.models.tooltip(),k={top:30,right:20,bottom:50,left:60},l=a.utils.defaultColor(),m=null,n=null,o=!0,p=!0,q=!0,r=!1,s=!1,t=a.utils.state(),u=null,v=null,w=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd"),x=250;f.orient("bottom").tickPadding(7),g.orient(r?"right":"left"),j.valueFormatter(function(a,b){return g.tickFormat()(a,b)}).headerFormatter(function(a,b){return f.tickFormat()(a,b)});var y=a.utils.renderWatch(w,x),z=function(a){return function(){return{active:a.map(function(a){return!a.disabled})}}},A=function(a){return function(b){void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return e.dispatch.on("elementMouseover.tooltip",function(a){j.data(a).position(a.pos).hidden(!1)}),e.dispatch.on("elementMouseout.tooltip",function(){j.hidden(!0)}),b.dispatch=w,b.lines=e,b.legend=h,b.xAxis=f,b.yAxis=g,b.interactiveLayer=i,b.tooltip=j,b.dispatch=w,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return m},set:function(a){m=a}},height:{get:function(){return n},set:function(a){n=a}},showLegend:{get:function(){return o},set:function(a){o=a}},showXAxis:{get:function(){return p},set:function(a){p=a}},showYAxis:{get:function(){return q},set:function(a){q=a}},defaultState:{get:function(){return u},set:function(a){u=a}},noData:{get:function(){return v},set:function(a){v=a}},tooltips:{get:function(){return j.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),j.enabled(!!b)}},tooltipContent:{get:function(){return j.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),j.contentGenerator(b)}},margin:{get:function(){return k},set:function(a){k.top=void 0!==a.top?a.top:k.top,k.right=void 0!==a.right?a.right:k.right,k.bottom=void 0!==a.bottom?a.bottom:k.bottom,k.left=void 0!==a.left?a.left:k.left}},duration:{get:function(){return x},set:function(a){x=a,y.reset(x),e.duration(x),f.duration(x),g.duration(x)}},color:{get:function(){return l},set:function(b){l=a.utils.getColor(b),h.color(l),e.color(l)}},rightAlignYAxis:{get:function(){return r},set:function(a){r=a,g.orient(r?"right":"left")}},useInteractiveGuideline:{get:function(){return s},set:function(a){s=a,s&&(e.interactive(!1),e.useVoronoi(!1))}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.linePlusBarChart=function(){"use strict";function b(v){return v.each(function(v){function J(a){var b=+("e"==a),c=b?1:-1,d=X/3;return"M"+.5*c+","+d+"A6,6 0 0 "+b+" "+6.5*c+","+(d+6)+"V"+(2*d-6)+"A6,6 0 0 "+b+" "+.5*c+","+2*d+"ZM"+2.5*c+","+(d+8)+"V"+(2*d-8)+"M"+4.5*c+","+(d+8)+"V"+(2*d-8)}function S(){u.empty()||u.extent(I),kb.data([u.empty()?e.domain():I]).each(function(a){var b=e(a[0])-e.range()[0],c=e.range()[1]-e(a[1]);d3.select(this).select(".left").attr("width",0>b?0:b),d3.select(this).select(".right").attr("x",e(a[1])).attr("width",0>c?0:c)})}function T(){I=u.empty()?null:u.extent(),c=u.empty()?e.domain():u.extent(),K.brush({extent:c,brush:u}),S(),l.width(V).height(W).color(v.map(function(a,b){return a.color||C(a,b)}).filter(function(a,b){return!v[b].disabled&&v[b].bar})),j.width(V).height(W).color(v.map(function(a,b){return a.color||C(a,b)}).filter(function(a,b){return!v[b].disabled&&!v[b].bar}));var b=db.select(".nv-focus .nv-barsWrap").datum(Z.length?Z.map(function(a){return{key:a.key,values:a.values.filter(function(a,b){return l.x()(a,b)>=c[0]&&l.x()(a,b)<=c[1]})}}):[{values:[]}]),h=db.select(".nv-focus .nv-linesWrap").datum($[0].disabled?[{values:[]}]:$.map(function(a){return{area:a.area,fillOpacity:a.fillOpacity,key:a.key,values:a.values.filter(function(a,b){return j.x()(a,b)>=c[0]&&j.x()(a,b)<=c[1]})}}));d=Z.length?l.xScale():j.xScale(),n.scale(d)._ticks(a.utils.calcTicksX(V/100,v)).tickSize(-W,0),n.domain([Math.ceil(c[0]),Math.floor(c[1])]),db.select(".nv-x.nv-axis").transition().duration(L).call(n),b.transition().duration(L).call(l),h.transition().duration(L).call(j),db.select(".nv-focus .nv-x.nv-axis").attr("transform","translate(0,"+f.range()[0]+")"),p.scale(f)._ticks(a.utils.calcTicksY(W/36,v)).tickSize(-V,0),q.scale(g)._ticks(a.utils.calcTicksY(W/36,v)).tickSize(Z.length?0:-V,0),db.select(".nv-focus .nv-y1.nv-axis").style("opacity",Z.length?1:0),db.select(".nv-focus .nv-y2.nv-axis").style("opacity",$.length&&!$[0].disabled?1:0).attr("transform","translate("+d.range()[1]+",0)"),db.select(".nv-focus .nv-y1.nv-axis").transition().duration(L).call(p),db.select(".nv-focus .nv-y2.nv-axis").transition().duration(L).call(q)}var U=d3.select(this);a.utils.initSVG(U);var V=a.utils.availableWidth(y,U,w),W=a.utils.availableHeight(z,U,w)-(E?H:0),X=H-x.top-x.bottom;if(b.update=function(){U.transition().duration(L).call(b)},b.container=this,M.setter(R(v),b.update).getter(Q(v)).update(),M.disabled=v.map(function(a){return!!a.disabled}),!N){var Y;N={};for(Y in M)N[Y]=M[Y]instanceof Array?M[Y].slice(0):M[Y]}if(!(v&&v.length&&v.filter(function(a){return a.values.length}).length))return a.utils.noData(b,U),b;U.selectAll(".nv-noData").remove();var Z=v.filter(function(a){return!a.disabled&&a.bar}),$=v.filter(function(a){return!a.bar});d=l.xScale(),e=o.scale(),f=l.yScale(),g=j.yScale(),h=m.yScale(),i=k.yScale();var _=v.filter(function(a){return!a.disabled&&a.bar}).map(function(a){return a.values.map(function(a,b){return{x:A(a,b),y:B(a,b)}})}),ab=v.filter(function(a){return!a.disabled&&!a.bar}).map(function(a){return a.values.map(function(a,b){return{x:A(a,b),y:B(a,b)}})});d.range([0,V]),e.domain(d3.extent(d3.merge(_.concat(ab)),function(a){return a.x})).range([0,V]);var bb=U.selectAll("g.nv-wrap.nv-linePlusBar").data([v]),cb=bb.enter().append("g").attr("class","nvd3 nv-wrap nv-linePlusBar").append("g"),db=bb.select("g");cb.append("g").attr("class","nv-legendWrap");var eb=cb.append("g").attr("class","nv-focus");eb.append("g").attr("class","nv-x nv-axis"),eb.append("g").attr("class","nv-y1 nv-axis"),eb.append("g").attr("class","nv-y2 nv-axis"),eb.append("g").attr("class","nv-barsWrap"),eb.append("g").attr("class","nv-linesWrap");var fb=cb.append("g").attr("class","nv-context");if(fb.append("g").attr("class","nv-x nv-axis"),fb.append("g").attr("class","nv-y1 nv-axis"),fb.append("g").attr("class","nv-y2 nv-axis"),fb.append("g").attr("class","nv-barsWrap"),fb.append("g").attr("class","nv-linesWrap"),fb.append("g").attr("class","nv-brushBackground"),fb.append("g").attr("class","nv-x nv-brush"),D){var gb=t.align()?V/2:V,hb=t.align()?gb:0;t.width(gb),db.select(".nv-legendWrap").datum(v.map(function(a){return a.originalKey=void 0===a.originalKey?a.key:a.originalKey,a.key=a.originalKey+(a.bar?O:P),a})).call(t),w.top!=t.height()&&(w.top=t.height(),W=a.utils.availableHeight(z,U,w)-H),db.select(".nv-legendWrap").attr("transform","translate("+hb+","+-w.top+")")}bb.attr("transform","translate("+w.left+","+w.top+")"),db.select(".nv-context").style("display",E?"initial":"none"),m.width(V).height(X).color(v.map(function(a,b){return a.color||C(a,b)}).filter(function(a,b){return!v[b].disabled&&v[b].bar})),k.width(V).height(X).color(v.map(function(a,b){return a.color||C(a,b)}).filter(function(a,b){return!v[b].disabled&&!v[b].bar}));var ib=db.select(".nv-context .nv-barsWrap").datum(Z.length?Z:[{values:[]}]),jb=db.select(".nv-context .nv-linesWrap").datum($[0].disabled?[{values:[]}]:$);db.select(".nv-context").attr("transform","translate(0,"+(W+w.bottom+x.top)+")"),ib.transition().call(m),jb.transition().call(k),G&&(o._ticks(a.utils.calcTicksX(V/100,v)).tickSize(-X,0),db.select(".nv-context .nv-x.nv-axis").attr("transform","translate(0,"+h.range()[0]+")"),db.select(".nv-context .nv-x.nv-axis").transition().call(o)),F&&(r.scale(h)._ticks(X/36).tickSize(-V,0),s.scale(i)._ticks(X/36).tickSize(Z.length?0:-V,0),db.select(".nv-context .nv-y3.nv-axis").style("opacity",Z.length?1:0).attr("transform","translate(0,"+e.range()[0]+")"),db.select(".nv-context .nv-y2.nv-axis").style("opacity",$.length?1:0).attr("transform","translate("+e.range()[1]+",0)"),db.select(".nv-context .nv-y1.nv-axis").transition().call(r),db.select(".nv-context .nv-y2.nv-axis").transition().call(s)),u.x(e).on("brush",T),I&&u.extent(I);var kb=db.select(".nv-brushBackground").selectAll("g").data([I||u.extent()]),lb=kb.enter().append("g");lb.append("rect").attr("class","left").attr("x",0).attr("y",0).attr("height",X),lb.append("rect").attr("class","right").attr("x",0).attr("y",0).attr("height",X);var mb=db.select(".nv-x.nv-brush").call(u);mb.selectAll("rect").attr("height",X),mb.selectAll(".resize").append("path").attr("d",J),t.dispatch.on("stateChange",function(a){for(var c in a)M[c]=a[c];K.stateChange(M),b.update()}),K.on("changeState",function(a){"undefined"!=typeof a.disabled&&(v.forEach(function(b,c){b.disabled=a.disabled[c]}),M.disabled=a.disabled),b.update()}),T()}),b}var c,d,e,f,g,h,i,j=a.models.line(),k=a.models.line(),l=a.models.historicalBar(),m=a.models.historicalBar(),n=a.models.axis(),o=a.models.axis(),p=a.models.axis(),q=a.models.axis(),r=a.models.axis(),s=a.models.axis(),t=a.models.legend(),u=d3.svg.brush(),v=a.models.tooltip(),w={top:30,right:30,bottom:30,left:60},x={top:0,right:30,bottom:20,left:60},y=null,z=null,A=function(a){return a.x},B=function(a){return a.y},C=a.utils.defaultColor(),D=!0,E=!0,F=!1,G=!0,H=50,I=null,J=null,K=d3.dispatch("brush","stateChange","changeState"),L=0,M=a.utils.state(),N=null,O=" (left axis)",P=" (right axis)";j.clipEdge(!0),k.interactive(!1),n.orient("bottom").tickPadding(5),p.orient("left"),q.orient("right"),o.orient("bottom").tickPadding(5),r.orient("left"),s.orient("right"),v.headerEnabled(!0).headerFormatter(function(a,b){return n.tickFormat()(a,b)});var Q=function(a){return function(){return{active:a.map(function(a){return!a.disabled})}}},R=function(a){return function(b){void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return j.dispatch.on("elementMouseover.tooltip",function(a){v.duration(100).valueFormatter(function(a,b){return q.tickFormat()(a,b)}).data(a).position(a.pos).hidden(!1)}),j.dispatch.on("elementMouseout.tooltip",function(){v.hidden(!0)}),l.dispatch.on("elementMouseover.tooltip",function(a){a.value=b.x()(a.data),a.series={value:b.y()(a.data),color:a.color},v.duration(0).valueFormatter(function(a,b){return p.tickFormat()(a,b)}).data(a).hidden(!1)}),l.dispatch.on("elementMouseout.tooltip",function(){v.hidden(!0)}),l.dispatch.on("elementMousemove.tooltip",function(){v.position({top:d3.event.pageY,left:d3.event.pageX})()}),b.dispatch=K,b.legend=t,b.lines=j,b.lines2=k,b.bars=l,b.bars2=m,b.xAxis=n,b.x2Axis=o,b.y1Axis=p,b.y2Axis=q,b.y3Axis=r,b.y4Axis=s,b.tooltip=v,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return y},set:function(a){y=a}},height:{get:function(){return z},set:function(a){z=a}},showLegend:{get:function(){return D},set:function(a){D=a}},brushExtent:{get:function(){return I},set:function(a){I=a}},noData:{get:function(){return J},set:function(a){J=a}},focusEnable:{get:function(){return E},set:function(a){E=a}},focusHeight:{get:function(){return H},set:function(a){H=a}},focusShowAxisX:{get:function(){return G},set:function(a){G=a}},focusShowAxisY:{get:function(){return F},set:function(a){F=a}},legendLeftAxisHint:{get:function(){return O},set:function(a){O=a}},legendRightAxisHint:{get:function(){return P},set:function(a){P=a}},tooltips:{get:function(){return v.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),v.enabled(!!b)}},tooltipContent:{get:function(){return v.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),v.contentGenerator(b)}},margin:{get:function(){return w},set:function(a){w.top=void 0!==a.top?a.top:w.top,w.right=void 0!==a.right?a.right:w.right,w.bottom=void 0!==a.bottom?a.bottom:w.bottom,w.left=void 0!==a.left?a.left:w.left}},duration:{get:function(){return L},set:function(a){L=a}},color:{get:function(){return C},set:function(b){C=a.utils.getColor(b),t.color(C)}},x:{get:function(){return A},set:function(a){A=a,j.x(a),k.x(a),l.x(a),m.x(a)}},y:{get:function(){return B},set:function(a){B=a,j.y(a),k.y(a),l.y(a),m.y(a)}}}),a.utils.inheritOptions(b,j),a.utils.initOptions(b),b},a.models.lineWithFocusChart=function(){"use strict";function b(o){return o.each(function(o){function z(a){var b=+("e"==a),c=b?1:-1,d=M/3;return"M"+.5*c+","+d+"A6,6 0 0 "+b+" "+6.5*c+","+(d+6)+"V"+(2*d-6)+"A6,6 0 0 "+b+" "+.5*c+","+2*d+"ZM"+2.5*c+","+(d+8)+"V"+(2*d-8)+"M"+4.5*c+","+(d+8)+"V"+(2*d-8)}function G(){n.empty()||n.extent(y),U.data([n.empty()?e.domain():y]).each(function(a){var b=e(a[0])-c.range()[0],d=K-e(a[1]);d3.select(this).select(".left").attr("width",0>b?0:b),d3.select(this).select(".right").attr("x",e(a[1])).attr("width",0>d?0:d)})}function H(){y=n.empty()?null:n.extent();var a=n.empty()?e.domain():n.extent();if(!(Math.abs(a[0]-a[1])<=1)){A.brush({extent:a,brush:n}),G();var b=Q.select(".nv-focus .nv-linesWrap").datum(o.filter(function(a){return!a.disabled}).map(function(b){return{key:b.key,area:b.area,values:b.values.filter(function(b,c){return g.x()(b,c)>=a[0]&&g.x()(b,c)<=a[1]})}}));b.transition().duration(B).call(g),Q.select(".nv-focus .nv-x.nv-axis").transition().duration(B).call(i),Q.select(".nv-focus .nv-y.nv-axis").transition().duration(B).call(j)}}var I=d3.select(this),J=this;a.utils.initSVG(I);var K=a.utils.availableWidth(t,I,q),L=a.utils.availableHeight(u,I,q)-v,M=v-r.top-r.bottom;if(b.update=function(){I.transition().duration(B).call(b)},b.container=this,C.setter(F(o),b.update).getter(E(o)).update(),C.disabled=o.map(function(a){return!!a.disabled}),!D){var N;D={};for(N in C)D[N]=C[N]instanceof Array?C[N].slice(0):C[N]}if(!(o&&o.length&&o.filter(function(a){return a.values.length}).length))return a.utils.noData(b,I),b;I.selectAll(".nv-noData").remove(),c=g.xScale(),d=g.yScale(),e=h.xScale(),f=h.yScale();var O=I.selectAll("g.nv-wrap.nv-lineWithFocusChart").data([o]),P=O.enter().append("g").attr("class","nvd3 nv-wrap nv-lineWithFocusChart").append("g"),Q=O.select("g");P.append("g").attr("class","nv-legendWrap");var R=P.append("g").attr("class","nv-focus");R.append("g").attr("class","nv-x nv-axis"),R.append("g").attr("class","nv-y nv-axis"),R.append("g").attr("class","nv-linesWrap"),R.append("g").attr("class","nv-interactive");var S=P.append("g").attr("class","nv-context");S.append("g").attr("class","nv-x nv-axis"),S.append("g").attr("class","nv-y nv-axis"),S.append("g").attr("class","nv-linesWrap"),S.append("g").attr("class","nv-brushBackground"),S.append("g").attr("class","nv-x nv-brush"),x&&(m.width(K),Q.select(".nv-legendWrap").datum(o).call(m),q.top!=m.height()&&(q.top=m.height(),L=a.utils.availableHeight(u,I,q)-v),Q.select(".nv-legendWrap").attr("transform","translate(0,"+-q.top+")")),O.attr("transform","translate("+q.left+","+q.top+")"),w&&(p.width(K).height(L).margin({left:q.left,top:q.top}).svgContainer(I).xScale(c),O.select(".nv-interactive").call(p)),g.width(K).height(L).color(o.map(function(a,b){return a.color||s(a,b)}).filter(function(a,b){return!o[b].disabled})),h.defined(g.defined()).width(K).height(M).color(o.map(function(a,b){return a.color||s(a,b)}).filter(function(a,b){return!o[b].disabled})),Q.select(".nv-context").attr("transform","translate(0,"+(L+q.bottom+r.top)+")");var T=Q.select(".nv-context .nv-linesWrap").datum(o.filter(function(a){return!a.disabled}));d3.transition(T).call(h),i.scale(c)._ticks(a.utils.calcTicksX(K/100,o)).tickSize(-L,0),j.scale(d)._ticks(a.utils.calcTicksY(L/36,o)).tickSize(-K,0),Q.select(".nv-focus .nv-x.nv-axis").attr("transform","translate(0,"+L+")"),n.x(e).on("brush",function(){H()}),y&&n.extent(y);var U=Q.select(".nv-brushBackground").selectAll("g").data([y||n.extent()]),V=U.enter().append("g");V.append("rect").attr("class","left").attr("x",0).attr("y",0).attr("height",M),V.append("rect").attr("class","right").attr("x",0).attr("y",0).attr("height",M);var W=Q.select(".nv-x.nv-brush").call(n);W.selectAll("rect").attr("height",M),W.selectAll(".resize").append("path").attr("d",z),H(),k.scale(e)._ticks(a.utils.calcTicksX(K/100,o)).tickSize(-M,0),Q.select(".nv-context .nv-x.nv-axis").attr("transform","translate(0,"+f.range()[0]+")"),d3.transition(Q.select(".nv-context .nv-x.nv-axis")).call(k),l.scale(f)._ticks(a.utils.calcTicksY(M/36,o)).tickSize(-K,0),d3.transition(Q.select(".nv-context .nv-y.nv-axis")).call(l),Q.select(".nv-context .nv-x.nv-axis").attr("transform","translate(0,"+f.range()[0]+")"),m.dispatch.on("stateChange",function(a){for(var c in a)C[c]=a[c];A.stateChange(C),b.update()}),p.dispatch.on("elementMousemove",function(c){g.clearHighlights();var d,f,h,k=[];if(o.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(i,j){var l=n.empty()?e.domain():n.extent(),m=i.values.filter(function(a,b){return g.x()(a,b)>=l[0]&&g.x()(a,b)<=l[1]});f=a.interactiveBisect(m,c.pointXValue,g.x());var o=m[f],p=b.y()(o,f);null!=p&&g.highlightPoint(j,f,!0),void 0!==o&&(void 0===d&&(d=o),void 0===h&&(h=b.xScale()(b.x()(o,f))),k.push({key:i.key,value:b.y()(o,f),color:s(i,i.seriesIndex)}))}),k.length>2){var l=b.yScale().invert(c.mouseY),m=Math.abs(b.yScale().domain()[0]-b.yScale().domain()[1]),r=.03*m,t=a.nearestValueIndex(k.map(function(a){return a.value}),l,r);null!==t&&(k[t].highlight=!0)}var u=i.tickFormat()(b.x()(d,f));p.tooltip.position({left:c.mouseX+q.left,top:c.mouseY+q.top}).chartContainer(J.parentNode).valueFormatter(function(a){return null==a?"N/A":j.tickFormat()(a)}).data({value:u,index:f,series:k})(),p.renderGuideLine(h)}),p.dispatch.on("elementMouseout",function(){g.clearHighlights()}),A.on("changeState",function(a){"undefined"!=typeof a.disabled&&o.forEach(function(b,c){b.disabled=a.disabled[c]}),b.update()})}),b}var c,d,e,f,g=a.models.line(),h=a.models.line(),i=a.models.axis(),j=a.models.axis(),k=a.models.axis(),l=a.models.axis(),m=a.models.legend(),n=d3.svg.brush(),o=a.models.tooltip(),p=a.interactiveGuideline(),q={top:30,right:30,bottom:30,left:60},r={top:0,right:30,bottom:20,left:60},s=a.utils.defaultColor(),t=null,u=null,v=50,w=!1,x=!0,y=null,z=null,A=d3.dispatch("brush","stateChange","changeState"),B=250,C=a.utils.state(),D=null;g.clipEdge(!0).duration(0),h.interactive(!1),i.orient("bottom").tickPadding(5),j.orient("left"),k.orient("bottom").tickPadding(5),l.orient("left"),o.valueFormatter(function(a,b){return j.tickFormat()(a,b)}).headerFormatter(function(a,b){return i.tickFormat()(a,b)});var E=function(a){return function(){return{active:a.map(function(a){return!a.disabled})}}},F=function(a){return function(b){void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return g.dispatch.on("elementMouseover.tooltip",function(a){o.data(a).position(a.pos).hidden(!1)}),g.dispatch.on("elementMouseout.tooltip",function(){o.hidden(!0)}),b.dispatch=A,b.legend=m,b.lines=g,b.lines2=h,b.xAxis=i,b.yAxis=j,b.x2Axis=k,b.y2Axis=l,b.interactiveLayer=p,b.tooltip=o,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return t},set:function(a){t=a}},height:{get:function(){return u},set:function(a){u=a}},focusHeight:{get:function(){return v},set:function(a){v=a}},showLegend:{get:function(){return x},set:function(a){x=a}},brushExtent:{get:function(){return y},set:function(a){y=a}},defaultState:{get:function(){return D},set:function(a){D=a}},noData:{get:function(){return z},set:function(a){z=a}},tooltips:{get:function(){return o.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),o.enabled(!!b)}},tooltipContent:{get:function(){return o.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),o.contentGenerator(b)}},margin:{get:function(){return q},set:function(a){q.top=void 0!==a.top?a.top:q.top,q.right=void 0!==a.right?a.right:q.right,q.bottom=void 0!==a.bottom?a.bottom:q.bottom,q.left=void 0!==a.left?a.left:q.left}},color:{get:function(){return s},set:function(b){s=a.utils.getColor(b),m.color(s)}},interpolate:{get:function(){return g.interpolate()},set:function(a){g.interpolate(a),h.interpolate(a)}},xTickFormat:{get:function(){return i.tickFormat()},set:function(a){i.tickFormat(a),k.tickFormat(a)}},yTickFormat:{get:function(){return j.tickFormat()},set:function(a){j.tickFormat(a),l.tickFormat(a)}},duration:{get:function(){return B},set:function(a){B=a,j.duration(B),l.duration(B),i.duration(B),k.duration(B)}},x:{get:function(){return g.x()},set:function(a){g.x(a),h.x(a)}},y:{get:function(){return g.y()},set:function(a){g.y(a),h.y(a)}},useInteractiveGuideline:{get:function(){return w},set:function(a){w=a,w&&(g.interactive(!1),g.useVoronoi(!1))}}}),a.utils.inheritOptions(b,g),a.utils.initOptions(b),b},a.models.multiBar=function(){"use strict";function b(E){return C.reset(),E.each(function(b){var E=k-j.left-j.right,F=l-j.top-j.bottom;p=d3.select(this),a.utils.initSVG(p);var G=0;if(x&&b.length&&(x=[{values:b[0].values.map(function(a){return{x:a.x,y:0,series:a.series,size:.01}})}]),u){var H=d3.layout.stack().offset(v).values(function(a){return a.values}).y(r)(!b.length&&x?x:b);H.forEach(function(a,c){a.nonStackable?(b[c].nonStackableSeries=G++,H[c]=b[c]):c>0&&H[c-1].nonStackable&&H[c].values.map(function(a,b){a.y0-=H[c-1].values[b].y,a.y1=a.y0+a.y})}),b=H}b.forEach(function(a,b){a.values.forEach(function(c){c.series=b,c.key=a.key})}),u&&b[0].values.map(function(a,c){var d=0,e=0;b.map(function(a,f){if(!b[f].nonStackable){var g=a.values[c];g.size=Math.abs(g.y),g.y<0?(g.y1=e,e-=g.size):(g.y1=g.size+d,d+=g.size)}})});var I=d&&e?[]:b.map(function(a,b){return a.values.map(function(a,c){return{x:q(a,c),y:r(a,c),y0:a.y0,y1:a.y1,idx:b}})});m.domain(d||d3.merge(I).map(function(a){return a.x})).rangeBands(f||[0,E],A),n.domain(e||d3.extent(d3.merge(I).map(function(a){var c=a.y;return u&&!b[a.idx].nonStackable&&(c=a.y>0?a.y1:a.y1+a.y),c}).concat(s))).range(g||[F,0]),m.domain()[0]===m.domain()[1]&&m.domain(m.domain()[0]?[m.domain()[0]-.01*m.domain()[0],m.domain()[1]+.01*m.domain()[1]]:[-1,1]),n.domain()[0]===n.domain()[1]&&n.domain(n.domain()[0]?[n.domain()[0]+.01*n.domain()[0],n.domain()[1]-.01*n.domain()[1]]:[-1,1]),h=h||m,i=i||n;var J=p.selectAll("g.nv-wrap.nv-multibar").data([b]),K=J.enter().append("g").attr("class","nvd3 nv-wrap nv-multibar"),L=K.append("defs"),M=K.append("g"),N=J.select("g");M.append("g").attr("class","nv-groups"),J.attr("transform","translate("+j.left+","+j.top+")"),L.append("clipPath").attr("id","nv-edge-clip-"+o).append("rect"),J.select("#nv-edge-clip-"+o+" rect").attr("width",E).attr("height",F),N.attr("clip-path",t?"url(#nv-edge-clip-"+o+")":"");var O=J.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a,b){return b});O.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6);var P=C.transition(O.exit().selectAll("rect.nv-bar"),"multibarExit",Math.min(100,z)).attr("y",function(a){var c=i(0)||0;return u&&b[a.series]&&!b[a.series].nonStackable&&(c=i(a.y0)),c}).attr("height",0).remove();P.delay&&P.delay(function(a,b){var c=b*(z/(D+1))-b;return c}),O.attr("class",function(a,b){return"nv-group nv-series-"+b}).classed("hover",function(a){return a.hover}).style("fill",function(a,b){return w(a,b)}).style("stroke",function(a,b){return w(a,b)}),O.style("stroke-opacity",1).style("fill-opacity",.75);var Q=O.selectAll("rect.nv-bar").data(function(a){return x&&!b.length?x.values:a.values});Q.exit().remove();Q.enter().append("rect").attr("class",function(a,b){return r(a,b)<0?"nv-bar negative":"nv-bar positive"}).attr("x",function(a,c,d){return u&&!b[d].nonStackable?0:d*m.rangeBand()/b.length}).attr("y",function(a,c,d){return i(u&&!b[d].nonStackable?a.y0:0)||0}).attr("height",0).attr("width",function(a,c,d){return m.rangeBand()/(u&&!b[d].nonStackable?1:b.length)}).attr("transform",function(a,b){return"translate("+m(q(a,b))+",0)"});Q.style("fill",function(a,b,c){return w(a,c,b)}).style("stroke",function(a,b,c){return w(a,c,b)}).on("mouseover",function(a,b){d3.select(this).classed("hover",!0),B.elementMouseover({data:a,index:b,color:d3.select(this).style("fill")})}).on("mouseout",function(a,b){d3.select(this).classed("hover",!1),B.elementMouseout({data:a,index:b,color:d3.select(this).style("fill")})}).on("mousemove",function(a,b){B.elementMousemove({data:a,index:b,color:d3.select(this).style("fill")})}).on("click",function(a,b){B.elementClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation()}).on("dblclick",function(a,b){B.elementDblClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation()}),Q.attr("class",function(a,b){return r(a,b)<0?"nv-bar negative":"nv-bar positive"}).attr("transform",function(a,b){return"translate("+m(q(a,b))+",0)"}),y&&(c||(c=b.map(function(){return!0})),Q.style("fill",function(a,b,d){return d3.rgb(y(a,b)).darker(c.map(function(a,b){return b}).filter(function(a,b){return!c[b]})[d]).toString()}).style("stroke",function(a,b,d){return d3.rgb(y(a,b)).darker(c.map(function(a,b){return b}).filter(function(a,b){return!c[b]})[d]).toString()}));var R=Q.watchTransition(C,"multibar",Math.min(250,z)).delay(function(a,c){return c*z/b[0].values.length});u?R.attr("y",function(a,c,d){var e=0;return e=b[d].nonStackable?r(a,c)<0?n(0):n(0)-n(r(a,c))<-1?n(0)-1:n(r(a,c))||0:n(a.y1)}).attr("height",function(a,c,d){return b[d].nonStackable?Math.max(Math.abs(n(r(a,c))-n(0)),1)||0:Math.max(Math.abs(n(a.y+a.y0)-n(a.y0)),1)}).attr("x",function(a,c,d){var e=0;return b[d].nonStackable&&(e=a.series*m.rangeBand()/b.length,b.length!==G&&(e=b[d].nonStackableSeries*m.rangeBand()/(2*G))),e}).attr("width",function(a,c,d){if(b[d].nonStackable){var e=m.rangeBand()/G;return b.length!==G&&(e=m.rangeBand()/(2*G)),e}return m.rangeBand()}):R.attr("x",function(a){return a.series*m.rangeBand()/b.length}).attr("width",m.rangeBand()/b.length).attr("y",function(a,b){return r(a,b)<0?n(0):n(0)-n(r(a,b))<1?n(0)-1:n(r(a,b))||0}).attr("height",function(a,b){return Math.max(Math.abs(n(r(a,b))-n(0)),1)||0}),h=m.copy(),i=n.copy(),b[0]&&b[0].values&&(D=b[0].values.length)}),C.renderEnd("multibar immediate"),b}var c,d,e,f,g,h,i,j={top:0,right:0,bottom:0,left:0},k=960,l=500,m=d3.scale.ordinal(),n=d3.scale.linear(),o=Math.floor(1e4*Math.random()),p=null,q=function(a){return a.x},r=function(a){return a.y},s=[0],t=!0,u=!1,v="zero",w=a.utils.defaultColor(),x=!1,y=null,z=500,A=.1,B=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove","renderEnd"),C=a.utils.renderWatch(B,z),D=0;return b.dispatch=B,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return k},set:function(a){k=a}},height:{get:function(){return l},set:function(a){l=a}},x:{get:function(){return q},set:function(a){q=a}},y:{get:function(){return r},set:function(a){r=a}},xScale:{get:function(){return m},set:function(a){m=a}},yScale:{get:function(){return n},set:function(a){n=a}},xDomain:{get:function(){return d},set:function(a){d=a}},yDomain:{get:function(){return e},set:function(a){e=a}},xRange:{get:function(){return f},set:function(a){f=a}},yRange:{get:function(){return g},set:function(a){g=a}},forceY:{get:function(){return s},set:function(a){s=a}},stacked:{get:function(){return u},set:function(a){u=a}},stackOffset:{get:function(){return v},set:function(a){v=a}},clipEdge:{get:function(){return t},set:function(a){t=a}},disabled:{get:function(){return c},set:function(a){c=a}},id:{get:function(){return o},set:function(a){o=a}},hideable:{get:function(){return x},set:function(a){x=a}},groupSpacing:{get:function(){return A},set:function(a){A=a}},margin:{get:function(){return j},set:function(a){j.top=void 0!==a.top?a.top:j.top,j.right=void 0!==a.right?a.right:j.right,j.bottom=void 0!==a.bottom?a.bottom:j.bottom,j.left=void 0!==a.left?a.left:j.left}},duration:{get:function(){return z},set:function(a){z=a,C.reset(z)}},color:{get:function(){return w},set:function(b){w=a.utils.getColor(b)}},barColor:{get:function(){return y},set:function(b){y=b?a.utils.getColor(b):null}}}),a.utils.initOptions(b),b},a.models.multiBarChart=function(){"use strict";function b(j){return D.reset(),D.models(e),r&&D.models(f),s&&D.models(g),j.each(function(j){var z=d3.select(this);a.utils.initSVG(z);var D=a.utils.availableWidth(l,z,k),H=a.utils.availableHeight(m,z,k);if(b.update=function(){0===C?z.call(b):z.transition().duration(C).call(b)},b.container=this,x.setter(G(j),b.update).getter(F(j)).update(),x.disabled=j.map(function(a){return!!a.disabled}),!y){var I;y={};for(I in x)y[I]=x[I]instanceof Array?x[I].slice(0):x[I]}if(!(j&&j.length&&j.filter(function(a){return a.values.length}).length))return a.utils.noData(b,z),b;z.selectAll(".nv-noData").remove(),c=e.xScale(),d=e.yScale();
var J=z.selectAll("g.nv-wrap.nv-multiBarWithLegend").data([j]),K=J.enter().append("g").attr("class","nvd3 nv-wrap nv-multiBarWithLegend").append("g"),L=J.select("g");if(K.append("g").attr("class","nv-x nv-axis"),K.append("g").attr("class","nv-y nv-axis"),K.append("g").attr("class","nv-barsWrap"),K.append("g").attr("class","nv-legendWrap"),K.append("g").attr("class","nv-controlsWrap"),q&&(h.width(D-B()),L.select(".nv-legendWrap").datum(j).call(h),k.top!=h.height()&&(k.top=h.height(),H=a.utils.availableHeight(m,z,k)),L.select(".nv-legendWrap").attr("transform","translate("+B()+","+-k.top+")")),o){var M=[{key:p.grouped||"Grouped",disabled:e.stacked()},{key:p.stacked||"Stacked",disabled:!e.stacked()}];i.width(B()).color(["#444","#444","#444"]),L.select(".nv-controlsWrap").datum(M).attr("transform","translate(0,"+-k.top+")").call(i)}J.attr("transform","translate("+k.left+","+k.top+")"),t&&L.select(".nv-y.nv-axis").attr("transform","translate("+D+",0)"),e.disabled(j.map(function(a){return a.disabled})).width(D).height(H).color(j.map(function(a,b){return a.color||n(a,b)}).filter(function(a,b){return!j[b].disabled}));var N=L.select(".nv-barsWrap").datum(j.filter(function(a){return!a.disabled}));if(N.call(e),r){f.scale(c)._ticks(a.utils.calcTicksX(D/100,j)).tickSize(-H,0),L.select(".nv-x.nv-axis").attr("transform","translate(0,"+d.range()[0]+")"),L.select(".nv-x.nv-axis").call(f);var O=L.select(".nv-x.nv-axis > g").selectAll("g");if(O.selectAll("line, text").style("opacity",1),v){var P=function(a,b){return"translate("+a+","+b+")"},Q=5,R=17;O.selectAll("text").attr("transform",function(a,b,c){return P(0,c%2==0?Q:R)});var S=d3.selectAll(".nv-x.nv-axis .nv-wrap g g text")[0].length;L.selectAll(".nv-x.nv-axis .nv-axisMaxMin text").attr("transform",function(a,b){return P(0,0===b||S%2!==0?R:Q)})}u&&O.filter(function(a,b){return b%Math.ceil(j[0].values.length/(D/100))!==0}).selectAll("text, line").style("opacity",0),w&&O.selectAll(".tick text").attr("transform","rotate("+w+" 0,0)").style("text-anchor",w>0?"start":"end"),L.select(".nv-x.nv-axis").selectAll("g.nv-axisMaxMin text").style("opacity",1)}s&&(g.scale(d)._ticks(a.utils.calcTicksY(H/36,j)).tickSize(-D,0),L.select(".nv-y.nv-axis").call(g)),h.dispatch.on("stateChange",function(a){for(var c in a)x[c]=a[c];A.stateChange(x),b.update()}),i.dispatch.on("legendClick",function(a){if(a.disabled){switch(M=M.map(function(a){return a.disabled=!0,a}),a.disabled=!1,a.key){case"Grouped":case p.grouped:e.stacked(!1);break;case"Stacked":case p.stacked:e.stacked(!0)}x.stacked=e.stacked(),A.stateChange(x),b.update()}}),A.on("changeState",function(a){"undefined"!=typeof a.disabled&&(j.forEach(function(b,c){b.disabled=a.disabled[c]}),x.disabled=a.disabled),"undefined"!=typeof a.stacked&&(e.stacked(a.stacked),x.stacked=a.stacked,E=a.stacked),b.update()})}),D.renderEnd("multibarchart immediate"),b}var c,d,e=a.models.multiBar(),f=a.models.axis(),g=a.models.axis(),h=a.models.legend(),i=a.models.legend(),j=a.models.tooltip(),k={top:30,right:20,bottom:50,left:60},l=null,m=null,n=a.utils.defaultColor(),o=!0,p={},q=!0,r=!0,s=!0,t=!1,u=!0,v=!1,w=0,x=a.utils.state(),y=null,z=null,A=d3.dispatch("stateChange","changeState","renderEnd"),B=function(){return o?180:0},C=250;x.stacked=!1,e.stacked(!1),f.orient("bottom").tickPadding(7).showMaxMin(!1).tickFormat(function(a){return a}),g.orient(t?"right":"left").tickFormat(d3.format(",.1f")),j.duration(0).valueFormatter(function(a,b){return g.tickFormat()(a,b)}).headerFormatter(function(a,b){return f.tickFormat()(a,b)}),i.updateState(!1);var D=a.utils.renderWatch(A),E=!1,F=function(a){return function(){return{active:a.map(function(a){return!a.disabled}),stacked:E}}},G=function(a){return function(b){void 0!==b.stacked&&(E=b.stacked),void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return e.dispatch.on("elementMouseover.tooltip",function(a){a.value=b.x()(a.data),a.series={key:a.data.key,value:b.y()(a.data),color:a.color},j.data(a).hidden(!1)}),e.dispatch.on("elementMouseout.tooltip",function(){j.hidden(!0)}),e.dispatch.on("elementMousemove.tooltip",function(){j.position({top:d3.event.pageY,left:d3.event.pageX})()}),b.dispatch=A,b.multibar=e,b.legend=h,b.controls=i,b.xAxis=f,b.yAxis=g,b.state=x,b.tooltip=j,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return l},set:function(a){l=a}},height:{get:function(){return m},set:function(a){m=a}},showLegend:{get:function(){return q},set:function(a){q=a}},showControls:{get:function(){return o},set:function(a){o=a}},controlLabels:{get:function(){return p},set:function(a){p=a}},showXAxis:{get:function(){return r},set:function(a){r=a}},showYAxis:{get:function(){return s},set:function(a){s=a}},defaultState:{get:function(){return y},set:function(a){y=a}},noData:{get:function(){return z},set:function(a){z=a}},reduceXTicks:{get:function(){return u},set:function(a){u=a}},rotateLabels:{get:function(){return w},set:function(a){w=a}},staggerLabels:{get:function(){return v},set:function(a){v=a}},tooltips:{get:function(){return j.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),j.enabled(!!b)}},tooltipContent:{get:function(){return j.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),j.contentGenerator(b)}},margin:{get:function(){return k},set:function(a){k.top=void 0!==a.top?a.top:k.top,k.right=void 0!==a.right?a.right:k.right,k.bottom=void 0!==a.bottom?a.bottom:k.bottom,k.left=void 0!==a.left?a.left:k.left}},duration:{get:function(){return C},set:function(a){C=a,e.duration(C),f.duration(C),g.duration(C),D.reset(C)}},color:{get:function(){return n},set:function(b){n=a.utils.getColor(b),h.color(n)}},rightAlignYAxis:{get:function(){return t},set:function(a){t=a,g.orient(t?"right":"left")}},barColor:{get:function(){return e.barColor},set:function(a){e.barColor(a),h.color(function(a,b){return d3.rgb("#ccc").darker(1.5*b).toString()})}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.multiBarHorizontal=function(){"use strict";function b(m){return E.reset(),m.each(function(b){var m=k-j.left-j.right,C=l-j.top-j.bottom;n=d3.select(this),a.utils.initSVG(n),w&&(b=d3.layout.stack().offset("zero").values(function(a){return a.values}).y(r)(b)),b.forEach(function(a,b){a.values.forEach(function(c){c.series=b,c.key=a.key})}),w&&b[0].values.map(function(a,c){var d=0,e=0;b.map(function(a){var b=a.values[c];b.size=Math.abs(b.y),b.y<0?(b.y1=e-b.size,e-=b.size):(b.y1=d,d+=b.size)})});var F=d&&e?[]:b.map(function(a){return a.values.map(function(a,b){return{x:q(a,b),y:r(a,b),y0:a.y0,y1:a.y1}})});o.domain(d||d3.merge(F).map(function(a){return a.x})).rangeBands(f||[0,C],A),p.domain(e||d3.extent(d3.merge(F).map(function(a){return w?a.y>0?a.y1+a.y:a.y1:a.y}).concat(t))),p.range(x&&!w?g||[p.domain()[0]<0?z:0,m-(p.domain()[1]>0?z:0)]:g||[0,m]),h=h||o,i=i||d3.scale.linear().domain(p.domain()).range([p(0),p(0)]);{var G=d3.select(this).selectAll("g.nv-wrap.nv-multibarHorizontal").data([b]),H=G.enter().append("g").attr("class","nvd3 nv-wrap nv-multibarHorizontal"),I=(H.append("defs"),H.append("g"));G.select("g")}I.append("g").attr("class","nv-groups"),G.attr("transform","translate("+j.left+","+j.top+")");var J=G.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a,b){return b});J.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6),J.exit().watchTransition(E,"multibarhorizontal: exit groups").style("stroke-opacity",1e-6).style("fill-opacity",1e-6).remove(),J.attr("class",function(a,b){return"nv-group nv-series-"+b}).classed("hover",function(a){return a.hover}).style("fill",function(a,b){return u(a,b)}).style("stroke",function(a,b){return u(a,b)}),J.watchTransition(E,"multibarhorizontal: groups").style("stroke-opacity",1).style("fill-opacity",.75);var K=J.selectAll("g.nv-bar").data(function(a){return a.values});K.exit().remove();var L=K.enter().append("g").attr("transform",function(a,c,d){return"translate("+i(w?a.y0:0)+","+(w?0:d*o.rangeBand()/b.length+o(q(a,c)))+")"});L.append("rect").attr("width",0).attr("height",o.rangeBand()/(w?1:b.length)),K.on("mouseover",function(a,b){d3.select(this).classed("hover",!0),D.elementMouseover({data:a,index:b,color:d3.select(this).style("fill")})}).on("mouseout",function(a,b){d3.select(this).classed("hover",!1),D.elementMouseout({data:a,index:b,color:d3.select(this).style("fill")})}).on("mouseout",function(a,b){D.elementMouseout({data:a,index:b,color:d3.select(this).style("fill")})}).on("mousemove",function(a,b){D.elementMousemove({data:a,index:b,color:d3.select(this).style("fill")})}).on("click",function(a,b){D.elementClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation()}).on("dblclick",function(a,b){D.elementDblClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation()}),s(b[0],0)&&(L.append("polyline"),K.select("polyline").attr("fill","none").attr("points",function(a,c){var d=s(a,c),e=.8*o.rangeBand()/(2*(w?1:b.length));d=d.length?d:[-Math.abs(d),Math.abs(d)],d=d.map(function(a){return p(a)-p(0)});var f=[[d[0],-e],[d[0],e],[d[0],0],[d[1],0],[d[1],-e],[d[1],e]];return f.map(function(a){return a.join(",")}).join(" ")}).attr("transform",function(a,c){var d=o.rangeBand()/(2*(w?1:b.length));return"translate("+(r(a,c)<0?0:p(r(a,c))-p(0))+", "+d+")"})),L.append("text"),x&&!w?(K.select("text").attr("text-anchor",function(a,b){return r(a,b)<0?"end":"start"}).attr("y",o.rangeBand()/(2*b.length)).attr("dy",".32em").text(function(a,b){var c=B(r(a,b)),d=s(a,b);return void 0===d?c:d.length?c+"+"+B(Math.abs(d[1]))+"-"+B(Math.abs(d[0])):c+"±"+B(Math.abs(d))}),K.watchTransition(E,"multibarhorizontal: bars").select("text").attr("x",function(a,b){return r(a,b)<0?-4:p(r(a,b))-p(0)+4})):K.selectAll("text").text(""),y&&!w?(L.append("text").classed("nv-bar-label",!0),K.select("text.nv-bar-label").attr("text-anchor",function(a,b){return r(a,b)<0?"start":"end"}).attr("y",o.rangeBand()/(2*b.length)).attr("dy",".32em").text(function(a,b){return q(a,b)}),K.watchTransition(E,"multibarhorizontal: bars").select("text.nv-bar-label").attr("x",function(a,b){return r(a,b)<0?p(0)-p(r(a,b))+4:-4})):K.selectAll("text.nv-bar-label").text(""),K.attr("class",function(a,b){return r(a,b)<0?"nv-bar negative":"nv-bar positive"}),v&&(c||(c=b.map(function(){return!0})),K.style("fill",function(a,b,d){return d3.rgb(v(a,b)).darker(c.map(function(a,b){return b}).filter(function(a,b){return!c[b]})[d]).toString()}).style("stroke",function(a,b,d){return d3.rgb(v(a,b)).darker(c.map(function(a,b){return b}).filter(function(a,b){return!c[b]})[d]).toString()})),w?K.watchTransition(E,"multibarhorizontal: bars").attr("transform",function(a,b){return"translate("+p(a.y1)+","+o(q(a,b))+")"}).select("rect").attr("width",function(a,b){return Math.abs(p(r(a,b)+a.y0)-p(a.y0))}).attr("height",o.rangeBand()):K.watchTransition(E,"multibarhorizontal: bars").attr("transform",function(a,c){return"translate("+p(r(a,c)<0?r(a,c):0)+","+(a.series*o.rangeBand()/b.length+o(q(a,c)))+")"}).select("rect").attr("height",o.rangeBand()/b.length).attr("width",function(a,b){return Math.max(Math.abs(p(r(a,b))-p(0)),1)}),h=o.copy(),i=p.copy()}),E.renderEnd("multibarHorizontal immediate"),b}var c,d,e,f,g,h,i,j={top:0,right:0,bottom:0,left:0},k=960,l=500,m=Math.floor(1e4*Math.random()),n=null,o=d3.scale.ordinal(),p=d3.scale.linear(),q=function(a){return a.x},r=function(a){return a.y},s=function(a){return a.yErr},t=[0],u=a.utils.defaultColor(),v=null,w=!1,x=!1,y=!1,z=60,A=.1,B=d3.format(",.2f"),C=250,D=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove","renderEnd"),E=a.utils.renderWatch(D,C);return b.dispatch=D,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return k},set:function(a){k=a}},height:{get:function(){return l},set:function(a){l=a}},x:{get:function(){return q},set:function(a){q=a}},y:{get:function(){return r},set:function(a){r=a}},yErr:{get:function(){return s},set:function(a){s=a}},xScale:{get:function(){return o},set:function(a){o=a}},yScale:{get:function(){return p},set:function(a){p=a}},xDomain:{get:function(){return d},set:function(a){d=a}},yDomain:{get:function(){return e},set:function(a){e=a}},xRange:{get:function(){return f},set:function(a){f=a}},yRange:{get:function(){return g},set:function(a){g=a}},forceY:{get:function(){return t},set:function(a){t=a}},stacked:{get:function(){return w},set:function(a){w=a}},showValues:{get:function(){return x},set:function(a){x=a}},disabled:{get:function(){return c},set:function(a){c=a}},id:{get:function(){return m},set:function(a){m=a}},valueFormat:{get:function(){return B},set:function(a){B=a}},valuePadding:{get:function(){return z},set:function(a){z=a}},groupSpacing:{get:function(){return A},set:function(a){A=a}},margin:{get:function(){return j},set:function(a){j.top=void 0!==a.top?a.top:j.top,j.right=void 0!==a.right?a.right:j.right,j.bottom=void 0!==a.bottom?a.bottom:j.bottom,j.left=void 0!==a.left?a.left:j.left}},duration:{get:function(){return C},set:function(a){C=a,E.reset(C)}},color:{get:function(){return u},set:function(b){u=a.utils.getColor(b)}},barColor:{get:function(){return v},set:function(b){v=b?a.utils.getColor(b):null}}}),a.utils.initOptions(b),b},a.models.multiBarHorizontalChart=function(){"use strict";function b(j){return C.reset(),C.models(e),r&&C.models(f),s&&C.models(g),j.each(function(j){var w=d3.select(this);a.utils.initSVG(w);var C=a.utils.availableWidth(l,w,k),D=a.utils.availableHeight(m,w,k);if(b.update=function(){w.transition().duration(z).call(b)},b.container=this,t=e.stacked(),u.setter(B(j),b.update).getter(A(j)).update(),u.disabled=j.map(function(a){return!!a.disabled}),!v){var E;v={};for(E in u)v[E]=u[E]instanceof Array?u[E].slice(0):u[E]}if(!(j&&j.length&&j.filter(function(a){return a.values.length}).length))return a.utils.noData(b,w),b;w.selectAll(".nv-noData").remove(),c=e.xScale(),d=e.yScale();var F=w.selectAll("g.nv-wrap.nv-multiBarHorizontalChart").data([j]),G=F.enter().append("g").attr("class","nvd3 nv-wrap nv-multiBarHorizontalChart").append("g"),H=F.select("g");if(G.append("g").attr("class","nv-x nv-axis"),G.append("g").attr("class","nv-y nv-axis").append("g").attr("class","nv-zeroLine").append("line"),G.append("g").attr("class","nv-barsWrap"),G.append("g").attr("class","nv-legendWrap"),G.append("g").attr("class","nv-controlsWrap"),q&&(h.width(C-y()),H.select(".nv-legendWrap").datum(j).call(h),k.top!=h.height()&&(k.top=h.height(),D=a.utils.availableHeight(m,w,k)),H.select(".nv-legendWrap").attr("transform","translate("+y()+","+-k.top+")")),o){var I=[{key:p.grouped||"Grouped",disabled:e.stacked()},{key:p.stacked||"Stacked",disabled:!e.stacked()}];i.width(y()).color(["#444","#444","#444"]),H.select(".nv-controlsWrap").datum(I).attr("transform","translate(0,"+-k.top+")").call(i)}F.attr("transform","translate("+k.left+","+k.top+")"),e.disabled(j.map(function(a){return a.disabled})).width(C).height(D).color(j.map(function(a,b){return a.color||n(a,b)}).filter(function(a,b){return!j[b].disabled}));var J=H.select(".nv-barsWrap").datum(j.filter(function(a){return!a.disabled}));if(J.transition().call(e),r){f.scale(c)._ticks(a.utils.calcTicksY(D/24,j)).tickSize(-C,0),H.select(".nv-x.nv-axis").call(f);var K=H.select(".nv-x.nv-axis").selectAll("g");K.selectAll("line, text")}s&&(g.scale(d)._ticks(a.utils.calcTicksX(C/100,j)).tickSize(-D,0),H.select(".nv-y.nv-axis").attr("transform","translate(0,"+D+")"),H.select(".nv-y.nv-axis").call(g)),H.select(".nv-zeroLine line").attr("x1",d(0)).attr("x2",d(0)).attr("y1",0).attr("y2",-D),h.dispatch.on("stateChange",function(a){for(var c in a)u[c]=a[c];x.stateChange(u),b.update()}),i.dispatch.on("legendClick",function(a){if(a.disabled){switch(I=I.map(function(a){return a.disabled=!0,a}),a.disabled=!1,a.key){case"Grouped":e.stacked(!1);break;case"Stacked":e.stacked(!0)}u.stacked=e.stacked(),x.stateChange(u),t=e.stacked(),b.update()}}),x.on("changeState",function(a){"undefined"!=typeof a.disabled&&(j.forEach(function(b,c){b.disabled=a.disabled[c]}),u.disabled=a.disabled),"undefined"!=typeof a.stacked&&(e.stacked(a.stacked),u.stacked=a.stacked,t=a.stacked),b.update()})}),C.renderEnd("multibar horizontal chart immediate"),b}var c,d,e=a.models.multiBarHorizontal(),f=a.models.axis(),g=a.models.axis(),h=a.models.legend().height(30),i=a.models.legend().height(30),j=a.models.tooltip(),k={top:30,right:20,bottom:50,left:60},l=null,m=null,n=a.utils.defaultColor(),o=!0,p={},q=!0,r=!0,s=!0,t=!1,u=a.utils.state(),v=null,w=null,x=d3.dispatch("stateChange","changeState","renderEnd"),y=function(){return o?180:0},z=250;u.stacked=!1,e.stacked(t),f.orient("left").tickPadding(5).showMaxMin(!1).tickFormat(function(a){return a}),g.orient("bottom").tickFormat(d3.format(",.1f")),j.duration(0).valueFormatter(function(a,b){return g.tickFormat()(a,b)}).headerFormatter(function(a,b){return f.tickFormat()(a,b)}),i.updateState(!1);var A=function(a){return function(){return{active:a.map(function(a){return!a.disabled}),stacked:t}}},B=function(a){return function(b){void 0!==b.stacked&&(t=b.stacked),void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}},C=a.utils.renderWatch(x,z);return e.dispatch.on("elementMouseover.tooltip",function(a){a.value=b.x()(a.data),a.series={key:a.data.key,value:b.y()(a.data),color:a.color},j.data(a).hidden(!1)}),e.dispatch.on("elementMouseout.tooltip",function(){j.hidden(!0)}),e.dispatch.on("elementMousemove.tooltip",function(){j.position({top:d3.event.pageY,left:d3.event.pageX})()}),b.dispatch=x,b.multibar=e,b.legend=h,b.controls=i,b.xAxis=f,b.yAxis=g,b.state=u,b.tooltip=j,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return l},set:function(a){l=a}},height:{get:function(){return m},set:function(a){m=a}},showLegend:{get:function(){return q},set:function(a){q=a}},showControls:{get:function(){return o},set:function(a){o=a}},controlLabels:{get:function(){return p},set:function(a){p=a}},showXAxis:{get:function(){return r},set:function(a){r=a}},showYAxis:{get:function(){return s},set:function(a){s=a}},defaultState:{get:function(){return v},set:function(a){v=a}},noData:{get:function(){return w},set:function(a){w=a}},tooltips:{get:function(){return j.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),j.enabled(!!b)}},tooltipContent:{get:function(){return j.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),j.contentGenerator(b)}},margin:{get:function(){return k},set:function(a){k.top=void 0!==a.top?a.top:k.top,k.right=void 0!==a.right?a.right:k.right,k.bottom=void 0!==a.bottom?a.bottom:k.bottom,k.left=void 0!==a.left?a.left:k.left}},duration:{get:function(){return z},set:function(a){z=a,C.reset(z),e.duration(z),f.duration(z),g.duration(z)}},color:{get:function(){return n},set:function(b){n=a.utils.getColor(b),h.color(n)}},barColor:{get:function(){return e.barColor},set:function(a){e.barColor(a),h.color(function(a,b){return d3.rgb("#ccc").darker(1.5*b).toString()})}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.multiChart=function(){"use strict";function b(j){return j.each(function(j){function k(a){var b=2===j[a.seriesIndex].yAxis?z:y;a.value=a.point.x,a.series={value:a.point.y,color:a.point.color},B.duration(100).valueFormatter(function(a,c){return b.tickFormat()(a,c)}).data(a).position(a.pos).hidden(!1)}function l(a){var b=2===j[a.seriesIndex].yAxis?z:y;a.point.x=v.x()(a.point),a.point.y=v.y()(a.point),B.duration(100).valueFormatter(function(a,c){return b.tickFormat()(a,c)}).data(a).position(a.pos).hidden(!1)}function n(a){var b=2===j[a.data.series].yAxis?z:y;a.value=t.x()(a.data),a.series={value:t.y()(a.data),color:a.color},B.duration(0).valueFormatter(function(a,c){return b.tickFormat()(a,c)}).data(a).hidden(!1)}var C=d3.select(this);a.utils.initSVG(C),b.update=function(){C.transition().call(b)},b.container=this;var D=a.utils.availableWidth(g,C,e),E=a.utils.availableHeight(h,C,e),F=j.filter(function(a){return"line"==a.type&&1==a.yAxis}),G=j.filter(function(a){return"line"==a.type&&2==a.yAxis}),H=j.filter(function(a){return"bar"==a.type&&1==a.yAxis}),I=j.filter(function(a){return"bar"==a.type&&2==a.yAxis}),J=j.filter(function(a){return"area"==a.type&&1==a.yAxis}),K=j.filter(function(a){return"area"==a.type&&2==a.yAxis});if(!(j&&j.length&&j.filter(function(a){return a.values.length}).length))return a.utils.noData(b,C),b;C.selectAll(".nv-noData").remove();var L=j.filter(function(a){return!a.disabled&&1==a.yAxis}).map(function(a){return a.values.map(function(a){return{x:a.x,y:a.y}})}),M=j.filter(function(a){return!a.disabled&&2==a.yAxis}).map(function(a){return a.values.map(function(a){return{x:a.x,y:a.y}})});o.domain(d3.extent(d3.merge(L.concat(M)),function(a){return a.x})).range([0,D]);var N=C.selectAll("g.wrap.multiChart").data([j]),O=N.enter().append("g").attr("class","wrap nvd3 multiChart").append("g");O.append("g").attr("class","nv-x nv-axis"),O.append("g").attr("class","nv-y1 nv-axis"),O.append("g").attr("class","nv-y2 nv-axis"),O.append("g").attr("class","lines1Wrap"),O.append("g").attr("class","lines2Wrap"),O.append("g").attr("class","bars1Wrap"),O.append("g").attr("class","bars2Wrap"),O.append("g").attr("class","stack1Wrap"),O.append("g").attr("class","stack2Wrap"),O.append("g").attr("class","legendWrap");var P=N.select("g"),Q=j.map(function(a,b){return j[b].color||f(a,b)});if(i){var R=A.align()?D/2:D,S=A.align()?R:0;A.width(R),A.color(Q),P.select(".legendWrap").datum(j.map(function(a){return a.originalKey=void 0===a.originalKey?a.key:a.originalKey,a.key=a.originalKey+(1==a.yAxis?"":" (right axis)"),a})).call(A),e.top!=A.height()&&(e.top=A.height(),E=a.utils.availableHeight(h,C,e)),P.select(".legendWrap").attr("transform","translate("+S+","+-e.top+")")}r.width(D).height(E).interpolate(m).color(Q.filter(function(a,b){return!j[b].disabled&&1==j[b].yAxis&&"line"==j[b].type})),s.width(D).height(E).interpolate(m).color(Q.filter(function(a,b){return!j[b].disabled&&2==j[b].yAxis&&"line"==j[b].type})),t.width(D).height(E).color(Q.filter(function(a,b){return!j[b].disabled&&1==j[b].yAxis&&"bar"==j[b].type})),u.width(D).height(E).color(Q.filter(function(a,b){return!j[b].disabled&&2==j[b].yAxis&&"bar"==j[b].type})),v.width(D).height(E).color(Q.filter(function(a,b){return!j[b].disabled&&1==j[b].yAxis&&"area"==j[b].type})),w.width(D).height(E).color(Q.filter(function(a,b){return!j[b].disabled&&2==j[b].yAxis&&"area"==j[b].type})),P.attr("transform","translate("+e.left+","+e.top+")");var T=P.select(".lines1Wrap").datum(F.filter(function(a){return!a.disabled})),U=P.select(".bars1Wrap").datum(H.filter(function(a){return!a.disabled})),V=P.select(".stack1Wrap").datum(J.filter(function(a){return!a.disabled})),W=P.select(".lines2Wrap").datum(G.filter(function(a){return!a.disabled})),X=P.select(".bars2Wrap").datum(I.filter(function(a){return!a.disabled})),Y=P.select(".stack2Wrap").datum(K.filter(function(a){return!a.disabled})),Z=J.length?J.map(function(a){return a.values}).reduce(function(a,b){return a.map(function(a,c){return{x:a.x,y:a.y+b[c].y}})}).concat([{x:0,y:0}]):[],$=K.length?K.map(function(a){return a.values}).reduce(function(a,b){return a.map(function(a,c){return{x:a.x,y:a.y+b[c].y}})}).concat([{x:0,y:0}]):[];p.domain(c||d3.extent(d3.merge(L).concat(Z),function(a){return a.y})).range([0,E]),q.domain(d||d3.extent(d3.merge(M).concat($),function(a){return a.y})).range([0,E]),r.yDomain(p.domain()),t.yDomain(p.domain()),v.yDomain(p.domain()),s.yDomain(q.domain()),u.yDomain(q.domain()),w.yDomain(q.domain()),J.length&&d3.transition(V).call(v),K.length&&d3.transition(Y).call(w),H.length&&d3.transition(U).call(t),I.length&&d3.transition(X).call(u),F.length&&d3.transition(T).call(r),G.length&&d3.transition(W).call(s),x._ticks(a.utils.calcTicksX(D/100,j)).tickSize(-E,0),P.select(".nv-x.nv-axis").attr("transform","translate(0,"+E+")"),d3.transition(P.select(".nv-x.nv-axis")).call(x),y._ticks(a.utils.calcTicksY(E/36,j)).tickSize(-D,0),d3.transition(P.select(".nv-y1.nv-axis")).call(y),z._ticks(a.utils.calcTicksY(E/36,j)).tickSize(-D,0),d3.transition(P.select(".nv-y2.nv-axis")).call(z),P.select(".nv-y1.nv-axis").classed("nv-disabled",L.length?!1:!0).attr("transform","translate("+o.range()[0]+",0)"),P.select(".nv-y2.nv-axis").classed("nv-disabled",M.length?!1:!0).attr("transform","translate("+o.range()[1]+",0)"),A.dispatch.on("stateChange",function(){b.update()}),r.dispatch.on("elementMouseover.tooltip",k),s.dispatch.on("elementMouseover.tooltip",k),r.dispatch.on("elementMouseout.tooltip",function(){B.hidden(!0)}),s.dispatch.on("elementMouseout.tooltip",function(){B.hidden(!0)}),v.dispatch.on("elementMouseover.tooltip",l),w.dispatch.on("elementMouseover.tooltip",l),v.dispatch.on("elementMouseout.tooltip",function(){B.hidden(!0)}),w.dispatch.on("elementMouseout.tooltip",function(){B.hidden(!0)}),t.dispatch.on("elementMouseover.tooltip",n),u.dispatch.on("elementMouseover.tooltip",n),t.dispatch.on("elementMouseout.tooltip",function(){B.hidden(!0)}),u.dispatch.on("elementMouseout.tooltip",function(){B.hidden(!0)}),t.dispatch.on("elementMousemove.tooltip",function(){B.position({top:d3.event.pageY,left:d3.event.pageX})()}),u.dispatch.on("elementMousemove.tooltip",function(){B.position({top:d3.event.pageY,left:d3.event.pageX})()})}),b}var c,d,e={top:30,right:20,bottom:50,left:60},f=a.utils.defaultColor(),g=null,h=null,i=!0,j=null,k=function(a){return a.x},l=function(a){return a.y},m="monotone",n=!0,o=d3.scale.linear(),p=d3.scale.linear(),q=d3.scale.linear(),r=a.models.line().yScale(p),s=a.models.line().yScale(q),t=a.models.multiBar().stacked(!1).yScale(p),u=a.models.multiBar().stacked(!1).yScale(q),v=a.models.stackedArea().yScale(p),w=a.models.stackedArea().yScale(q),x=a.models.axis().scale(o).orient("bottom").tickPadding(5),y=a.models.axis().scale(p).orient("left"),z=a.models.axis().scale(q).orient("right"),A=a.models.legend().height(30),B=a.models.tooltip(),C=d3.dispatch();return b.dispatch=C,b.lines1=r,b.lines2=s,b.bars1=t,b.bars2=u,b.stack1=v,b.stack2=w,b.xAxis=x,b.yAxis1=y,b.yAxis2=z,b.tooltip=B,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return g},set:function(a){g=a}},height:{get:function(){return h},set:function(a){h=a}},showLegend:{get:function(){return i},set:function(a){i=a}},yDomain1:{get:function(){return c},set:function(a){c=a}},yDomain2:{get:function(){return d},set:function(a){d=a}},noData:{get:function(){return j},set:function(a){j=a}},interpolate:{get:function(){return m},set:function(a){m=a}},tooltips:{get:function(){return B.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),B.enabled(!!b)}},tooltipContent:{get:function(){return B.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),B.contentGenerator(b)}},margin:{get:function(){return e},set:function(a){e.top=void 0!==a.top?a.top:e.top,e.right=void 0!==a.right?a.right:e.right,e.bottom=void 0!==a.bottom?a.bottom:e.bottom,e.left=void 0!==a.left?a.left:e.left}},color:{get:function(){return f},set:function(b){f=a.utils.getColor(b)}},x:{get:function(){return k},set:function(a){k=a,r.x(a),s.x(a),t.x(a),u.x(a),v.x(a),w.x(a)}},y:{get:function(){return l},set:function(a){l=a,r.y(a),s.y(a),v.y(a),w.y(a),t.y(a),u.y(a)}},useVoronoi:{get:function(){return n},set:function(a){n=a,r.useVoronoi(a),s.useVoronoi(a),v.useVoronoi(a),w.useVoronoi(a)}}}),a.utils.initOptions(b),b},a.models.ohlcBar=function(){"use strict";function b(y){return y.each(function(b){k=d3.select(this);var y=a.utils.availableWidth(h,k,g),A=a.utils.availableHeight(i,k,g);a.utils.initSVG(k);var B=y/b[0].values.length*.9;l.domain(c||d3.extent(b[0].values.map(n).concat(t))),l.range(v?e||[.5*y/b[0].values.length,y*(b[0].values.length-.5)/b[0].values.length]:e||[5+B/2,y-B/2-5]),m.domain(d||[d3.min(b[0].values.map(s).concat(u)),d3.max(b[0].values.map(r).concat(u))]).range(f||[A,0]),l.domain()[0]===l.domain()[1]&&l.domain(l.domain()[0]?[l.domain()[0]-.01*l.domain()[0],l.domain()[1]+.01*l.domain()[1]]:[-1,1]),m.domain()[0]===m.domain()[1]&&m.domain(m.domain()[0]?[m.domain()[0]+.01*m.domain()[0],m.domain()[1]-.01*m.domain()[1]]:[-1,1]);var C=d3.select(this).selectAll("g.nv-wrap.nv-ohlcBar").data([b[0].values]),D=C.enter().append("g").attr("class","nvd3 nv-wrap nv-ohlcBar"),E=D.append("defs"),F=D.append("g"),G=C.select("g");F.append("g").attr("class","nv-ticks"),C.attr("transform","translate("+g.left+","+g.top+")"),k.on("click",function(a,b){z.chartClick({data:a,index:b,pos:d3.event,id:j})}),E.append("clipPath").attr("id","nv-chart-clip-path-"+j).append("rect"),C.select("#nv-chart-clip-path-"+j+" rect").attr("width",y).attr("height",A),G.attr("clip-path",w?"url(#nv-chart-clip-path-"+j+")":"");var H=C.select(".nv-ticks").selectAll(".nv-tick").data(function(a){return a});H.exit().remove(),H.enter().append("path").attr("class",function(a,b,c){return(p(a,b)>q(a,b)?"nv-tick negative":"nv-tick positive")+" nv-tick-"+c+"-"+b}).attr("d",function(a,b){return"m0,0l0,"+(m(p(a,b))-m(r(a,b)))+"l"+-B/2+",0l"+B/2+",0l0,"+(m(s(a,b))-m(p(a,b)))+"l0,"+(m(q(a,b))-m(s(a,b)))+"l"+B/2+",0l"+-B/2+",0z"}).attr("transform",function(a,b){return"translate("+l(n(a,b))+","+m(r(a,b))+")"}).attr("fill",function(){return x[0]}).attr("stroke",function(){return x[0]}).attr("x",0).attr("y",function(a,b){return m(Math.max(0,o(a,b)))}).attr("height",function(a,b){return Math.abs(m(o(a,b))-m(0))}),H.attr("class",function(a,b,c){return(p(a,b)>q(a,b)?"nv-tick negative":"nv-tick positive")+" nv-tick-"+c+"-"+b}),d3.transition(H).attr("transform",function(a,b){return"translate("+l(n(a,b))+","+m(r(a,b))+")"}).attr("d",function(a,c){var d=y/b[0].values.length*.9;return"m0,0l0,"+(m(p(a,c))-m(r(a,c)))+"l"+-d/2+",0l"+d/2+",0l0,"+(m(s(a,c))-m(p(a,c)))+"l0,"+(m(q(a,c))-m(s(a,c)))+"l"+d/2+",0l"+-d/2+",0z"})}),b}var c,d,e,f,g={top:0,right:0,bottom:0,left:0},h=null,i=null,j=Math.floor(1e4*Math.random()),k=null,l=d3.scale.linear(),m=d3.scale.linear(),n=function(a){return a.x},o=function(a){return a.y},p=function(a){return a.open},q=function(a){return a.close},r=function(a){return a.high},s=function(a){return a.low},t=[],u=[],v=!1,w=!0,x=a.utils.defaultColor(),y=!1,z=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd","chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove");return b.highlightPoint=function(a,c){b.clearHighlights(),k.select(".nv-ohlcBar .nv-tick-0-"+a).classed("hover",c)},b.clearHighlights=function(){k.select(".nv-ohlcBar .nv-tick.hover").classed("hover",!1)},b.dispatch=z,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return h},set:function(a){h=a}},height:{get:function(){return i},set:function(a){i=a}},xScale:{get:function(){return l},set:function(a){l=a}},yScale:{get:function(){return m},set:function(a){m=a}},xDomain:{get:function(){return c},set:function(a){c=a}},yDomain:{get:function(){return d},set:function(a){d=a}},xRange:{get:function(){return e},set:function(a){e=a}},yRange:{get:function(){return f},set:function(a){f=a}},forceX:{get:function(){return t},set:function(a){t=a}},forceY:{get:function(){return u},set:function(a){u=a}},padData:{get:function(){return v},set:function(a){v=a}},clipEdge:{get:function(){return w},set:function(a){w=a}},id:{get:function(){return j},set:function(a){j=a}},interactive:{get:function(){return y},set:function(a){y=a}},x:{get:function(){return n},set:function(a){n=a}},y:{get:function(){return o},set:function(a){o=a}},open:{get:function(){return p()},set:function(a){p=a}},close:{get:function(){return q()},set:function(a){q=a}},high:{get:function(){return r},set:function(a){r=a}},low:{get:function(){return s},set:function(a){s=a}},margin:{get:function(){return g},set:function(a){g.top=void 0!=a.top?a.top:g.top,g.right=void 0!=a.right?a.right:g.right,g.bottom=void 0!=a.bottom?a.bottom:g.bottom,g.left=void 0!=a.left?a.left:g.left
}},color:{get:function(){return x},set:function(b){x=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.parallelCoordinates=function(){"use strict";function b(p){return p.each(function(b){function p(a){return F(h.map(function(b){if(isNaN(a[b])||isNaN(parseFloat(a[b]))){var c=g[b].domain(),d=g[b].range(),e=c[0]-(c[1]-c[0])/9;if(J.indexOf(b)<0){var h=d3.scale.linear().domain([e,c[1]]).range([x-12,d[1]]);g[b].brush.y(h),J.push(b)}return[f(b),g[b](e)]}return J.length>0?(D.style("display","inline"),E.style("display","inline")):(D.style("display","none"),E.style("display","none")),[f(b),g[b](a[b])]}))}function q(){var a=h.filter(function(a){return!g[a].brush.empty()}),b=a.map(function(a){return g[a].brush.extent()});k=[],a.forEach(function(a,c){k[c]={dimension:a,extent:b[c]}}),l=[],M.style("display",function(c){var d=a.every(function(a,d){return isNaN(c[a])&&b[d][0]==g[a].brush.y().domain()[0]?!0:b[d][0]<=c[a]&&c[a]<=b[d][1]});return d&&l.push(c),d?null:"none"}),o.brush({filters:k,active:l})}function r(a){m[a]=this.parentNode.__origin__=f(a),L.attr("visibility","hidden")}function s(a){m[a]=Math.min(w,Math.max(0,this.parentNode.__origin__+=d3.event.x)),M.attr("d",p),h.sort(function(a,b){return u(a)-u(b)}),f.domain(h),N.attr("transform",function(a){return"translate("+u(a)+")"})}function t(a){delete this.parentNode.__origin__,delete m[a],d3.select(this.parentNode).attr("transform","translate("+f(a)+")"),M.attr("d",p),L.attr("d",p).attr("visibility",null)}function u(a){var b=m[a];return null==b?f(a):b}var v=d3.select(this),w=a.utils.availableWidth(d,v,c),x=a.utils.availableHeight(e,v,c);a.utils.initSVG(v),l=b,f.rangePoints([0,w],1).domain(h);var y={};h.forEach(function(a){var c=d3.extent(b,function(b){return+b[a]});return y[a]=!1,void 0===c[0]&&(y[a]=!0,c[0]=0,c[1]=0),c[0]===c[1]&&(c[0]=c[0]-1,c[1]=c[1]+1),g[a]=d3.scale.linear().domain(c).range([.9*(x-12),0]),g[a].brush=d3.svg.brush().y(g[a]).on("brush",q),"name"!=a});var z=v.selectAll("g.nv-wrap.nv-parallelCoordinates").data([b]),A=z.enter().append("g").attr("class","nvd3 nv-wrap nv-parallelCoordinates"),B=A.append("g"),C=z.select("g");B.append("g").attr("class","nv-parallelCoordinates background"),B.append("g").attr("class","nv-parallelCoordinates foreground"),B.append("g").attr("class","nv-parallelCoordinates missingValuesline"),z.attr("transform","translate("+c.left+","+c.top+")");var D,E,F=d3.svg.line().interpolate("cardinal").tension(n),G=d3.svg.axis().orient("left"),H=d3.behavior.drag().on("dragstart",r).on("drag",s).on("dragend",t),I=f.range()[1]-f.range()[0],J=[],K=[0+I/2,x-12,w-I/2,x-12];D=z.select(".missingValuesline").selectAll("line").data([K]),D.enter().append("line"),D.exit().remove(),D.attr("x1",function(a){return a[0]}).attr("y1",function(a){return a[1]}).attr("x2",function(a){return a[2]}).attr("y2",function(a){return a[3]}),E=z.select(".missingValuesline").selectAll("text").data(["undefined values"]),E.append("text").data(["undefined values"]),E.enter().append("text"),E.exit().remove(),E.attr("y",x).attr("x",w-92-I/2).text(function(a){return a});var L=z.select(".background").selectAll("path").data(b);L.enter().append("path"),L.exit().remove(),L.attr("d",p);var M=z.select(".foreground").selectAll("path").data(b);M.enter().append("path"),M.exit().remove(),M.attr("d",p).attr("stroke",j),M.on("mouseover",function(a,b){d3.select(this).classed("hover",!0),o.elementMouseover({label:a.name,data:a.data,index:b,pos:[d3.mouse(this.parentNode)[0],d3.mouse(this.parentNode)[1]]})}),M.on("mouseout",function(a,b){d3.select(this).classed("hover",!1),o.elementMouseout({label:a.name,data:a.data,index:b})});var N=C.selectAll(".dimension").data(h),O=N.enter().append("g").attr("class","nv-parallelCoordinates dimension");O.append("g").attr("class","nv-parallelCoordinates nv-axis"),O.append("g").attr("class","nv-parallelCoordinates-brush"),O.append("text").attr("class","nv-parallelCoordinates nv-label"),N.attr("transform",function(a){return"translate("+f(a)+",0)"}),N.exit().remove(),N.select(".nv-label").style("cursor","move").attr("dy","-1em").attr("text-anchor","middle").text(String).on("mouseover",function(a){o.elementMouseover({dim:a,pos:[d3.mouse(this.parentNode.parentNode)[0],d3.mouse(this.parentNode.parentNode)[1]]})}).on("mouseout",function(a){o.elementMouseout({dim:a})}).call(H),N.select(".nv-axis").each(function(a,b){d3.select(this).call(G.scale(g[a]).tickFormat(d3.format(i[b])))}),N.select(".nv-parallelCoordinates-brush").each(function(a){d3.select(this).call(g[a].brush)}).selectAll("rect").attr("x",-8).attr("width",16)}),b}var c={top:30,right:0,bottom:10,left:0},d=null,e=null,f=d3.scale.ordinal(),g={},h=[],i=[],j=a.utils.defaultColor(),k=[],l=[],m=[],n=1,o=d3.dispatch("brush","elementMouseover","elementMouseout");return b.dispatch=o,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return d},set:function(a){d=a}},height:{get:function(){return e},set:function(a){e=a}},dimensionNames:{get:function(){return h},set:function(a){h=a}},dimensionFormats:{get:function(){return i},set:function(a){i=a}},lineTension:{get:function(){return n},set:function(a){n=a}},dimensions:{get:function(){return h},set:function(b){a.deprecated("dimensions","use dimensionNames instead"),h=b}},margin:{get:function(){return c},set:function(a){c.top=void 0!==a.top?a.top:c.top,c.right=void 0!==a.right?a.right:c.right,c.bottom=void 0!==a.bottom?a.bottom:c.bottom,c.left=void 0!==a.left?a.left:c.left}},color:{get:function(){return j},set:function(b){j=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.pie=function(){"use strict";function b(E){return D.reset(),E.each(function(b){function E(a,b){a.endAngle=isNaN(a.endAngle)?0:a.endAngle,a.startAngle=isNaN(a.startAngle)?0:a.startAngle,p||(a.innerRadius=0);var c=d3.interpolate(this._current,a);return this._current=c(0),function(a){return B[b](c(a))}}var F=d-c.left-c.right,G=e-c.top-c.bottom,H=Math.min(F,G)/2,I=[],J=[];if(i=d3.select(this),0===z.length)for(var K=H-H/5,L=y*H,M=0;M<b[0].length;M++)I.push(K),J.push(L);else I=z.map(function(a){return(a.outer-a.outer/5)*H}),J=z.map(function(a){return(a.inner-a.inner/5)*H}),y=d3.min(z.map(function(a){return a.inner-a.inner/5}));a.utils.initSVG(i);var N=i.selectAll(".nv-wrap.nv-pie").data(b),O=N.enter().append("g").attr("class","nvd3 nv-wrap nv-pie nv-chart-"+h),P=O.append("g"),Q=N.select("g"),R=P.append("g").attr("class","nv-pie");P.append("g").attr("class","nv-pieLabels"),N.attr("transform","translate("+c.left+","+c.top+")"),Q.select(".nv-pie").attr("transform","translate("+F/2+","+G/2+")"),Q.select(".nv-pieLabels").attr("transform","translate("+F/2+","+G/2+")"),i.on("click",function(a,b){A.chartClick({data:a,index:b,pos:d3.event,id:h})}),B=[],C=[];for(var M=0;M<b[0].length;M++){var S=d3.svg.arc().outerRadius(I[M]),T=d3.svg.arc().outerRadius(I[M]+5);u!==!1&&(S.startAngle(u),T.startAngle(u)),w!==!1&&(S.endAngle(w),T.endAngle(w)),p&&(S.innerRadius(J[M]),T.innerRadius(J[M])),S.cornerRadius&&x&&(S.cornerRadius(x),T.cornerRadius(x)),B.push(S),C.push(T)}var U=d3.layout.pie().sort(null).value(function(a){return a.disabled?0:g(a)});U.padAngle&&v&&U.padAngle(v),p&&q&&(R.append("text").attr("class","nv-pie-title"),N.select(".nv-pie-title").style("text-anchor","middle").text(function(){return q}).style("font-size",Math.min(F,G)*y*2/(q.length+2)+"px").attr("dy","0.35em").attr("transform",function(){return"translate(0, "+s+")"}));var V=N.select(".nv-pie").selectAll(".nv-slice").data(U),W=N.select(".nv-pieLabels").selectAll(".nv-label").data(U);V.exit().remove(),W.exit().remove();var X=V.enter().append("g");X.attr("class","nv-slice"),X.on("mouseover",function(a,b){d3.select(this).classed("hover",!0),r&&d3.select(this).select("path").transition().duration(70).attr("d",C[b]),A.elementMouseover({data:a.data,index:b,color:d3.select(this).style("fill")})}),X.on("mouseout",function(a,b){d3.select(this).classed("hover",!1),r&&d3.select(this).select("path").transition().duration(50).attr("d",B[b]),A.elementMouseout({data:a.data,index:b})}),X.on("mousemove",function(a,b){A.elementMousemove({data:a.data,index:b})}),X.on("click",function(a,b){A.elementClick({data:a.data,index:b,color:d3.select(this).style("fill")})}),X.on("dblclick",function(a,b){A.elementDblClick({data:a.data,index:b,color:d3.select(this).style("fill")})}),V.attr("fill",function(a,b){return j(a.data,b)}),V.attr("stroke",function(a,b){return j(a.data,b)});X.append("path").each(function(a){this._current=a});if(V.select("path").transition().attr("d",function(a,b){return B[b](a)}).attrTween("d",E),l){for(var Y=[],M=0;M<b[0].length;M++)Y.push(B[M]),m?p&&(Y[M]=d3.svg.arc().outerRadius(B[M].outerRadius()),u!==!1&&Y[M].startAngle(u),w!==!1&&Y[M].endAngle(w)):p||Y[M].innerRadius(0);W.enter().append("g").classed("nv-label",!0).each(function(a){var b=d3.select(this);b.attr("transform",function(a,b){if(t){a.outerRadius=I[b]+10,a.innerRadius=I[b]+15;var c=(a.startAngle+a.endAngle)/2*(180/Math.PI);return(a.startAngle+a.endAngle)/2<Math.PI?c-=90:c+=90,"translate("+Y[b].centroid(a)+") rotate("+c+")"}return a.outerRadius=H+10,a.innerRadius=H+15,"translate("+Y[b].centroid(a)+")"}),b.append("rect").style("stroke","#fff").style("fill","#fff").attr("rx",3).attr("ry",3),b.append("text").style("text-anchor",t?(a.startAngle+a.endAngle)/2<Math.PI?"start":"end":"middle").style("fill","#000")});var Z={},$=14,_=140,ab=function(a){return Math.floor(a[0]/_)*_+","+Math.floor(a[1]/$)*$};W.watchTransition(D,"pie labels").attr("transform",function(a,b){if(t){a.outerRadius=I[b]+10,a.innerRadius=I[b]+15;var c=(a.startAngle+a.endAngle)/2*(180/Math.PI);return(a.startAngle+a.endAngle)/2<Math.PI?c-=90:c+=90,"translate("+Y[b].centroid(a)+") rotate("+c+")"}a.outerRadius=H+10,a.innerRadius=H+15;var d=Y[b].centroid(a);if(a.value){var e=ab(d);Z[e]&&(d[1]-=$),Z[ab(d)]=!0}return"translate("+d+")"}),W.select(".nv-label text").style("text-anchor",function(a){return t?(a.startAngle+a.endAngle)/2<Math.PI?"start":"end":"middle"}).text(function(a,b){var c=(a.endAngle-a.startAngle)/(2*Math.PI),d="";if(!a.value||o>c)return"";if("function"==typeof n)d=n(a,b,{key:f(a.data),value:g(a.data),percent:k(c)});else switch(n){case"key":d=f(a.data);break;case"value":d=k(g(a.data));break;case"percent":d=d3.format("%")(c)}return d})}}),D.renderEnd("pie immediate"),b}var c={top:0,right:0,bottom:0,left:0},d=500,e=500,f=function(a){return a.x},g=function(a){return a.y},h=Math.floor(1e4*Math.random()),i=null,j=a.utils.defaultColor(),k=d3.format(",.2f"),l=!0,m=!1,n="key",o=.02,p=!1,q=!1,r=!0,s=0,t=!1,u=!1,v=!1,w=!1,x=0,y=.5,z=[],A=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove","renderEnd"),B=[],C=[],D=a.utils.renderWatch(A);return b.dispatch=A,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{arcsRadius:{get:function(){return z},set:function(a){z=a}},width:{get:function(){return d},set:function(a){d=a}},height:{get:function(){return e},set:function(a){e=a}},showLabels:{get:function(){return l},set:function(a){l=a}},title:{get:function(){return q},set:function(a){q=a}},titleOffset:{get:function(){return s},set:function(a){s=a}},labelThreshold:{get:function(){return o},set:function(a){o=a}},valueFormat:{get:function(){return k},set:function(a){k=a}},x:{get:function(){return f},set:function(a){f=a}},id:{get:function(){return h},set:function(a){h=a}},endAngle:{get:function(){return w},set:function(a){w=a}},startAngle:{get:function(){return u},set:function(a){u=a}},padAngle:{get:function(){return v},set:function(a){v=a}},cornerRadius:{get:function(){return x},set:function(a){x=a}},donutRatio:{get:function(){return y},set:function(a){y=a}},labelsOutside:{get:function(){return m},set:function(a){m=a}},labelSunbeamLayout:{get:function(){return t},set:function(a){t=a}},donut:{get:function(){return p},set:function(a){p=a}},growOnHover:{get:function(){return r},set:function(a){r=a}},pieLabelsOutside:{get:function(){return m},set:function(b){m=b,a.deprecated("pieLabelsOutside","use labelsOutside instead")}},donutLabelsOutside:{get:function(){return m},set:function(b){m=b,a.deprecated("donutLabelsOutside","use labelsOutside instead")}},labelFormat:{get:function(){return k},set:function(b){k=b,a.deprecated("labelFormat","use valueFormat instead")}},margin:{get:function(){return c},set:function(a){c.top="undefined"!=typeof a.top?a.top:c.top,c.right="undefined"!=typeof a.right?a.right:c.right,c.bottom="undefined"!=typeof a.bottom?a.bottom:c.bottom,c.left="undefined"!=typeof a.left?a.left:c.left}},y:{get:function(){return g},set:function(a){g=d3.functor(a)}},color:{get:function(){return j},set:function(b){j=a.utils.getColor(b)}},labelType:{get:function(){return n},set:function(a){n=a||"key"}}}),a.utils.initOptions(b),b},a.models.pieChart=function(){"use strict";function b(e){return q.reset(),q.models(c),e.each(function(e){var k=d3.select(this);a.utils.initSVG(k);var n=a.utils.availableWidth(g,k,f),o=a.utils.availableHeight(h,k,f);if(b.update=function(){k.transition().call(b)},b.container=this,l.setter(s(e),b.update).getter(r(e)).update(),l.disabled=e.map(function(a){return!!a.disabled}),!m){var q;m={};for(q in l)m[q]=l[q]instanceof Array?l[q].slice(0):l[q]}if(!e||!e.length)return a.utils.noData(b,k),b;k.selectAll(".nv-noData").remove();var t=k.selectAll("g.nv-wrap.nv-pieChart").data([e]),u=t.enter().append("g").attr("class","nvd3 nv-wrap nv-pieChart").append("g"),v=t.select("g");if(u.append("g").attr("class","nv-pieWrap"),u.append("g").attr("class","nv-legendWrap"),i)if("top"===j)d.width(n).key(c.x()),t.select(".nv-legendWrap").datum(e).call(d),f.top!=d.height()&&(f.top=d.height(),o=a.utils.availableHeight(h,k,f)),t.select(".nv-legendWrap").attr("transform","translate(0,"+-f.top+")");else if("right"===j){var w=a.models.legend().width();w>n/2&&(w=n/2),d.height(o).key(c.x()),d.width(w),n-=d.width(),t.select(".nv-legendWrap").datum(e).call(d).attr("transform","translate("+n+",0)")}t.attr("transform","translate("+f.left+","+f.top+")"),c.width(n).height(o);var x=v.select(".nv-pieWrap").datum([e]);d3.transition(x).call(c),d.dispatch.on("stateChange",function(a){for(var c in a)l[c]=a[c];p.stateChange(l),b.update()}),p.on("changeState",function(a){"undefined"!=typeof a.disabled&&(e.forEach(function(b,c){b.disabled=a.disabled[c]}),l.disabled=a.disabled),b.update()})}),q.renderEnd("pieChart immediate"),b}var c=a.models.pie(),d=a.models.legend(),e=a.models.tooltip(),f={top:30,right:20,bottom:20,left:20},g=null,h=null,i=!0,j="top",k=a.utils.defaultColor(),l=a.utils.state(),m=null,n=null,o=250,p=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd");e.headerEnabled(!1).duration(0).valueFormatter(function(a,b){return c.valueFormat()(a,b)});var q=a.utils.renderWatch(p),r=function(a){return function(){return{active:a.map(function(a){return!a.disabled})}}},s=function(a){return function(b){void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return c.dispatch.on("elementMouseover.tooltip",function(a){a.series={key:b.x()(a.data),value:b.y()(a.data),color:a.color},e.data(a).hidden(!1)}),c.dispatch.on("elementMouseout.tooltip",function(){e.hidden(!0)}),c.dispatch.on("elementMousemove.tooltip",function(){e.position({top:d3.event.pageY,left:d3.event.pageX})()}),b.legend=d,b.dispatch=p,b.pie=c,b.tooltip=e,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{noData:{get:function(){return n},set:function(a){n=a}},showLegend:{get:function(){return i},set:function(a){i=a}},legendPosition:{get:function(){return j},set:function(a){j=a}},defaultState:{get:function(){return m},set:function(a){m=a}},tooltips:{get:function(){return e.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),e.enabled(!!b)}},tooltipContent:{get:function(){return e.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),e.contentGenerator(b)}},color:{get:function(){return k},set:function(a){k=a,d.color(k),c.color(k)}},duration:{get:function(){return o},set:function(a){o=a,q.reset(o)}},margin:{get:function(){return f},set:function(a){f.top=void 0!==a.top?a.top:f.top,f.right=void 0!==a.right?a.right:f.right,f.bottom=void 0!==a.bottom?a.bottom:f.bottom,f.left=void 0!==a.left?a.left:f.left}}}),a.utils.inheritOptions(b,c),a.utils.initOptions(b),b},a.models.scatter=function(){"use strict";function b(N){return P.reset(),N.each(function(b){function N(){if(O=!1,!w)return!1;if(M===!0){var a=d3.merge(b.map(function(a,b){return a.values.map(function(a,c){var d=p(a,c),e=q(a,c);return[m(d)+1e-4*Math.random(),n(e)+1e-4*Math.random(),b,c,a]}).filter(function(a,b){return x(a[4],b)})}));if(0==a.length)return!1;a.length<3&&(a.push([m.range()[0]-20,n.range()[0]-20,null,null]),a.push([m.range()[1]+20,n.range()[1]+20,null,null]),a.push([m.range()[0]-20,n.range()[0]+20,null,null]),a.push([m.range()[1]+20,n.range()[1]-20,null,null]));var c=d3.geom.polygon([[-10,-10],[-10,i+10],[h+10,i+10],[h+10,-10]]),d=d3.geom.voronoi(a).map(function(b,d){return{data:c.clip(b),series:a[d][2],point:a[d][3]}});U.select(".nv-point-paths").selectAll("path").remove();var e=U.select(".nv-point-paths").selectAll("path").data(d),f=e.enter().append("svg:path").attr("d",function(a){return a&&a.data&&0!==a.data.length?"M"+a.data.join(",")+"Z":"M 0 0"}).attr("id",function(a,b){return"nv-path-"+b}).attr("clip-path",function(a,b){return"url(#nv-clip-"+b+")"});C&&f.style("fill",d3.rgb(230,230,230)).style("fill-opacity",.4).style("stroke-opacity",1).style("stroke",d3.rgb(200,200,200)),B&&(U.select(".nv-point-clips").selectAll("clipPath").remove(),U.select(".nv-point-clips").selectAll("clipPath").data(a).enter().append("svg:clipPath").attr("id",function(a,b){return"nv-clip-"+b}).append("svg:circle").attr("cx",function(a){return a[0]}).attr("cy",function(a){return a[1]}).attr("r",D));var k=function(a,c){if(O)return 0;var d=b[a.series];if(void 0!==d){var e=d.values[a.point];e.color=j(d,a.series),e.x=p(e),e.y=q(e);var f=l.node().getBoundingClientRect(),h=window.pageYOffset||document.documentElement.scrollTop,i=window.pageXOffset||document.documentElement.scrollLeft,k={left:m(p(e,a.point))+f.left+i+g.left+10,top:n(q(e,a.point))+f.top+h+g.top+10};c({point:e,series:d,pos:k,seriesIndex:a.series,pointIndex:a.point})}};e.on("click",function(a){k(a,L.elementClick)}).on("dblclick",function(a){k(a,L.elementDblClick)}).on("mouseover",function(a){k(a,L.elementMouseover)}).on("mouseout",function(a){k(a,L.elementMouseout)})}else U.select(".nv-groups").selectAll(".nv-group").selectAll(".nv-point").on("click",function(a,c){if(O||!b[a.series])return 0;var d=b[a.series],e=d.values[c];L.elementClick({point:e,series:d,pos:[m(p(e,c))+g.left,n(q(e,c))+g.top],seriesIndex:a.series,pointIndex:c})}).on("dblclick",function(a,c){if(O||!b[a.series])return 0;var d=b[a.series],e=d.values[c];L.elementDblClick({point:e,series:d,pos:[m(p(e,c))+g.left,n(q(e,c))+g.top],seriesIndex:a.series,pointIndex:c})}).on("mouseover",function(a,c){if(O||!b[a.series])return 0;var d=b[a.series],e=d.values[c];L.elementMouseover({point:e,series:d,pos:[m(p(e,c))+g.left,n(q(e,c))+g.top],seriesIndex:a.series,pointIndex:c,color:j(a,c)})}).on("mouseout",function(a,c){if(O||!b[a.series])return 0;var d=b[a.series],e=d.values[c];L.elementMouseout({point:e,series:d,seriesIndex:a.series,pointIndex:c,color:j(a,c)})})}l=d3.select(this);var R=a.utils.availableWidth(h,l,g),S=a.utils.availableHeight(i,l,g);a.utils.initSVG(l),b.forEach(function(a,b){a.values.forEach(function(a){a.series=b})});var T=E&&F&&I?[]:d3.merge(b.map(function(a){return a.values.map(function(a,b){return{x:p(a,b),y:q(a,b),size:r(a,b)}})}));m.domain(E||d3.extent(T.map(function(a){return a.x}).concat(t))),m.range(y&&b[0]?G||[(R*z+R)/(2*b[0].values.length),R-R*(1+z)/(2*b[0].values.length)]:G||[0,R]),n.domain(F||d3.extent(T.map(function(a){return a.y}).concat(u))).range(H||[S,0]),o.domain(I||d3.extent(T.map(function(a){return a.size}).concat(v))).range(J||Q),K=m.domain()[0]===m.domain()[1]||n.domain()[0]===n.domain()[1],m.domain()[0]===m.domain()[1]&&m.domain(m.domain()[0]?[m.domain()[0]-.01*m.domain()[0],m.domain()[1]+.01*m.domain()[1]]:[-1,1]),n.domain()[0]===n.domain()[1]&&n.domain(n.domain()[0]?[n.domain()[0]-.01*n.domain()[0],n.domain()[1]+.01*n.domain()[1]]:[-1,1]),isNaN(m.domain()[0])&&m.domain([-1,1]),isNaN(n.domain()[0])&&n.domain([-1,1]),c=c||m,d=d||n,e=e||o;var U=l.selectAll("g.nv-wrap.nv-scatter").data([b]),V=U.enter().append("g").attr("class","nvd3 nv-wrap nv-scatter nv-chart-"+k),W=V.append("defs"),X=V.append("g"),Y=U.select("g");U.classed("nv-single-point",K),X.append("g").attr("class","nv-groups"),X.append("g").attr("class","nv-point-paths"),V.append("g").attr("class","nv-point-clips"),U.attr("transform","translate("+g.left+","+g.top+")"),W.append("clipPath").attr("id","nv-edge-clip-"+k).append("rect"),U.select("#nv-edge-clip-"+k+" rect").attr("width",R).attr("height",S>0?S:0),Y.attr("clip-path",A?"url(#nv-edge-clip-"+k+")":""),O=!0;var Z=U.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a){return a.key});Z.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6),Z.exit().remove(),Z.attr("class",function(a,b){return"nv-group nv-series-"+b}).classed("hover",function(a){return a.hover}),Z.watchTransition(P,"scatter: groups").style("fill",function(a,b){return j(a,b)}).style("stroke",function(a,b){return j(a,b)}).style("stroke-opacity",1).style("fill-opacity",.5);var $=Z.selectAll("path.nv-point").data(function(a){return a.values.map(function(a,b){return[a,b]}).filter(function(a,b){return x(a[0],b)})});$.enter().append("path").style("fill",function(a){return a.color}).style("stroke",function(a){return a.color}).attr("transform",function(a){return"translate("+c(p(a[0],a[1]))+","+d(q(a[0],a[1]))+")"}).attr("d",a.utils.symbol().type(function(a){return s(a[0])}).size(function(a){return o(r(a[0],a[1]))})),$.exit().remove(),Z.exit().selectAll("path.nv-point").watchTransition(P,"scatter exit").attr("transform",function(a){return"translate("+m(p(a[0],a[1]))+","+n(q(a[0],a[1]))+")"}).remove(),$.each(function(a){d3.select(this).classed("nv-point",!0).classed("nv-point-"+a[1],!0).classed("nv-noninteractive",!w).classed("hover",!1)}),$.watchTransition(P,"scatter points").attr("transform",function(a){return"translate("+m(p(a[0],a[1]))+","+n(q(a[0],a[1]))+")"}).attr("d",a.utils.symbol().type(function(a){return s(a[0])}).size(function(a){return o(r(a[0],a[1]))})),clearTimeout(f),f=setTimeout(N,300),c=m.copy(),d=n.copy(),e=o.copy()}),P.renderEnd("scatter immediate"),b}var c,d,e,f,g={top:0,right:0,bottom:0,left:0},h=null,i=null,j=a.utils.defaultColor(),k=Math.floor(1e5*Math.random()),l=null,m=d3.scale.linear(),n=d3.scale.linear(),o=d3.scale.linear(),p=function(a){return a.x},q=function(a){return a.y},r=function(a){return a.size||1},s=function(a){return a.shape||"circle"},t=[],u=[],v=[],w=!0,x=function(a){return!a.notActive},y=!1,z=.1,A=!1,B=!0,C=!1,D=function(){return 25},E=null,F=null,G=null,H=null,I=null,J=null,K=!1,L=d3.dispatch("elementClick","elementDblClick","elementMouseover","elementMouseout","renderEnd"),M=!0,N=250,O=!1,P=a.utils.renderWatch(L,N),Q=[16,256];return b.dispatch=L,b.options=a.utils.optionsFunc.bind(b),b._calls=new function(){this.clearHighlights=function(){return a.dom.write(function(){l.selectAll(".nv-point.hover").classed("hover",!1)}),null},this.highlightPoint=function(b,c,d){a.dom.write(function(){l.select(" .nv-series-"+b+" .nv-point-"+c).classed("hover",d)})}},L.on("elementMouseover.point",function(a){w&&b._calls.highlightPoint(a.seriesIndex,a.pointIndex,!0)}),L.on("elementMouseout.point",function(a){w&&b._calls.highlightPoint(a.seriesIndex,a.pointIndex,!1)}),b._options=Object.create({},{width:{get:function(){return h},set:function(a){h=a}},height:{get:function(){return i},set:function(a){i=a}},xScale:{get:function(){return m},set:function(a){m=a}},yScale:{get:function(){return n},set:function(a){n=a}},pointScale:{get:function(){return o},set:function(a){o=a}},xDomain:{get:function(){return E},set:function(a){E=a}},yDomain:{get:function(){return F},set:function(a){F=a}},pointDomain:{get:function(){return I},set:function(a){I=a}},xRange:{get:function(){return G},set:function(a){G=a}},yRange:{get:function(){return H},set:function(a){H=a}},pointRange:{get:function(){return J},set:function(a){J=a}},forceX:{get:function(){return t},set:function(a){t=a}},forceY:{get:function(){return u},set:function(a){u=a}},forcePoint:{get:function(){return v},set:function(a){v=a}},interactive:{get:function(){return w},set:function(a){w=a}},pointActive:{get:function(){return x},set:function(a){x=a}},padDataOuter:{get:function(){return z},set:function(a){z=a}},padData:{get:function(){return y},set:function(a){y=a}},clipEdge:{get:function(){return A},set:function(a){A=a}},clipVoronoi:{get:function(){return B},set:function(a){B=a}},clipRadius:{get:function(){return D},set:function(a){D=a}},showVoronoi:{get:function(){return C},set:function(a){C=a}},id:{get:function(){return k},set:function(a){k=a}},x:{get:function(){return p},set:function(a){p=d3.functor(a)}},y:{get:function(){return q},set:function(a){q=d3.functor(a)}},pointSize:{get:function(){return r},set:function(a){r=d3.functor(a)}},pointShape:{get:function(){return s},set:function(a){s=d3.functor(a)}},margin:{get:function(){return g},set:function(a){g.top=void 0!==a.top?a.top:g.top,g.right=void 0!==a.right?a.right:g.right,g.bottom=void 0!==a.bottom?a.bottom:g.bottom,g.left=void 0!==a.left?a.left:g.left}},duration:{get:function(){return N},set:function(a){N=a,P.reset(N)}},color:{get:function(){return j},set:function(b){j=a.utils.getColor(b)}},useVoronoi:{get:function(){return M},set:function(a){M=a,M===!1&&(B=!1)}}}),a.utils.initOptions(b),b},a.models.scatterChart=function(){"use strict";function b(z){return D.reset(),D.models(c),t&&D.models(d),u&&D.models(e),q&&D.models(g),r&&D.models(h),z.each(function(z){m=d3.select(this),a.utils.initSVG(m);var G=a.utils.availableWidth(k,m,j),H=a.utils.availableHeight(l,m,j);if(b.update=function(){0===A?m.call(b):m.transition().duration(A).call(b)},b.container=this,w.setter(F(z),b.update).getter(E(z)).update(),w.disabled=z.map(function(a){return!!a.disabled}),!x){var I;x={};for(I in w)x[I]=w[I]instanceof Array?w[I].slice(0):w[I]}if(!(z&&z.length&&z.filter(function(a){return a.values.length}).length))return a.utils.noData(b,m),D.renderEnd("scatter immediate"),b;m.selectAll(".nv-noData").remove(),o=c.xScale(),p=c.yScale();var J=m.selectAll("g.nv-wrap.nv-scatterChart").data([z]),K=J.enter().append("g").attr("class","nvd3 nv-wrap nv-scatterChart nv-chart-"+c.id()),L=K.append("g"),M=J.select("g");if(L.append("rect").attr("class","nvd3 nv-background").style("pointer-events","none"),L.append("g").attr("class","nv-x nv-axis"),L.append("g").attr("class","nv-y nv-axis"),L.append("g").attr("class","nv-scatterWrap"),L.append("g").attr("class","nv-regressionLinesWrap"),L.append("g").attr("class","nv-distWrap"),L.append("g").attr("class","nv-legendWrap"),v&&M.select(".nv-y.nv-axis").attr("transform","translate("+G+",0)"),s){var N=G;f.width(N),J.select(".nv-legendWrap").datum(z).call(f),j.top!=f.height()&&(j.top=f.height(),H=a.utils.availableHeight(l,m,j)),J.select(".nv-legendWrap").attr("transform","translate(0,"+-j.top+")")}J.attr("transform","translate("+j.left+","+j.top+")"),c.width(G).height(H).color(z.map(function(a,b){return a.color=a.color||n(a,b),a.color}).filter(function(a,b){return!z[b].disabled})),J.select(".nv-scatterWrap").datum(z.filter(function(a){return!a.disabled})).call(c),J.select(".nv-regressionLinesWrap").attr("clip-path","url(#nv-edge-clip-"+c.id()+")");var O=J.select(".nv-regressionLinesWrap").selectAll(".nv-regLines").data(function(a){return a});O.enter().append("g").attr("class","nv-regLines");var P=O.selectAll(".nv-regLine").data(function(a){return[a]});P.enter().append("line").attr("class","nv-regLine").style("stroke-opacity",0),P.filter(function(a){return a.intercept&&a.slope}).watchTransition(D,"scatterPlusLineChart: regline").attr("x1",o.range()[0]).attr("x2",o.range()[1]).attr("y1",function(a){return p(o.domain()[0]*a.slope+a.intercept)}).attr("y2",function(a){return p(o.domain()[1]*a.slope+a.intercept)}).style("stroke",function(a,b,c){return n(a,c)}).style("stroke-opacity",function(a){return a.disabled||"undefined"==typeof a.slope||"undefined"==typeof a.intercept?0:1}),t&&(d.scale(o)._ticks(a.utils.calcTicksX(G/100,z)).tickSize(-H,0),M.select(".nv-x.nv-axis").attr("transform","translate(0,"+p.range()[0]+")").call(d)),u&&(e.scale(p)._ticks(a.utils.calcTicksY(H/36,z)).tickSize(-G,0),M.select(".nv-y.nv-axis").call(e)),q&&(g.getData(c.x()).scale(o).width(G).color(z.map(function(a,b){return a.color||n(a,b)}).filter(function(a,b){return!z[b].disabled})),L.select(".nv-distWrap").append("g").attr("class","nv-distributionX"),M.select(".nv-distributionX").attr("transform","translate(0,"+p.range()[0]+")").datum(z.filter(function(a){return!a.disabled})).call(g)),r&&(h.getData(c.y()).scale(p).width(H).color(z.map(function(a,b){return a.color||n(a,b)}).filter(function(a,b){return!z[b].disabled})),L.select(".nv-distWrap").append("g").attr("class","nv-distributionY"),M.select(".nv-distributionY").attr("transform","translate("+(v?G:-h.size())+",0)").datum(z.filter(function(a){return!a.disabled})).call(h)),f.dispatch.on("stateChange",function(a){for(var c in a)w[c]=a[c];y.stateChange(w),b.update()}),y.on("changeState",function(a){"undefined"!=typeof a.disabled&&(z.forEach(function(b,c){b.disabled=a.disabled[c]}),w.disabled=a.disabled),b.update()}),c.dispatch.on("elementMouseout.tooltip",function(a){i.hidden(!0),m.select(".nv-chart-"+c.id()+" .nv-series-"+a.seriesIndex+" .nv-distx-"+a.pointIndex).attr("y1",0),m.select(".nv-chart-"+c.id()+" .nv-series-"+a.seriesIndex+" .nv-disty-"+a.pointIndex).attr("x2",h.size())}),c.dispatch.on("elementMouseover.tooltip",function(a){m.select(".nv-series-"+a.seriesIndex+" .nv-distx-"+a.pointIndex).attr("y1",a.pos.top-H-j.top),m.select(".nv-series-"+a.seriesIndex+" .nv-disty-"+a.pointIndex).attr("x2",a.pos.left+g.size()-j.left),i.position(a.pos).data(a).hidden(!1)}),B=o.copy(),C=p.copy()}),D.renderEnd("scatter with line immediate"),b}var c=a.models.scatter(),d=a.models.axis(),e=a.models.axis(),f=a.models.legend(),g=a.models.distribution(),h=a.models.distribution(),i=a.models.tooltip(),j={top:30,right:20,bottom:50,left:75},k=null,l=null,m=null,n=a.utils.defaultColor(),o=c.xScale(),p=c.yScale(),q=!1,r=!1,s=!0,t=!0,u=!0,v=!1,w=a.utils.state(),x=null,y=d3.dispatch("stateChange","changeState","renderEnd"),z=null,A=250;c.xScale(o).yScale(p),d.orient("bottom").tickPadding(10),e.orient(v?"right":"left").tickPadding(10),g.axis("x"),h.axis("y"),i.headerFormatter(function(a,b){return d.tickFormat()(a,b)}).valueFormatter(function(a,b){return e.tickFormat()(a,b)});var B,C,D=a.utils.renderWatch(y,A),E=function(a){return function(){return{active:a.map(function(a){return!a.disabled})}}},F=function(a){return function(b){void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return b.dispatch=y,b.scatter=c,b.legend=f,b.xAxis=d,b.yAxis=e,b.distX=g,b.distY=h,b.tooltip=i,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return k},set:function(a){k=a}},height:{get:function(){return l},set:function(a){l=a}},container:{get:function(){return m},set:function(a){m=a}},showDistX:{get:function(){return q},set:function(a){q=a}},showDistY:{get:function(){return r},set:function(a){r=a}},showLegend:{get:function(){return s},set:function(a){s=a}},showXAxis:{get:function(){return t},set:function(a){t=a}},showYAxis:{get:function(){return u},set:function(a){u=a}},defaultState:{get:function(){return x},set:function(a){x=a}},noData:{get:function(){return z},set:function(a){z=a}},duration:{get:function(){return A},set:function(a){A=a}},tooltips:{get:function(){return i.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),i.enabled(!!b)
}},tooltipContent:{get:function(){return i.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),i.contentGenerator(b)}},tooltipXContent:{get:function(){return i.contentGenerator()},set:function(){a.deprecated("tooltipContent","This option is removed, put values into main tooltip.")}},tooltipYContent:{get:function(){return i.contentGenerator()},set:function(){a.deprecated("tooltipContent","This option is removed, put values into main tooltip.")}},margin:{get:function(){return j},set:function(a){j.top=void 0!==a.top?a.top:j.top,j.right=void 0!==a.right?a.right:j.right,j.bottom=void 0!==a.bottom?a.bottom:j.bottom,j.left=void 0!==a.left?a.left:j.left}},rightAlignYAxis:{get:function(){return v},set:function(a){v=a,e.orient(a?"right":"left")}},color:{get:function(){return n},set:function(b){n=a.utils.getColor(b),f.color(n),g.color(n),h.color(n)}}}),a.utils.inheritOptions(b,c),a.utils.initOptions(b),b},a.models.sparkline=function(){"use strict";function b(k){return k.each(function(b){var k=h-g.left-g.right,q=i-g.top-g.bottom;j=d3.select(this),a.utils.initSVG(j),l.domain(c||d3.extent(b,n)).range(e||[0,k]),m.domain(d||d3.extent(b,o)).range(f||[q,0]);{var r=j.selectAll("g.nv-wrap.nv-sparkline").data([b]),s=r.enter().append("g").attr("class","nvd3 nv-wrap nv-sparkline");s.append("g"),r.select("g")}r.attr("transform","translate("+g.left+","+g.top+")");var t=r.selectAll("path").data(function(a){return[a]});t.enter().append("path"),t.exit().remove(),t.style("stroke",function(a,b){return a.color||p(a,b)}).attr("d",d3.svg.line().x(function(a,b){return l(n(a,b))}).y(function(a,b){return m(o(a,b))}));var u=r.selectAll("circle.nv-point").data(function(a){function b(b){if(-1!=b){var c=a[b];return c.pointIndex=b,c}return null}var c=a.map(function(a,b){return o(a,b)}),d=b(c.lastIndexOf(m.domain()[1])),e=b(c.indexOf(m.domain()[0])),f=b(c.length-1);return[e,d,f].filter(function(a){return null!=a})});u.enter().append("circle"),u.exit().remove(),u.attr("cx",function(a){return l(n(a,a.pointIndex))}).attr("cy",function(a){return m(o(a,a.pointIndex))}).attr("r",2).attr("class",function(a){return n(a,a.pointIndex)==l.domain()[1]?"nv-point nv-currentValue":o(a,a.pointIndex)==m.domain()[0]?"nv-point nv-minValue":"nv-point nv-maxValue"})}),b}var c,d,e,f,g={top:2,right:0,bottom:2,left:0},h=400,i=32,j=null,k=!0,l=d3.scale.linear(),m=d3.scale.linear(),n=function(a){return a.x},o=function(a){return a.y},p=a.utils.getColor(["#000"]);return b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return h},set:function(a){h=a}},height:{get:function(){return i},set:function(a){i=a}},xDomain:{get:function(){return c},set:function(a){c=a}},yDomain:{get:function(){return d},set:function(a){d=a}},xRange:{get:function(){return e},set:function(a){e=a}},yRange:{get:function(){return f},set:function(a){f=a}},xScale:{get:function(){return l},set:function(a){l=a}},yScale:{get:function(){return m},set:function(a){m=a}},animate:{get:function(){return k},set:function(a){k=a}},x:{get:function(){return n},set:function(a){n=d3.functor(a)}},y:{get:function(){return o},set:function(a){o=d3.functor(a)}},margin:{get:function(){return g},set:function(a){g.top=void 0!==a.top?a.top:g.top,g.right=void 0!==a.right?a.right:g.right,g.bottom=void 0!==a.bottom?a.bottom:g.bottom,g.left=void 0!==a.left?a.left:g.left}},color:{get:function(){return p},set:function(b){p=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.sparklinePlus=function(){"use strict";function b(p){return p.each(function(p){function q(){if(!j){var a=z.selectAll(".nv-hoverValue").data(i),b=a.enter().append("g").attr("class","nv-hoverValue").style("stroke-opacity",0).style("fill-opacity",0);a.exit().transition().duration(250).style("stroke-opacity",0).style("fill-opacity",0).remove(),a.attr("transform",function(a){return"translate("+c(e.x()(p[a],a))+",0)"}).transition().duration(250).style("stroke-opacity",1).style("fill-opacity",1),i.length&&(b.append("line").attr("x1",0).attr("y1",-f.top).attr("x2",0).attr("y2",u),b.append("text").attr("class","nv-xValue").attr("x",-6).attr("y",-f.top).attr("text-anchor","end").attr("dy",".9em"),z.select(".nv-hoverValue .nv-xValue").text(k(e.x()(p[i[0]],i[0]))),b.append("text").attr("class","nv-yValue").attr("x",6).attr("y",-f.top).attr("text-anchor","start").attr("dy",".9em"),z.select(".nv-hoverValue .nv-yValue").text(l(e.y()(p[i[0]],i[0]))))}}function r(){function a(a,b){for(var c=Math.abs(e.x()(a[0],0)-b),d=0,f=0;f<a.length;f++)Math.abs(e.x()(a[f],f)-b)<c&&(c=Math.abs(e.x()(a[f],f)-b),d=f);return d}if(!j){var b=d3.mouse(this)[0]-f.left;i=[a(p,Math.round(c.invert(b)))],q()}}var s=d3.select(this);a.utils.initSVG(s);var t=a.utils.availableWidth(g,s,f),u=a.utils.availableHeight(h,s,f);if(b.update=function(){s.call(b)},b.container=this,!p||!p.length)return a.utils.noData(b,s),b;s.selectAll(".nv-noData").remove();var v=e.y()(p[p.length-1],p.length-1);c=e.xScale(),d=e.yScale();var w=s.selectAll("g.nv-wrap.nv-sparklineplus").data([p]),x=w.enter().append("g").attr("class","nvd3 nv-wrap nv-sparklineplus"),y=x.append("g"),z=w.select("g");y.append("g").attr("class","nv-sparklineWrap"),y.append("g").attr("class","nv-valueWrap"),y.append("g").attr("class","nv-hoverArea"),w.attr("transform","translate("+f.left+","+f.top+")");var A=z.select(".nv-sparklineWrap");if(e.width(t).height(u),A.call(e),m){var B=z.select(".nv-valueWrap"),C=B.selectAll(".nv-currentValue").data([v]);C.enter().append("text").attr("class","nv-currentValue").attr("dx",o?-8:8).attr("dy",".9em").style("text-anchor",o?"end":"start"),C.attr("x",t+(o?f.right:0)).attr("y",n?function(a){return d(a)}:0).style("fill",e.color()(p[p.length-1],p.length-1)).text(l(v))}y.select(".nv-hoverArea").append("rect").on("mousemove",r).on("click",function(){j=!j}).on("mouseout",function(){i=[],q()}),z.select(".nv-hoverArea rect").attr("transform",function(){return"translate("+-f.left+","+-f.top+")"}).attr("width",t+f.left+f.right).attr("height",u+f.top)}),b}var c,d,e=a.models.sparkline(),f={top:15,right:100,bottom:10,left:50},g=null,h=null,i=[],j=!1,k=d3.format(",r"),l=d3.format(",.2f"),m=!0,n=!0,o=!1,p=null;return b.sparkline=e,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return g},set:function(a){g=a}},height:{get:function(){return h},set:function(a){h=a}},xTickFormat:{get:function(){return k},set:function(a){k=a}},yTickFormat:{get:function(){return l},set:function(a){l=a}},showLastValue:{get:function(){return m},set:function(a){m=a}},alignValue:{get:function(){return n},set:function(a){n=a}},rightAlignValue:{get:function(){return o},set:function(a){o=a}},noData:{get:function(){return p},set:function(a){p=a}},margin:{get:function(){return f},set:function(a){f.top=void 0!==a.top?a.top:f.top,f.right=void 0!==a.right?a.right:f.right,f.bottom=void 0!==a.bottom?a.bottom:f.bottom,f.left=void 0!==a.left?a.left:f.left}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.stackedArea=function(){"use strict";function b(m){return u.reset(),u.models(r),m.each(function(m){var s=f-e.left-e.right,v=g-e.top-e.bottom;j=d3.select(this),a.utils.initSVG(j),c=r.xScale(),d=r.yScale();var w=m;m.forEach(function(a,b){a.seriesIndex=b,a.values=a.values.map(function(a,c){return a.index=c,a.seriesIndex=b,a})});var x=m.filter(function(a){return!a.disabled});m=d3.layout.stack().order(o).offset(n).values(function(a){return a.values}).x(k).y(l).out(function(a,b,c){a.display={y:c,y0:b}})(x);var y=j.selectAll("g.nv-wrap.nv-stackedarea").data([m]),z=y.enter().append("g").attr("class","nvd3 nv-wrap nv-stackedarea"),A=z.append("defs"),B=z.append("g"),C=y.select("g");B.append("g").attr("class","nv-areaWrap"),B.append("g").attr("class","nv-scatterWrap"),y.attr("transform","translate("+e.left+","+e.top+")"),0==r.forceY().length&&r.forceY().push(0),r.width(s).height(v).x(k).y(function(a){return a.display.y+a.display.y0}).forceY([0]).color(m.map(function(a){return a.color||h(a,a.seriesIndex)}));var D=C.select(".nv-scatterWrap").datum(m);D.call(r),A.append("clipPath").attr("id","nv-edge-clip-"+i).append("rect"),y.select("#nv-edge-clip-"+i+" rect").attr("width",s).attr("height",v),C.attr("clip-path",q?"url(#nv-edge-clip-"+i+")":"");var E=d3.svg.area().x(function(a,b){return c(k(a,b))}).y0(function(a){return d(a.display.y0)}).y1(function(a){return d(a.display.y+a.display.y0)}).interpolate(p),F=d3.svg.area().x(function(a,b){return c(k(a,b))}).y0(function(a){return d(a.display.y0)}).y1(function(a){return d(a.display.y0)}),G=C.select(".nv-areaWrap").selectAll("path.nv-area").data(function(a){return a});G.enter().append("path").attr("class",function(a,b){return"nv-area nv-area-"+b}).attr("d",function(a){return F(a.values,a.seriesIndex)}).on("mouseover",function(a){d3.select(this).classed("hover",!0),t.areaMouseover({point:a,series:a.key,pos:[d3.event.pageX,d3.event.pageY],seriesIndex:a.seriesIndex})}).on("mouseout",function(a){d3.select(this).classed("hover",!1),t.areaMouseout({point:a,series:a.key,pos:[d3.event.pageX,d3.event.pageY],seriesIndex:a.seriesIndex})}).on("click",function(a){d3.select(this).classed("hover",!1),t.areaClick({point:a,series:a.key,pos:[d3.event.pageX,d3.event.pageY],seriesIndex:a.seriesIndex})}),G.exit().remove(),G.style("fill",function(a){return a.color||h(a,a.seriesIndex)}).style("stroke",function(a){return a.color||h(a,a.seriesIndex)}),G.watchTransition(u,"stackedArea path").attr("d",function(a,b){return E(a.values,b)}),r.dispatch.on("elementMouseover.area",function(a){C.select(".nv-chart-"+i+" .nv-area-"+a.seriesIndex).classed("hover",!0)}),r.dispatch.on("elementMouseout.area",function(a){C.select(".nv-chart-"+i+" .nv-area-"+a.seriesIndex).classed("hover",!1)}),b.d3_stackedOffset_stackPercent=function(a){var b,c,d,e=a.length,f=a[0].length,g=[];for(c=0;f>c;++c){for(b=0,d=0;b<w.length;b++)d+=l(w[b].values[c]);if(d)for(b=0;e>b;b++)a[b][c][1]/=d;else for(b=0;e>b;b++)a[b][c][1]=0}for(c=0;f>c;++c)g[c]=0;return g}}),u.renderEnd("stackedArea immediate"),b}var c,d,e={top:0,right:0,bottom:0,left:0},f=960,g=500,h=a.utils.defaultColor(),i=Math.floor(1e5*Math.random()),j=null,k=function(a){return a.x},l=function(a){return a.y},m="stack",n="zero",o="default",p="linear",q=!1,r=a.models.scatter(),s=250,t=d3.dispatch("areaClick","areaMouseover","areaMouseout","renderEnd","elementClick","elementMouseover","elementMouseout");r.pointSize(2.2).pointDomain([2.2,2.2]);var u=a.utils.renderWatch(t,s);return b.dispatch=t,b.scatter=r,r.dispatch.on("elementClick",function(){t.elementClick.apply(this,arguments)}),r.dispatch.on("elementMouseover",function(){t.elementMouseover.apply(this,arguments)}),r.dispatch.on("elementMouseout",function(){t.elementMouseout.apply(this,arguments)}),b.interpolate=function(a){return arguments.length?(p=a,b):p},b.duration=function(a){return arguments.length?(s=a,u.reset(s),r.duration(s),b):s},b.dispatch=t,b.scatter=r,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return f},set:function(a){f=a}},height:{get:function(){return g},set:function(a){g=a}},clipEdge:{get:function(){return q},set:function(a){q=a}},offset:{get:function(){return n},set:function(a){n=a}},order:{get:function(){return o},set:function(a){o=a}},interpolate:{get:function(){return p},set:function(a){p=a}},x:{get:function(){return k},set:function(a){k=d3.functor(a)}},y:{get:function(){return l},set:function(a){l=d3.functor(a)}},margin:{get:function(){return e},set:function(a){e.top=void 0!==a.top?a.top:e.top,e.right=void 0!==a.right?a.right:e.right,e.bottom=void 0!==a.bottom?a.bottom:e.bottom,e.left=void 0!==a.left?a.left:e.left}},color:{get:function(){return h},set:function(b){h=a.utils.getColor(b)}},style:{get:function(){return m},set:function(a){switch(m=a){case"stack":b.offset("zero"),b.order("default");break;case"stream":b.offset("wiggle"),b.order("inside-out");break;case"stream-center":b.offset("silhouette"),b.order("inside-out");break;case"expand":b.offset("expand"),b.order("default");break;case"stack_percent":b.offset(b.d3_stackedOffset_stackPercent),b.order("default")}}},duration:{get:function(){return s},set:function(a){s=a,u.reset(s),r.duration(s)}}}),a.utils.inheritOptions(b,r),a.utils.initOptions(b),b},a.models.stackedAreaChart=function(){"use strict";function b(k){return F.reset(),F.models(e),r&&F.models(f),s&&F.models(g),k.each(function(k){var x=d3.select(this),F=this;a.utils.initSVG(x);var K=a.utils.availableWidth(m,x,l),L=a.utils.availableHeight(n,x,l);if(b.update=function(){x.transition().duration(C).call(b)},b.container=this,v.setter(I(k),b.update).getter(H(k)).update(),v.disabled=k.map(function(a){return!!a.disabled}),!w){var M;w={};for(M in v)w[M]=v[M]instanceof Array?v[M].slice(0):v[M]}if(!(k&&k.length&&k.filter(function(a){return a.values.length}).length))return a.utils.noData(b,x),b;x.selectAll(".nv-noData").remove(),c=e.xScale(),d=e.yScale();var N=x.selectAll("g.nv-wrap.nv-stackedAreaChart").data([k]),O=N.enter().append("g").attr("class","nvd3 nv-wrap nv-stackedAreaChart").append("g"),P=N.select("g");if(O.append("rect").style("opacity",0),O.append("g").attr("class","nv-x nv-axis"),O.append("g").attr("class","nv-y nv-axis"),O.append("g").attr("class","nv-stackedWrap"),O.append("g").attr("class","nv-legendWrap"),O.append("g").attr("class","nv-controlsWrap"),O.append("g").attr("class","nv-interactive"),P.select("rect").attr("width",K).attr("height",L),q){var Q=p?K-z:K;h.width(Q),P.select(".nv-legendWrap").datum(k).call(h),l.top!=h.height()&&(l.top=h.height(),L=a.utils.availableHeight(n,x,l)),P.select(".nv-legendWrap").attr("transform","translate("+(K-Q)+","+-l.top+")")}if(p){var R=[{key:B.stacked||"Stacked",metaKey:"Stacked",disabled:"stack"!=e.style(),style:"stack"},{key:B.stream||"Stream",metaKey:"Stream",disabled:"stream"!=e.style(),style:"stream"},{key:B.expanded||"Expanded",metaKey:"Expanded",disabled:"expand"!=e.style(),style:"expand"},{key:B.stack_percent||"Stack %",metaKey:"Stack_Percent",disabled:"stack_percent"!=e.style(),style:"stack_percent"}];z=A.length/3*260,R=R.filter(function(a){return-1!==A.indexOf(a.metaKey)}),i.width(z).color(["#444","#444","#444"]),P.select(".nv-controlsWrap").datum(R).call(i),l.top!=Math.max(i.height(),h.height())&&(l.top=Math.max(i.height(),h.height()),L=a.utils.availableHeight(n,x,l)),P.select(".nv-controlsWrap").attr("transform","translate(0,"+-l.top+")")}N.attr("transform","translate("+l.left+","+l.top+")"),t&&P.select(".nv-y.nv-axis").attr("transform","translate("+K+",0)"),u&&(j.width(K).height(L).margin({left:l.left,top:l.top}).svgContainer(x).xScale(c),N.select(".nv-interactive").call(j)),e.width(K).height(L);var S=P.select(".nv-stackedWrap").datum(k);if(S.transition().call(e),r&&(f.scale(c)._ticks(a.utils.calcTicksX(K/100,k)).tickSize(-L,0),P.select(".nv-x.nv-axis").attr("transform","translate(0,"+L+")"),P.select(".nv-x.nv-axis").transition().duration(0).call(f)),s){var T;if(T="wiggle"===e.offset()?0:a.utils.calcTicksY(L/36,k),g.scale(d)._ticks(T).tickSize(-K,0),"expand"===e.style()||"stack_percent"===e.style()){var U=g.tickFormat();D&&U===J||(D=U),g.tickFormat(J)}else D&&(g.tickFormat(D),D=null);P.select(".nv-y.nv-axis").transition().duration(0).call(g)}e.dispatch.on("areaClick.toggle",function(a){k.forEach(1===k.filter(function(a){return!a.disabled}).length?function(a){a.disabled=!1}:function(b,c){b.disabled=c!=a.seriesIndex}),v.disabled=k.map(function(a){return!!a.disabled}),y.stateChange(v),b.update()}),h.dispatch.on("stateChange",function(a){for(var c in a)v[c]=a[c];y.stateChange(v),b.update()}),i.dispatch.on("legendClick",function(a){a.disabled&&(R=R.map(function(a){return a.disabled=!0,a}),a.disabled=!1,e.style(a.style),v.style=e.style(),y.stateChange(v),b.update())}),j.dispatch.on("elementMousemove",function(c){e.clearHighlights();var d,g,h,i=[];if(k.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(f,j){g=a.interactiveBisect(f.values,c.pointXValue,b.x());var k=f.values[g],l=b.y()(k,g);if(null!=l&&e.highlightPoint(j,g,!0),"undefined"!=typeof k){"undefined"==typeof d&&(d=k),"undefined"==typeof h&&(h=b.xScale()(b.x()(k,g)));var m="expand"==e.style()?k.display.y:b.y()(k,g);i.push({key:f.key,value:m,color:o(f,f.seriesIndex),stackedValue:k.display})}}),i.reverse(),i.length>2){var m=b.yScale().invert(c.mouseY),n=null;i.forEach(function(a,b){m=Math.abs(m);var c=Math.abs(a.stackedValue.y0),d=Math.abs(a.stackedValue.y);return m>=c&&d+c>=m?void(n=b):void 0}),null!=n&&(i[n].highlight=!0)}var p=f.tickFormat()(b.x()(d,g)),q=j.tooltip.valueFormatter();"expand"===e.style()||"stack_percent"===e.style()?(E||(E=q),q=d3.format(".1%")):E&&(q=E,E=null),j.tooltip.position({left:h+l.left,top:c.mouseY+l.top}).chartContainer(F.parentNode).valueFormatter(q).data({value:p,series:i})(),j.renderGuideLine(h)}),j.dispatch.on("elementMouseout",function(){e.clearHighlights()}),y.on("changeState",function(a){"undefined"!=typeof a.disabled&&k.length===a.disabled.length&&(k.forEach(function(b,c){b.disabled=a.disabled[c]}),v.disabled=a.disabled),"undefined"!=typeof a.style&&(e.style(a.style),G=a.style),b.update()})}),F.renderEnd("stacked Area chart immediate"),b}var c,d,e=a.models.stackedArea(),f=a.models.axis(),g=a.models.axis(),h=a.models.legend(),i=a.models.legend(),j=a.interactiveGuideline(),k=a.models.tooltip(),l={top:30,right:25,bottom:50,left:60},m=null,n=null,o=a.utils.defaultColor(),p=!0,q=!0,r=!0,s=!0,t=!1,u=!1,v=a.utils.state(),w=null,x=null,y=d3.dispatch("stateChange","changeState","renderEnd"),z=250,A=["Stacked","Stream","Expanded"],B={},C=250;v.style=e.style(),f.orient("bottom").tickPadding(7),g.orient(t?"right":"left"),k.headerFormatter(function(a,b){return f.tickFormat()(a,b)}).valueFormatter(function(a,b){return g.tickFormat()(a,b)}),j.tooltip.headerFormatter(function(a,b){return f.tickFormat()(a,b)}).valueFormatter(function(a,b){return g.tickFormat()(a,b)});var D=null,E=null;i.updateState(!1);var F=a.utils.renderWatch(y),G=e.style(),H=function(a){return function(){return{active:a.map(function(a){return!a.disabled}),style:e.style()}}},I=function(a){return function(b){void 0!==b.style&&(G=b.style),void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}},J=d3.format("%");return e.dispatch.on("elementMouseover.tooltip",function(a){a.point.x=e.x()(a.point),a.point.y=e.y()(a.point),k.data(a).position(a.pos).hidden(!1)}),e.dispatch.on("elementMouseout.tooltip",function(){k.hidden(!0)}),b.dispatch=y,b.stacked=e,b.legend=h,b.controls=i,b.xAxis=f,b.yAxis=g,b.interactiveLayer=j,b.tooltip=k,b.dispatch=y,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return m},set:function(a){m=a}},height:{get:function(){return n},set:function(a){n=a}},showLegend:{get:function(){return q},set:function(a){q=a}},showXAxis:{get:function(){return r},set:function(a){r=a}},showYAxis:{get:function(){return s},set:function(a){s=a}},defaultState:{get:function(){return w},set:function(a){w=a}},noData:{get:function(){return x},set:function(a){x=a}},showControls:{get:function(){return p},set:function(a){p=a}},controlLabels:{get:function(){return B},set:function(a){B=a}},controlOptions:{get:function(){return A},set:function(a){A=a}},tooltips:{get:function(){return k.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),k.enabled(!!b)}},tooltipContent:{get:function(){return k.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),k.contentGenerator(b)}},margin:{get:function(){return l},set:function(a){l.top=void 0!==a.top?a.top:l.top,l.right=void 0!==a.right?a.right:l.right,l.bottom=void 0!==a.bottom?a.bottom:l.bottom,l.left=void 0!==a.left?a.left:l.left}},duration:{get:function(){return C},set:function(a){C=a,F.reset(C),e.duration(C),f.duration(C),g.duration(C)}},color:{get:function(){return o},set:function(b){o=a.utils.getColor(b),h.color(o),e.color(o)}},rightAlignYAxis:{get:function(){return t},set:function(a){t=a,g.orient(t?"right":"left")}},useInteractiveGuideline:{get:function(){return u},set:function(a){u=!!a,b.interactive(!a),b.useVoronoi(!a),e.scatter.interactive(!a)}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.sunburst=function(){"use strict";function b(u){return t.reset(),u.each(function(b){function t(a){a.x0=a.x,a.dx0=a.dx}function u(a){var b=d3.interpolate(p.domain(),[a.x,a.x+a.dx]),c=d3.interpolate(q.domain(),[a.y,1]),d=d3.interpolate(q.range(),[a.y?20:0,y]);return function(a,e){return e?function(){return s(a)}:function(e){return p.domain(b(e)),q.domain(c(e)).range(d(e)),s(a)}}}l=d3.select(this);var v,w=a.utils.availableWidth(g,l,f),x=a.utils.availableHeight(h,l,f),y=Math.min(w,x)/2;a.utils.initSVG(l);var z=l.selectAll(".nv-wrap.nv-sunburst").data(b),A=z.enter().append("g").attr("class","nvd3 nv-wrap nv-sunburst nv-chart-"+k),B=A.selectAll("nv-sunburst");z.attr("transform","translate("+w/2+","+x/2+")"),l.on("click",function(a,b){o.chartClick({data:a,index:b,pos:d3.event,id:k})}),q.range([0,y]),c=c||b,e=b[0],r.value(j[i]||j.count),v=B.data(r.nodes).enter().append("path").attr("d",s).style("fill",function(a){return m((a.children?a:a.parent).name)}).style("stroke","#FFF").on("click",function(a){d!==c&&c!==a&&(d=c),c=a,v.transition().duration(n).attrTween("d",u(a))}).each(t).on("dblclick",function(a){d.parent==a&&v.transition().duration(n).attrTween("d",u(e))}).each(t).on("mouseover",function(a){d3.select(this).classed("hover",!0).style("opacity",.8),o.elementMouseover({data:a,color:d3.select(this).style("fill")})}).on("mouseout",function(a){d3.select(this).classed("hover",!1).style("opacity",1),o.elementMouseout({data:a})}).on("mousemove",function(a){o.elementMousemove({data:a})})}),t.renderEnd("sunburst immediate"),b}var c,d,e,f={top:0,right:0,bottom:0,left:0},g=null,h=null,i="count",j={count:function(){return 1},size:function(a){return a.size}},k=Math.floor(1e4*Math.random()),l=null,m=a.utils.defaultColor(),n=500,o=d3.dispatch("chartClick","elementClick","elementDblClick","elementMousemove","elementMouseover","elementMouseout","renderEnd"),p=d3.scale.linear().range([0,2*Math.PI]),q=d3.scale.sqrt(),r=d3.layout.partition().sort(null).value(function(){return 1}),s=d3.svg.arc().startAngle(function(a){return Math.max(0,Math.min(2*Math.PI,p(a.x)))}).endAngle(function(a){return Math.max(0,Math.min(2*Math.PI,p(a.x+a.dx)))}).innerRadius(function(a){return Math.max(0,q(a.y))}).outerRadius(function(a){return Math.max(0,q(a.y+a.dy))}),t=a.utils.renderWatch(o);return b.dispatch=o,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return g},set:function(a){g=a}},height:{get:function(){return h},set:function(a){h=a}},mode:{get:function(){return i},set:function(a){i=a}},id:{get:function(){return k},set:function(a){k=a}},duration:{get:function(){return n},set:function(a){n=a}},margin:{get:function(){return f},set:function(a){f.top=void 0!=a.top?a.top:f.top,f.right=void 0!=a.right?a.right:f.right,f.bottom=void 0!=a.bottom?a.bottom:f.bottom,f.left=void 0!=a.left?a.left:f.left}},color:{get:function(){return m},set:function(b){m=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.sunburstChart=function(){"use strict";function b(d){return m.reset(),m.models(c),d.each(function(d){var h=d3.select(this);a.utils.initSVG(h);var i=a.utils.availableWidth(f,h,e),j=a.utils.availableHeight(g,h,e);if(b.update=function(){0===k?h.call(b):h.transition().duration(k).call(b)},b.container=this,!d||!d.length)return a.utils.noData(b,h),b;h.selectAll(".nv-noData").remove();var l=h.selectAll("g.nv-wrap.nv-sunburstChart").data(d),m=l.enter().append("g").attr("class","nvd3 nv-wrap nv-sunburstChart").append("g"),n=l.select("g");m.append("g").attr("class","nv-sunburstWrap"),l.attr("transform","translate("+e.left+","+e.top+")"),c.width(i).height(j);var o=n.select(".nv-sunburstWrap").datum(d);d3.transition(o).call(c)}),m.renderEnd("sunburstChart immediate"),b}var c=a.models.sunburst(),d=a.models.tooltip(),e={top:30,right:20,bottom:20,left:20},f=null,g=null,h=a.utils.defaultColor(),i=(Math.round(1e5*Math.random()),null),j=null,k=250,l=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd"),m=a.utils.renderWatch(l);return d.headerEnabled(!1).duration(0).valueFormatter(function(a){return a}),c.dispatch.on("elementMouseover.tooltip",function(a){a.series={key:a.data.name,value:a.data.size,color:a.color},d.data(a).hidden(!1)}),c.dispatch.on("elementMouseout.tooltip",function(){d.hidden(!0)}),c.dispatch.on("elementMousemove.tooltip",function(){d.position({top:d3.event.pageY,left:d3.event.pageX})()}),b.dispatch=l,b.sunburst=c,b.tooltip=d,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{noData:{get:function(){return j},set:function(a){j=a}},defaultState:{get:function(){return i},set:function(a){i=a}},color:{get:function(){return h},set:function(a){h=a,c.color(h)}},duration:{get:function(){return k},set:function(a){k=a,m.reset(k),c.duration(k)}},margin:{get:function(){return e},set:function(a){e.top=void 0!==a.top?a.top:e.top,e.right=void 0!==a.right?a.right:e.right,e.bottom=void 0!==a.bottom?a.bottom:e.bottom,e.left=void 0!==a.left?a.left:e.left}}}),a.utils.inheritOptions(b,c),a.utils.initOptions(b),b},a.version="1.8.1"}();/*
 Copyright (C) Federico Zivolo 2019
 Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT).
 */(function(e,t){'object'==typeof exports&&'undefined'!=typeof module?module.exports=t():'function'==typeof define&&define.amd?define(t):e.Popper=t()})(this,function(){'use strict';function e(e){return e&&'[object Function]'==={}.toString.call(e)}function t(e,t){if(1!==e.nodeType)return[];var o=e.ownerDocument.defaultView,n=o.getComputedStyle(e,null);return t?n[t]:n}function o(e){return'HTML'===e.nodeName?e:e.parentNode||e.host}function n(e){if(!e)return document.body;switch(e.nodeName){case'HTML':case'BODY':return e.ownerDocument.body;case'#document':return e.body;}var i=t(e),r=i.overflow,p=i.overflowX,s=i.overflowY;return /(auto|scroll|overlay)/.test(r+s+p)?e:n(o(e))}function r(e){return 11===e?pe:10===e?se:pe||se}function p(e){if(!e)return document.documentElement;for(var o=r(10)?document.body:null,n=e.offsetParent||null;n===o&&e.nextElementSibling;)n=(e=e.nextElementSibling).offsetParent;var i=n&&n.nodeName;return i&&'BODY'!==i&&'HTML'!==i?-1!==['TH','TD','TABLE'].indexOf(n.nodeName)&&'static'===t(n,'position')?p(n):n:e?e.ownerDocument.documentElement:document.documentElement}function s(e){var t=e.nodeName;return'BODY'!==t&&('HTML'===t||p(e.firstElementChild)===e)}function d(e){return null===e.parentNode?e:d(e.parentNode)}function a(e,t){if(!e||!e.nodeType||!t||!t.nodeType)return document.documentElement;var o=e.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_FOLLOWING,n=o?e:t,i=o?t:e,r=document.createRange();r.setStart(n,0),r.setEnd(i,0);var l=r.commonAncestorContainer;if(e!==l&&t!==l||n.contains(i))return s(l)?l:p(l);var f=d(e);return f.host?a(f.host,t):a(e,d(t).host)}function l(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:'top',o='top'===t?'scrollTop':'scrollLeft',n=e.nodeName;if('BODY'===n||'HTML'===n){var i=e.ownerDocument.documentElement,r=e.ownerDocument.scrollingElement||i;return r[o]}return e[o]}function f(e,t){var o=2<arguments.length&&void 0!==arguments[2]&&arguments[2],n=l(t,'top'),i=l(t,'left'),r=o?-1:1;return e.top+=n*r,e.bottom+=n*r,e.left+=i*r,e.right+=i*r,e}function m(e,t){var o='x'===t?'Left':'Top',n='Left'==o?'Right':'Bottom';return parseFloat(e['border'+o+'Width'],10)+parseFloat(e['border'+n+'Width'],10)}function h(e,t,o,n){return ee(t['offset'+e],t['scroll'+e],o['client'+e],o['offset'+e],o['scroll'+e],r(10)?parseInt(o['offset'+e])+parseInt(n['margin'+('Height'===e?'Top':'Left')])+parseInt(n['margin'+('Height'===e?'Bottom':'Right')]):0)}function c(e){var t=e.body,o=e.documentElement,n=r(10)&&getComputedStyle(o);return{height:h('Height',t,o,n),width:h('Width',t,o,n)}}function g(e){return fe({},e,{right:e.left+e.width,bottom:e.top+e.height})}function u(e){var o={};try{if(r(10)){o=e.getBoundingClientRect();var n=l(e,'top'),i=l(e,'left');o.top+=n,o.left+=i,o.bottom+=n,o.right+=i}else o=e.getBoundingClientRect()}catch(t){}var p={left:o.left,top:o.top,width:o.right-o.left,height:o.bottom-o.top},s='HTML'===e.nodeName?c(e.ownerDocument):{},d=s.width||e.clientWidth||p.right-p.left,a=s.height||e.clientHeight||p.bottom-p.top,f=e.offsetWidth-d,h=e.offsetHeight-a;if(f||h){var u=t(e);f-=m(u,'x'),h-=m(u,'y'),p.width-=f,p.height-=h}return g(p)}function b(e,o){var i=2<arguments.length&&void 0!==arguments[2]&&arguments[2],p=r(10),s='HTML'===o.nodeName,d=u(e),a=u(o),l=n(e),m=t(o),h=parseFloat(m.borderTopWidth,10),c=parseFloat(m.borderLeftWidth,10);i&&s&&(a.top=ee(a.top,0),a.left=ee(a.left,0));var b=g({top:d.top-a.top-h,left:d.left-a.left-c,width:d.width,height:d.height});if(b.marginTop=0,b.marginLeft=0,!p&&s){var w=parseFloat(m.marginTop,10),y=parseFloat(m.marginLeft,10);b.top-=h-w,b.bottom-=h-w,b.left-=c-y,b.right-=c-y,b.marginTop=w,b.marginLeft=y}return(p&&!i?o.contains(l):o===l&&'BODY'!==l.nodeName)&&(b=f(b,o)),b}function w(e){var t=1<arguments.length&&void 0!==arguments[1]&&arguments[1],o=e.ownerDocument.documentElement,n=b(e,o),i=ee(o.clientWidth,window.innerWidth||0),r=ee(o.clientHeight,window.innerHeight||0),p=t?0:l(o),s=t?0:l(o,'left'),d={top:p-n.top+n.marginTop,left:s-n.left+n.marginLeft,width:i,height:r};return g(d)}function y(e){var n=e.nodeName;if('BODY'===n||'HTML'===n)return!1;if('fixed'===t(e,'position'))return!0;var i=o(e);return!!i&&y(i)}function E(e){if(!e||!e.parentElement||r())return document.documentElement;for(var o=e.parentElement;o&&'none'===t(o,'transform');)o=o.parentElement;return o||document.documentElement}function v(e,t,i,r){var p=4<arguments.length&&void 0!==arguments[4]&&arguments[4],s={top:0,left:0},d=p?E(e):a(e,t);if('viewport'===r)s=w(d,p);else{var l;'scrollParent'===r?(l=n(o(t)),'BODY'===l.nodeName&&(l=e.ownerDocument.documentElement)):'window'===r?l=e.ownerDocument.documentElement:l=r;var f=b(l,d,p);if('HTML'===l.nodeName&&!y(d)){var m=c(e.ownerDocument),h=m.height,g=m.width;s.top+=f.top-f.marginTop,s.bottom=h+f.top,s.left+=f.left-f.marginLeft,s.right=g+f.left}else s=f}i=i||0;var u='number'==typeof i;return s.left+=u?i:i.left||0,s.top+=u?i:i.top||0,s.right-=u?i:i.right||0,s.bottom-=u?i:i.bottom||0,s}function x(e){var t=e.width,o=e.height;return t*o}function O(e,t,o,n,i){var r=5<arguments.length&&void 0!==arguments[5]?arguments[5]:0;if(-1===e.indexOf('auto'))return e;var p=v(o,n,r,i),s={top:{width:p.width,height:t.top-p.top},right:{width:p.right-t.right,height:p.height},bottom:{width:p.width,height:p.bottom-t.bottom},left:{width:t.left-p.left,height:p.height}},d=Object.keys(s).map(function(e){return fe({key:e},s[e],{area:x(s[e])})}).sort(function(e,t){return t.area-e.area}),a=d.filter(function(e){var t=e.width,n=e.height;return t>=o.clientWidth&&n>=o.clientHeight}),l=0<a.length?a[0].key:d[0].key,f=e.split('-')[1];return l+(f?'-'+f:'')}function L(e,t,o){var n=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null,i=n?E(t):a(t,o);return b(o,i,n)}function S(e){var t=e.ownerDocument.defaultView,o=t.getComputedStyle(e),n=parseFloat(o.marginTop||0)+parseFloat(o.marginBottom||0),i=parseFloat(o.marginLeft||0)+parseFloat(o.marginRight||0),r={width:e.offsetWidth+i,height:e.offsetHeight+n};return r}function T(e){var t={left:'right',right:'left',bottom:'top',top:'bottom'};return e.replace(/left|right|bottom|top/g,function(e){return t[e]})}function C(e,t,o){o=o.split('-')[0];var n=S(e),i={width:n.width,height:n.height},r=-1!==['right','left'].indexOf(o),p=r?'top':'left',s=r?'left':'top',d=r?'height':'width',a=r?'width':'height';return i[p]=t[p]+t[d]/2-n[d]/2,i[s]=o===s?t[s]-n[a]:t[T(s)],i}function D(e,t){return Array.prototype.find?e.find(t):e.filter(t)[0]}function N(e,t,o){if(Array.prototype.findIndex)return e.findIndex(function(e){return e[t]===o});var n=D(e,function(e){return e[t]===o});return e.indexOf(n)}function P(t,o,n){var i=void 0===n?t:t.slice(0,N(t,'name',n));return i.forEach(function(t){t['function']&&console.warn('`modifier.function` is deprecated, use `modifier.fn`!');var n=t['function']||t.fn;t.enabled&&e(n)&&(o.offsets.popper=g(o.offsets.popper),o.offsets.reference=g(o.offsets.reference),o=n(o,t))}),o}function k(){if(!this.state.isDestroyed){var e={instance:this,styles:{},arrowStyles:{},attributes:{},flipped:!1,offsets:{}};e.offsets.reference=L(this.state,this.popper,this.reference,this.options.positionFixed),e.placement=O(this.options.placement,e.offsets.reference,this.popper,this.reference,this.options.modifiers.flip.boundariesElement,this.options.modifiers.flip.padding),e.originalPlacement=e.placement,e.positionFixed=this.options.positionFixed,e.offsets.popper=C(this.popper,e.offsets.reference,e.placement),e.offsets.popper.position=this.options.positionFixed?'fixed':'absolute',e=P(this.modifiers,e),this.state.isCreated?this.options.onUpdate(e):(this.state.isCreated=!0,this.options.onCreate(e))}}function W(e,t){return e.some(function(e){var o=e.name,n=e.enabled;return n&&o===t})}function B(e){for(var t=[!1,'ms','Webkit','Moz','O'],o=e.charAt(0).toUpperCase()+e.slice(1),n=0;n<t.length;n++){var i=t[n],r=i?''+i+o:e;if('undefined'!=typeof document.body.style[r])return r}return null}function H(){return this.state.isDestroyed=!0,W(this.modifiers,'applyStyle')&&(this.popper.removeAttribute('x-placement'),this.popper.style.position='',this.popper.style.top='',this.popper.style.left='',this.popper.style.right='',this.popper.style.bottom='',this.popper.style.willChange='',this.popper.style[B('transform')]=''),this.disableEventListeners(),this.options.removeOnDestroy&&this.popper.parentNode.removeChild(this.popper),this}function A(e){var t=e.ownerDocument;return t?t.defaultView:window}function M(e,t,o,i){var r='BODY'===e.nodeName,p=r?e.ownerDocument.defaultView:e;p.addEventListener(t,o,{passive:!0}),r||M(n(p.parentNode),t,o,i),i.push(p)}function F(e,t,o,i){o.updateBound=i,A(e).addEventListener('resize',o.updateBound,{passive:!0});var r=n(e);return M(r,'scroll',o.updateBound,o.scrollParents),o.scrollElement=r,o.eventsEnabled=!0,o}function I(){this.state.eventsEnabled||(this.state=F(this.reference,this.options,this.state,this.scheduleUpdate))}function R(e,t){return A(e).removeEventListener('resize',t.updateBound),t.scrollParents.forEach(function(e){e.removeEventListener('scroll',t.updateBound)}),t.updateBound=null,t.scrollParents=[],t.scrollElement=null,t.eventsEnabled=!1,t}function U(){this.state.eventsEnabled&&(cancelAnimationFrame(this.scheduleUpdate),this.state=R(this.reference,this.state))}function Y(e){return''!==e&&!isNaN(parseFloat(e))&&isFinite(e)}function V(e,t){Object.keys(t).forEach(function(o){var n='';-1!==['width','height','top','right','bottom','left'].indexOf(o)&&Y(t[o])&&(n='px'),e.style[o]=t[o]+n})}function j(e,t){Object.keys(t).forEach(function(o){var n=t[o];!1===n?e.removeAttribute(o):e.setAttribute(o,t[o])})}function q(e,t){var o=e.offsets,n=o.popper,i=o.reference,r=$,p=function(e){return e},s=r(i.width),d=r(n.width),a=-1!==['left','right'].indexOf(e.placement),l=-1!==e.placement.indexOf('-'),f=t?a||l||s%2==d%2?r:Z:p,m=t?r:p;return{left:f(1==s%2&&1==d%2&&!l&&t?n.left-1:n.left),top:m(n.top),bottom:m(n.bottom),right:f(n.right)}}function K(e,t,o){var n=D(e,function(e){var o=e.name;return o===t}),i=!!n&&e.some(function(e){return e.name===o&&e.enabled&&e.order<n.order});if(!i){var r='`'+t+'`';console.warn('`'+o+'`'+' modifier is required by '+r+' modifier in order to work, be sure to include it before '+r+'!')}return i}function z(e){return'end'===e?'start':'start'===e?'end':e}function G(e){var t=1<arguments.length&&void 0!==arguments[1]&&arguments[1],o=ce.indexOf(e),n=ce.slice(o+1).concat(ce.slice(0,o));return t?n.reverse():n}function _(e,t,o,n){var i=e.match(/((?:\-|\+)?\d*\.?\d*)(.*)/),r=+i[1],p=i[2];if(!r)return e;if(0===p.indexOf('%')){var s;switch(p){case'%p':s=o;break;case'%':case'%r':default:s=n;}var d=g(s);return d[t]/100*r}if('vh'===p||'vw'===p){var a;return a='vh'===p?ee(document.documentElement.clientHeight,window.innerHeight||0):ee(document.documentElement.clientWidth,window.innerWidth||0),a/100*r}return r}function X(e,t,o,n){var i=[0,0],r=-1!==['right','left'].indexOf(n),p=e.split(/(\+|\-)/).map(function(e){return e.trim()}),s=p.indexOf(D(p,function(e){return-1!==e.search(/,|\s/)}));p[s]&&-1===p[s].indexOf(',')&&console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.');var d=/\s*,\s*|\s+/,a=-1===s?[p]:[p.slice(0,s).concat([p[s].split(d)[0]]),[p[s].split(d)[1]].concat(p.slice(s+1))];return a=a.map(function(e,n){var i=(1===n?!r:r)?'height':'width',p=!1;return e.reduce(function(e,t){return''===e[e.length-1]&&-1!==['+','-'].indexOf(t)?(e[e.length-1]=t,p=!0,e):p?(e[e.length-1]+=t,p=!1,e):e.concat(t)},[]).map(function(e){return _(e,i,t,o)})}),a.forEach(function(e,t){e.forEach(function(o,n){Y(o)&&(i[t]+=o*('-'===e[n-1]?-1:1))})}),i}function J(e,t){var o,n=t.offset,i=e.placement,r=e.offsets,p=r.popper,s=r.reference,d=i.split('-')[0];return o=Y(+n)?[+n,0]:X(n,p,s,d),'left'===d?(p.top+=o[0],p.left-=o[1]):'right'===d?(p.top+=o[0],p.left+=o[1]):'top'===d?(p.left+=o[0],p.top-=o[1]):'bottom'===d&&(p.left+=o[0],p.top+=o[1]),e.popper=p,e}for(var Q=Math.min,Z=Math.floor,$=Math.round,ee=Math.max,te='undefined'!=typeof window&&'undefined'!=typeof document,oe=['Edge','Trident','Firefox'],ne=0,ie=0;ie<oe.length;ie+=1)if(te&&0<=navigator.userAgent.indexOf(oe[ie])){ne=1;break}var i=te&&window.Promise,re=i?function(e){var t=!1;return function(){t||(t=!0,window.Promise.resolve().then(function(){t=!1,e()}))}}:function(e){var t=!1;return function(){t||(t=!0,setTimeout(function(){t=!1,e()},ne))}},pe=te&&!!(window.MSInputMethodContext&&document.documentMode),se=te&&/MSIE 10/.test(navigator.userAgent),de=function(e,t){if(!(e instanceof t))throw new TypeError('Cannot call a class as a function')},ae=function(){function e(e,t){for(var o,n=0;n<t.length;n++)o=t[n],o.enumerable=o.enumerable||!1,o.configurable=!0,'value'in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}return function(t,o,n){return o&&e(t.prototype,o),n&&e(t,n),t}}(),le=function(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e},fe=Object.assign||function(e){for(var t,o=1;o<arguments.length;o++)for(var n in t=arguments[o],t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e},me=te&&/Firefox/i.test(navigator.userAgent),he=['auto-start','auto','auto-end','top-start','top','top-end','right-start','right','right-end','bottom-end','bottom','bottom-start','left-end','left','left-start'],ce=he.slice(3),ge={FLIP:'flip',CLOCKWISE:'clockwise',COUNTERCLOCKWISE:'counterclockwise'},ue=function(){function t(o,n){var i=this,r=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{};de(this,t),this.scheduleUpdate=function(){return requestAnimationFrame(i.update)},this.update=re(this.update.bind(this)),this.options=fe({},t.Defaults,r),this.state={isDestroyed:!1,isCreated:!1,scrollParents:[]},this.reference=o&&o.jquery?o[0]:o,this.popper=n&&n.jquery?n[0]:n,this.options.modifiers={},Object.keys(fe({},t.Defaults.modifiers,r.modifiers)).forEach(function(e){i.options.modifiers[e]=fe({},t.Defaults.modifiers[e]||{},r.modifiers?r.modifiers[e]:{})}),this.modifiers=Object.keys(this.options.modifiers).map(function(e){return fe({name:e},i.options.modifiers[e])}).sort(function(e,t){return e.order-t.order}),this.modifiers.forEach(function(t){t.enabled&&e(t.onLoad)&&t.onLoad(i.reference,i.popper,i.options,t,i.state)}),this.update();var p=this.options.eventsEnabled;p&&this.enableEventListeners(),this.state.eventsEnabled=p}return ae(t,[{key:'update',value:function(){return k.call(this)}},{key:'destroy',value:function(){return H.call(this)}},{key:'enableEventListeners',value:function(){return I.call(this)}},{key:'disableEventListeners',value:function(){return U.call(this)}}]),t}();return ue.Utils=('undefined'==typeof window?global:window).PopperUtils,ue.placements=he,ue.Defaults={placement:'bottom',positionFixed:!1,eventsEnabled:!0,removeOnDestroy:!1,onCreate:function(){},onUpdate:function(){},modifiers:{shift:{order:100,enabled:!0,fn:function(e){var t=e.placement,o=t.split('-')[0],n=t.split('-')[1];if(n){var i=e.offsets,r=i.reference,p=i.popper,s=-1!==['bottom','top'].indexOf(o),d=s?'left':'top',a=s?'width':'height',l={start:le({},d,r[d]),end:le({},d,r[d]+r[a]-p[a])};e.offsets.popper=fe({},p,l[n])}return e}},offset:{order:200,enabled:!0,fn:J,offset:0},preventOverflow:{order:300,enabled:!0,fn:function(e,t){var o=t.boundariesElement||p(e.instance.popper);e.instance.reference===o&&(o=p(o));var n=B('transform'),i=e.instance.popper.style,r=i.top,s=i.left,d=i[n];i.top='',i.left='',i[n]='';var a=v(e.instance.popper,e.instance.reference,t.padding,o,e.positionFixed);i.top=r,i.left=s,i[n]=d,t.boundaries=a;var l=t.priority,f=e.offsets.popper,m={primary:function(e){var o=f[e];return f[e]<a[e]&&!t.escapeWithReference&&(o=ee(f[e],a[e])),le({},e,o)},secondary:function(e){var o='right'===e?'left':'top',n=f[o];return f[e]>a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),le({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=fe({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]<r(n[d])&&(e.offsets.popper[d]=r(n[d])-o[a]),o[d]>r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-u<s[m]&&(e.offsets.popper[m]-=s[m]-(d[c]-u)),d[m]+u>s[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f],10),E=parseFloat(w['border'+f+'Width'],10),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},le(n,m,$(v)),le(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ge.FLIP:p=[n,i];break;case ge.CLOCKWISE:p=G(n);break;case ge.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)<f(l.right)||'top'===n&&f(a.bottom)>f(l.top)||'bottom'===n&&f(a.top)<f(l.bottom),h=f(a.left)<f(o.left),c=f(a.right)>f(o.right),g=f(a.top)<f(o.top),u=f(a.bottom)>f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u),E=!!t.flipVariationsByContent&&(w&&'start'===r&&c||w&&'end'===r&&h||!w&&'start'===r&&u||!w&&'end'===r&&g),v=y||E;(m||b||v)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),v&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=fe({},e.offsets.popper,C(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport',flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=D(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottom<o.top||t.left>o.right||t.top>o.bottom||t.right<o.left){if(!0===e.hide)return e;e.hide=!0,e.attributes['x-out-of-boundaries']=''}else{if(!1===e.hide)return e;e.hide=!1,e.attributes['x-out-of-boundaries']=!1}return e}},computeStyle:{order:850,enabled:!0,fn:function(e,t){var o=t.x,n=t.y,i=e.offsets.popper,r=D(e.instance.modifiers,function(e){return'applyStyle'===e.name}).gpuAcceleration;void 0!==r&&console.warn('WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!');var s,d,a=void 0===r?t.gpuAcceleration:r,l=p(e.instance.popper),f=u(l),m={position:i.position},h=q(e,2>window.devicePixelRatio||!me),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=B('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=fe({},E,e.attributes),e.styles=fe({},m,e.styles),e.arrowStyles=fe({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return V(e.instance.popper,e.styles),j(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&V(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),V(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ue});
//# sourceMappingURL=popper.min.js.map
!function(){function n(n){return n&&(n.ownerDocument||n.document||n).documentElement}function t(n){return n&&(n.ownerDocument&&n.ownerDocument.defaultView||n.document&&n||n.defaultView)}function e(n,t){return t>n?-1:n>t?1:n>=t?0:NaN}function r(n){return null===n?NaN:+n}function i(n){return!isNaN(n)}function u(n){return{left:function(t,e,r,i){for(arguments.length<3&&(r=0),arguments.length<4&&(i=t.length);i>r;){var u=r+i>>>1;n(t[u],e)<0?r=u+1:i=u}return r},right:function(t,e,r,i){for(arguments.length<3&&(r=0),arguments.length<4&&(i=t.length);i>r;){var u=r+i>>>1;n(t[u],e)>0?i=u:r=u+1}return r}}}function o(n){return n.length}function a(n){for(var t=1;n*t%1;)t*=10;return t}function l(n,t){for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}function c(){this._=Object.create(null)}function f(n){return(n+="")===bo||n[0]===_o?_o+n:n}function s(n){return(n+="")[0]===_o?n.slice(1):n}function h(n){return f(n)in this._}function p(n){return(n=f(n))in this._&&delete this._[n]}function g(){var n=[];for(var t in this._)n.push(s(t));return n}function v(){var n=0;for(var t in this._)++n;return n}function d(){for(var n in this._)return!1;return!0}function y(){this._=Object.create(null)}function m(n){return n}function M(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function x(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(var e=0,r=wo.length;r>e;++e){var i=wo[e]+t;if(i in n)return i}}function b(){}function _(){}function w(n){function t(){for(var t,r=e,i=-1,u=r.length;++i<u;)(t=r[i].on)&&t.apply(this,arguments);return n}var e=[],r=new c;return t.on=function(t,i){var u,o=r.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,e=e.slice(0,u=e.indexOf(o)).concat(e.slice(u+1)),r.remove(t)),i&&e.push(r.set(t,{on:i})),n)},t}function S(){ao.event.preventDefault()}function k(){for(var n,t=ao.event;n=t.sourceEvent;)t=n;return t}function N(n){for(var t=new _,e=0,r=arguments.length;++e<r;)t[arguments[e]]=w(t);return t.of=function(e,r){return function(i){try{var u=i.sourceEvent=ao.event;i.target=n,ao.event=i,t[i.type].apply(e,r)}finally{ao.event=u}}},t}function E(n){return ko(n,Co),n}function A(n){return"function"==typeof n?n:function(){return No(n,this)}}function C(n){return"function"==typeof n?n:function(){return Eo(n,this)}}function z(n,t){function e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function i(){this.setAttribute(n,t)}function u(){this.setAttributeNS(n.space,n.local,t)}function o(){var e=t.apply(this,arguments);null==e?this.removeAttribute(n):this.setAttribute(n,e)}function a(){var e=t.apply(this,arguments);null==e?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,e)}return n=ao.ns.qualify(n),null==t?n.local?r:e:"function"==typeof t?n.local?a:o:n.local?u:i}function L(n){return n.trim().replace(/\s+/g," ")}function q(n){return new RegExp("(?:^|\\s+)"+ao.requote(n)+"(?:\\s+|$)","g")}function T(n){return(n+"").trim().split(/^|\s+/)}function R(n,t){function e(){for(var e=-1;++e<i;)n[e](this,t)}function r(){for(var e=-1,r=t.apply(this,arguments);++e<i;)n[e](this,r)}n=T(n).map(D);var i=n.length;return"function"==typeof t?r:e}function D(n){var t=q(n);return function(e,r){if(i=e.classList)return r?i.add(n):i.remove(n);var i=e.getAttribute("class")||"";r?(t.lastIndex=0,t.test(i)||e.setAttribute("class",L(i+" "+n))):e.setAttribute("class",L(i.replace(t," ")))}}function P(n,t,e){function r(){this.style.removeProperty(n)}function i(){this.style.setProperty(n,t,e)}function u(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(n):this.style.setProperty(n,r,e)}return null==t?r:"function"==typeof t?u:i}function U(n,t){function e(){delete this[n]}function r(){this[n]=t}function i(){var e=t.apply(this,arguments);null==e?delete this[n]:this[n]=e}return null==t?e:"function"==typeof t?i:r}function j(n){function t(){var t=this.ownerDocument,e=this.namespaceURI;return e===zo&&t.documentElement.namespaceURI===zo?t.createElement(n):t.createElementNS(e,n)}function e(){return this.ownerDocument.createElementNS(n.space,n.local)}return"function"==typeof n?n:(n=ao.ns.qualify(n)).local?e:t}function F(){var n=this.parentNode;n&&n.removeChild(this)}function H(n){return{__data__:n}}function O(n){return function(){return Ao(this,n)}}function I(n){return arguments.length||(n=e),function(t,e){return t&&e?n(t.__data__,e.__data__):!t-!e}}function Y(n,t){for(var e=0,r=n.length;r>e;e++)for(var i,u=n[e],o=0,a=u.length;a>o;o++)(i=u[o])&&t(i,o,e);return n}function Z(n){return ko(n,qo),n}function V(n){var t,e;return function(r,i,u){var o,a=n[u].update,l=a.length;for(u!=e&&(e=u,t=0),i>=t&&(t=i+1);!(o=a[t])&&++t<l;);return o}}function X(n,t,e){function r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function i(){var i=l(t,co(arguments));r.call(this),this.addEventListener(n,this[o]=i,i.$=e),i._=t}function u(){var t,e=new RegExp("^__on([^.]+)"+ao.requote(n)+"$");for(var r in this)if(t=r.match(e)){var i=this[r];this.removeEventListener(t[1],i,i.$),delete this[r]}}var o="__on"+n,a=n.indexOf("."),l=$;a>0&&(n=n.slice(0,a));var c=To.get(n);return c&&(n=c,l=B),a?t?i:r:t?b:u}function $(n,t){return function(e){var r=ao.event;ao.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{ao.event=r}}}function B(n,t){var e=$(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function W(e){var r=".dragsuppress-"+ ++Do,i="click"+r,u=ao.select(t(e)).on("touchmove"+r,S).on("dragstart"+r,S).on("selectstart"+r,S);if(null==Ro&&(Ro="onselectstart"in e?!1:x(e.style,"userSelect")),Ro){var o=n(e).style,a=o[Ro];o[Ro]="none"}return function(n){if(u.on(r,null),Ro&&(o[Ro]=a),n){var t=function(){u.on(i,null)};u.on(i,function(){S(),t()},!0),setTimeout(t,0)}}}function J(n,e){e.changedTouches&&(e=e.changedTouches[0]);var r=n.ownerSVGElement||n;if(r.createSVGPoint){var i=r.createSVGPoint();if(0>Po){var u=t(n);if(u.scrollX||u.scrollY){r=ao.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var o=r[0][0].getScreenCTM();Po=!(o.f||o.e),r.remove()}}return Po?(i.x=e.pageX,i.y=e.pageY):(i.x=e.clientX,i.y=e.clientY),i=i.matrixTransform(n.getScreenCTM().inverse()),[i.x,i.y]}var a=n.getBoundingClientRect();return[e.clientX-a.left-n.clientLeft,e.clientY-a.top-n.clientTop]}function G(){return ao.event.changedTouches[0].identifier}function K(n){return n>0?1:0>n?-1:0}function Q(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function nn(n){return n>1?0:-1>n?Fo:Math.acos(n)}function tn(n){return n>1?Io:-1>n?-Io:Math.asin(n)}function en(n){return((n=Math.exp(n))-1/n)/2}function rn(n){return((n=Math.exp(n))+1/n)/2}function un(n){return((n=Math.exp(2*n))-1)/(n+1)}function on(n){return(n=Math.sin(n/2))*n}function an(){}function ln(n,t,e){return this instanceof ln?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof ln?new ln(n.h,n.s,n.l):_n(""+n,wn,ln):new ln(n,t,e)}function cn(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?u+(o-u)*n/60:180>n?o:240>n?u+(o-u)*(240-n)/60:u}function i(n){return Math.round(255*r(n))}var u,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,u=2*e-o,new mn(i(n+120),i(n),i(n-120))}function fn(n,t,e){return this instanceof fn?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof fn?new fn(n.h,n.c,n.l):n instanceof hn?gn(n.l,n.a,n.b):gn((n=Sn((n=ao.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new fn(n,t,e)}function sn(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new hn(e,Math.cos(n*=Yo)*t,Math.sin(n)*t)}function hn(n,t,e){return this instanceof hn?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof hn?new hn(n.l,n.a,n.b):n instanceof fn?sn(n.h,n.c,n.l):Sn((n=mn(n)).r,n.g,n.b):new hn(n,t,e)}function pn(n,t,e){var r=(n+16)/116,i=r+t/500,u=r-e/200;return i=vn(i)*na,r=vn(r)*ta,u=vn(u)*ea,new mn(yn(3.2404542*i-1.5371385*r-.4985314*u),yn(-.969266*i+1.8760108*r+.041556*u),yn(.0556434*i-.2040259*r+1.0572252*u))}function gn(n,t,e){return n>0?new fn(Math.atan2(e,t)*Zo,Math.sqrt(t*t+e*e),n):new fn(NaN,NaN,n)}function vn(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function dn(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function yn(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function mn(n,t,e){return this instanceof mn?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof mn?new mn(n.r,n.g,n.b):_n(""+n,mn,cn):new mn(n,t,e)}function Mn(n){return new mn(n>>16,n>>8&255,255&n)}function xn(n){return Mn(n)+""}function bn(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function _n(n,t,e){var r,i,u,o=0,a=0,l=0;if(r=/([a-z]+)\((.*)\)/.exec(n=n.toLowerCase()))switch(i=r[2].split(","),r[1]){case"hsl":return e(parseFloat(i[0]),parseFloat(i[1])/100,parseFloat(i[2])/100);case"rgb":return t(Nn(i[0]),Nn(i[1]),Nn(i[2]))}return(u=ua.get(n))?t(u.r,u.g,u.b):(null==n||"#"!==n.charAt(0)||isNaN(u=parseInt(n.slice(1),16))||(4===n.length?(o=(3840&u)>>4,o=o>>4|o,a=240&u,a=a>>4|a,l=15&u,l=l<<4|l):7===n.length&&(o=(16711680&u)>>16,a=(65280&u)>>8,l=255&u)),t(o,a,l))}function wn(n,t,e){var r,i,u=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-u,l=(o+u)/2;return a?(i=.5>l?a/(o+u):a/(2-o-u),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=NaN,i=l>0&&1>l?0:r),new ln(r,i,l)}function Sn(n,t,e){n=kn(n),t=kn(t),e=kn(e);var r=dn((.4124564*n+.3575761*t+.1804375*e)/na),i=dn((.2126729*n+.7151522*t+.072175*e)/ta),u=dn((.0193339*n+.119192*t+.9503041*e)/ea);return hn(116*i-16,500*(r-i),200*(i-u))}function kn(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function Nn(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function En(n){return"function"==typeof n?n:function(){return n}}function An(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),Cn(t,e,n,r)}}function Cn(n,t,e,r){function i(){var n,t=l.status;if(!t&&Ln(l)||t>=200&&300>t||304===t){try{n=e.call(u,l)}catch(r){return void o.error.call(u,r)}o.load.call(u,n)}else o.error.call(u,l)}var u={},o=ao.dispatch("beforesend","progress","load","error"),a={},l=new XMLHttpRequest,c=null;return!this.XDomainRequest||"withCredentials"in l||!/^(http(s)?:)?\/\//.test(n)||(l=new XDomainRequest),"onload"in l?l.onload=l.onerror=i:l.onreadystatechange=function(){l.readyState>3&&i()},l.onprogress=function(n){var t=ao.event;ao.event=n;try{o.progress.call(u,l)}finally{ao.event=t}},u.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",u)},u.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",u):t},u.responseType=function(n){return arguments.length?(c=n,u):c},u.response=function(n){return e=n,u},["get","post"].forEach(function(n){u[n]=function(){return u.send.apply(u,[n].concat(co(arguments)))}}),u.send=function(e,r,i){if(2===arguments.length&&"function"==typeof r&&(i=r,r=null),l.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),l.setRequestHeader)for(var f in a)l.setRequestHeader(f,a[f]);return null!=t&&l.overrideMimeType&&l.overrideMimeType(t),null!=c&&(l.responseType=c),null!=i&&u.on("error",i).on("load",function(n){i(null,n)}),o.beforesend.call(u,l),l.send(null==r?null:r),u},u.abort=function(){return l.abort(),u},ao.rebind(u,o,"on"),null==r?u:u.get(zn(r))}function zn(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function Ln(n){var t=n.responseType;return t&&"text"!==t?n.response:n.responseText}function qn(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var i=e+t,u={c:n,t:i,n:null};return aa?aa.n=u:oa=u,aa=u,la||(ca=clearTimeout(ca),la=1,fa(Tn)),u}function Tn(){var n=Rn(),t=Dn()-n;t>24?(isFinite(t)&&(clearTimeout(ca),ca=setTimeout(Tn,t)),la=0):(la=1,fa(Tn))}function Rn(){for(var n=Date.now(),t=oa;t;)n>=t.t&&t.c(n-t.t)&&(t.c=null),t=t.n;return n}function Dn(){for(var n,t=oa,e=1/0;t;)t.c?(t.t<e&&(e=t.t),t=(n=t).n):t=n?n.n=t.n:oa=t.n;return aa=n,e}function Pn(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Un(n,t){var e=Math.pow(10,3*xo(8-t));return{scale:t>8?function(n){return n/e}:function(n){return n*e},symbol:n}}function jn(n){var t=n.decimal,e=n.thousands,r=n.grouping,i=n.currency,u=r&&e?function(n,t){for(var i=n.length,u=[],o=0,a=r[0],l=0;i>0&&a>0&&(l+a+1>t&&(a=Math.max(1,t-l)),u.push(n.substring(i-=a,i+a)),!((l+=a+1)>t));)a=r[o=(o+1)%r.length];return u.reverse().join(e)}:m;return function(n){var e=ha.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"-",l=e[4]||"",c=e[5],f=+e[6],s=e[7],h=e[8],p=e[9],g=1,v="",d="",y=!1,m=!0;switch(h&&(h=+h.substring(1)),(c||"0"===r&&"="===o)&&(c=r="0",o="="),p){case"n":s=!0,p="g";break;case"%":g=100,d="%",p="f";break;case"p":g=100,d="%",p="r";break;case"b":case"o":case"x":case"X":"#"===l&&(v="0"+p.toLowerCase());case"c":m=!1;case"d":y=!0,h=0;break;case"s":g=-1,p="r"}"$"===l&&(v=i[0],d=i[1]),"r"!=p||h||(p="g"),null!=h&&("g"==p?h=Math.max(1,Math.min(21,h)):"e"!=p&&"f"!=p||(h=Math.max(0,Math.min(20,h)))),p=pa.get(p)||Fn;var M=c&&s;return function(n){var e=d;if(y&&n%1)return"";var i=0>n||0===n&&0>1/n?(n=-n,"-"):"-"===a?"":a;if(0>g){var l=ao.formatPrefix(n,h);n=l.scale(n),e=l.symbol+d}else n*=g;n=p(n,h);var x,b,_=n.lastIndexOf(".");if(0>_){var w=m?n.lastIndexOf("e"):-1;0>w?(x=n,b=""):(x=n.substring(0,w),b=n.substring(w))}else x=n.substring(0,_),b=t+n.substring(_+1);!c&&s&&(x=u(x,1/0));var S=v.length+x.length+b.length+(M?0:i.length),k=f>S?new Array(S=f-S+1).join(r):"";return M&&(x=u(k+x,k.length?f-b.length:1/0)),i+=v,n=x+b,("<"===o?i+n+k:">"===o?k+i+n:"^"===o?k.substring(0,S>>=1)+i+n+k.substring(S):i+(M?n:k+n))+e}}}function Fn(n){return n+""}function Hn(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function On(n,t,e){function r(t){var e=n(t),r=u(e,1);return r-t>t-e?e:r}function i(e){return t(e=n(new va(e-1)),1),e}function u(n,e){return t(n=new va(+n),e),n}function o(n,r,u){var o=i(n),a=[];if(u>1)for(;r>o;)e(o)%u||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{va=Hn;var r=new Hn;return r._=n,o(r,t,e)}finally{va=Date}}n.floor=n,n.round=r,n.ceil=i,n.offset=u,n.range=o;var l=n.utc=In(n);return l.floor=l,l.round=In(r),l.ceil=In(i),l.offset=In(u),l.range=a,n}function In(n){return function(t,e){try{va=Hn;var r=new Hn;return r._=t,n(r,e)._}finally{va=Date}}}function Yn(n){function t(n){function t(t){for(var e,i,u,o=[],a=-1,l=0;++a<r;)37===n.charCodeAt(a)&&(o.push(n.slice(l,a)),null!=(i=ya[e=n.charAt(++a)])&&(e=n.charAt(++a)),(u=A[e])&&(e=u(t,null==i?"e"===e?" ":"0":i)),o.push(e),l=a+1);return o.push(n.slice(l,a)),o.join("")}var r=n.length;return t.parse=function(t){var r={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},i=e(r,n,t,0);if(i!=t.length)return null;"p"in r&&(r.H=r.H%12+12*r.p);var u=null!=r.Z&&va!==Hn,o=new(u?Hn:va);return"j"in r?o.setFullYear(r.y,0,r.j):"W"in r||"U"in r?("w"in r||(r.w="W"in r?1:0),o.setFullYear(r.y,0,1),o.setFullYear(r.y,0,"W"in r?(r.w+6)%7+7*r.W-(o.getDay()+5)%7:r.w+7*r.U-(o.getDay()+6)%7)):o.setFullYear(r.y,r.m,r.d),o.setHours(r.H+(r.Z/100|0),r.M+r.Z%100,r.S,r.L),u?o._:o},t.toString=function(){return n},t}function e(n,t,e,r){for(var i,u,o,a=0,l=t.length,c=e.length;l>a;){if(r>=c)return-1;if(i=t.charCodeAt(a++),37===i){if(o=t.charAt(a++),u=C[o in ya?t.charAt(a++):o],!u||(r=u(n,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){_.lastIndex=0;var r=_.exec(t.slice(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){x.lastIndex=0;var r=x.exec(t.slice(e));return r?(n.w=b.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){N.lastIndex=0;var r=N.exec(t.slice(e));return r?(n.m=E.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,e){S.lastIndex=0;var r=S.exec(t.slice(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,r){return e(n,A.c.toString(),t,r)}function l(n,t,r){return e(n,A.x.toString(),t,r)}function c(n,t,r){return e(n,A.X.toString(),t,r)}function f(n,t,e){var r=M.get(t.slice(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var s=n.dateTime,h=n.date,p=n.time,g=n.periods,v=n.days,d=n.shortDays,y=n.months,m=n.shortMonths;t.utc=function(n){function e(n){try{va=Hn;var t=new va;return t._=n,r(t)}finally{va=Date}}var r=t(n);return e.parse=function(n){try{va=Hn;var t=r.parse(n);return t&&t._}finally{va=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=ct;var M=ao.map(),x=Vn(v),b=Xn(v),_=Vn(d),w=Xn(d),S=Vn(y),k=Xn(y),N=Vn(m),E=Xn(m);g.forEach(function(n,t){M.set(n.toLowerCase(),t)});var A={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return m[n.getMonth()]},B:function(n){return y[n.getMonth()]},c:t(s),d:function(n,t){return Zn(n.getDate(),t,2)},e:function(n,t){return Zn(n.getDate(),t,2)},H:function(n,t){return Zn(n.getHours(),t,2)},I:function(n,t){return Zn(n.getHours()%12||12,t,2)},j:function(n,t){return Zn(1+ga.dayOfYear(n),t,3)},L:function(n,t){return Zn(n.getMilliseconds(),t,3)},m:function(n,t){return Zn(n.getMonth()+1,t,2)},M:function(n,t){return Zn(n.getMinutes(),t,2)},p:function(n){return g[+(n.getHours()>=12)]},S:function(n,t){return Zn(n.getSeconds(),t,2)},U:function(n,t){return Zn(ga.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return Zn(ga.mondayOfYear(n),t,2)},x:t(h),X:t(p),y:function(n,t){return Zn(n.getFullYear()%100,t,2)},Y:function(n,t){return Zn(n.getFullYear()%1e4,t,4)},Z:at,"%":function(){return"%"}},C={a:r,A:i,b:u,B:o,c:a,d:tt,e:tt,H:rt,I:rt,j:et,L:ot,m:nt,M:it,p:f,S:ut,U:Bn,w:$n,W:Wn,x:l,X:c,y:Gn,Y:Jn,Z:Kn,"%":lt};return t}function Zn(n,t,e){var r=0>n?"-":"",i=(r?-n:n)+"",u=i.length;return r+(e>u?new Array(e-u+1).join(t)+i:i)}function Vn(n){return new RegExp("^(?:"+n.map(ao.requote).join("|")+")","i")}function Xn(n){for(var t=new c,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return t}function $n(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Bn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e));return r?(n.U=+r[0],e+r[0].length):-1}function Wn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e));return r?(n.W=+r[0],e+r[0].length):-1}function Jn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Gn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.y=Qn(+r[0]),e+r[0].length):-1}function Kn(n,t,e){return/^[+-]\d{4}$/.test(t=t.slice(e,e+5))?(n.Z=-t,e+5):-1}function Qn(n){return n+(n>68?1900:2e3)}function nt(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function tt(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function et(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function rt(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function it(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function ut(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ot(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function at(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=xo(t)/60|0,i=xo(t)%60;return e+Zn(r,"0",2)+Zn(i,"0",2)}function lt(n,t,e){Ma.lastIndex=0;var r=Ma.exec(t.slice(e,e+1));return r?e+r[0].length:-1}function ct(n){for(var t=n.length,e=-1;++e<t;)n[e][0]=this(n[e][0]);return function(t){for(var e=0,r=n[e];!r[1](t);)r=n[++e];return r[0](t)}}function ft(){}function st(n,t,e){var r=e.s=n+t,i=r-n,u=r-i;e.t=n-u+(t-i)}function ht(n,t){n&&wa.hasOwnProperty(n.type)&&wa[n.type](n,t)}function pt(n,t,e){var r,i=-1,u=n.length-e;for(t.lineStart();++i<u;)r=n[i],t.point(r[0],r[1],r[2]);t.lineEnd()}function gt(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)pt(n[e],t,1);t.polygonEnd()}function vt(){function n(n,t){n*=Yo,t=t*Yo/2+Fo/4;var e=n-r,o=e>=0?1:-1,a=o*e,l=Math.cos(t),c=Math.sin(t),f=u*c,s=i*l+f*Math.cos(a),h=f*o*Math.sin(a);ka.add(Math.atan2(h,s)),r=n,i=l,u=c}var t,e,r,i,u;Na.point=function(o,a){Na.point=n,r=(t=o)*Yo,i=Math.cos(a=(e=a)*Yo/2+Fo/4),u=Math.sin(a)},Na.lineEnd=function(){n(t,e)}}function dt(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function yt(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function mt(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function Mt(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function xt(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function bt(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function _t(n){return[Math.atan2(n[1],n[0]),tn(n[2])]}function wt(n,t){return xo(n[0]-t[0])<Uo&&xo(n[1]-t[1])<Uo}function St(n,t){n*=Yo;var e=Math.cos(t*=Yo);kt(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function kt(n,t,e){++Ea,Ca+=(n-Ca)/Ea,za+=(t-za)/Ea,La+=(e-La)/Ea}function Nt(){function n(n,i){n*=Yo;var u=Math.cos(i*=Yo),o=u*Math.cos(n),a=u*Math.sin(n),l=Math.sin(i),c=Math.atan2(Math.sqrt((c=e*l-r*a)*c+(c=r*o-t*l)*c+(c=t*a-e*o)*c),t*o+e*a+r*l);Aa+=c,qa+=c*(t+(t=o)),Ta+=c*(e+(e=a)),Ra+=c*(r+(r=l)),kt(t,e,r)}var t,e,r;ja.point=function(i,u){i*=Yo;var o=Math.cos(u*=Yo);t=o*Math.cos(i),e=o*Math.sin(i),r=Math.sin(u),ja.point=n,kt(t,e,r)}}function Et(){ja.point=St}function At(){function n(n,t){n*=Yo;var e=Math.cos(t*=Yo),o=e*Math.cos(n),a=e*Math.sin(n),l=Math.sin(t),c=i*l-u*a,f=u*o-r*l,s=r*a-i*o,h=Math.sqrt(c*c+f*f+s*s),p=r*o+i*a+u*l,g=h&&-nn(p)/h,v=Math.atan2(h,p);Da+=g*c,Pa+=g*f,Ua+=g*s,Aa+=v,qa+=v*(r+(r=o)),Ta+=v*(i+(i=a)),Ra+=v*(u+(u=l)),kt(r,i,u)}var t,e,r,i,u;ja.point=function(o,a){t=o,e=a,ja.point=n,o*=Yo;var l=Math.cos(a*=Yo);r=l*Math.cos(o),i=l*Math.sin(o),u=Math.sin(a),kt(r,i,u)},ja.lineEnd=function(){n(t,e),ja.lineEnd=Et,ja.point=St}}function Ct(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.invert&&t.invert&&(e.invert=function(e,r){return e=t.invert(e,r),e&&n.invert(e[0],e[1])}),e}function zt(){return!0}function Lt(n,t,e,r,i){var u=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,e=n[0],r=n[t];if(wt(e,r)){i.lineStart();for(var a=0;t>a;++a)i.point((e=n[a])[0],e[1]);return void i.lineEnd()}var l=new Tt(e,n,null,!0),c=new Tt(e,null,l,!1);l.o=c,u.push(l),o.push(c),l=new Tt(r,n,null,!1),c=new Tt(r,null,l,!0),l.o=c,u.push(l),o.push(c)}}),o.sort(t),qt(u),qt(o),u.length){for(var a=0,l=e,c=o.length;c>a;++a)o[a].e=l=!l;for(var f,s,h=u[0];;){for(var p=h,g=!0;p.v;)if((p=p.n)===h)return;f=p.z,i.lineStart();do{if(p.v=p.o.v=!0,p.e){if(g)for(var a=0,c=f.length;c>a;++a)i.point((s=f[a])[0],s[1]);else r(p.x,p.n.x,1,i);p=p.n}else{if(g){f=p.p.z;for(var a=f.length-1;a>=0;--a)i.point((s=f[a])[0],s[1])}else r(p.x,p.p.x,-1,i);p=p.p}p=p.o,f=p.z,g=!g}while(!p.v);i.lineEnd()}}}function qt(n){if(t=n.length){for(var t,e,r=0,i=n[0];++r<t;)i.n=e=n[r],e.p=i,i=e;i.n=e=n[0],e.p=i}}function Tt(n,t,e,r){this.x=n,this.z=t,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Rt(n,t,e,r){return function(i,u){function o(t,e){var r=i(t,e);n(t=r[0],e=r[1])&&u.point(t,e)}function a(n,t){var e=i(n,t);d.point(e[0],e[1])}function l(){m.point=a,d.lineStart()}function c(){m.point=o,d.lineEnd()}function f(n,t){v.push([n,t]);var e=i(n,t);x.point(e[0],e[1])}function s(){x.lineStart(),v=[]}function h(){f(v[0][0],v[0][1]),x.lineEnd();var n,t=x.clean(),e=M.buffer(),r=e.length;if(v.pop(),g.push(v),v=null,r)if(1&t){n=e[0];var i,r=n.length-1,o=-1;if(r>0){for(b||(u.polygonStart(),b=!0),u.lineStart();++o<r;)u.point((i=n[o])[0],i[1]);u.lineEnd()}}else r>1&&2&t&&e.push(e.pop().concat(e.shift())),p.push(e.filter(Dt))}var p,g,v,d=t(u),y=i.invert(r[0],r[1]),m={point:o,lineStart:l,lineEnd:c,polygonStart:function(){m.point=f,m.lineStart=s,m.lineEnd=h,p=[],g=[]},polygonEnd:function(){m.point=o,m.lineStart=l,m.lineEnd=c,p=ao.merge(p);var n=Ot(y,g);p.length?(b||(u.polygonStart(),b=!0),Lt(p,Ut,n,e,u)):n&&(b||(u.polygonStart(),b=!0),u.lineStart(),e(null,null,1,u),u.lineEnd()),b&&(u.polygonEnd(),b=!1),p=g=null},sphere:function(){u.polygonStart(),u.lineStart(),e(null,null,1,u),u.lineEnd(),u.polygonEnd()}},M=Pt(),x=t(M),b=!1;return m}}function Dt(n){return n.length>1}function Pt(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:b,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function Ut(n,t){return((n=n.x)[0]<0?n[1]-Io-Uo:Io-n[1])-((t=t.x)[0]<0?t[1]-Io-Uo:Io-t[1])}function jt(n){var t,e=NaN,r=NaN,i=NaN;return{lineStart:function(){n.lineStart(),t=1},point:function(u,o){var a=u>0?Fo:-Fo,l=xo(u-e);xo(l-Fo)<Uo?(n.point(e,r=(r+o)/2>0?Io:-Io),n.point(i,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(u,r),t=0):i!==a&&l>=Fo&&(xo(e-i)<Uo&&(e-=i*Uo),xo(u-a)<Uo&&(u-=a*Uo),r=Ft(e,r,u,o),n.point(i,r),n.lineEnd(),n.lineStart(),n.point(a,r),t=0),n.point(e=u,r=o),i=a},lineEnd:function(){n.lineEnd(),e=r=NaN},clean:function(){return 2-t}}}function Ft(n,t,e,r){var i,u,o=Math.sin(n-e);return xo(o)>Uo?Math.atan((Math.sin(t)*(u=Math.cos(r))*Math.sin(e)-Math.sin(r)*(i=Math.cos(t))*Math.sin(n))/(i*u*o)):(t+r)/2}function Ht(n,t,e,r){var i;if(null==n)i=e*Io,r.point(-Fo,i),r.point(0,i),r.point(Fo,i),r.point(Fo,0),r.point(Fo,-i),r.point(0,-i),r.point(-Fo,-i),r.point(-Fo,0),r.point(-Fo,i);else if(xo(n[0]-t[0])>Uo){var u=n[0]<t[0]?Fo:-Fo;i=e*u/2,r.point(-u,i),r.point(0,i),r.point(u,i)}else r.point(t[0],t[1])}function Ot(n,t){var e=n[0],r=n[1],i=[Math.sin(e),-Math.cos(e),0],u=0,o=0;ka.reset();for(var a=0,l=t.length;l>a;++a){var c=t[a],f=c.length;if(f)for(var s=c[0],h=s[0],p=s[1]/2+Fo/4,g=Math.sin(p),v=Math.cos(p),d=1;;){d===f&&(d=0),n=c[d];var y=n[0],m=n[1]/2+Fo/4,M=Math.sin(m),x=Math.cos(m),b=y-h,_=b>=0?1:-1,w=_*b,S=w>Fo,k=g*M;if(ka.add(Math.atan2(k*_*Math.sin(w),v*x+k*Math.cos(w))),u+=S?b+_*Ho:b,S^h>=e^y>=e){var N=mt(dt(s),dt(n));bt(N);var E=mt(i,N);bt(E);var A=(S^b>=0?-1:1)*tn(E[2]);(r>A||r===A&&(N[0]||N[1]))&&(o+=S^b>=0?1:-1)}if(!d++)break;h=y,g=M,v=x,s=n}}return(-Uo>u||Uo>u&&-Uo>ka)^1&o}function It(n){function t(n,t){return Math.cos(n)*Math.cos(t)>u}function e(n){var e,u,l,c,f;return{lineStart:function(){c=l=!1,f=1},point:function(s,h){var p,g=[s,h],v=t(s,h),d=o?v?0:i(s,h):v?i(s+(0>s?Fo:-Fo),h):0;if(!e&&(c=l=v)&&n.lineStart(),v!==l&&(p=r(e,g),(wt(e,p)||wt(g,p))&&(g[0]+=Uo,g[1]+=Uo,v=t(g[0],g[1]))),v!==l)f=0,v?(n.lineStart(),p=r(g,e),n.point(p[0],p[1])):(p=r(e,g),n.point(p[0],p[1]),n.lineEnd()),e=p;else if(a&&e&&o^v){var y;d&u||!(y=r(g,e,!0))||(f=0,o?(n.lineStart(),n.point(y[0][0],y[0][1]),n.point(y[1][0],y[1][1]),n.lineEnd()):(n.point(y[1][0],y[1][1]),n.lineEnd(),n.lineStart(),n.point(y[0][0],y[0][1])))}!v||e&&wt(e,g)||n.point(g[0],g[1]),e=g,l=v,u=d},lineEnd:function(){l&&n.lineEnd(),e=null},clean:function(){return f|(c&&l)<<1}}}function r(n,t,e){var r=dt(n),i=dt(t),o=[1,0,0],a=mt(r,i),l=yt(a,a),c=a[0],f=l-c*c;if(!f)return!e&&n;var s=u*l/f,h=-u*c/f,p=mt(o,a),g=xt(o,s),v=xt(a,h);Mt(g,v);var d=p,y=yt(g,d),m=yt(d,d),M=y*y-m*(yt(g,g)-1);if(!(0>M)){var x=Math.sqrt(M),b=xt(d,(-y-x)/m);if(Mt(b,g),b=_t(b),!e)return b;var _,w=n[0],S=t[0],k=n[1],N=t[1];w>S&&(_=w,w=S,S=_);var E=S-w,A=xo(E-Fo)<Uo,C=A||Uo>E;if(!A&&k>N&&(_=k,k=N,N=_),C?A?k+N>0^b[1]<(xo(b[0]-w)<Uo?k:N):k<=b[1]&&b[1]<=N:E>Fo^(w<=b[0]&&b[0]<=S)){var z=xt(d,(-y+x)/m);return Mt(z,g),[b,_t(z)]}}}function i(t,e){var r=o?n:Fo-n,i=0;return-r>t?i|=1:t>r&&(i|=2),-r>e?i|=4:e>r&&(i|=8),i}var u=Math.cos(n),o=u>0,a=xo(u)>Uo,l=ve(n,6*Yo);return Rt(t,e,l,o?[0,-n]:[-Fo,n-Fo])}function Yt(n,t,e,r){return function(i){var u,o=i.a,a=i.b,l=o.x,c=o.y,f=a.x,s=a.y,h=0,p=1,g=f-l,v=s-c;if(u=n-l,g||!(u>0)){if(u/=g,0>g){if(h>u)return;p>u&&(p=u)}else if(g>0){if(u>p)return;u>h&&(h=u)}if(u=e-l,g||!(0>u)){if(u/=g,0>g){if(u>p)return;u>h&&(h=u)}else if(g>0){if(h>u)return;p>u&&(p=u)}if(u=t-c,v||!(u>0)){if(u/=v,0>v){if(h>u)return;p>u&&(p=u)}else if(v>0){if(u>p)return;u>h&&(h=u)}if(u=r-c,v||!(0>u)){if(u/=v,0>v){if(u>p)return;u>h&&(h=u)}else if(v>0){if(h>u)return;p>u&&(p=u)}return h>0&&(i.a={x:l+h*g,y:c+h*v}),1>p&&(i.b={x:l+p*g,y:c+p*v}),i}}}}}}function Zt(n,t,e,r){function i(r,i){return xo(r[0]-n)<Uo?i>0?0:3:xo(r[0]-e)<Uo?i>0?2:1:xo(r[1]-t)<Uo?i>0?1:0:i>0?3:2}function u(n,t){return o(n.x,t.x)}function o(n,t){var e=i(n,1),r=i(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(a){function l(n){for(var t=0,e=d.length,r=n[1],i=0;e>i;++i)for(var u,o=1,a=d[i],l=a.length,c=a[0];l>o;++o)u=a[o],c[1]<=r?u[1]>r&&Q(c,u,n)>0&&++t:u[1]<=r&&Q(c,u,n)<0&&--t,c=u;return 0!==t}function c(u,a,l,c){var f=0,s=0;if(null==u||(f=i(u,l))!==(s=i(a,l))||o(u,a)<0^l>0){do c.point(0===f||3===f?n:e,f>1?r:t);while((f=(f+l+4)%4)!==s)}else c.point(a[0],a[1])}function f(i,u){return i>=n&&e>=i&&u>=t&&r>=u}function s(n,t){f(n,t)&&a.point(n,t)}function h(){C.point=g,d&&d.push(y=[]),S=!0,w=!1,b=_=NaN}function p(){v&&(g(m,M),x&&w&&E.rejoin(),v.push(E.buffer())),C.point=s,w&&a.lineEnd()}function g(n,t){n=Math.max(-Ha,Math.min(Ha,n)),t=Math.max(-Ha,Math.min(Ha,t));var e=f(n,t);if(d&&y.push([n,t]),S)m=n,M=t,x=e,S=!1,e&&(a.lineStart(),a.point(n,t));else if(e&&w)a.point(n,t);else{var r={a:{x:b,y:_},b:{x:n,y:t}};A(r)?(w||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),k=!1):e&&(a.lineStart(),a.point(n,t),k=!1)}b=n,_=t,w=e}var v,d,y,m,M,x,b,_,w,S,k,N=a,E=Pt(),A=Yt(n,t,e,r),C={point:s,lineStart:h,lineEnd:p,polygonStart:function(){a=E,v=[],d=[],k=!0},polygonEnd:function(){a=N,v=ao.merge(v);var t=l([n,r]),e=k&&t,i=v.length;(e||i)&&(a.polygonStart(),e&&(a.lineStart(),c(null,null,1,a),a.lineEnd()),i&&Lt(v,u,t,c,a),a.polygonEnd()),v=d=y=null}};return C}}function Vt(n){var t=0,e=Fo/3,r=ae(n),i=r(t,e);return i.parallels=function(n){return arguments.length?r(t=n[0]*Fo/180,e=n[1]*Fo/180):[t/Fo*180,e/Fo*180]},i}function Xt(n,t){function e(n,t){var e=Math.sqrt(u-2*i*Math.sin(t))/i;return[e*Math.sin(n*=i),o-e*Math.cos(n)]}var r=Math.sin(n),i=(r+Math.sin(t))/2,u=1+r*(2*i-r),o=Math.sqrt(u)/i;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/i,tn((u-(n*n+e*e)*i*i)/(2*i))]},e}function $t(){function n(n,t){Ia+=i*n-r*t,r=n,i=t}var t,e,r,i;$a.point=function(u,o){$a.point=n,t=r=u,e=i=o},$a.lineEnd=function(){n(t,e)}}function Bt(n,t){Ya>n&&(Ya=n),n>Va&&(Va=n),Za>t&&(Za=t),t>Xa&&(Xa=t)}function Wt(){function n(n,t){o.push("M",n,",",t,u)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function i(){o.push("Z")}var u=Jt(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return u=Jt(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Jt(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function Gt(n,t){Ca+=n,za+=t,++La}function Kt(){function n(n,r){var i=n-t,u=r-e,o=Math.sqrt(i*i+u*u);qa+=o*(t+n)/2,Ta+=o*(e+r)/2,Ra+=o,Gt(t=n,e=r)}var t,e;Wa.point=function(r,i){Wa.point=n,Gt(t=r,e=i)}}function Qt(){Wa.point=Gt}function ne(){function n(n,t){var e=n-r,u=t-i,o=Math.sqrt(e*e+u*u);qa+=o*(r+n)/2,Ta+=o*(i+t)/2,Ra+=o,o=i*n-r*t,Da+=o*(r+n),Pa+=o*(i+t),Ua+=3*o,Gt(r=n,i=t)}var t,e,r,i;Wa.point=function(u,o){Wa.point=n,Gt(t=r=u,e=i=o)},Wa.lineEnd=function(){n(t,e)}}function te(n){function t(t,e){n.moveTo(t+o,e),n.arc(t,e,o,0,Ho)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function i(){a.point=t}function u(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:i,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=i,a.point=t},pointRadius:function(n){return o=n,a},result:b};return a}function ee(n){function t(n){return(a?r:e)(n)}function e(t){return ue(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){M=NaN,S.point=u,t.lineStart()}function u(e,r){var u=dt([e,r]),o=n(e,r);i(M,x,m,b,_,w,M=o[0],x=o[1],m=e,b=u[0],_=u[1],w=u[2],a,t),t.point(M,x)}function o(){S.point=e,t.lineEnd()}function l(){
r(),S.point=c,S.lineEnd=f}function c(n,t){u(s=n,h=t),p=M,g=x,v=b,d=_,y=w,S.point=u}function f(){i(M,x,m,b,_,w,p,g,s,v,d,y,a,t),S.lineEnd=o,o()}var s,h,p,g,v,d,y,m,M,x,b,_,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=l},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function i(t,e,r,a,l,c,f,s,h,p,g,v,d,y){var m=f-t,M=s-e,x=m*m+M*M;if(x>4*u&&d--){var b=a+p,_=l+g,w=c+v,S=Math.sqrt(b*b+_*_+w*w),k=Math.asin(w/=S),N=xo(xo(w)-1)<Uo||xo(r-h)<Uo?(r+h)/2:Math.atan2(_,b),E=n(N,k),A=E[0],C=E[1],z=A-t,L=C-e,q=M*z-m*L;(q*q/x>u||xo((m*z+M*L)/x-.5)>.3||o>a*p+l*g+c*v)&&(i(t,e,r,a,l,c,A,C,N,b/=S,_/=S,w,d,y),y.point(A,C),i(A,C,N,b,_,w,f,s,h,p,g,v,d,y))}}var u=.5,o=Math.cos(30*Yo),a=16;return t.precision=function(n){return arguments.length?(a=(u=n*n)>0&&16,t):Math.sqrt(u)},t}function re(n){var t=ee(function(t,e){return n([t*Zo,e*Zo])});return function(n){return le(t(n))}}function ie(n){this.stream=n}function ue(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function oe(n){return ae(function(){return n})()}function ae(n){function t(n){return n=a(n[0]*Yo,n[1]*Yo),[n[0]*h+l,c-n[1]*h]}function e(n){return n=a.invert((n[0]-l)/h,(c-n[1])/h),n&&[n[0]*Zo,n[1]*Zo]}function r(){a=Ct(o=se(y,M,x),u);var n=u(v,d);return l=p-n[0]*h,c=g+n[1]*h,i()}function i(){return f&&(f.valid=!1,f=null),t}var u,o,a,l,c,f,s=ee(function(n,t){return n=u(n,t),[n[0]*h+l,c-n[1]*h]}),h=150,p=480,g=250,v=0,d=0,y=0,M=0,x=0,b=Fa,_=m,w=null,S=null;return t.stream=function(n){return f&&(f.valid=!1),f=le(b(o,s(_(n)))),f.valid=!0,f},t.clipAngle=function(n){return arguments.length?(b=null==n?(w=n,Fa):It((w=+n)*Yo),i()):w},t.clipExtent=function(n){return arguments.length?(S=n,_=n?Zt(n[0][0],n[0][1],n[1][0],n[1][1]):m,i()):S},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(p=+n[0],g=+n[1],r()):[p,g]},t.center=function(n){return arguments.length?(v=n[0]%360*Yo,d=n[1]%360*Yo,r()):[v*Zo,d*Zo]},t.rotate=function(n){return arguments.length?(y=n[0]%360*Yo,M=n[1]%360*Yo,x=n.length>2?n[2]%360*Yo:0,r()):[y*Zo,M*Zo,x*Zo]},ao.rebind(t,s,"precision"),function(){return u=n.apply(this,arguments),t.invert=u.invert&&e,r()}}function le(n){return ue(n,function(t,e){n.point(t*Yo,e*Yo)})}function ce(n,t){return[n,t]}function fe(n,t){return[n>Fo?n-Ho:-Fo>n?n+Ho:n,t]}function se(n,t,e){return n?t||e?Ct(pe(n),ge(t,e)):pe(n):t||e?ge(t,e):fe}function he(n){return function(t,e){return t+=n,[t>Fo?t-Ho:-Fo>t?t+Ho:t,e]}}function pe(n){var t=he(n);return t.invert=he(-n),t}function ge(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,l=Math.sin(n)*e,c=Math.sin(t),f=c*r+a*i;return[Math.atan2(l*u-f*o,a*r-c*i),tn(f*u+l*o)]}var r=Math.cos(n),i=Math.sin(n),u=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,l=Math.sin(n)*e,c=Math.sin(t),f=c*u-l*o;return[Math.atan2(l*u+c*o,a*r+f*i),tn(f*r-a*i)]},e}function ve(n,t){var e=Math.cos(n),r=Math.sin(n);return function(i,u,o,a){var l=o*t;null!=i?(i=de(e,i),u=de(e,u),(o>0?u>i:i>u)&&(i+=o*Ho)):(i=n+o*Ho,u=n-.5*l);for(var c,f=i;o>0?f>u:u>f;f-=l)a.point((c=_t([e,-r*Math.cos(f),-r*Math.sin(f)]))[0],c[1])}}function de(n,t){var e=dt(t);e[0]-=n,bt(e);var r=nn(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Uo)%(2*Math.PI)}function ye(n,t,e){var r=ao.range(n,t-Uo,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function me(n,t,e){var r=ao.range(n,t-Uo,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function Me(n){return n.source}function xe(n){return n.target}function be(n,t,e,r){var i=Math.cos(t),u=Math.sin(t),o=Math.cos(r),a=Math.sin(r),l=i*Math.cos(n),c=i*Math.sin(n),f=o*Math.cos(e),s=o*Math.sin(e),h=2*Math.asin(Math.sqrt(on(r-t)+i*o*on(e-n))),p=1/Math.sin(h),g=h?function(n){var t=Math.sin(n*=h)*p,e=Math.sin(h-n)*p,r=e*l+t*f,i=e*c+t*s,o=e*u+t*a;return[Math.atan2(i,r)*Zo,Math.atan2(o,Math.sqrt(r*r+i*i))*Zo]}:function(){return[n*Zo,t*Zo]};return g.distance=h,g}function _e(){function n(n,i){var u=Math.sin(i*=Yo),o=Math.cos(i),a=xo((n*=Yo)-t),l=Math.cos(a);Ja+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*u-e*o*l)*a),e*u+r*o*l),t=n,e=u,r=o}var t,e,r;Ga.point=function(i,u){t=i*Yo,e=Math.sin(u*=Yo),r=Math.cos(u),Ga.point=n},Ga.lineEnd=function(){Ga.point=Ga.lineEnd=b}}function we(n,t){function e(t,e){var r=Math.cos(t),i=Math.cos(e),u=n(r*i);return[u*i*Math.sin(t),u*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),i=t(r),u=Math.sin(i),o=Math.cos(i);return[Math.atan2(n*u,r*o),Math.asin(r&&e*u/r)]},e}function Se(n,t){function e(n,t){o>0?-Io+Uo>t&&(t=-Io+Uo):t>Io-Uo&&(t=Io-Uo);var e=o/Math.pow(i(t),u);return[e*Math.sin(u*n),o-e*Math.cos(u*n)]}var r=Math.cos(n),i=function(n){return Math.tan(Fo/4+n/2)},u=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(i(t)/i(n)),o=r*Math.pow(i(n),u)/u;return u?(e.invert=function(n,t){var e=o-t,r=K(u)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/u,2*Math.atan(Math.pow(o/r,1/u))-Io]},e):Ne}function ke(n,t){function e(n,t){var e=u-t;return[e*Math.sin(i*n),u-e*Math.cos(i*n)]}var r=Math.cos(n),i=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),u=r/i+n;return xo(i)<Uo?ce:(e.invert=function(n,t){var e=u-t;return[Math.atan2(n,e)/i,u-K(i)*Math.sqrt(n*n+e*e)]},e)}function Ne(n,t){return[n,Math.log(Math.tan(Fo/4+t/2))]}function Ee(n){var t,e=oe(n),r=e.scale,i=e.translate,u=e.clipExtent;return e.scale=function(){var n=r.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.translate=function(){var n=i.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var o=u.apply(e,arguments);if(o===e){if(t=null==n){var a=Fo*r(),l=i();u([[l[0]-a,l[1]-a],[l[0]+a,l[1]+a]])}}else t&&(o=null);return o},e.clipExtent(null)}function Ae(n,t){return[Math.log(Math.tan(Fo/4+t/2)),-n]}function Ce(n){return n[0]}function ze(n){return n[1]}function Le(n){for(var t=n.length,e=[0,1],r=2,i=2;t>i;i++){for(;r>1&&Q(n[e[r-2]],n[e[r-1]],n[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function qe(n,t){return n[0]-t[0]||n[1]-t[1]}function Te(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Re(n,t,e,r){var i=n[0],u=e[0],o=t[0]-i,a=r[0]-u,l=n[1],c=e[1],f=t[1]-l,s=r[1]-c,h=(a*(l-c)-s*(i-u))/(s*o-a*f);return[i+h*o,l+h*f]}function De(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function Pe(){rr(this),this.edge=this.site=this.circle=null}function Ue(n){var t=cl.pop()||new Pe;return t.site=n,t}function je(n){Be(n),ol.remove(n),cl.push(n),rr(n)}function Fe(n){var t=n.circle,e=t.x,r=t.cy,i={x:e,y:r},u=n.P,o=n.N,a=[n];je(n);for(var l=u;l.circle&&xo(e-l.circle.x)<Uo&&xo(r-l.circle.cy)<Uo;)u=l.P,a.unshift(l),je(l),l=u;a.unshift(l),Be(l);for(var c=o;c.circle&&xo(e-c.circle.x)<Uo&&xo(r-c.circle.cy)<Uo;)o=c.N,a.push(c),je(c),c=o;a.push(c),Be(c);var f,s=a.length;for(f=1;s>f;++f)c=a[f],l=a[f-1],nr(c.edge,l.site,c.site,i);l=a[0],c=a[s-1],c.edge=Ke(l.site,c.site,null,i),$e(l),$e(c)}function He(n){for(var t,e,r,i,u=n.x,o=n.y,a=ol._;a;)if(r=Oe(a,o)-u,r>Uo)a=a.L;else{if(i=u-Ie(a,o),!(i>Uo)){r>-Uo?(t=a.P,e=a):i>-Uo?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var l=Ue(n);if(ol.insert(t,l),t||e){if(t===e)return Be(t),e=Ue(t.site),ol.insert(l,e),l.edge=e.edge=Ke(t.site,l.site),$e(t),void $e(e);if(!e)return void(l.edge=Ke(t.site,l.site));Be(t),Be(e);var c=t.site,f=c.x,s=c.y,h=n.x-f,p=n.y-s,g=e.site,v=g.x-f,d=g.y-s,y=2*(h*d-p*v),m=h*h+p*p,M=v*v+d*d,x={x:(d*m-p*M)/y+f,y:(h*M-v*m)/y+s};nr(e.edge,c,g,x),l.edge=Ke(c,n,null,x),e.edge=Ke(n,g,null,x),$e(t),$e(e)}}function Oe(n,t){var e=n.site,r=e.x,i=e.y,u=i-t;if(!u)return r;var o=n.P;if(!o)return-(1/0);e=o.site;var a=e.x,l=e.y,c=l-t;if(!c)return a;var f=a-r,s=1/u-1/c,h=f/c;return s?(-h+Math.sqrt(h*h-2*s*(f*f/(-2*c)-l+c/2+i-u/2)))/s+r:(r+a)/2}function Ie(n,t){var e=n.N;if(e)return Oe(e,t);var r=n.site;return r.y===t?r.x:1/0}function Ye(n){this.site=n,this.edges=[]}function Ze(n){for(var t,e,r,i,u,o,a,l,c,f,s=n[0][0],h=n[1][0],p=n[0][1],g=n[1][1],v=ul,d=v.length;d--;)if(u=v[d],u&&u.prepare())for(a=u.edges,l=a.length,o=0;l>o;)f=a[o].end(),r=f.x,i=f.y,c=a[++o%l].start(),t=c.x,e=c.y,(xo(r-t)>Uo||xo(i-e)>Uo)&&(a.splice(o,0,new tr(Qe(u.site,f,xo(r-s)<Uo&&g-i>Uo?{x:s,y:xo(t-s)<Uo?e:g}:xo(i-g)<Uo&&h-r>Uo?{x:xo(e-g)<Uo?t:h,y:g}:xo(r-h)<Uo&&i-p>Uo?{x:h,y:xo(t-h)<Uo?e:p}:xo(i-p)<Uo&&r-s>Uo?{x:xo(e-p)<Uo?t:s,y:p}:null),u.site,null)),++l)}function Ve(n,t){return t.angle-n.angle}function Xe(){rr(this),this.x=this.y=this.arc=this.site=this.cy=null}function $e(n){var t=n.P,e=n.N;if(t&&e){var r=t.site,i=n.site,u=e.site;if(r!==u){var o=i.x,a=i.y,l=r.x-o,c=r.y-a,f=u.x-o,s=u.y-a,h=2*(l*s-c*f);if(!(h>=-jo)){var p=l*l+c*c,g=f*f+s*s,v=(s*p-c*g)/h,d=(l*g-f*p)/h,s=d+a,y=fl.pop()||new Xe;y.arc=n,y.site=i,y.x=v+o,y.y=s+Math.sqrt(v*v+d*d),y.cy=s,n.circle=y;for(var m=null,M=ll._;M;)if(y.y<M.y||y.y===M.y&&y.x<=M.x){if(!M.L){m=M.P;break}M=M.L}else{if(!M.R){m=M;break}M=M.R}ll.insert(m,y),m||(al=y)}}}}function Be(n){var t=n.circle;t&&(t.P||(al=t.N),ll.remove(t),fl.push(t),rr(t),n.circle=null)}function We(n){for(var t,e=il,r=Yt(n[0][0],n[0][1],n[1][0],n[1][1]),i=e.length;i--;)t=e[i],(!Je(t,n)||!r(t)||xo(t.a.x-t.b.x)<Uo&&xo(t.a.y-t.b.y)<Uo)&&(t.a=t.b=null,e.splice(i,1))}function Je(n,t){var e=n.b;if(e)return!0;var r,i,u=n.a,o=t[0][0],a=t[1][0],l=t[0][1],c=t[1][1],f=n.l,s=n.r,h=f.x,p=f.y,g=s.x,v=s.y,d=(h+g)/2,y=(p+v)/2;if(v===p){if(o>d||d>=a)return;if(h>g){if(u){if(u.y>=c)return}else u={x:d,y:l};e={x:d,y:c}}else{if(u){if(u.y<l)return}else u={x:d,y:c};e={x:d,y:l}}}else if(r=(h-g)/(v-p),i=y-r*d,-1>r||r>1)if(h>g){if(u){if(u.y>=c)return}else u={x:(l-i)/r,y:l};e={x:(c-i)/r,y:c}}else{if(u){if(u.y<l)return}else u={x:(c-i)/r,y:c};e={x:(l-i)/r,y:l}}else if(v>p){if(u){if(u.x>=a)return}else u={x:o,y:r*o+i};e={x:a,y:r*a+i}}else{if(u){if(u.x<o)return}else u={x:a,y:r*a+i};e={x:o,y:r*o+i}}return n.a=u,n.b=e,!0}function Ge(n,t){this.l=n,this.r=t,this.a=this.b=null}function Ke(n,t,e,r){var i=new Ge(n,t);return il.push(i),e&&nr(i,n,t,e),r&&nr(i,t,n,r),ul[n.i].edges.push(new tr(i,n,t)),ul[t.i].edges.push(new tr(i,t,n)),i}function Qe(n,t,e){var r=new Ge(n,null);return r.a=t,r.b=e,il.push(r),r}function nr(n,t,e,r){n.a||n.b?n.l===e?n.b=r:n.a=r:(n.a=r,n.l=t,n.r=e)}function tr(n,t,e){var r=n.a,i=n.b;this.edge=n,this.site=t,this.angle=e?Math.atan2(e.y-t.y,e.x-t.x):n.l===t?Math.atan2(i.x-r.x,r.y-i.y):Math.atan2(r.x-i.x,i.y-r.y)}function er(){this._=null}function rr(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function ir(n,t){var e=t,r=t.R,i=e.U;i?i.L===e?i.L=r:i.R=r:n._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function ur(n,t){var e=t,r=t.L,i=e.U;i?i.L===e?i.L=r:i.R=r:n._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function or(n){for(;n.L;)n=n.L;return n}function ar(n,t){var e,r,i,u=n.sort(lr).pop();for(il=[],ul=new Array(n.length),ol=new er,ll=new er;;)if(i=al,u&&(!i||u.y<i.y||u.y===i.y&&u.x<i.x))u.x===e&&u.y===r||(ul[u.i]=new Ye(u),He(u),e=u.x,r=u.y),u=n.pop();else{if(!i)break;Fe(i.arc)}t&&(We(t),Ze(t));var o={cells:ul,edges:il};return ol=ll=il=ul=null,o}function lr(n,t){return t.y-n.y||t.x-n.x}function cr(n,t,e){return(n.x-e.x)*(t.y-n.y)-(n.x-t.x)*(e.y-n.y)}function fr(n){return n.x}function sr(n){return n.y}function hr(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function pr(n,t,e,r,i,u){if(!n(t,e,r,i,u)){var o=.5*(e+i),a=.5*(r+u),l=t.nodes;l[0]&&pr(n,l[0],e,r,o,a),l[1]&&pr(n,l[1],o,r,i,a),l[2]&&pr(n,l[2],e,a,o,u),l[3]&&pr(n,l[3],o,a,i,u)}}function gr(n,t,e,r,i,u,o){var a,l=1/0;return function c(n,f,s,h,p){if(!(f>u||s>o||r>h||i>p)){if(g=n.point){var g,v=t-n.x,d=e-n.y,y=v*v+d*d;if(l>y){var m=Math.sqrt(l=y);r=t-m,i=e-m,u=t+m,o=e+m,a=g}}for(var M=n.nodes,x=.5*(f+h),b=.5*(s+p),_=t>=x,w=e>=b,S=w<<1|_,k=S+4;k>S;++S)if(n=M[3&S])switch(3&S){case 0:c(n,f,s,x,b);break;case 1:c(n,x,s,h,b);break;case 2:c(n,f,b,x,p);break;case 3:c(n,x,b,h,p)}}}(n,r,i,u,o),a}function vr(n,t){n=ao.rgb(n),t=ao.rgb(t);var e=n.r,r=n.g,i=n.b,u=t.r-e,o=t.g-r,a=t.b-i;return function(n){return"#"+bn(Math.round(e+u*n))+bn(Math.round(r+o*n))+bn(Math.round(i+a*n))}}function dr(n,t){var e,r={},i={};for(e in n)e in t?r[e]=Mr(n[e],t[e]):i[e]=n[e];for(e in t)e in n||(i[e]=t[e]);return function(n){for(e in r)i[e]=r[e](n);return i}}function yr(n,t){return n=+n,t=+t,function(e){return n*(1-e)+t*e}}function mr(n,t){var e,r,i,u=hl.lastIndex=pl.lastIndex=0,o=-1,a=[],l=[];for(n+="",t+="";(e=hl.exec(n))&&(r=pl.exec(t));)(i=r.index)>u&&(i=t.slice(u,i),a[o]?a[o]+=i:a[++o]=i),(e=e[0])===(r=r[0])?a[o]?a[o]+=r:a[++o]=r:(a[++o]=null,l.push({i:o,x:yr(e,r)})),u=pl.lastIndex;return u<t.length&&(i=t.slice(u),a[o]?a[o]+=i:a[++o]=i),a.length<2?l[0]?(t=l[0].x,function(n){return t(n)+""}):function(){return t}:(t=l.length,function(n){for(var e,r=0;t>r;++r)a[(e=l[r]).i]=e.x(n);return a.join("")})}function Mr(n,t){for(var e,r=ao.interpolators.length;--r>=0&&!(e=ao.interpolators[r](n,t)););return e}function xr(n,t){var e,r=[],i=[],u=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(Mr(n[e],t[e]));for(;u>e;++e)i[e]=n[e];for(;o>e;++e)i[e]=t[e];return function(n){for(e=0;a>e;++e)i[e]=r[e](n);return i}}function br(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function _r(n){return function(t){return 1-n(1-t)}}function wr(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function Sr(n){return n*n}function kr(n){return n*n*n}function Nr(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function Er(n){return function(t){return Math.pow(t,n)}}function Ar(n){return 1-Math.cos(n*Io)}function Cr(n){return Math.pow(2,10*(n-1))}function zr(n){return 1-Math.sqrt(1-n*n)}function Lr(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/Ho*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*Ho/t)}}function qr(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function Tr(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Rr(n,t){n=ao.hcl(n),t=ao.hcl(t);var e=n.h,r=n.c,i=n.l,u=t.h-e,o=t.c-r,a=t.l-i;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(u)?(u=0,e=isNaN(e)?t.h:e):u>180?u-=360:-180>u&&(u+=360),function(n){return sn(e+u*n,r+o*n,i+a*n)+""}}function Dr(n,t){n=ao.hsl(n),t=ao.hsl(t);var e=n.h,r=n.s,i=n.l,u=t.h-e,o=t.s-r,a=t.l-i;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(u)?(u=0,e=isNaN(e)?t.h:e):u>180?u-=360:-180>u&&(u+=360),function(n){return cn(e+u*n,r+o*n,i+a*n)+""}}function Pr(n,t){n=ao.lab(n),t=ao.lab(t);var e=n.l,r=n.a,i=n.b,u=t.l-e,o=t.a-r,a=t.b-i;return function(n){return pn(e+u*n,r+o*n,i+a*n)+""}}function Ur(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function jr(n){var t=[n.a,n.b],e=[n.c,n.d],r=Hr(t),i=Fr(t,e),u=Hr(Or(e,t,-i))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,i*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Zo,this.translate=[n.e,n.f],this.scale=[r,u],this.skew=u?Math.atan2(i,u)*Zo:0}function Fr(n,t){return n[0]*t[0]+n[1]*t[1]}function Hr(n){var t=Math.sqrt(Fr(n,n));return t&&(n[0]/=t,n[1]/=t),t}function Or(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}function Ir(n){return n.length?n.pop()+",":""}function Yr(n,t,e,r){if(n[0]!==t[0]||n[1]!==t[1]){var i=e.push("translate(",null,",",null,")");r.push({i:i-4,x:yr(n[0],t[0])},{i:i-2,x:yr(n[1],t[1])})}else(t[0]||t[1])&&e.push("translate("+t+")")}function Zr(n,t,e,r){n!==t?(n-t>180?t+=360:t-n>180&&(n+=360),r.push({i:e.push(Ir(e)+"rotate(",null,")")-2,x:yr(n,t)})):t&&e.push(Ir(e)+"rotate("+t+")")}function Vr(n,t,e,r){n!==t?r.push({i:e.push(Ir(e)+"skewX(",null,")")-2,x:yr(n,t)}):t&&e.push(Ir(e)+"skewX("+t+")")}function Xr(n,t,e,r){if(n[0]!==t[0]||n[1]!==t[1]){var i=e.push(Ir(e)+"scale(",null,",",null,")");r.push({i:i-4,x:yr(n[0],t[0])},{i:i-2,x:yr(n[1],t[1])})}else 1===t[0]&&1===t[1]||e.push(Ir(e)+"scale("+t+")")}function $r(n,t){var e=[],r=[];return n=ao.transform(n),t=ao.transform(t),Yr(n.translate,t.translate,e,r),Zr(n.rotate,t.rotate,e,r),Vr(n.skew,t.skew,e,r),Xr(n.scale,t.scale,e,r),n=t=null,function(n){for(var t,i=-1,u=r.length;++i<u;)e[(t=r[i]).i]=t.x(n);return e.join("")}}function Br(n,t){return t=(t-=n=+n)||1/t,function(e){return(e-n)/t}}function Wr(n,t){return t=(t-=n=+n)||1/t,function(e){return Math.max(0,Math.min(1,(e-n)/t))}}function Jr(n){for(var t=n.source,e=n.target,r=Kr(t,e),i=[t];t!==r;)t=t.parent,i.push(t);for(var u=i.length;e!==r;)i.splice(u,0,e),e=e.parent;return i}function Gr(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function Kr(n,t){if(n===t)return n;for(var e=Gr(n),r=Gr(t),i=e.pop(),u=r.pop(),o=null;i===u;)o=i,i=e.pop(),u=r.pop();return o}function Qr(n){n.fixed|=2}function ni(n){n.fixed&=-7}function ti(n){n.fixed|=4,n.px=n.x,n.py=n.y}function ei(n){n.fixed&=-5}function ri(n,t,e){var r=0,i=0;if(n.charge=0,!n.leaf)for(var u,o=n.nodes,a=o.length,l=-1;++l<a;)u=o[l],null!=u&&(ri(u,t,e),n.charge+=u.charge,r+=u.charge*u.cx,i+=u.charge*u.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var c=t*e[n.point.index];n.charge+=n.pointCharge=c,r+=c*n.point.x,i+=c*n.point.y}n.cx=r/n.charge,n.cy=i/n.charge}function ii(n,t){return ao.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=fi,n}function ui(n,t){for(var e=[n];null!=(n=e.pop());)if(t(n),(i=n.children)&&(r=i.length))for(var r,i;--r>=0;)e.push(i[r])}function oi(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(u=n.children)&&(i=u.length))for(var i,u,o=-1;++o<i;)e.push(u[o]);for(;null!=(n=r.pop());)t(n)}function ai(n){return n.children}function li(n){return n.value}function ci(n,t){return t.value-n.value}function fi(n){return ao.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function si(n){return n.x}function hi(n){return n.y}function pi(n,t,e){n.y0=t,n.y=e}function gi(n){return ao.range(n.length)}function vi(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function di(n){for(var t,e=1,r=0,i=n[0][1],u=n.length;u>e;++e)(t=n[e][1])>i&&(r=e,i=t);return r}function yi(n){return n.reduce(mi,0)}function mi(n,t){return n+t[1]}function Mi(n,t){return xi(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function xi(n,t){for(var e=-1,r=+n[0],i=(n[1]-r)/t,u=[];++e<=t;)u[e]=i*e+r;return u}function bi(n){return[ao.min(n),ao.max(n)]}function _i(n,t){return n.value-t.value}function wi(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function Si(n,t){n._pack_next=t,t._pack_prev=n}function ki(n,t){var e=t.x-n.x,r=t.y-n.y,i=n.r+t.r;return.999*i*i>e*e+r*r}function Ni(n){function t(n){f=Math.min(n.x-n.r,f),s=Math.max(n.x+n.r,s),h=Math.min(n.y-n.r,h),p=Math.max(n.y+n.r,p)}if((e=n.children)&&(c=e.length)){var e,r,i,u,o,a,l,c,f=1/0,s=-(1/0),h=1/0,p=-(1/0);if(e.forEach(Ei),r=e[0],r.x=-r.r,r.y=0,t(r),c>1&&(i=e[1],i.x=i.r,i.y=0,t(i),c>2))for(u=e[2],zi(r,i,u),t(u),wi(r,u),r._pack_prev=u,wi(u,i),i=r._pack_next,o=3;c>o;o++){zi(r,i,u=e[o]);var g=0,v=1,d=1;for(a=i._pack_next;a!==i;a=a._pack_next,v++)if(ki(a,u)){g=1;break}if(1==g)for(l=r._pack_prev;l!==a._pack_prev&&!ki(l,u);l=l._pack_prev,d++);g?(d>v||v==d&&i.r<r.r?Si(r,i=a):Si(r=l,i),o--):(wi(r,u),i=u,t(u))}var y=(f+s)/2,m=(h+p)/2,M=0;for(o=0;c>o;o++)u=e[o],u.x-=y,u.y-=m,M=Math.max(M,u.r+Math.sqrt(u.x*u.x+u.y*u.y));n.r=M,e.forEach(Ai)}}function Ei(n){n._pack_next=n._pack_prev=n}function Ai(n){delete n._pack_next,delete n._pack_prev}function Ci(n,t,e,r){var i=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,i)for(var u=-1,o=i.length;++u<o;)Ci(i[u],t,e,r)}function zi(n,t,e){var r=n.r+e.r,i=t.x-n.x,u=t.y-n.y;if(r&&(i||u)){var o=t.r+e.r,a=i*i+u*u;o*=o,r*=r;var l=.5+(r-o)/(2*a),c=Math.sqrt(Math.max(0,2*o*(r+a)-(r-=a)*r-o*o))/(2*a);e.x=n.x+l*i+c*u,e.y=n.y+l*u-c*i}else e.x=n.x+r,e.y=n.y}function Li(n,t){return n.parent==t.parent?1:2}function qi(n){var t=n.children;return t.length?t[0]:n.t}function Ti(n){var t,e=n.children;return(t=e.length)?e[t-1]:n.t}function Ri(n,t,e){var r=e/(t.i-n.i);t.c-=r,t.s+=e,n.c+=r,t.z+=e,t.m+=e}function Di(n){for(var t,e=0,r=0,i=n.children,u=i.length;--u>=0;)t=i[u],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Pi(n,t,e){return n.a.parent===t.parent?n.a:e}function Ui(n){return 1+ao.max(n,function(n){return n.y})}function ji(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Fi(n){var t=n.children;return t&&t.length?Fi(t[0]):n}function Hi(n){var t,e=n.children;return e&&(t=e.length)?Hi(e[t-1]):n}function Oi(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Ii(n,t){var e=n.x+t[3],r=n.y+t[0],i=n.dx-t[1]-t[3],u=n.dy-t[0]-t[2];return 0>i&&(e+=i/2,i=0),0>u&&(r+=u/2,u=0),{x:e,y:r,dx:i,dy:u}}function Yi(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Zi(n){return n.rangeExtent?n.rangeExtent():Yi(n.range())}function Vi(n,t,e,r){var i=e(n[0],n[1]),u=r(t[0],t[1]);return function(n){return u(i(n))}}function Xi(n,t){var e,r=0,i=n.length-1,u=n[r],o=n[i];return u>o&&(e=r,r=i,i=e,e=u,u=o,o=e),n[r]=t.floor(u),n[i]=t.ceil(o),n}function $i(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:Sl}function Bi(n,t,e,r){var i=[],u=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)i.push(e(n[o-1],n[o])),u.push(r(t[o-1],t[o]));return function(t){var e=ao.bisect(n,t,1,a)-1;return u[e](i[e](t))}}function Wi(n,t,e,r){function i(){var i=Math.min(n.length,t.length)>2?Bi:Vi,l=r?Wr:Br;return o=i(n,t,l,e),a=i(t,n,l,Mr),u}function u(n){return o(n)}var o,a;return u.invert=function(n){return a(n)},u.domain=function(t){return arguments.length?(n=t.map(Number),i()):n},u.range=function(n){return arguments.length?(t=n,i()):t},u.rangeRound=function(n){return u.range(n).interpolate(Ur)},u.clamp=function(n){return arguments.length?(r=n,i()):r},u.interpolate=function(n){return arguments.length?(e=n,i()):e},u.ticks=function(t){return Qi(n,t)},u.tickFormat=function(t,e){return nu(n,t,e)},u.nice=function(t){return Gi(n,t),i()},u.copy=function(){return Wi(n,t,e,r)},i()}function Ji(n,t){return ao.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Gi(n,t){return Xi(n,$i(Ki(n,t)[2])),Xi(n,$i(Ki(n,t)[2])),n}function Ki(n,t){null==t&&(t=10);var e=Yi(n),r=e[1]-e[0],i=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),u=t/r*i;return.15>=u?i*=10:.35>=u?i*=5:.75>=u&&(i*=2),e[0]=Math.ceil(e[0]/i)*i,e[1]=Math.floor(e[1]/i)*i+.5*i,e[2]=i,e}function Qi(n,t){return ao.range.apply(ao,Ki(n,t))}function nu(n,t,e){var r=Ki(n,t);if(e){var i=ha.exec(e);if(i.shift(),"s"===i[8]){var u=ao.formatPrefix(Math.max(xo(r[0]),xo(r[1])));return i[7]||(i[7]="."+tu(u.scale(r[2]))),i[8]="f",e=ao.format(i.join("")),function(n){return e(u.scale(n))+u.symbol}}i[7]||(i[7]="."+eu(i[8],r)),e=i.join("")}else e=",."+tu(r[2])+"f";return ao.format(e)}function tu(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function eu(n,t){var e=tu(t[2]);return n in kl?Math.abs(e-tu(Math.max(xo(t[0]),xo(t[1]))))+ +("e"!==n):e-2*("%"===n)}function ru(n,t,e,r){function i(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function u(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(i(t))}return o.invert=function(t){return u(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(i)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(i)),o):t},o.nice=function(){var t=Xi(r.map(i),e?Math:El);return n.domain(t),r=t.map(u),o},o.ticks=function(){var n=Yi(r),o=[],a=n[0],l=n[1],c=Math.floor(i(a)),f=Math.ceil(i(l)),s=t%1?2:t;if(isFinite(f-c)){if(e){for(;f>c;c++)for(var h=1;s>h;h++)o.push(u(c)*h);o.push(u(c))}else for(o.push(u(c));c++<f;)for(var h=s-1;h>0;h--)o.push(u(c)*h);for(c=0;o[c]<a;c++);for(f=o.length;o[f-1]>l;f--);o=o.slice(c,f)}return o},o.tickFormat=function(n,e){if(!arguments.length)return Nl;arguments.length<2?e=Nl:"function"!=typeof e&&(e=ao.format(e));var r=Math.max(1,t*n/o.ticks().length);return function(n){var o=n/u(Math.round(i(n)));return t-.5>o*t&&(o*=t),r>=o?e(n):""}},o.copy=function(){return ru(n.copy(),t,e,r)},Ji(o,n)}function iu(n,t,e){function r(t){return n(i(t))}var i=uu(t),u=uu(1/t);return r.invert=function(t){return u(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(i)),r):e},r.ticks=function(n){return Qi(e,n)},r.tickFormat=function(n,t){return nu(e,n,t)},r.nice=function(n){return r.domain(Gi(e,n))},r.exponent=function(o){return arguments.length?(i=uu(t=o),u=uu(1/t),n.domain(e.map(i)),r):t},r.copy=function(){return iu(n.copy(),t,e)},Ji(r,n)}function uu(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function ou(n,t){function e(e){return u[((i.get(e)||("range"===t.t?i.set(e,n.push(e)):NaN))-1)%u.length]}function r(t,e){return ao.range(n.length).map(function(n){return t+e*n})}var i,u,o;return e.domain=function(r){if(!arguments.length)return n;n=[],i=new c;for(var u,o=-1,a=r.length;++o<a;)i.has(u=r[o])||i.set(u,n.push(u));return e[t.t].apply(e,t.a)},e.range=function(n){return arguments.length?(u=n,o=0,t={t:"range",a:arguments},e):u},e.rangePoints=function(i,a){arguments.length<2&&(a=0);var l=i[0],c=i[1],f=n.length<2?(l=(l+c)/2,0):(c-l)/(n.length-1+a);return u=r(l+f*a/2,f),o=0,t={t:"rangePoints",a:arguments},e},e.rangeRoundPoints=function(i,a){arguments.length<2&&(a=0);var l=i[0],c=i[1],f=n.length<2?(l=c=Math.round((l+c)/2),0):(c-l)/(n.length-1+a)|0;return u=r(l+Math.round(f*a/2+(c-l-(n.length-1+a)*f)/2),f),o=0,t={t:"rangeRoundPoints",a:arguments},e},e.rangeBands=function(i,a,l){arguments.length<2&&(a=0),arguments.length<3&&(l=a);var c=i[1]<i[0],f=i[c-0],s=i[1-c],h=(s-f)/(n.length-a+2*l);return u=r(f+h*l,h),c&&u.reverse(),o=h*(1-a),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(i,a,l){arguments.length<2&&(a=0),arguments.length<3&&(l=a);var c=i[1]<i[0],f=i[c-0],s=i[1-c],h=Math.floor((s-f)/(n.length-a+2*l));return u=r(f+Math.round((s-f-(n.length-a)*h)/2),h),c&&u.reverse(),o=Math.round(h*(1-a)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return o},e.rangeExtent=function(){return Yi(t.a[0])},e.copy=function(){return ou(n,t)},e.domain(n)}function au(n,t){function u(){var e=0,r=t.length;for(a=[];++e<r;)a[e-1]=ao.quantile(n,e/r);return o}function o(n){return isNaN(n=+n)?void 0:t[ao.bisect(a,n)]}var a;return o.domain=function(t){return arguments.length?(n=t.map(r).filter(i).sort(e),u()):n},o.range=function(n){return arguments.length?(t=n,u()):t},o.quantiles=function(){return a},o.invertExtent=function(e){return e=t.indexOf(e),0>e?[NaN,NaN]:[e>0?a[e-1]:n[0],e<a.length?a[e]:n[n.length-1]]},o.copy=function(){return au(n,t)},u()}function lu(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.floor(u*(t-n))))]}function i(){return u=e.length/(t-n),o=e.length-1,r}var u,o;return r.domain=function(e){return arguments.length?(n=+e[0],t=+e[e.length-1],i()):[n,t]},r.range=function(n){return arguments.length?(e=n,i()):e},r.invertExtent=function(t){return t=e.indexOf(t),t=0>t?NaN:t/u+n,[t,t+1/u]},r.copy=function(){return lu(n,t,e)},i()}function cu(n,t){function e(e){return e>=e?t[ao.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return cu(n,t)},e}function fu(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Qi(n,t)},t.tickFormat=function(t,e){return nu(n,t,e)},t.copy=function(){return fu(n)},t}function su(){return 0}function hu(n){return n.innerRadius}function pu(n){return n.outerRadius}function gu(n){return n.startAngle}function vu(n){return n.endAngle}function du(n){return n&&n.padAngle}function yu(n,t,e,r){return(n-e)*t-(t-r)*n>0?0:1}function mu(n,t,e,r,i){var u=n[0]-t[0],o=n[1]-t[1],a=(i?r:-r)/Math.sqrt(u*u+o*o),l=a*o,c=-a*u,f=n[0]+l,s=n[1]+c,h=t[0]+l,p=t[1]+c,g=(f+h)/2,v=(s+p)/2,d=h-f,y=p-s,m=d*d+y*y,M=e-r,x=f*p-h*s,b=(0>y?-1:1)*Math.sqrt(Math.max(0,M*M*m-x*x)),_=(x*y-d*b)/m,w=(-x*d-y*b)/m,S=(x*y+d*b)/m,k=(-x*d+y*b)/m,N=_-g,E=w-v,A=S-g,C=k-v;return N*N+E*E>A*A+C*C&&(_=S,w=k),[[_-l,w-c],[_*e/M,w*e/M]]}function Mu(n){function t(t){function o(){c.push("M",u(n(f),a))}for(var l,c=[],f=[],s=-1,h=t.length,p=En(e),g=En(r);++s<h;)i.call(this,l=t[s],s)?f.push([+p.call(this,l,s),+g.call(this,l,s)]):f.length&&(o(),f=[]);return f.length&&o(),c.length?c.join(""):null}var e=Ce,r=ze,i=zt,u=xu,o=u.key,a=.7;return t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.defined=function(n){return arguments.length?(i=n,t):i},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?u=n:(u=Tl.get(n)||xu).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function xu(n){return n.length>1?n.join("L"):n+"Z"}function bu(n){return n.join("L")+"Z"}function _u(n){for(var t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("H",(r[0]+(r=n[t])[0])/2,"V",r[1]);return e>1&&i.push("H",r[0]),i.join("")}function wu(n){for(var t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("V",(r=n[t])[1],"H",r[0]);return i.join("")}function Su(n){for(var t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("H",(r=n[t])[0],"V",r[1]);return i.join("")}function ku(n,t){return n.length<4?xu(n):n[1]+Au(n.slice(1,-1),Cu(n,t))}function Nu(n,t){return n.length<3?bu(n):n[0]+Au((n.push(n[0]),n),Cu([n[n.length-2]].concat(n,[n[1]]),t))}function Eu(n,t){return n.length<3?xu(n):n[0]+Au(n,Cu(n,t))}function Au(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return xu(n);var e=n.length!=t.length,r="",i=n[0],u=n[1],o=t[0],a=o,l=1;if(e&&(r+="Q"+(u[0]-2*o[0]/3)+","+(u[1]-2*o[1]/3)+","+u[0]+","+u[1],i=n[1],l=2),t.length>1){a=t[1],u=n[l],l++,r+="C"+(i[0]+o[0])+","+(i[1]+o[1])+","+(u[0]-a[0])+","+(u[1]-a[1])+","+u[0]+","+u[1];for(var c=2;c<t.length;c++,l++)u=n[l],a=t[c],r+="S"+(u[0]-a[0])+","+(u[1]-a[1])+","+u[0]+","+u[1]}if(e){var f=n[l];r+="Q"+(u[0]+2*a[0]/3)+","+(u[1]+2*a[1]/3)+","+f[0]+","+f[1]}return r}function Cu(n,t){for(var e,r=[],i=(1-t)/2,u=n[0],o=n[1],a=1,l=n.length;++a<l;)e=u,u=o,o=n[a],r.push([i*(o[0]-e[0]),i*(o[1]-e[1])]);return r}function zu(n){if(n.length<3)return xu(n);var t=1,e=n.length,r=n[0],i=r[0],u=r[1],o=[i,i,i,(r=n[1])[0]],a=[u,u,u,r[1]],l=[i,",",u,"L",Ru(Pl,o),",",Ru(Pl,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Du(l,o,a);return n.pop(),l.push("L",r),l.join("")}function Lu(n){if(n.length<4)return xu(n);for(var t,e=[],r=-1,i=n.length,u=[0],o=[0];++r<3;)t=n[r],u.push(t[0]),o.push(t[1]);for(e.push(Ru(Pl,u)+","+Ru(Pl,o)),--r;++r<i;)t=n[r],u.shift(),u.push(t[0]),o.shift(),o.push(t[1]),Du(e,u,o);return e.join("")}function qu(n){for(var t,e,r=-1,i=n.length,u=i+4,o=[],a=[];++r<4;)e=n[r%i],o.push(e[0]),a.push(e[1]);for(t=[Ru(Pl,o),",",Ru(Pl,a)],--r;++r<u;)e=n[r%i],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Du(t,o,a);return t.join("")}function Tu(n,t){var e=n.length-1;if(e)for(var r,i,u=n[0][0],o=n[0][1],a=n[e][0]-u,l=n[e][1]-o,c=-1;++c<=e;)r=n[c],i=c/e,r[0]=t*r[0]+(1-t)*(u+i*a),r[1]=t*r[1]+(1-t)*(o+i*l);return zu(n)}function Ru(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function Du(n,t,e){n.push("C",Ru(Rl,t),",",Ru(Rl,e),",",Ru(Dl,t),",",Ru(Dl,e),",",Ru(Pl,t),",",Ru(Pl,e))}function Pu(n,t){return(t[1]-n[1])/(t[0]-n[0])}function Uu(n){for(var t=0,e=n.length-1,r=[],i=n[0],u=n[1],o=r[0]=Pu(i,u);++t<e;)r[t]=(o+(o=Pu(i=u,u=n[t+1])))/2;return r[t]=o,r}function ju(n){for(var t,e,r,i,u=[],o=Uu(n),a=-1,l=n.length-1;++a<l;)t=Pu(n[a],n[a+1]),xo(t)<Uo?o[a]=o[a+1]=0:(e=o[a]/t,r=o[a+1]/t,i=e*e+r*r,i>9&&(i=3*t/Math.sqrt(i),o[a]=i*e,o[a+1]=i*r));for(a=-1;++a<=l;)i=(n[Math.min(l,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),u.push([i||0,o[a]*i||0]);return u}function Fu(n){return n.length<3?xu(n):n[0]+Au(n,ju(n))}function Hu(n){for(var t,e,r,i=-1,u=n.length;++i<u;)t=n[i],e=t[0],r=t[1]-Io,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return n}function Ou(n){function t(t){function l(){v.push("M",a(n(y),s),f,c(n(d.reverse()),s),"Z")}for(var h,p,g,v=[],d=[],y=[],m=-1,M=t.length,x=En(e),b=En(i),_=e===r?function(){
return p}:En(r),w=i===u?function(){return g}:En(u);++m<M;)o.call(this,h=t[m],m)?(d.push([p=+x.call(this,h,m),g=+b.call(this,h,m)]),y.push([+_.call(this,h,m),+w.call(this,h,m)])):d.length&&(l(),d=[],y=[]);return d.length&&l(),v.length?v.join(""):null}var e=Ce,r=Ce,i=0,u=ze,o=zt,a=xu,l=a.key,c=a,f="L",s=.7;return t.x=function(n){return arguments.length?(e=r=n,t):r},t.x0=function(n){return arguments.length?(e=n,t):e},t.x1=function(n){return arguments.length?(r=n,t):r},t.y=function(n){return arguments.length?(i=u=n,t):u},t.y0=function(n){return arguments.length?(i=n,t):i},t.y1=function(n){return arguments.length?(u=n,t):u},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(l="function"==typeof n?a=n:(a=Tl.get(n)||xu).key,c=a.reverse||a,f=a.closed?"M":"L",t):l},t.tension=function(n){return arguments.length?(s=n,t):s},t}function Iu(n){return n.radius}function Yu(n){return[n.x,n.y]}function Zu(n){return function(){var t=n.apply(this,arguments),e=t[0],r=t[1]-Io;return[e*Math.cos(r),e*Math.sin(r)]}}function Vu(){return 64}function Xu(){return"circle"}function $u(n){var t=Math.sqrt(n/Fo);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function Bu(n){return function(){var t,e,r;(t=this[n])&&(r=t[e=t.active])&&(r.timer.c=null,r.timer.t=NaN,--t.count?delete t[e]:delete this[n],t.active+=.5,r.event&&r.event.interrupt.call(this,this.__data__,r.index))}}function Wu(n,t,e){return ko(n,Yl),n.namespace=t,n.id=e,n}function Ju(n,t,e,r){var i=n.id,u=n.namespace;return Y(n,"function"==typeof e?function(n,o,a){n[u][i].tween.set(t,r(e.call(n,n.__data__,o,a)))}:(e=r(e),function(n){n[u][i].tween.set(t,e)}))}function Gu(n){return null==n&&(n=""),function(){this.textContent=n}}function Ku(n){return null==n?"__transition__":"__transition_"+n+"__"}function Qu(n,t,e,r,i){function u(n){var t=v.delay;return f.t=t+l,n>=t?o(n-t):void(f.c=o)}function o(e){var i=g.active,u=g[i];u&&(u.timer.c=null,u.timer.t=NaN,--g.count,delete g[i],u.event&&u.event.interrupt.call(n,n.__data__,u.index));for(var o in g)if(r>+o){var c=g[o];c.timer.c=null,c.timer.t=NaN,--g.count,delete g[o]}f.c=a,qn(function(){return f.c&&a(e||1)&&(f.c=null,f.t=NaN),1},0,l),g.active=r,v.event&&v.event.start.call(n,n.__data__,t),p=[],v.tween.forEach(function(e,r){(r=r.call(n,n.__data__,t))&&p.push(r)}),h=v.ease,s=v.duration}function a(i){for(var u=i/s,o=h(u),a=p.length;a>0;)p[--a].call(n,o);return u>=1?(v.event&&v.event.end.call(n,n.__data__,t),--g.count?delete g[r]:delete n[e],1):void 0}var l,f,s,h,p,g=n[e]||(n[e]={active:0,count:0}),v=g[r];v||(l=i.time,f=qn(u,0,l),v=g[r]={tween:new c,time:l,timer:f,delay:i.delay,duration:i.duration,ease:i.ease,index:t},i=null,++g.count)}function no(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate("+(isFinite(r)?r:e(n))+",0)"})}function to(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate(0,"+(isFinite(r)?r:e(n))+")"})}function eo(n){return n.toISOString()}function ro(n,t,e){function r(t){return n(t)}function i(n,e){var r=n[1]-n[0],i=r/e,u=ao.bisect(Kl,i);return u==Kl.length?[t.year,Ki(n.map(function(n){return n/31536e6}),e)[2]]:u?t[i/Kl[u-1]<Kl[u]/i?u-1:u]:[tc,Ki(n,e)[2]]}return r.invert=function(t){return io(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(io)},r.nice=function(n,t){function e(e){return!isNaN(e)&&!n.range(e,io(+e+1),t).length}var u=r.domain(),o=Yi(u),a=null==n?i(o,10):"number"==typeof n&&i(o,n);return a&&(n=a[0],t=a[1]),r.domain(Xi(u,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=io(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=io(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Yi(r.domain()),u=null==n?i(e,10):"number"==typeof n?i(e,n):!n.range&&[{range:n},t];return u&&(n=u[0],t=u[1]),n.range(e[0],io(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return ro(n.copy(),t,e)},Ji(r,n)}function io(n){return new Date(n)}function uo(n){return JSON.parse(n.responseText)}function oo(n){var t=fo.createRange();return t.selectNode(fo.body),t.createContextualFragment(n.responseText)}var ao={version:"3.5.17"},lo=[].slice,co=function(n){return lo.call(n)},fo=this.document;if(fo)try{co(fo.documentElement.childNodes)[0].nodeType}catch(so){co=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}if(Date.now||(Date.now=function(){return+new Date}),fo)try{fo.createElement("DIV").style.setProperty("opacity",0,"")}catch(ho){var po=this.Element.prototype,go=po.setAttribute,vo=po.setAttributeNS,yo=this.CSSStyleDeclaration.prototype,mo=yo.setProperty;po.setAttribute=function(n,t){go.call(this,n,t+"")},po.setAttributeNS=function(n,t,e){vo.call(this,n,t,e+"")},yo.setProperty=function(n,t,e){mo.call(this,n,t+"",e)}}ao.ascending=e,ao.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:NaN},ao.min=function(n,t){var e,r,i=-1,u=n.length;if(1===arguments.length){for(;++i<u;)if(null!=(r=n[i])&&r>=r){e=r;break}for(;++i<u;)null!=(r=n[i])&&e>r&&(e=r)}else{for(;++i<u;)if(null!=(r=t.call(n,n[i],i))&&r>=r){e=r;break}for(;++i<u;)null!=(r=t.call(n,n[i],i))&&e>r&&(e=r)}return e},ao.max=function(n,t){var e,r,i=-1,u=n.length;if(1===arguments.length){for(;++i<u;)if(null!=(r=n[i])&&r>=r){e=r;break}for(;++i<u;)null!=(r=n[i])&&r>e&&(e=r)}else{for(;++i<u;)if(null!=(r=t.call(n,n[i],i))&&r>=r){e=r;break}for(;++i<u;)null!=(r=t.call(n,n[i],i))&&r>e&&(e=r)}return e},ao.extent=function(n,t){var e,r,i,u=-1,o=n.length;if(1===arguments.length){for(;++u<o;)if(null!=(r=n[u])&&r>=r){e=i=r;break}for(;++u<o;)null!=(r=n[u])&&(e>r&&(e=r),r>i&&(i=r))}else{for(;++u<o;)if(null!=(r=t.call(n,n[u],u))&&r>=r){e=i=r;break}for(;++u<o;)null!=(r=t.call(n,n[u],u))&&(e>r&&(e=r),r>i&&(i=r))}return[e,i]},ao.sum=function(n,t){var e,r=0,u=n.length,o=-1;if(1===arguments.length)for(;++o<u;)i(e=+n[o])&&(r+=e);else for(;++o<u;)i(e=+t.call(n,n[o],o))&&(r+=e);return r},ao.mean=function(n,t){var e,u=0,o=n.length,a=-1,l=o;if(1===arguments.length)for(;++a<o;)i(e=r(n[a]))?u+=e:--l;else for(;++a<o;)i(e=r(t.call(n,n[a],a)))?u+=e:--l;return l?u/l:void 0},ao.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),i=+n[r-1],u=e-r;return u?i+u*(n[r]-i):i},ao.median=function(n,t){var u,o=[],a=n.length,l=-1;if(1===arguments.length)for(;++l<a;)i(u=r(n[l]))&&o.push(u);else for(;++l<a;)i(u=r(t.call(n,n[l],l)))&&o.push(u);return o.length?ao.quantile(o.sort(e),.5):void 0},ao.variance=function(n,t){var e,u,o=n.length,a=0,l=0,c=-1,f=0;if(1===arguments.length)for(;++c<o;)i(e=r(n[c]))&&(u=e-a,a+=u/++f,l+=u*(e-a));else for(;++c<o;)i(e=r(t.call(n,n[c],c)))&&(u=e-a,a+=u/++f,l+=u*(e-a));return f>1?l/(f-1):void 0},ao.deviation=function(){var n=ao.variance.apply(this,arguments);return n?Math.sqrt(n):n};var Mo=u(e);ao.bisectLeft=Mo.left,ao.bisect=ao.bisectRight=Mo.right,ao.bisector=function(n){return u(1===n.length?function(t,r){return e(n(t),r)}:n)},ao.shuffle=function(n,t,e){(u=arguments.length)<3&&(e=n.length,2>u&&(t=0));for(var r,i,u=e-t;u;)i=Math.random()*u--|0,r=n[u+t],n[u+t]=n[i+t],n[i+t]=r;return n},ao.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},ao.pairs=function(n){for(var t,e=0,r=n.length-1,i=n[0],u=new Array(0>r?0:r);r>e;)u[e]=[t=i,i=n[++e]];return u},ao.transpose=function(n){if(!(i=n.length))return[];for(var t=-1,e=ao.min(n,o),r=new Array(e);++t<e;)for(var i,u=-1,a=r[t]=new Array(i);++u<i;)a[u]=n[u][t];return r},ao.zip=function(){return ao.transpose(arguments)},ao.keys=function(n){var t=[];for(var e in n)t.push(e);return t},ao.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},ao.entries=function(n){var t=[];for(var e in n)t.push({key:e,value:n[e]});return t},ao.merge=function(n){for(var t,e,r,i=n.length,u=-1,o=0;++u<i;)o+=n[u].length;for(e=new Array(o);--i>=0;)for(r=n[i],t=r.length;--t>=0;)e[--o]=r[t];return e};var xo=Math.abs;ao.range=function(n,t,e){if(arguments.length<3&&(e=1,arguments.length<2&&(t=n,n=0)),(t-n)/e===1/0)throw new Error("infinite range");var r,i=[],u=a(xo(e)),o=-1;if(n*=u,t*=u,e*=u,0>e)for(;(r=n+e*++o)>t;)i.push(r/u);else for(;(r=n+e*++o)<t;)i.push(r/u);return i},ao.map=function(n,t){var e=new c;if(n instanceof c)n.forEach(function(n,t){e.set(n,t)});else if(Array.isArray(n)){var r,i=-1,u=n.length;if(1===arguments.length)for(;++i<u;)e.set(i,n[i]);else for(;++i<u;)e.set(t.call(n,r=n[i],i),r)}else for(var o in n)e.set(o,n[o]);return e};var bo="__proto__",_o="\x00";l(c,{has:h,get:function(n){return this._[f(n)]},set:function(n,t){return this._[f(n)]=t},remove:p,keys:g,values:function(){var n=[];for(var t in this._)n.push(this._[t]);return n},entries:function(){var n=[];for(var t in this._)n.push({key:s(t),value:this._[t]});return n},size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,s(t),this._[t])}}),ao.nest=function(){function n(t,o,a){if(a>=u.length)return r?r.call(i,o):e?o.sort(e):o;for(var l,f,s,h,p=-1,g=o.length,v=u[a++],d=new c;++p<g;)(h=d.get(l=v(f=o[p])))?h.push(f):d.set(l,[f]);return t?(f=t(),s=function(e,r){f.set(e,n(t,r,a))}):(f={},s=function(e,r){f[e]=n(t,r,a)}),d.forEach(s),f}function t(n,e){if(e>=u.length)return n;var r=[],i=o[e++];return n.forEach(function(n,i){r.push({key:n,values:t(i,e)})}),i?r.sort(function(n,t){return i(n.key,t.key)}):r}var e,r,i={},u=[],o=[];return i.map=function(t,e){return n(e,t,0)},i.entries=function(e){return t(n(ao.map,e,0),0)},i.key=function(n){return u.push(n),i},i.sortKeys=function(n){return o[u.length-1]=n,i},i.sortValues=function(n){return e=n,i},i.rollup=function(n){return r=n,i},i},ao.set=function(n){var t=new y;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},l(y,{has:h,add:function(n){return this._[f(n+="")]=!0,n},remove:p,values:g,size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,s(t))}}),ao.behavior={},ao.rebind=function(n,t){for(var e,r=1,i=arguments.length;++r<i;)n[e=arguments[r]]=M(n,t,t[e]);return n};var wo=["webkit","ms","moz","Moz","o","O"];ao.dispatch=function(){for(var n=new _,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=w(n);return n},_.prototype.on=function(n,t){var e=n.indexOf("."),r="";if(e>=0&&(r=n.slice(e+1),n=n.slice(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},ao.event=null,ao.requote=function(n){return n.replace(So,"\\$&")};var So=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,ko={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},No=function(n,t){return t.querySelector(n)},Eo=function(n,t){return t.querySelectorAll(n)},Ao=function(n,t){var e=n.matches||n[x(n,"matchesSelector")];return(Ao=function(n,t){return e.call(n,t)})(n,t)};"function"==typeof Sizzle&&(No=function(n,t){return Sizzle(n,t)[0]||null},Eo=Sizzle,Ao=Sizzle.matchesSelector),ao.selection=function(){return ao.select(fo.documentElement)};var Co=ao.selection.prototype=[];Co.select=function(n){var t,e,r,i,u=[];n=A(n);for(var o=-1,a=this.length;++o<a;){u.push(t=[]),t.parentNode=(r=this[o]).parentNode;for(var l=-1,c=r.length;++l<c;)(i=r[l])?(t.push(e=n.call(i,i.__data__,l,o)),e&&"__data__"in i&&(e.__data__=i.__data__)):t.push(null)}return E(u)},Co.selectAll=function(n){var t,e,r=[];n=C(n);for(var i=-1,u=this.length;++i<u;)for(var o=this[i],a=-1,l=o.length;++a<l;)(e=o[a])&&(r.push(t=co(n.call(e,e.__data__,a,i))),t.parentNode=e);return E(r)};var zo="http://www.w3.org/1999/xhtml",Lo={svg:"http://www.w3.org/2000/svg",xhtml:zo,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};ao.ns={prefix:Lo,qualify:function(n){var t=n.indexOf(":"),e=n;return t>=0&&"xmlns"!==(e=n.slice(0,t))&&(n=n.slice(t+1)),Lo.hasOwnProperty(e)?{space:Lo[e],local:n}:n}},Co.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=ao.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(z(t,n[t]));return this}return this.each(z(n,t))},Co.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=T(n)).length,i=-1;if(t=e.classList){for(;++i<r;)if(!t.contains(n[i]))return!1}else for(t=e.getAttribute("class");++i<r;)if(!q(n[i]).test(t))return!1;return!0}for(t in n)this.each(R(t,n[t]));return this}return this.each(R(n,t))},Co.style=function(n,e,r){var i=arguments.length;if(3>i){if("string"!=typeof n){2>i&&(e="");for(r in n)this.each(P(r,n[r],e));return this}if(2>i){var u=this.node();return t(u).getComputedStyle(u,null).getPropertyValue(n)}r=""}return this.each(P(n,e,r))},Co.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(U(t,n[t]));return this}return this.each(U(n,t))},Co.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},Co.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},Co.append=function(n){return n=j(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},Co.insert=function(n,t){return n=j(n),t=A(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},Co.remove=function(){return this.each(F)},Co.data=function(n,t){function e(n,e){var r,i,u,o=n.length,s=e.length,h=Math.min(o,s),p=new Array(s),g=new Array(s),v=new Array(o);if(t){var d,y=new c,m=new Array(o);for(r=-1;++r<o;)(i=n[r])&&(y.has(d=t.call(i,i.__data__,r))?v[r]=i:y.set(d,i),m[r]=d);for(r=-1;++r<s;)(i=y.get(d=t.call(e,u=e[r],r)))?i!==!0&&(p[r]=i,i.__data__=u):g[r]=H(u),y.set(d,!0);for(r=-1;++r<o;)r in m&&y.get(m[r])!==!0&&(v[r]=n[r])}else{for(r=-1;++r<h;)i=n[r],u=e[r],i?(i.__data__=u,p[r]=i):g[r]=H(u);for(;s>r;++r)g[r]=H(e[r]);for(;o>r;++r)v[r]=n[r]}g.update=p,g.parentNode=p.parentNode=v.parentNode=n.parentNode,a.push(g),l.push(p),f.push(v)}var r,i,u=-1,o=this.length;if(!arguments.length){for(n=new Array(o=(r=this[0]).length);++u<o;)(i=r[u])&&(n[u]=i.__data__);return n}var a=Z([]),l=E([]),f=E([]);if("function"==typeof n)for(;++u<o;)e(r=this[u],n.call(r,r.parentNode.__data__,u));else for(;++u<o;)e(r=this[u],n);return l.enter=function(){return a},l.exit=function(){return f},l},Co.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},Co.filter=function(n){var t,e,r,i=[];"function"!=typeof n&&(n=O(n));for(var u=0,o=this.length;o>u;u++){i.push(t=[]),t.parentNode=(e=this[u]).parentNode;for(var a=0,l=e.length;l>a;a++)(r=e[a])&&n.call(r,r.__data__,a,u)&&t.push(r)}return E(i)},Co.order=function(){for(var n=-1,t=this.length;++n<t;)for(var e,r=this[n],i=r.length-1,u=r[i];--i>=0;)(e=r[i])&&(u&&u!==e.nextSibling&&u.parentNode.insertBefore(e,u),u=e);return this},Co.sort=function(n){n=I.apply(this,arguments);for(var t=-1,e=this.length;++t<e;)this[t].sort(n);return this.order()},Co.each=function(n){return Y(this,function(t,e,r){n.call(t,t.__data__,e,r)})},Co.call=function(n){var t=co(arguments);return n.apply(t[0]=this,t),this},Co.empty=function(){return!this.node()},Co.node=function(){for(var n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,i=e.length;i>r;r++){var u=e[r];if(u)return u}return null},Co.size=function(){var n=0;return Y(this,function(){++n}),n};var qo=[];ao.selection.enter=Z,ao.selection.enter.prototype=qo,qo.append=Co.append,qo.empty=Co.empty,qo.node=Co.node,qo.call=Co.call,qo.size=Co.size,qo.select=function(n){for(var t,e,r,i,u,o=[],a=-1,l=this.length;++a<l;){r=(i=this[a]).update,o.push(t=[]),t.parentNode=i.parentNode;for(var c=-1,f=i.length;++c<f;)(u=i[c])?(t.push(r[c]=e=n.call(i.parentNode,u.__data__,c,a)),e.__data__=u.__data__):t.push(null)}return E(o)},qo.insert=function(n,t){return arguments.length<2&&(t=V(this)),Co.insert.call(this,n,t)},ao.select=function(t){var e;return"string"==typeof t?(e=[No(t,fo)],e.parentNode=fo.documentElement):(e=[t],e.parentNode=n(t)),E([e])},ao.selectAll=function(n){var t;return"string"==typeof n?(t=co(Eo(n,fo)),t.parentNode=fo.documentElement):(t=co(n),t.parentNode=null),E([t])},Co.on=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(X(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(X(n,t,e))};var To=ao.map({mouseenter:"mouseover",mouseleave:"mouseout"});fo&&To.forEach(function(n){"on"+n in fo&&To.remove(n)});var Ro,Do=0;ao.mouse=function(n){return J(n,k())};var Po=this.navigator&&/WebKit/.test(this.navigator.userAgent)?-1:0;ao.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=k().changedTouches),t)for(var r,i=0,u=t.length;u>i;++i)if((r=t[i]).identifier===e)return J(n,r)},ao.behavior.drag=function(){function n(){this.on("mousedown.drag",u).on("touchstart.drag",o)}function e(n,t,e,u,o){return function(){function a(){var n,e,r=t(h,v);r&&(n=r[0]-M[0],e=r[1]-M[1],g|=n|e,M=r,p({type:"drag",x:r[0]+c[0],y:r[1]+c[1],dx:n,dy:e}))}function l(){t(h,v)&&(y.on(u+d,null).on(o+d,null),m(g),p({type:"dragend"}))}var c,f=this,s=ao.event.target.correspondingElement||ao.event.target,h=f.parentNode,p=r.of(f,arguments),g=0,v=n(),d=".drag"+(null==v?"":"-"+v),y=ao.select(e(s)).on(u+d,a).on(o+d,l),m=W(s),M=t(h,v);i?(c=i.apply(f,arguments),c=[c.x-M[0],c.y-M[1]]):c=[0,0],p({type:"dragstart"})}}var r=N(n,"drag","dragstart","dragend"),i=null,u=e(b,ao.mouse,t,"mousemove","mouseup"),o=e(G,ao.touch,m,"touchmove","touchend");return n.origin=function(t){return arguments.length?(i=t,n):i},ao.rebind(n,r,"on")},ao.touches=function(n,t){return arguments.length<2&&(t=k().touches),t?co(t).map(function(t){var e=J(n,t);return e.identifier=t.identifier,e}):[]};var Uo=1e-6,jo=Uo*Uo,Fo=Math.PI,Ho=2*Fo,Oo=Ho-Uo,Io=Fo/2,Yo=Fo/180,Zo=180/Fo,Vo=Math.SQRT2,Xo=2,$o=4;ao.interpolateZoom=function(n,t){var e,r,i=n[0],u=n[1],o=n[2],a=t[0],l=t[1],c=t[2],f=a-i,s=l-u,h=f*f+s*s;if(jo>h)r=Math.log(c/o)/Vo,e=function(n){return[i+n*f,u+n*s,o*Math.exp(Vo*n*r)]};else{var p=Math.sqrt(h),g=(c*c-o*o+$o*h)/(2*o*Xo*p),v=(c*c-o*o-$o*h)/(2*c*Xo*p),d=Math.log(Math.sqrt(g*g+1)-g),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-d)/Vo,e=function(n){var t=n*r,e=rn(d),a=o/(Xo*p)*(e*un(Vo*t+d)-en(d));return[i+a*f,u+a*s,o*e/rn(Vo*t+d)]}}return e.duration=1e3*r,e},ao.behavior.zoom=function(){function n(n){n.on(L,s).on(Wo+".zoom",p).on("dblclick.zoom",g).on(R,h)}function e(n){return[(n[0]-k.x)/k.k,(n[1]-k.y)/k.k]}function r(n){return[n[0]*k.k+k.x,n[1]*k.k+k.y]}function i(n){k.k=Math.max(A[0],Math.min(A[1],n))}function u(n,t){t=r(t),k.x+=n[0]-t[0],k.y+=n[1]-t[1]}function o(t,e,r,o){t.__chart__={x:k.x,y:k.y,k:k.k},i(Math.pow(2,o)),u(d=e,r),t=ao.select(t),C>0&&(t=t.transition().duration(C)),t.call(n.event)}function a(){b&&b.domain(x.range().map(function(n){return(n-k.x)/k.k}).map(x.invert)),w&&w.domain(_.range().map(function(n){return(n-k.y)/k.k}).map(_.invert))}function l(n){z++||n({type:"zoomstart"})}function c(n){a(),n({type:"zoom",scale:k.k,translate:[k.x,k.y]})}function f(n){--z||(n({type:"zoomend"}),d=null)}function s(){function n(){a=1,u(ao.mouse(i),h),c(o)}function r(){s.on(q,null).on(T,null),p(a),f(o)}var i=this,o=D.of(i,arguments),a=0,s=ao.select(t(i)).on(q,n).on(T,r),h=e(ao.mouse(i)),p=W(i);Il.call(i),l(o)}function h(){function n(){var n=ao.touches(g);return p=k.k,n.forEach(function(n){n.identifier in d&&(d[n.identifier]=e(n))}),n}function t(){var t=ao.event.target;ao.select(t).on(x,r).on(b,a),_.push(t);for(var e=ao.event.changedTouches,i=0,u=e.length;u>i;++i)d[e[i].identifier]=null;var l=n(),c=Date.now();if(1===l.length){if(500>c-M){var f=l[0];o(g,f,d[f.identifier],Math.floor(Math.log(k.k)/Math.LN2)+1),S()}M=c}else if(l.length>1){var f=l[0],s=l[1],h=f[0]-s[0],p=f[1]-s[1];y=h*h+p*p}}function r(){var n,t,e,r,o=ao.touches(g);Il.call(g);for(var a=0,l=o.length;l>a;++a,r=null)if(e=o[a],r=d[e.identifier]){if(t)break;n=e,t=r}if(r){var f=(f=e[0]-n[0])*f+(f=e[1]-n[1])*f,s=y&&Math.sqrt(f/y);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+r[0])/2,(t[1]+r[1])/2],i(s*p)}M=null,u(n,t),c(v)}function a(){if(ao.event.touches.length){for(var t=ao.event.changedTouches,e=0,r=t.length;r>e;++e)delete d[t[e].identifier];for(var i in d)return void n()}ao.selectAll(_).on(m,null),w.on(L,s).on(R,h),N(),f(v)}var p,g=this,v=D.of(g,arguments),d={},y=0,m=".zoom-"+ao.event.changedTouches[0].identifier,x="touchmove"+m,b="touchend"+m,_=[],w=ao.select(g),N=W(g);t(),l(v),w.on(L,null).on(R,t)}function p(){var n=D.of(this,arguments);m?clearTimeout(m):(Il.call(this),v=e(d=y||ao.mouse(this)),l(n)),m=setTimeout(function(){m=null,f(n)},50),S(),i(Math.pow(2,.002*Bo())*k.k),u(d,v),c(n)}function g(){var n=ao.mouse(this),t=Math.log(k.k)/Math.LN2;o(this,n,e(n),ao.event.shiftKey?Math.ceil(t)-1:Math.floor(t)+1)}var v,d,y,m,M,x,b,_,w,k={x:0,y:0,k:1},E=[960,500],A=Jo,C=250,z=0,L="mousedown.zoom",q="mousemove.zoom",T="mouseup.zoom",R="touchstart.zoom",D=N(n,"zoomstart","zoom","zoomend");return Wo||(Wo="onwheel"in fo?(Bo=function(){return-ao.event.deltaY*(ao.event.deltaMode?120:1)},"wheel"):"onmousewheel"in fo?(Bo=function(){return ao.event.wheelDelta},"mousewheel"):(Bo=function(){return-ao.event.detail},"MozMousePixelScroll")),n.event=function(n){n.each(function(){var n=D.of(this,arguments),t=k;Hl?ao.select(this).transition().each("start.zoom",function(){k=this.__chart__||{x:0,y:0,k:1},l(n)}).tween("zoom:zoom",function(){var e=E[0],r=E[1],i=d?d[0]:e/2,u=d?d[1]:r/2,o=ao.interpolateZoom([(i-k.x)/k.k,(u-k.y)/k.k,e/k.k],[(i-t.x)/t.k,(u-t.y)/t.k,e/t.k]);return function(t){var r=o(t),a=e/r[2];this.__chart__=k={x:i-r[0]*a,y:u-r[1]*a,k:a},c(n)}}).each("interrupt.zoom",function(){f(n)}).each("end.zoom",function(){f(n)}):(this.__chart__=k,l(n),c(n),f(n))})},n.translate=function(t){return arguments.length?(k={x:+t[0],y:+t[1],k:k.k},a(),n):[k.x,k.y]},n.scale=function(t){return arguments.length?(k={x:k.x,y:k.y,k:null},i(+t),a(),n):k.k},n.scaleExtent=function(t){return arguments.length?(A=null==t?Jo:[+t[0],+t[1]],n):A},n.center=function(t){return arguments.length?(y=t&&[+t[0],+t[1]],n):y},n.size=function(t){return arguments.length?(E=t&&[+t[0],+t[1]],n):E},n.duration=function(t){return arguments.length?(C=+t,n):C},n.x=function(t){return arguments.length?(b=t,x=t.copy(),k={x:0,y:0,k:1},n):b},n.y=function(t){return arguments.length?(w=t,_=t.copy(),k={x:0,y:0,k:1},n):w},ao.rebind(n,D,"on")};var Bo,Wo,Jo=[0,1/0];ao.color=an,an.prototype.toString=function(){return this.rgb()+""},ao.hsl=ln;var Go=ln.prototype=new an;Go.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new ln(this.h,this.s,this.l/n)},Go.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new ln(this.h,this.s,n*this.l)},Go.rgb=function(){return cn(this.h,this.s,this.l)},ao.hcl=fn;var Ko=fn.prototype=new an;Ko.brighter=function(n){return new fn(this.h,this.c,Math.min(100,this.l+Qo*(arguments.length?n:1)))},Ko.darker=function(n){return new fn(this.h,this.c,Math.max(0,this.l-Qo*(arguments.length?n:1)))},Ko.rgb=function(){return sn(this.h,this.c,this.l).rgb()},ao.lab=hn;var Qo=18,na=.95047,ta=1,ea=1.08883,ra=hn.prototype=new an;ra.brighter=function(n){return new hn(Math.min(100,this.l+Qo*(arguments.length?n:1)),this.a,this.b)},ra.darker=function(n){return new hn(Math.max(0,this.l-Qo*(arguments.length?n:1)),this.a,this.b)},ra.rgb=function(){return pn(this.l,this.a,this.b)},ao.rgb=mn;var ia=mn.prototype=new an;ia.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,i=30;return t||e||r?(t&&i>t&&(t=i),e&&i>e&&(e=i),r&&i>r&&(r=i),new mn(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new mn(i,i,i)},ia.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new mn(n*this.r,n*this.g,n*this.b)},ia.hsl=function(){return wn(this.r,this.g,this.b)},ia.toString=function(){return"#"+bn(this.r)+bn(this.g)+bn(this.b)};var ua=ao.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});ua.forEach(function(n,t){ua.set(n,Mn(t))}),ao.functor=En,ao.xhr=An(m),ao.dsv=function(n,t){function e(n,e,u){arguments.length<3&&(u=e,e=null);var o=Cn(n,t,null==e?r:i(e),u);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:i(n)):e},o}function r(n){return e.parse(n.responseText)}function i(n){return function(t){return e.parse(t.responseText,n)}}function u(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),l=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var i=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(i(n),e)}:i})},e.parseRows=function(n,t){function e(){if(f>=c)return o;if(i)return i=!1,u;var t=f;if(34===n.charCodeAt(t)){for(var e=t;e++<c;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}f=e+2;var r=n.charCodeAt(e+1);return 13===r?(i=!0,10===n.charCodeAt(e+2)&&++f):10===r&&(i=!0),n.slice(t+1,e).replace(/""/g,'"')}for(;c>f;){var r=n.charCodeAt(f++),a=1;if(10===r)i=!0;else if(13===r)i=!0,10===n.charCodeAt(f)&&(++f,++a);else if(r!==l)continue;return n.slice(t,f-a)}return n.slice(t)}for(var r,i,u={},o={},a=[],c=n.length,f=0,s=0;(r=e())!==o;){for(var h=[];r!==u&&r!==o;)h.push(r),r=e();t&&null==(h=t(h,s++))||a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new y,i=[];return t.forEach(function(n){for(var t in n)r.has(t)||i.push(r.add(t))}),[i.map(o).join(n)].concat(t.map(function(t){return i.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(u).join("\n")},e},ao.csv=ao.dsv(",","text/csv"),ao.tsv=ao.dsv("	","text/tab-separated-values");var oa,aa,la,ca,fa=this[x(this,"requestAnimationFrame")]||function(n){setTimeout(n,17)};ao.timer=function(){qn.apply(this,arguments)},ao.timer.flush=function(){Rn(),Dn()},ao.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var sa=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(Un);ao.formatPrefix=function(n,t){var e=0;return(n=+n)&&(0>n&&(n*=-1),t&&(n=ao.round(n,Pn(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),sa[8+e/3]};var ha=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,pa=ao.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=ao.round(n,Pn(n,t))).toFixed(Math.max(0,Math.min(20,Pn(n*(1+1e-15),t))))}}),ga=ao.time={},va=Date;Hn.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){da.setUTCDate.apply(this._,arguments)},setDay:function(){da.setUTCDay.apply(this._,arguments)},setFullYear:function(){da.setUTCFullYear.apply(this._,arguments)},setHours:function(){da.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){da.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){da.setUTCMinutes.apply(this._,arguments)},setMonth:function(){da.setUTCMonth.apply(this._,arguments)},setSeconds:function(){da.setUTCSeconds.apply(this._,arguments)},setTime:function(){da.setTime.apply(this._,arguments)}};var da=Date.prototype;ga.year=On(function(n){return n=ga.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),ga.years=ga.year.range,ga.years.utc=ga.year.utc.range,ga.day=On(function(n){var t=new va(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),ga.days=ga.day.range,ga.days.utc=ga.day.utc.range,ga.dayOfYear=function(n){var t=ga.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=ga[n]=On(function(n){return(n=ga.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=ga.year(n).getDay();return Math.floor((ga.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});ga[n+"s"]=e.range,ga[n+"s"].utc=e.utc.range,ga[n+"OfYear"]=function(n){var e=ga.year(n).getDay();return Math.floor((ga.dayOfYear(n)+(e+t)%7)/7)}}),ga.week=ga.sunday,ga.weeks=ga.sunday.range,ga.weeks.utc=ga.sunday.utc.range,ga.weekOfYear=ga.sundayOfYear;var ya={"-":"",_:" ",0:"0"},ma=/^\s*\d+/,Ma=/^%/;ao.locale=function(n){return{numberFormat:jn(n),timeFormat:Yn(n)}};var xa=ao.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});ao.format=xa.numberFormat,ao.geo={},ft.prototype={s:0,t:0,add:function(n){st(n,this.t,ba),st(ba.s,this.s,this),this.s?this.t+=ba.t:this.s=ba.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var ba=new ft;ao.geo.stream=function(n,t){n&&_a.hasOwnProperty(n.type)?_a[n.type](n,t):ht(n,t)};var _a={Feature:function(n,t){ht(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,i=e.length;++r<i;)ht(e[r].geometry,t)}},wa={Sphere:function(n,t){t.sphere()},Point:function(n,t){n=n.coordinates,t.point(n[0],n[1],n[2])},MultiPoint:function(n,t){for(var e=n.coordinates,r=-1,i=e.length;++r<i;)n=e[r],t.point(n[0],n[1],n[2])},LineString:function(n,t){pt(n.coordinates,t,0)},MultiLineString:function(n,t){for(var e=n.coordinates,r=-1,i=e.length;++r<i;)pt(e[r],t,0)},Polygon:function(n,t){gt(n.coordinates,t)},MultiPolygon:function(n,t){for(var e=n.coordinates,r=-1,i=e.length;++r<i;)gt(e[r],t)},GeometryCollection:function(n,t){for(var e=n.geometries,r=-1,i=e.length;++r<i;)ht(e[r],t)}};ao.geo.area=function(n){return Sa=0,ao.geo.stream(n,Na),Sa};var Sa,ka=new ft,Na={sphere:function(){Sa+=4*Fo},point:b,lineStart:b,lineEnd:b,polygonStart:function(){ka.reset(),Na.lineStart=vt},polygonEnd:function(){var n=2*ka;Sa+=0>n?4*Fo+n:n,Na.lineStart=Na.lineEnd=Na.point=b}};ao.geo.bounds=function(){function n(n,t){M.push(x=[f=n,h=n]),s>t&&(s=t),t>p&&(p=t)}function t(t,e){var r=dt([t*Yo,e*Yo]);if(y){var i=mt(y,r),u=[i[1],-i[0],0],o=mt(u,i);bt(o),o=_t(o);var l=t-g,c=l>0?1:-1,v=o[0]*Zo*c,d=xo(l)>180;if(d^(v>c*g&&c*t>v)){var m=o[1]*Zo;m>p&&(p=m)}else if(v=(v+360)%360-180,d^(v>c*g&&c*t>v)){var m=-o[1]*Zo;s>m&&(s=m)}else s>e&&(s=e),e>p&&(p=e);d?g>t?a(f,t)>a(f,h)&&(h=t):a(t,h)>a(f,h)&&(f=t):h>=f?(f>t&&(f=t),t>h&&(h=t)):t>g?a(f,t)>a(f,h)&&(h=t):a(t,h)>a(f,h)&&(f=t)}else n(t,e);y=r,g=t}function e(){b.point=t}function r(){x[0]=f,x[1]=h,b.point=n,y=null}function i(n,e){if(y){var r=n-g;m+=xo(r)>180?r+(r>0?360:-360):r}else v=n,d=e;Na.point(n,e),t(n,e)}function u(){Na.lineStart()}function o(){i(v,d),Na.lineEnd(),xo(m)>Uo&&(f=-(h=180)),x[0]=f,x[1]=h,y=null}function a(n,t){return(t-=n)<0?t+360:t}function l(n,t){return n[0]-t[0]}function c(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var f,s,h,p,g,v,d,y,m,M,x,b={point:n,lineStart:e,lineEnd:r,polygonStart:function(){b.point=i,b.lineStart=u,b.lineEnd=o,m=0,Na.polygonStart()},polygonEnd:function(){Na.polygonEnd(),b.point=n,b.lineStart=e,b.lineEnd=r,0>ka?(f=-(h=180),s=-(p=90)):m>Uo?p=90:-Uo>m&&(s=-90),x[0]=f,x[1]=h}};return function(n){p=h=-(f=s=1/0),M=[],ao.geo.stream(n,b);var t=M.length;if(t){M.sort(l);for(var e,r=1,i=M[0],u=[i];t>r;++r)e=M[r],c(e[0],i)||c(e[1],i)?(a(i[0],e[1])>a(i[0],i[1])&&(i[1]=e[1]),a(e[0],i[1])>a(i[0],i[1])&&(i[0]=e[0])):u.push(i=e);for(var o,e,g=-(1/0),t=u.length-1,r=0,i=u[t];t>=r;i=e,++r)e=u[r],(o=a(i[1],e[0]))>g&&(g=o,f=e[0],h=i[1])}return M=x=null,f===1/0||s===1/0?[[NaN,NaN],[NaN,NaN]]:[[f,s],[h,p]]}}(),ao.geo.centroid=function(n){Ea=Aa=Ca=za=La=qa=Ta=Ra=Da=Pa=Ua=0,ao.geo.stream(n,ja);var t=Da,e=Pa,r=Ua,i=t*t+e*e+r*r;return jo>i&&(t=qa,e=Ta,r=Ra,Uo>Aa&&(t=Ca,e=za,r=La),i=t*t+e*e+r*r,jo>i)?[NaN,NaN]:[Math.atan2(e,t)*Zo,tn(r/Math.sqrt(i))*Zo]};var Ea,Aa,Ca,za,La,qa,Ta,Ra,Da,Pa,Ua,ja={sphere:b,point:St,lineStart:Nt,lineEnd:Et,polygonStart:function(){ja.lineStart=At},polygonEnd:function(){ja.lineStart=Nt}},Fa=Rt(zt,jt,Ht,[-Fo,-Fo/2]),Ha=1e9;ao.geo.clipExtent=function(){var n,t,e,r,i,u,o={stream:function(n){return i&&(i.valid=!1),i=u(n),i.valid=!0,i},extent:function(a){return arguments.length?(u=Zt(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),i&&(i.valid=!1,i=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(ao.geo.conicEqualArea=function(){return Vt(Xt)}).raw=Xt,ao.geo.albers=function(){return ao.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},ao.geo.albersUsa=function(){function n(n){var u=n[0],o=n[1];return t=null,e(u,o),t||(r(u,o),t)||i(u,o),t}var t,e,r,i,u=ao.geo.albers(),o=ao.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=ao.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),l={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=u.scale(),e=u.translate(),r=(n[0]-e[0])/t,i=(n[1]-e[1])/t;return(i>=.12&&.234>i&&r>=-.425&&-.214>r?o:i>=.166&&.234>i&&r>=-.214&&-.115>r?a:u).invert(n)},n.stream=function(n){var t=u.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,i){t.point(n,i),e.point(n,i),r.point(n,i)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(u.precision(t),o.precision(t),a.precision(t),n):u.precision()},n.scale=function(t){return arguments.length?(u.scale(t),o.scale(.35*t),a.scale(t),n.translate(u.translate())):u.scale()},n.translate=function(t){if(!arguments.length)return u.translate();var c=u.scale(),f=+t[0],s=+t[1];return e=u.translate(t).clipExtent([[f-.455*c,s-.238*c],[f+.455*c,s+.238*c]]).stream(l).point,r=o.translate([f-.307*c,s+.201*c]).clipExtent([[f-.425*c+Uo,s+.12*c+Uo],[f-.214*c-Uo,s+.234*c-Uo]]).stream(l).point,i=a.translate([f-.205*c,s+.212*c]).clipExtent([[f-.214*c+Uo,s+.166*c+Uo],[f-.115*c-Uo,s+.234*c-Uo]]).stream(l).point,n},n.scale(1070)};var Oa,Ia,Ya,Za,Va,Xa,$a={point:b,lineStart:b,lineEnd:b,polygonStart:function(){Ia=0,$a.lineStart=$t},polygonEnd:function(){$a.lineStart=$a.lineEnd=$a.point=b,Oa+=xo(Ia/2)}},Ba={point:Bt,lineStart:b,lineEnd:b,polygonStart:b,polygonEnd:b},Wa={point:Gt,lineStart:Kt,lineEnd:Qt,polygonStart:function(){Wa.lineStart=ne},polygonEnd:function(){Wa.point=Gt,Wa.lineStart=Kt,Wa.lineEnd=Qt}};ao.geo.path=function(){function n(n){return n&&("function"==typeof a&&u.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=i(u)),ao.geo.stream(n,o)),u.result()}function t(){return o=null,n}var e,r,i,u,o,a=4.5;return n.area=function(n){return Oa=0,ao.geo.stream(n,i($a)),Oa},n.centroid=function(n){return Ca=za=La=qa=Ta=Ra=Da=Pa=Ua=0,ao.geo.stream(n,i(Wa)),Ua?[Da/Ua,Pa/Ua]:Ra?[qa/Ra,Ta/Ra]:La?[Ca/La,za/La]:[NaN,NaN]},n.bounds=function(n){return Va=Xa=-(Ya=Za=1/0),ao.geo.stream(n,i(Ba)),[[Ya,Za],[Va,Xa]]},n.projection=function(n){return arguments.length?(i=(e=n)?n.stream||re(n):m,t()):e},n.context=function(n){return arguments.length?(u=null==(r=n)?new Wt:new te(n),"function"!=typeof a&&u.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(u.pointRadius(+t),+t),n):a},n.projection(ao.geo.albersUsa()).context(null)},ao.geo.transform=function(n){return{stream:function(t){var e=new ie(t);for(var r in n)e[r]=n[r];return e}}},ie.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},ao.geo.projection=oe,ao.geo.projectionMutator=ae,(ao.geo.equirectangular=function(){return oe(ce)}).raw=ce.invert=ce,ao.geo.rotation=function(n){function t(t){return t=n(t[0]*Yo,t[1]*Yo),t[0]*=Zo,t[1]*=Zo,t}return n=se(n[0]%360*Yo,n[1]*Yo,n.length>2?n[2]*Yo:0),t.invert=function(t){return t=n.invert(t[0]*Yo,t[1]*Yo),t[0]*=Zo,t[1]*=Zo,t},t},fe.invert=ce,ao.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=se(-n[0]*Yo,-n[1]*Yo,0).invert,i=[];return e(null,null,1,{point:function(n,e){i.push(n=t(n,e)),n[0]*=Zo,n[1]*=Zo}}),{type:"Polygon",coordinates:[i]}}var t,e,r=[0,0],i=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=ve((t=+r)*Yo,i*Yo),n):t},n.precision=function(r){return arguments.length?(e=ve(t*Yo,(i=+r)*Yo),n):i},n.angle(90)},ao.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Yo,i=n[1]*Yo,u=t[1]*Yo,o=Math.sin(r),a=Math.cos(r),l=Math.sin(i),c=Math.cos(i),f=Math.sin(u),s=Math.cos(u);return Math.atan2(Math.sqrt((e=s*o)*e+(e=c*f-l*s*a)*e),l*f+c*s*a)},ao.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return ao.range(Math.ceil(u/d)*d,i,d).map(h).concat(ao.range(Math.ceil(c/y)*y,l,y).map(p)).concat(ao.range(Math.ceil(r/g)*g,e,g).filter(function(n){return xo(n%d)>Uo}).map(f)).concat(ao.range(Math.ceil(a/v)*v,o,v).filter(function(n){return xo(n%y)>Uo}).map(s))}var e,r,i,u,o,a,l,c,f,s,h,p,g=10,v=g,d=90,y=360,m=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(u).concat(p(l).slice(1),h(i).reverse().slice(1),p(c).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(u=+t[0][0],i=+t[1][0],c=+t[0][1],l=+t[1][1],u>i&&(t=u,u=i,i=t),c>l&&(t=c,c=l,l=t),n.precision(m)):[[u,c],[i,l]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(m)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],y=+t[1],n):[d,y]},n.minorStep=function(t){return arguments.length?(g=+t[0],v=+t[1],n):[g,v]},n.precision=function(t){return arguments.length?(m=+t,f=ye(a,o,90),s=me(r,e,m),h=ye(c,l,90),p=me(u,i,m),n):m},n.majorExtent([[-180,-90+Uo],[180,90-Uo]]).minorExtent([[-180,-80-Uo],[180,80+Uo]])},ao.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||i.apply(this,arguments)]}}var t,e,r=Me,i=xe;return n.distance=function(){return ao.geo.distance(t||r.apply(this,arguments),e||i.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(i=t,e="function"==typeof t?null:t,n):i},n.precision=function(){return arguments.length?n:0},n},ao.geo.interpolate=function(n,t){return be(n[0]*Yo,n[1]*Yo,t[0]*Yo,t[1]*Yo)},ao.geo.length=function(n){return Ja=0,ao.geo.stream(n,Ga),Ja};var Ja,Ga={sphere:b,point:b,lineStart:_e,lineEnd:b,polygonStart:b,polygonEnd:b},Ka=we(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(ao.geo.azimuthalEqualArea=function(){return oe(Ka)}).raw=Ka;var Qa=we(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},m);(ao.geo.azimuthalEquidistant=function(){return oe(Qa)}).raw=Qa,(ao.geo.conicConformal=function(){return Vt(Se)}).raw=Se,(ao.geo.conicEquidistant=function(){return Vt(ke)}).raw=ke;var nl=we(function(n){return 1/n},Math.atan);(ao.geo.gnomonic=function(){return oe(nl)}).raw=nl,Ne.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Io]},(ao.geo.mercator=function(){return Ee(Ne)}).raw=Ne;var tl=we(function(){return 1},Math.asin);(ao.geo.orthographic=function(){return oe(tl)}).raw=tl;var el=we(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(ao.geo.stereographic=function(){return oe(el)}).raw=el,Ae.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Io]},(ao.geo.transverseMercator=function(){var n=Ee(Ae),t=n.center,e=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?e([n[0],n[1],n.length>2?n[2]+90:90]):(n=e(),[n[0],n[1],n[2]-90])},e([0,0,90])}).raw=Ae,ao.geom={},ao.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,i=En(e),u=En(r),o=n.length,a=[],l=[];for(t=0;o>t;t++)a.push([+i.call(this,n[t],t),+u.call(this,n[t],t),t]);for(a.sort(qe),t=0;o>t;t++)l.push([a[t][0],-a[t][1]]);var c=Le(a),f=Le(l),s=f[0]===c[0],h=f[f.length-1]===c[c.length-1],p=[];for(t=c.length-1;t>=0;--t)p.push(n[a[c[t]][2]]);for(t=+s;t<f.length-h;++t)p.push(n[a[f[t]][2]]);return p}var e=Ce,r=ze;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t)},ao.geom.polygon=function(n){return ko(n,rl),n};var rl=ao.geom.polygon.prototype=[];rl.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],i=0;++t<e;)n=r,r=this[t],i+=n[1]*r[0]-n[0]*r[1];return.5*i},rl.centroid=function(n){var t,e,r=-1,i=this.length,u=0,o=0,a=this[i-1];for(arguments.length||(n=-1/(6*this.area()));++r<i;)t=a,a=this[r],e=t[0]*a[1]-a[0]*t[1],u+=(t[0]+a[0])*e,o+=(t[1]+a[1])*e;return[u*n,o*n]},rl.clip=function(n){for(var t,e,r,i,u,o,a=De(n),l=-1,c=this.length-De(this),f=this[c-1];++l<c;){for(t=n.slice(),n.length=0,i=this[l],u=t[(r=t.length-a)-1],e=-1;++e<r;)o=t[e],Te(o,f,i)?(Te(u,f,i)||n.push(Re(u,o,f,i)),n.push(o)):Te(u,f,i)&&n.push(Re(u,o,f,i)),u=o;a&&n.push(n[0]),f=i}return n};var il,ul,ol,al,ll,cl=[],fl=[];Ye.prototype.prepare=function(){for(var n,t=this.edges,e=t.length;e--;)n=t[e].edge,n.b&&n.a||t.splice(e,1);return t.sort(Ve),t.length},tr.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},er.prototype={insert:function(n,t){var e,r,i;if(n){if(t.P=n,t.N=n.N,n.N&&(n.N.P=t),n.N=t,n.R){for(n=n.R;n.L;)n=n.L;n.L=t}else n.R=t;e=n}else this._?(n=or(this._),t.P=null,t.N=n,n.P=n.L=t,e=n):(t.P=t.N=null,this._=t,e=null);for(t.L=t.R=null,t.U=e,t.C=!0,n=t;e&&e.C;)r=e.U,e===r.L?(i=r.R,i&&i.C?(e.C=i.C=!1,r.C=!0,n=r):(n===e.R&&(ir(this,e),n=e,e=n.U),e.C=!1,r.C=!0,ur(this,r))):(i=r.L,i&&i.C?(e.C=i.C=!1,r.C=!0,n=r):(n===e.L&&(ur(this,e),n=e,e=n.U),e.C=!1,r.C=!0,ir(this,r))),e=n.U;this._.C=!1},remove:function(n){n.N&&(n.N.P=n.P),n.P&&(n.P.N=n.N),n.N=n.P=null;var t,e,r,i=n.U,u=n.L,o=n.R;if(e=u?o?or(o):u:o,i?i.L===n?i.L=e:i.R=e:this._=e,u&&o?(r=e.C,e.C=n.C,e.L=u,u.U=e,e!==o?(i=e.U,e.U=n.U,n=e.R,i.L=n,e.R=o,o.U=e):(e.U=i,i=e,n=e.R)):(r=n.C,n=e),n&&(n.U=i),!r){if(n&&n.C)return void(n.C=!1);do{if(n===this._)break;if(n===i.L){if(t=i.R,t.C&&(t.C=!1,i.C=!0,ir(this,i),t=i.R),t.L&&t.L.C||t.R&&t.R.C){t.R&&t.R.C||(t.L.C=!1,t.C=!0,ur(this,t),t=i.R),t.C=i.C,i.C=t.R.C=!1,ir(this,i),n=this._;break}}else if(t=i.L,t.C&&(t.C=!1,i.C=!0,ur(this,i),t=i.L),t.L&&t.L.C||t.R&&t.R.C){t.L&&t.L.C||(t.R.C=!1,t.C=!0,ir(this,t),t=i.L),t.C=i.C,i.C=t.L.C=!1,ur(this,i),n=this._;break}t.C=!0,n=i,i=i.U}while(!n.C);n&&(n.C=!1)}}},ao.geom.voronoi=function(n){function t(n){var t=new Array(n.length),r=a[0][0],i=a[0][1],u=a[1][0],o=a[1][1];return ar(e(n),a).cells.forEach(function(e,a){var l=e.edges,c=e.site,f=t[a]=l.length?l.map(function(n){var t=n.start();return[t.x,t.y]}):c.x>=r&&c.x<=u&&c.y>=i&&c.y<=o?[[r,o],[u,o],[u,i],[r,i]]:[];f.point=n[a]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(u(n,t)/Uo)*Uo,y:Math.round(o(n,t)/Uo)*Uo,i:t}})}var r=Ce,i=ze,u=r,o=i,a=sl;return n?t(n):(t.links=function(n){return ar(e(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return ar(e(n)).cells.forEach(function(e,r){for(var i,u,o=e.site,a=e.edges.sort(Ve),l=-1,c=a.length,f=a[c-1].edge,s=f.l===o?f.r:f.l;++l<c;)i=f,u=s,f=a[l].edge,s=f.l===o?f.r:f.l,r<u.i&&r<s.i&&cr(o,u,s)<0&&t.push([n[r],n[u.i],n[s.i]])}),t},t.x=function(n){return arguments.length?(u=En(r=n),t):r},t.y=function(n){return arguments.length?(o=En(i=n),t):i},t.clipExtent=function(n){return arguments.length?(a=null==n?sl:n,t):a===sl?null:a},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):a===sl?null:a&&a[1]},t)};var sl=[[-1e6,-1e6],[1e6,1e6]];ao.geom.delaunay=function(n){return ao.geom.voronoi().triangles(n)},ao.geom.quadtree=function(n,t,e,r,i){function u(n){function u(n,t,e,r,i,u,o,a){if(!isNaN(e)&&!isNaN(r))if(n.leaf){var l=n.x,f=n.y;if(null!=l)if(xo(l-e)+xo(f-r)<.01)c(n,t,e,r,i,u,o,a);else{var s=n.point;n.x=n.y=n.point=null,c(n,s,l,f,i,u,o,a),c(n,t,e,r,i,u,o,a)}else n.x=e,n.y=r,n.point=t}else c(n,t,e,r,i,u,o,a)}function c(n,t,e,r,i,o,a,l){var c=.5*(i+a),f=.5*(o+l),s=e>=c,h=r>=f,p=h<<1|s;n.leaf=!1,n=n.nodes[p]||(n.nodes[p]=hr()),s?i=c:a=c,h?o=f:l=f,u(n,t,e,r,i,o,a,l)}var f,s,h,p,g,v,d,y,m,M=En(a),x=En(l);if(null!=t)v=t,d=e,y=r,m=i;else if(y=m=-(v=d=1/0),s=[],h=[],g=n.length,o)for(p=0;g>p;++p)f=n[p],f.x<v&&(v=f.x),f.y<d&&(d=f.y),f.x>y&&(y=f.x),f.y>m&&(m=f.y),s.push(f.x),h.push(f.y);else for(p=0;g>p;++p){var b=+M(f=n[p],p),_=+x(f,p);v>b&&(v=b),d>_&&(d=_),b>y&&(y=b),_>m&&(m=_),s.push(b),h.push(_)}var w=y-v,S=m-d;w>S?m=d+w:y=v+S;var k=hr();if(k.add=function(n){u(k,n,+M(n,++p),+x(n,p),v,d,y,m)},k.visit=function(n){pr(n,k,v,d,y,m)},k.find=function(n){return gr(k,n[0],n[1],v,d,y,m)},p=-1,null==t){for(;++p<g;)u(k,n[p],s[p],h[p],v,d,y,m);--p}else n.forEach(k.add);return s=h=n=f=null,k}var o,a=Ce,l=ze;return(o=arguments.length)?(a=fr,l=sr,3===o&&(i=e,r=t,e=t=0),u(n)):(u.x=function(n){return arguments.length?(a=n,u):a},u.y=function(n){return arguments.length?(l=n,u):l},u.extent=function(n){return arguments.length?(null==n?t=e=r=i=null:(t=+n[0][0],e=+n[0][1],r=+n[1][0],i=+n[1][1]),u):null==t?null:[[t,e],[r,i]]},u.size=function(n){return arguments.length?(null==n?t=e=r=i=null:(t=e=0,r=+n[0],i=+n[1]),u):null==t?null:[r-t,i-e]},u)},ao.interpolateRgb=vr,ao.interpolateObject=dr,ao.interpolateNumber=yr,ao.interpolateString=mr;var hl=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,pl=new RegExp(hl.source,"g");ao.interpolate=Mr,ao.interpolators=[function(n,t){var e=typeof t;return("string"===e?ua.has(t.toLowerCase())||/^(#|rgb\(|hsl\()/i.test(t)?vr:mr:t instanceof an?vr:Array.isArray(t)?xr:"object"===e&&isNaN(t)?dr:yr)(n,t)}],ao.interpolateArray=xr;var gl=function(){return m},vl=ao.map({linear:gl,poly:Er,quad:function(){return Sr},cubic:function(){return kr},sin:function(){return Ar},exp:function(){return Cr},circle:function(){return zr},elastic:Lr,back:qr,bounce:function(){return Tr}}),dl=ao.map({"in":m,out:_r,"in-out":wr,"out-in":function(n){return wr(_r(n))}});ao.ease=function(n){var t=n.indexOf("-"),e=t>=0?n.slice(0,t):n,r=t>=0?n.slice(t+1):"in";return e=vl.get(e)||gl,r=dl.get(r)||m,br(r(e.apply(null,lo.call(arguments,1))))},ao.interpolateHcl=Rr,ao.interpolateHsl=Dr,ao.interpolateLab=Pr,ao.interpolateRound=Ur,ao.transform=function(n){var t=fo.createElementNS(ao.ns.prefix.svg,"g");return(ao.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new jr(e?e.matrix:yl)})(n)},jr.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var yl={a:1,b:0,c:0,d:1,e:0,f:0};ao.interpolateTransform=$r,ao.layout={},ao.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(Jr(n[e]));return t}},ao.layout.chord=function(){function n(){var n,c,s,h,p,g={},v=[],d=ao.range(u),y=[];for(e=[],r=[],n=0,h=-1;++h<u;){for(c=0,p=-1;++p<u;)c+=i[h][p];v.push(c),y.push(ao.range(u)),n+=c}for(o&&d.sort(function(n,t){return o(v[n],v[t])}),a&&y.forEach(function(n,t){n.sort(function(n,e){return a(i[t][n],i[t][e])})}),n=(Ho-f*u)/n,c=0,h=-1;++h<u;){for(s=c,p=-1;++p<u;){var m=d[h],M=y[m][p],x=i[m][M],b=c,_=c+=x*n;g[m+"-"+M]={index:m,subindex:M,startAngle:b,endAngle:_,value:x}}r[m]={index:m,startAngle:s,endAngle:c,value:v[m]},c+=f}for(h=-1;++h<u;)for(p=h-1;++p<u;){var w=g[h+"-"+p],S=g[p+"-"+h];(w.value||S.value)&&e.push(w.value<S.value?{source:S,target:w}:{source:w,target:S})}l&&t()}function t(){e.sort(function(n,t){return l((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var e,r,i,u,o,a,l,c={},f=0;return c.matrix=function(n){return arguments.length?(u=(i=n)&&i.length,e=r=null,c):i},c.padding=function(n){return arguments.length?(f=n,e=r=null,c):f},c.sortGroups=function(n){return arguments.length?(o=n,e=r=null,c):o},c.sortSubgroups=function(n){return arguments.length?(a=n,e=null,c):a},c.sortChords=function(n){return arguments.length?(l=n,e&&t(),c):l},c.chords=function(){return e||n(),e},c.groups=function(){return r||n(),r},c},ao.layout.force=function(){function n(n){return function(t,e,r,i){if(t.point!==n){var u=t.cx-n.x,o=t.cy-n.y,a=i-e,l=u*u+o*o;if(l>a*a/y){if(v>l){var c=t.charge/l;n.px-=u*c,n.py-=o*c}return!0}if(t.point&&l&&v>l){var c=t.pointCharge/l;n.px-=u*c,n.py-=o*c}}return!t.charge}}function t(n){n.px=ao.event.x,n.py=ao.event.y,l.resume()}var e,r,i,u,o,a,l={},c=ao.dispatch("start","tick","end"),f=[1,1],s=.9,h=ml,p=Ml,g=-30,v=xl,d=.1,y=.64,M=[],x=[];return l.tick=function(){if((i*=.99)<.005)return e=null,c.end({type:"end",alpha:i=0}),!0;var t,r,l,h,p,v,y,m,b,_=M.length,w=x.length;for(r=0;w>r;++r)l=x[r],h=l.source,p=l.target,m=p.x-h.x,b=p.y-h.y,(v=m*m+b*b)&&(v=i*o[r]*((v=Math.sqrt(v))-u[r])/v,m*=v,b*=v,p.x-=m*(y=h.weight+p.weight?h.weight/(h.weight+p.weight):.5),p.y-=b*y,h.x+=m*(y=1-y),h.y+=b*y);if((y=i*d)&&(m=f[0]/2,b=f[1]/2,r=-1,y))for(;++r<_;)l=M[r],l.x+=(m-l.x)*y,l.y+=(b-l.y)*y;if(g)for(ri(t=ao.geom.quadtree(M),i,a),r=-1;++r<_;)(l=M[r]).fixed||t.visit(n(l));for(r=-1;++r<_;)l=M[r],l.fixed?(l.x=l.px,l.y=l.py):(l.x-=(l.px-(l.px=l.x))*s,l.y-=(l.py-(l.py=l.y))*s);c.tick({type:"tick",alpha:i})},l.nodes=function(n){return arguments.length?(M=n,l):M},l.links=function(n){return arguments.length?(x=n,l):x},l.size=function(n){return arguments.length?(f=n,l):f},l.linkDistance=function(n){return arguments.length?(h="function"==typeof n?n:+n,l):h},l.distance=l.linkDistance,l.linkStrength=function(n){return arguments.length?(p="function"==typeof n?n:+n,l):p},l.friction=function(n){return arguments.length?(s=+n,l):s},l.charge=function(n){return arguments.length?(g="function"==typeof n?n:+n,l):g},l.chargeDistance=function(n){return arguments.length?(v=n*n,l):Math.sqrt(v)},l.gravity=function(n){return arguments.length?(d=+n,l):d},l.theta=function(n){return arguments.length?(y=n*n,l):Math.sqrt(y)},l.alpha=function(n){return arguments.length?(n=+n,i?n>0?i=n:(e.c=null,e.t=NaN,e=null,c.end({type:"end",alpha:i=0})):n>0&&(c.start({type:"start",alpha:i=n}),e=qn(l.tick)),l):i},l.start=function(){function n(n,r){if(!e){for(e=new Array(i),l=0;i>l;++l)e[l]=[];for(l=0;c>l;++l){var u=x[l];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var o,a=e[t],l=-1,f=a.length;++l<f;)if(!isNaN(o=a[l][n]))return o;return Math.random()*r}var t,e,r,i=M.length,c=x.length,s=f[0],v=f[1];for(t=0;i>t;++t)(r=M[t]).index=t,r.weight=0;for(t=0;c>t;++t)r=x[t],"number"==typeof r.source&&(r.source=M[r.source]),"number"==typeof r.target&&(r.target=M[r.target]),++r.source.weight,++r.target.weight;for(t=0;i>t;++t)r=M[t],isNaN(r.x)&&(r.x=n("x",s)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof h)for(t=0;c>t;++t)u[t]=+h.call(this,x[t],t);else for(t=0;c>t;++t)u[t]=h;if(o=[],"function"==typeof p)for(t=0;c>t;++t)o[t]=+p.call(this,x[t],t);else for(t=0;c>t;++t)o[t]=p;if(a=[],"function"==typeof g)for(t=0;i>t;++t)a[t]=+g.call(this,M[t],t);else for(t=0;i>t;++t)a[t]=g;return l.resume()},l.resume=function(){return l.alpha(.1)},l.stop=function(){return l.alpha(0)},l.drag=function(){return r||(r=ao.behavior.drag().origin(m).on("dragstart.force",Qr).on("drag.force",t).on("dragend.force",ni)),arguments.length?void this.on("mouseover.force",ti).on("mouseout.force",ei).call(r):r},ao.rebind(l,c,"on")};var ml=20,Ml=1,xl=1/0;ao.layout.hierarchy=function(){function n(i){var u,o=[i],a=[];for(i.depth=0;null!=(u=o.pop());)if(a.push(u),(c=e.call(n,u,u.depth))&&(l=c.length)){for(var l,c,f;--l>=0;)o.push(f=c[l]),f.parent=u,f.depth=u.depth+1;r&&(u.value=0),u.children=c}else r&&(u.value=+r.call(n,u,u.depth)||0),delete u.children;return oi(i,function(n){var e,i;t&&(e=n.children)&&e.sort(t),r&&(i=n.parent)&&(i.value+=n.value)}),a}var t=ci,e=ai,r=li;return n.sort=function(e){return arguments.length?(t=e,n):t},n.children=function(t){return arguments.length?(e=t,n):e},n.value=function(t){return arguments.length?(r=t,n):r},n.revalue=function(t){return r&&(ui(t,function(n){n.children&&(n.value=0)}),oi(t,function(t){var e;t.children||(t.value=+r.call(n,t,t.depth)||0),(e=t.parent)&&(e.value+=t.value)})),t},n},ao.layout.partition=function(){function n(t,e,r,i){var u=t.children;if(t.x=e,t.y=t.depth*i,t.dx=r,t.dy=i,u&&(o=u.length)){var o,a,l,c=-1;for(r=t.value?r/t.value:0;++c<o;)n(a=u[c],e,l=a.value*r,i),e+=l}}function t(n){var e=n.children,r=0;if(e&&(i=e.length))for(var i,u=-1;++u<i;)r=Math.max(r,t(e[u]));return 1+r}function e(e,u){var o=r.call(this,e,u);return n(o[0],0,i[0],i[1]/t(o[0])),o}var r=ao.layout.hierarchy(),i=[1,1];return e.size=function(n){return arguments.length?(i=n,e):i},ii(e,r)},ao.layout.pie=function(){function n(o){var a,l=o.length,c=o.map(function(e,r){return+t.call(n,e,r)}),f=+("function"==typeof r?r.apply(this,arguments):r),s=("function"==typeof i?i.apply(this,arguments):i)-f,h=Math.min(Math.abs(s)/l,+("function"==typeof u?u.apply(this,arguments):u)),p=h*(0>s?-1:1),g=ao.sum(c),v=g?(s-l*p)/g:0,d=ao.range(l),y=[];return null!=e&&d.sort(e===bl?function(n,t){return c[t]-c[n]}:function(n,t){return e(o[n],o[t])}),d.forEach(function(n){y[n]={data:o[n],value:a=c[n],startAngle:f,endAngle:f+=a*v+p,padAngle:h}}),y}var t=Number,e=bl,r=0,i=Ho,u=0;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(i=t,n):i},n.padAngle=function(t){return arguments.length?(u=t,n):u},n};var bl={};ao.layout.stack=function(){function n(a,l){if(!(h=a.length))return a;var c=a.map(function(e,r){return t.call(n,e,r)}),f=c.map(function(t){return t.map(function(t,e){return[u.call(n,t,e),o.call(n,t,e)]})}),s=e.call(n,f,l);c=ao.permute(c,s),f=ao.permute(f,s);var h,p,g,v,d=r.call(n,f,l),y=c[0].length;for(g=0;y>g;++g)for(i.call(n,c[0][g],v=d[g],f[0][g][1]),p=1;h>p;++p)i.call(n,c[p][g],v+=f[p-1][g][1],f[p][g][1]);return a}var t=m,e=gi,r=vi,i=pi,u=si,o=hi;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:_l.get(t)||gi,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:wl.get(t)||vi,n):r},n.x=function(t){return arguments.length?(u=t,n):u},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(i=t,n):i},n};var _l=ao.map({"inside-out":function(n){var t,e,r=n.length,i=n.map(di),u=n.map(yi),o=ao.range(r).sort(function(n,t){return i[n]-i[t]}),a=0,l=0,c=[],f=[];for(t=0;r>t;++t)e=o[t],l>a?(a+=u[e],c.push(e)):(l+=u[e],f.push(e));return f.reverse().concat(c)},reverse:function(n){return ao.range(n.length).reverse()},"default":gi}),wl=ao.map({silhouette:function(n){var t,e,r,i=n.length,u=n[0].length,o=[],a=0,l=[];for(e=0;u>e;++e){for(t=0,r=0;i>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;u>e;++e)l[e]=(a-o[e])/2;return l},wiggle:function(n){var t,e,r,i,u,o,a,l,c,f=n.length,s=n[0],h=s.length,p=[];for(p[0]=l=c=0,e=1;h>e;++e){for(t=0,i=0;f>t;++t)i+=n[t][e][1];for(t=0,u=0,a=s[e][0]-s[e-1][0];f>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;u+=o*n[t][e][1]}p[e]=l-=i?u/i*a:0,c>l&&(c=l)}for(e=0;h>e;++e)p[e]-=c;return p},expand:function(n){var t,e,r,i=n.length,u=n[0].length,o=1/i,a=[];for(e=0;u>e;++e){for(t=0,r=0;i>t;t++)r+=n[t][e][1];if(r)for(t=0;i>t;t++)n[t][e][1]/=r;else for(t=0;i>t;t++)n[t][e][1]=o}for(e=0;u>e;++e)a[e]=0;return a},zero:vi});ao.layout.histogram=function(){function n(n,u){for(var o,a,l=[],c=n.map(e,this),f=r.call(this,c,u),s=i.call(this,f,c,u),u=-1,h=c.length,p=s.length-1,g=t?1:1/h;++u<p;)o=l[u]=[],o.dx=s[u+1]-(o.x=s[u]),o.y=0;if(p>0)for(u=-1;++u<h;)a=c[u],a>=f[0]&&a<=f[1]&&(o=l[ao.bisect(s,a,1,p)-1],o.y+=g,o.push(n[u]));return l}var t=!0,e=Number,r=bi,i=Mi;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=En(t),n):r},n.bins=function(t){return arguments.length?(i="number"==typeof t?function(n){return xi(n,t)}:En(t),n):i},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},ao.layout.pack=function(){function n(n,u){var o=e.call(this,n,u),a=o[0],l=i[0],c=i[1],f=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,oi(a,function(n){n.r=+f(n.value)}),oi(a,Ni),r){var s=r*(t?1:Math.max(2*a.r/l,2*a.r/c))/2;oi(a,function(n){n.r+=s}),oi(a,Ni),oi(a,function(n){n.r-=s})}return Ci(a,l/2,c/2,t?1:1/Math.max(2*a.r/l,2*a.r/c)),o}var t,e=ao.layout.hierarchy().sort(_i),r=0,i=[1,1];return n.size=function(t){return arguments.length?(i=t,n):i},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},ii(n,e)},ao.layout.tree=function(){function n(n,i){var f=o.call(this,n,i),s=f[0],h=t(s);if(oi(h,e),h.parent.m=-h.z,ui(h,r),c)ui(s,u);else{var p=s,g=s,v=s;ui(s,function(n){n.x<p.x&&(p=n),n.x>g.x&&(g=n),n.depth>v.depth&&(v=n)});var d=a(p,g)/2-p.x,y=l[0]/(g.x+a(g,p)/2+d),m=l[1]/(v.depth||1);ui(s,function(n){n.x=(n.x+d)*y,n.y=n.depth*m})}return f}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var i,u=t.children,o=0,a=u.length;a>o;++o)r.push((u[o]=i={_:u[o],parent:t,children:(i=u[o].children)&&i.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=i);return e.children[0]}function e(n){var t=n.children,e=n.parent.children,r=n.i?e[n.i-1]:null;if(t.length){Di(n);var u=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+a(n._,r._),n.m=n.z-u):n.z=u}else r&&(n.z=r.z+a(n._,r._));n.parent.A=i(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function i(n,t,e){if(t){for(var r,i=n,u=n,o=t,l=i.parent.children[0],c=i.m,f=u.m,s=o.m,h=l.m;o=Ti(o),i=qi(i),o&&i;)l=qi(l),u=Ti(u),u.a=n,r=o.z+s-i.z-c+a(o._,i._),r>0&&(Ri(Pi(o,n,e),n,r),c+=r,f+=r),s+=o.m,c+=i.m,h+=l.m,f+=u.m;o&&!Ti(u)&&(u.t=o,u.m+=s-f),i&&!qi(l)&&(l.t=i,l.m+=c-h,e=n)}return e}function u(n){n.x*=l[0],n.y=n.depth*l[1]}var o=ao.layout.hierarchy().sort(null).value(null),a=Li,l=[1,1],c=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(c=null==(l=t)?u:null,n):c?null:l},n.nodeSize=function(t){return arguments.length?(c=null==(l=t)?null:u,n):c?l:null},ii(n,o)},ao.layout.cluster=function(){function n(n,u){var o,a=t.call(this,n,u),l=a[0],c=0;oi(l,function(n){var t=n.children;t&&t.length?(n.x=ji(t),n.y=Ui(t)):(n.x=o?c+=e(n,o):0,n.y=0,o=n)});var f=Fi(l),s=Hi(l),h=f.x-e(f,s)/2,p=s.x+e(s,f)/2;return oi(l,i?function(n){n.x=(n.x-l.x)*r[0],n.y=(l.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(p-h)*r[0],n.y=(1-(l.y?n.y/l.y:1))*r[1]}),a}var t=ao.layout.hierarchy().sort(null).value(null),e=Li,r=[1,1],i=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(i=null==(r=t),n):i?null:r},n.nodeSize=function(t){return arguments.length?(i=null!=(r=t),n):i?r:null},ii(n,t)},ao.layout.treemap=function(){function n(n,t){for(var e,r,i=-1,u=n.length;++i<u;)r=(e=n[i]).value*(0>t?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var u=e.children;if(u&&u.length){var o,a,l,c=s(e),f=[],h=u.slice(),g=1/0,v="slice"===p?c.dx:"dice"===p?c.dy:"slice-dice"===p?1&e.depth?c.dy:c.dx:Math.min(c.dx,c.dy);for(n(h,c.dx*c.dy/e.value),f.area=0;(l=h.length)>0;)f.push(o=h[l-1]),f.area+=o.area,"squarify"!==p||(a=r(f,v))<=g?(h.pop(),g=a):(f.area-=f.pop().area,i(f,v,c,!1),v=Math.min(c.dx,c.dy),f.length=f.area=0,g=1/0);f.length&&(i(f,v,c,!0),f.length=f.area=0),u.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var u,o=s(t),a=r.slice(),l=[];for(n(a,o.dx*o.dy/t.value),l.area=0;u=a.pop();)l.push(u),l.area+=u.area,null!=u.z&&(i(l,u.z?o.dx:o.dy,o,!a.length),l.length=l.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,i=0,u=1/0,o=-1,a=n.length;++o<a;)(e=n[o].area)&&(u>e&&(u=e),e>i&&(i=e));return r*=r,t*=t,r?Math.max(t*i*g/r,r/(t*u*g)):1/0}function i(n,t,e,r){var i,u=-1,o=n.length,a=e.x,c=e.y,f=t?l(n.area/t):0;
if(t==e.dx){for((r||f>e.dy)&&(f=e.dy);++u<o;)i=n[u],i.x=a,i.y=c,i.dy=f,a+=i.dx=Math.min(e.x+e.dx-a,f?l(i.area/f):0);i.z=!0,i.dx+=e.x+e.dx-a,e.y+=f,e.dy-=f}else{for((r||f>e.dx)&&(f=e.dx);++u<o;)i=n[u],i.x=a,i.y=c,i.dx=f,c+=i.dy=Math.min(e.y+e.dy-c,f?l(i.area/f):0);i.z=!1,i.dy+=e.y+e.dy-c,e.x+=f,e.dx-=f}}function u(r){var i=o||a(r),u=i[0];return u.x=u.y=0,u.value?(u.dx=c[0],u.dy=c[1]):u.dx=u.dy=0,o&&a.revalue(u),n([u],u.dx*u.dy/u.value),(o?e:t)(u),h&&(o=i),i}var o,a=ao.layout.hierarchy(),l=Math.round,c=[1,1],f=null,s=Oi,h=!1,p="squarify",g=.5*(1+Math.sqrt(5));return u.size=function(n){return arguments.length?(c=n,u):c},u.padding=function(n){function t(t){var e=n.call(u,t,t.depth);return null==e?Oi(t):Ii(t,"number"==typeof e?[e,e,e,e]:e)}function e(t){return Ii(t,n)}if(!arguments.length)return f;var r;return s=null==(f=n)?Oi:"function"==(r=typeof n)?t:"number"===r?(n=[n,n,n,n],e):e,u},u.round=function(n){return arguments.length?(l=n?Math.round:Number,u):l!=Number},u.sticky=function(n){return arguments.length?(h=n,o=null,u):h},u.ratio=function(n){return arguments.length?(g=n,u):g},u.mode=function(n){return arguments.length?(p=n+"",u):p},ii(u,a)},ao.random={normal:function(n,t){var e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var e,r,i;do e=2*Math.random()-1,r=2*Math.random()-1,i=e*e+r*r;while(!i||i>1);return n+t*e*Math.sqrt(-2*Math.log(i)/i)}},logNormal:function(){var n=ao.random.normal.apply(ao,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=ao.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},ao.scale={};var Sl={floor:m,ceil:m};ao.scale.linear=function(){return Wi([0,1],[0,1],Mr,!1)};var kl={s:1,g:1,p:1,r:1,e:1};ao.scale.log=function(){return ru(ao.scale.linear().domain([0,1]),10,!0,[1,10])};var Nl=ao.format(".0e"),El={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};ao.scale.pow=function(){return iu(ao.scale.linear(),1,[0,1])},ao.scale.sqrt=function(){return ao.scale.pow().exponent(.5)},ao.scale.ordinal=function(){return ou([],{t:"range",a:[[]]})},ao.scale.category10=function(){return ao.scale.ordinal().range(Al)},ao.scale.category20=function(){return ao.scale.ordinal().range(Cl)},ao.scale.category20b=function(){return ao.scale.ordinal().range(zl)},ao.scale.category20c=function(){return ao.scale.ordinal().range(Ll)};var Al=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(xn),Cl=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(xn),zl=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(xn),Ll=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(xn);ao.scale.quantile=function(){return au([],[])},ao.scale.quantize=function(){return lu(0,1,[0,1])},ao.scale.threshold=function(){return cu([.5],[0,1])},ao.scale.identity=function(){return fu([0,1])},ao.svg={},ao.svg.arc=function(){function n(){var n=Math.max(0,+e.apply(this,arguments)),c=Math.max(0,+r.apply(this,arguments)),f=o.apply(this,arguments)-Io,s=a.apply(this,arguments)-Io,h=Math.abs(s-f),p=f>s?0:1;if(n>c&&(g=c,c=n,n=g),h>=Oo)return t(c,p)+(n?t(n,1-p):"")+"Z";var g,v,d,y,m,M,x,b,_,w,S,k,N=0,E=0,A=[];if((y=(+l.apply(this,arguments)||0)/2)&&(d=u===ql?Math.sqrt(n*n+c*c):+u.apply(this,arguments),p||(E*=-1),c&&(E=tn(d/c*Math.sin(y))),n&&(N=tn(d/n*Math.sin(y)))),c){m=c*Math.cos(f+E),M=c*Math.sin(f+E),x=c*Math.cos(s-E),b=c*Math.sin(s-E);var C=Math.abs(s-f-2*E)<=Fo?0:1;if(E&&yu(m,M,x,b)===p^C){var z=(f+s)/2;m=c*Math.cos(z),M=c*Math.sin(z),x=b=null}}else m=M=0;if(n){_=n*Math.cos(s-N),w=n*Math.sin(s-N),S=n*Math.cos(f+N),k=n*Math.sin(f+N);var L=Math.abs(f-s+2*N)<=Fo?0:1;if(N&&yu(_,w,S,k)===1-p^L){var q=(f+s)/2;_=n*Math.cos(q),w=n*Math.sin(q),S=k=null}}else _=w=0;if(h>Uo&&(g=Math.min(Math.abs(c-n)/2,+i.apply(this,arguments)))>.001){v=c>n^p?0:1;var T=g,R=g;if(Fo>h){var D=null==S?[_,w]:null==x?[m,M]:Re([m,M],[S,k],[x,b],[_,w]),P=m-D[0],U=M-D[1],j=x-D[0],F=b-D[1],H=1/Math.sin(Math.acos((P*j+U*F)/(Math.sqrt(P*P+U*U)*Math.sqrt(j*j+F*F)))/2),O=Math.sqrt(D[0]*D[0]+D[1]*D[1]);R=Math.min(g,(n-O)/(H-1)),T=Math.min(g,(c-O)/(H+1))}if(null!=x){var I=mu(null==S?[_,w]:[S,k],[m,M],c,T,p),Y=mu([x,b],[_,w],c,T,p);g===T?A.push("M",I[0],"A",T,",",T," 0 0,",v," ",I[1],"A",c,",",c," 0 ",1-p^yu(I[1][0],I[1][1],Y[1][0],Y[1][1]),",",p," ",Y[1],"A",T,",",T," 0 0,",v," ",Y[0]):A.push("M",I[0],"A",T,",",T," 0 1,",v," ",Y[0])}else A.push("M",m,",",M);if(null!=S){var Z=mu([m,M],[S,k],n,-R,p),V=mu([_,w],null==x?[m,M]:[x,b],n,-R,p);g===R?A.push("L",V[0],"A",R,",",R," 0 0,",v," ",V[1],"A",n,",",n," 0 ",p^yu(V[1][0],V[1][1],Z[1][0],Z[1][1]),",",1-p," ",Z[1],"A",R,",",R," 0 0,",v," ",Z[0]):A.push("L",V[0],"A",R,",",R," 0 0,",v," ",Z[0])}else A.push("L",_,",",w)}else A.push("M",m,",",M),null!=x&&A.push("A",c,",",c," 0 ",C,",",p," ",x,",",b),A.push("L",_,",",w),null!=S&&A.push("A",n,",",n," 0 ",L,",",1-p," ",S,",",k);return A.push("Z"),A.join("")}function t(n,t){return"M0,"+n+"A"+n+","+n+" 0 1,"+t+" 0,"+-n+"A"+n+","+n+" 0 1,"+t+" 0,"+n}var e=hu,r=pu,i=su,u=ql,o=gu,a=vu,l=du;return n.innerRadius=function(t){return arguments.length?(e=En(t),n):e},n.outerRadius=function(t){return arguments.length?(r=En(t),n):r},n.cornerRadius=function(t){return arguments.length?(i=En(t),n):i},n.padRadius=function(t){return arguments.length?(u=t==ql?ql:En(t),n):u},n.startAngle=function(t){return arguments.length?(o=En(t),n):o},n.endAngle=function(t){return arguments.length?(a=En(t),n):a},n.padAngle=function(t){return arguments.length?(l=En(t),n):l},n.centroid=function(){var n=(+e.apply(this,arguments)+ +r.apply(this,arguments))/2,t=(+o.apply(this,arguments)+ +a.apply(this,arguments))/2-Io;return[Math.cos(t)*n,Math.sin(t)*n]},n};var ql="auto";ao.svg.line=function(){return Mu(m)};var Tl=ao.map({linear:xu,"linear-closed":bu,step:_u,"step-before":wu,"step-after":Su,basis:zu,"basis-open":Lu,"basis-closed":qu,bundle:Tu,cardinal:Eu,"cardinal-open":ku,"cardinal-closed":Nu,monotone:Fu});Tl.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Rl=[0,2/3,1/3,0],Dl=[0,1/3,2/3,0],Pl=[0,1/6,2/3,1/6];ao.svg.line.radial=function(){var n=Mu(Hu);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},wu.reverse=Su,Su.reverse=wu,ao.svg.area=function(){return Ou(m)},ao.svg.area.radial=function(){var n=Ou(Hu);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},ao.svg.chord=function(){function n(n,a){var l=t(this,u,n,a),c=t(this,o,n,a);return"M"+l.p0+r(l.r,l.p1,l.a1-l.a0)+(e(l,c)?i(l.r,l.p1,l.r,l.p0):i(l.r,l.p1,c.r,c.p0)+r(c.r,c.p1,c.a1-c.a0)+i(c.r,c.p1,l.r,l.p0))+"Z"}function t(n,t,e,r){var i=t.call(n,e,r),u=a.call(n,i,r),o=l.call(n,i,r)-Io,f=c.call(n,i,r)-Io;return{r:u,a0:o,a1:f,p0:[u*Math.cos(o),u*Math.sin(o)],p1:[u*Math.cos(f),u*Math.sin(f)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>Fo)+",1 "+t}function i(n,t,e,r){return"Q 0,0 "+r}var u=Me,o=xe,a=Iu,l=gu,c=vu;return n.radius=function(t){return arguments.length?(a=En(t),n):a},n.source=function(t){return arguments.length?(u=En(t),n):u},n.target=function(t){return arguments.length?(o=En(t),n):o},n.startAngle=function(t){return arguments.length?(l=En(t),n):l},n.endAngle=function(t){return arguments.length?(c=En(t),n):c},n},ao.svg.diagonal=function(){function n(n,i){var u=t.call(this,n,i),o=e.call(this,n,i),a=(u.y+o.y)/2,l=[u,{x:u.x,y:a},{x:o.x,y:a},o];return l=l.map(r),"M"+l[0]+"C"+l[1]+" "+l[2]+" "+l[3]}var t=Me,e=xe,r=Yu;return n.source=function(e){return arguments.length?(t=En(e),n):t},n.target=function(t){return arguments.length?(e=En(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},ao.svg.diagonal.radial=function(){var n=ao.svg.diagonal(),t=Yu,e=n.projection;return n.projection=function(n){return arguments.length?e(Zu(t=n)):t},n},ao.svg.symbol=function(){function n(n,r){return(Ul.get(t.call(this,n,r))||$u)(e.call(this,n,r))}var t=Xu,e=Vu;return n.type=function(e){return arguments.length?(t=En(e),n):t},n.size=function(t){return arguments.length?(e=En(t),n):e},n};var Ul=ao.map({circle:$u,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*Fl)),e=t*Fl;return"M0,"+-t+"L"+e+",0 0,"+t+" "+-e+",0Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/jl),e=t*jl/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/jl),e=t*jl/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});ao.svg.symbolTypes=Ul.keys();var jl=Math.sqrt(3),Fl=Math.tan(30*Yo);Co.transition=function(n){for(var t,e,r=Hl||++Zl,i=Ku(n),u=[],o=Ol||{time:Date.now(),ease:Nr,delay:0,duration:250},a=-1,l=this.length;++a<l;){u.push(t=[]);for(var c=this[a],f=-1,s=c.length;++f<s;)(e=c[f])&&Qu(e,f,i,r,o),t.push(e)}return Wu(u,i,r)},Co.interrupt=function(n){return this.each(null==n?Il:Bu(Ku(n)))};var Hl,Ol,Il=Bu(Ku()),Yl=[],Zl=0;Yl.call=Co.call,Yl.empty=Co.empty,Yl.node=Co.node,Yl.size=Co.size,ao.transition=function(n,t){return n&&n.transition?Hl?n.transition(t):n:ao.selection().transition(n)},ao.transition.prototype=Yl,Yl.select=function(n){var t,e,r,i=this.id,u=this.namespace,o=[];n=A(n);for(var a=-1,l=this.length;++a<l;){o.push(t=[]);for(var c=this[a],f=-1,s=c.length;++f<s;)(r=c[f])&&(e=n.call(r,r.__data__,f,a))?("__data__"in r&&(e.__data__=r.__data__),Qu(e,f,u,i,r[u][i]),t.push(e)):t.push(null)}return Wu(o,u,i)},Yl.selectAll=function(n){var t,e,r,i,u,o=this.id,a=this.namespace,l=[];n=C(n);for(var c=-1,f=this.length;++c<f;)for(var s=this[c],h=-1,p=s.length;++h<p;)if(r=s[h]){u=r[a][o],e=n.call(r,r.__data__,h,c),l.push(t=[]);for(var g=-1,v=e.length;++g<v;)(i=e[g])&&Qu(i,g,a,o,u),t.push(i)}return Wu(l,a,o)},Yl.filter=function(n){var t,e,r,i=[];"function"!=typeof n&&(n=O(n));for(var u=0,o=this.length;o>u;u++){i.push(t=[]);for(var e=this[u],a=0,l=e.length;l>a;a++)(r=e[a])&&n.call(r,r.__data__,a,u)&&t.push(r)}return Wu(i,this.namespace,this.id)},Yl.tween=function(n,t){var e=this.id,r=this.namespace;return arguments.length<2?this.node()[r][e].tween.get(n):Y(this,null==t?function(t){t[r][e].tween.remove(n)}:function(i){i[r][e].tween.set(n,t)})},Yl.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function i(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function u(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?$r:Mr,a=ao.ns.qualify(n);return Ju(this,"attr."+n,t,a.local?u:i)},Yl.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(i));return r&&function(n){this.setAttribute(i,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(i.space,i.local));return r&&function(n){this.setAttributeNS(i.space,i.local,r(n))}}var i=ao.ns.qualify(n);return this.tween("attr."+n,i.local?r:e)},Yl.style=function(n,e,r){function i(){this.style.removeProperty(n)}function u(e){return null==e?i:(e+="",function(){var i,u=t(this).getComputedStyle(this,null).getPropertyValue(n);return u!==e&&(i=Mr(u,e),function(t){this.style.setProperty(n,i(t),r)})})}var o=arguments.length;if(3>o){if("string"!=typeof n){2>o&&(e="");for(r in n)this.style(r,n[r],e);return this}r=""}return Ju(this,"style."+n,e,u)},Yl.styleTween=function(n,e,r){function i(i,u){var o=e.call(this,i,u,t(this).getComputedStyle(this,null).getPropertyValue(n));return o&&function(t){this.style.setProperty(n,o(t),r)}}return arguments.length<3&&(r=""),this.tween("style."+n,i)},Yl.text=function(n){return Ju(this,"text",n,Gu)},Yl.remove=function(){var n=this.namespace;return this.each("end.transition",function(){var t;this[n].count<2&&(t=this.parentNode)&&t.removeChild(this)})},Yl.ease=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].ease:("function"!=typeof n&&(n=ao.ease.apply(ao,arguments)),Y(this,function(r){r[e][t].ease=n}))},Yl.delay=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].delay:Y(this,"function"==typeof n?function(r,i,u){r[e][t].delay=+n.call(r,r.__data__,i,u)}:(n=+n,function(r){r[e][t].delay=n}))},Yl.duration=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].duration:Y(this,"function"==typeof n?function(r,i,u){r[e][t].duration=Math.max(1,n.call(r,r.__data__,i,u))}:(n=Math.max(1,n),function(r){r[e][t].duration=n}))},Yl.each=function(n,t){var e=this.id,r=this.namespace;if(arguments.length<2){var i=Ol,u=Hl;try{Hl=e,Y(this,function(t,i,u){Ol=t[r][e],n.call(t,t.__data__,i,u)})}finally{Ol=i,Hl=u}}else Y(this,function(i){var u=i[r][e];(u.event||(u.event=ao.dispatch("start","end","interrupt"))).on(n,t)});return this},Yl.transition=function(){for(var n,t,e,r,i=this.id,u=++Zl,o=this.namespace,a=[],l=0,c=this.length;c>l;l++){a.push(n=[]);for(var t=this[l],f=0,s=t.length;s>f;f++)(e=t[f])&&(r=e[o][i],Qu(e,f,o,u,{time:r.time,ease:r.ease,delay:r.delay+r.duration,duration:r.duration})),n.push(e)}return Wu(a,o,u)},ao.svg.axis=function(){function n(n){n.each(function(){var n,c=ao.select(this),f=this.__chart__||e,s=this.__chart__=e.copy(),h=null==l?s.ticks?s.ticks.apply(s,a):s.domain():l,p=null==t?s.tickFormat?s.tickFormat.apply(s,a):m:t,g=c.selectAll(".tick").data(h,s),v=g.enter().insert("g",".domain").attr("class","tick").style("opacity",Uo),d=ao.transition(g.exit()).style("opacity",Uo).remove(),y=ao.transition(g.order()).style("opacity",1),M=Math.max(i,0)+o,x=Zi(s),b=c.selectAll(".domain").data([0]),_=(b.enter().append("path").attr("class","domain"),ao.transition(b));v.append("line"),v.append("text");var w,S,k,N,E=v.select("line"),A=y.select("line"),C=g.select("text").text(p),z=v.select("text"),L=y.select("text"),q="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(n=no,w="x",k="y",S="x2",N="y2",C.attr("dy",0>q?"0em":".71em").style("text-anchor","middle"),_.attr("d","M"+x[0]+","+q*u+"V0H"+x[1]+"V"+q*u)):(n=to,w="y",k="x",S="y2",N="x2",C.attr("dy",".32em").style("text-anchor",0>q?"end":"start"),_.attr("d","M"+q*u+","+x[0]+"H0V"+x[1]+"H"+q*u)),E.attr(N,q*i),z.attr(k,q*M),A.attr(S,0).attr(N,q*i),L.attr(w,0).attr(k,q*M),s.rangeBand){var T=s,R=T.rangeBand()/2;f=s=function(n){return T(n)+R}}else f.rangeBand?f=s:d.call(n,s,f);v.call(n,f,s),y.call(n,s,s)})}var t,e=ao.scale.linear(),r=Vl,i=6,u=6,o=3,a=[10],l=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Xl?t+"":Vl,n):r},n.ticks=function(){return arguments.length?(a=co(arguments),n):a},n.tickValues=function(t){return arguments.length?(l=t,n):l},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(i=+t,u=+arguments[e-1],n):i},n.innerTickSize=function(t){return arguments.length?(i=+t,n):i},n.outerTickSize=function(t){return arguments.length?(u=+t,n):u},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var Vl="bottom",Xl={top:1,right:1,bottom:1,left:1};ao.svg.brush=function(){function n(t){t.each(function(){var t=ao.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",u).on("touchstart.brush",u),o=t.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),t.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=t.selectAll(".resize").data(v,m);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return $l[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var l,s=ao.transition(t),h=ao.transition(o);c&&(l=Zi(c),h.attr("x",l[0]).attr("width",l[1]-l[0]),r(s)),f&&(l=Zi(f),h.attr("y",l[0]).attr("height",l[1]-l[0]),i(s)),e(s)})}function e(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+s[+/e$/.test(n)]+","+h[+/^s/.test(n)]+")"})}function r(n){n.select(".extent").attr("x",s[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",s[1]-s[0])}function i(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function u(){function u(){32==ao.event.keyCode&&(C||(M=null,L[0]-=s[1],L[1]-=h[1],C=2),S())}function v(){32==ao.event.keyCode&&2==C&&(L[0]+=s[1],L[1]+=h[1],C=0,S())}function d(){var n=ao.mouse(b),t=!1;x&&(n[0]+=x[0],n[1]+=x[1]),C||(ao.event.altKey?(M||(M=[(s[0]+s[1])/2,(h[0]+h[1])/2]),L[0]=s[+(n[0]<M[0])],L[1]=h[+(n[1]<M[1])]):M=null),E&&y(n,c,0)&&(r(k),t=!0),A&&y(n,f,1)&&(i(k),t=!0),t&&(e(k),w({type:"brush",mode:C?"move":"resize"}))}function y(n,t,e){var r,i,u=Zi(t),l=u[0],c=u[1],f=L[e],v=e?h:s,d=v[1]-v[0];return C&&(l-=f,c-=d+f),r=(e?g:p)?Math.max(l,Math.min(c,n[e])):n[e],C?i=(r+=f)+d:(M&&(f=Math.max(l,Math.min(c,2*M[e]-r))),r>f?(i=r,r=f):i=f),v[0]!=r||v[1]!=i?(e?a=null:o=null,v[0]=r,v[1]=i,!0):void 0}function m(){d(),k.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),ao.select("body").style("cursor",null),q.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),z(),w({type:"brushend"})}var M,x,b=this,_=ao.select(ao.event.target),w=l.of(b,arguments),k=ao.select(b),N=_.datum(),E=!/^(n|s)$/.test(N)&&c,A=!/^(e|w)$/.test(N)&&f,C=_.classed("extent"),z=W(b),L=ao.mouse(b),q=ao.select(t(b)).on("keydown.brush",u).on("keyup.brush",v);if(ao.event.changedTouches?q.on("touchmove.brush",d).on("touchend.brush",m):q.on("mousemove.brush",d).on("mouseup.brush",m),k.interrupt().selectAll("*").interrupt(),C)L[0]=s[0]-L[0],L[1]=h[0]-L[1];else if(N){var T=+/w$/.test(N),R=+/^n/.test(N);x=[s[1-T]-L[0],h[1-R]-L[1]],L[0]=s[T],L[1]=h[R]}else ao.event.altKey&&(M=L.slice());k.style("pointer-events","none").selectAll(".resize").style("display",null),ao.select("body").style("cursor",_.style("cursor")),w({type:"brushstart"}),d()}var o,a,l=N(n,"brushstart","brush","brushend"),c=null,f=null,s=[0,0],h=[0,0],p=!0,g=!0,v=Bl[0];return n.event=function(n){n.each(function(){var n=l.of(this,arguments),t={x:s,y:h,i:o,j:a},e=this.__chart__||t;this.__chart__=t,Hl?ao.select(this).transition().each("start.brush",function(){o=e.i,a=e.j,s=e.x,h=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=xr(s,t.x),r=xr(h,t.y);return o=a=null,function(i){s=t.x=e(i),h=t.y=r(i),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){o=t.i,a=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(c=t,v=Bl[!c<<1|!f],n):c},n.y=function(t){return arguments.length?(f=t,v=Bl[!c<<1|!f],n):f},n.clamp=function(t){return arguments.length?(c&&f?(p=!!t[0],g=!!t[1]):c?p=!!t:f&&(g=!!t),n):c&&f?[p,g]:c?p:f?g:null},n.extent=function(t){var e,r,i,u,l;return arguments.length?(c&&(e=t[0],r=t[1],f&&(e=e[0],r=r[0]),o=[e,r],c.invert&&(e=c(e),r=c(r)),e>r&&(l=e,e=r,r=l),e==s[0]&&r==s[1]||(s=[e,r])),f&&(i=t[0],u=t[1],c&&(i=i[1],u=u[1]),a=[i,u],f.invert&&(i=f(i),u=f(u)),i>u&&(l=i,i=u,u=l),i==h[0]&&u==h[1]||(h=[i,u])),n):(c&&(o?(e=o[0],r=o[1]):(e=s[0],r=s[1],c.invert&&(e=c.invert(e),r=c.invert(r)),e>r&&(l=e,e=r,r=l))),f&&(a?(i=a[0],u=a[1]):(i=h[0],u=h[1],f.invert&&(i=f.invert(i),u=f.invert(u)),i>u&&(l=i,i=u,u=l))),c&&f?[[e,i],[r,u]]:c?[e,r]:f&&[i,u])},n.clear=function(){return n.empty()||(s=[0,0],h=[0,0],o=a=null),n},n.empty=function(){return!!c&&s[0]==s[1]||!!f&&h[0]==h[1]},ao.rebind(n,l,"on")};var $l={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Bl=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Wl=ga.format=xa.timeFormat,Jl=Wl.utc,Gl=Jl("%Y-%m-%dT%H:%M:%S.%LZ");Wl.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?eo:Gl,eo.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},eo.toString=Gl.toString,ga.second=On(function(n){return new va(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),ga.seconds=ga.second.range,ga.seconds.utc=ga.second.utc.range,ga.minute=On(function(n){return new va(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),ga.minutes=ga.minute.range,ga.minutes.utc=ga.minute.utc.range,ga.hour=On(function(n){var t=n.getTimezoneOffset()/60;return new va(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),ga.hours=ga.hour.range,ga.hours.utc=ga.hour.utc.range,ga.month=On(function(n){return n=ga.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),ga.months=ga.month.range,ga.months.utc=ga.month.utc.range;var Kl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Ql=[[ga.second,1],[ga.second,5],[ga.second,15],[ga.second,30],[ga.minute,1],[ga.minute,5],[ga.minute,15],[ga.minute,30],[ga.hour,1],[ga.hour,3],[ga.hour,6],[ga.hour,12],[ga.day,1],[ga.day,2],[ga.week,1],[ga.month,1],[ga.month,3],[ga.year,1]],nc=Wl.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",zt]]),tc={range:function(n,t,e){return ao.range(Math.ceil(n/e)*e,+t,e).map(io)},floor:m,ceil:m};Ql.year=ga.year,ga.scale=function(){return ro(ao.scale.linear(),Ql,nc)};var ec=Ql.map(function(n){return[n[0].utc,n[1]]}),rc=Jl.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",zt]]);ec.year=ga.year.utc,ga.scale.utc=function(){return ro(ao.scale.linear(),ec,rc)},ao.text=An(function(n){return n.responseText}),ao.json=function(n,t){return Cn(n,"application/json",uo,t)},ao.html=function(n,t){return Cn(n,"text/html",oo,t)},ao.xml=An(function(n){return n.responseXML}),"function"==typeof define&&define.amd?(this.d3=ao,define(ao)):"object"==typeof module&&module.exports?module.exports=ao:this.d3=ao}();  $(function() {
   var $window     = $(window)
     , $top_link   = $('#toplink')
     , $body       = $('body, html')
     , offset      = $('#code').offset().top
     , hidePopover = function ($target) {
        $target.data('popover-hover', false);

        setTimeout(function () {
         if (!$target.data('popover-hover')) {
          $target.popover('hide');
         }
        }, 300);
     };

   $top_link.hide().click(function(event) {
    event.preventDefault();
    $body.animate({scrollTop:0}, 800);
   });

   $window.scroll(function() {
    if($window.scrollTop() > offset) {
     $top_link.fadeIn();
    } else {
     $top_link.fadeOut();
    }
   }).scroll();

   $('.popin')
    .popover({trigger: 'manual'})
    .on({
     'mouseenter.popover': function () {
      var $target = $(this);
      var $container = $target.children().first();

      $target.data('popover-hover', true);

      // popover already displayed
      if ($target.next('.popover').length) {
       return;
      }

      // show the popover
      $container.popover('show');

      // register mouse events on the popover
      $target.next('.popover:not(.popover-initialized)')
       .on({
        'mouseenter': function () {
         $target.data('popover-hover', true);
        },
        'mouseleave': function () {
         hidePopover($container);
        }
       })
       .addClass('popover-initialized');
     },
     'mouseleave.popover': function () {
      hidePopover($(this).children().first());
     }
    });
  });
       <div class="progress">
         <div class="progress-bar bg-{{level}}" role="progressbar" aria-valuenow="{{percent}}" aria-valuemin="0" aria-valuemax="100" style="width: {{percent}}%">
           <span class="sr-only">{{percent}}% covered ({{level}})</span>
         </div>
       </div>
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report\Html;

use SebastianBergmann\CodeCoverage\Node\File as FileNode;
use SebastianBergmann\CodeCoverage\Util;




final class File extends Renderer
{



private $htmlSpecialCharsFlags = \ENT_COMPAT | \ENT_HTML401 | \ENT_SUBSTITUTE;




public function render(FileNode $node, string $file): void
{
$template = new \Text_Template($this->templatePath . 'file.html', '{{', '}}');

$template->setVar(
[
'items' => $this->renderItems($node),
'lines' => $this->renderSource($node),
]
);

$this->setCommonTemplateVariables($template, $node);

$template->renderTo($file);
}

protected function renderItems(FileNode $node): string
{
$template = new \Text_Template($this->templatePath . 'file_item.html', '{{', '}}');

$methodItemTemplate = new \Text_Template(
$this->templatePath . 'method_item.html',
'{{',
'}}'
);

$items = $this->renderItemTemplate(
$template,
[
'name' => 'Total',
'numClasses' => $node->getNumClassesAndTraits(),
'numTestedClasses' => $node->getNumTestedClassesAndTraits(),
'numMethods' => $node->getNumFunctionsAndMethods(),
'numTestedMethods' => $node->getNumTestedFunctionsAndMethods(),
'linesExecutedPercent' => $node->getLineExecutedPercent(false),
'linesExecutedPercentAsString' => $node->getLineExecutedPercent(),
'numExecutedLines' => $node->getNumExecutedLines(),
'numExecutableLines' => $node->getNumExecutableLines(),
'testedMethodsPercent' => $node->getTestedFunctionsAndMethodsPercent(false),
'testedMethodsPercentAsString' => $node->getTestedFunctionsAndMethodsPercent(),
'testedClassesPercent' => $node->getTestedClassesAndTraitsPercent(false),
'testedClassesPercentAsString' => $node->getTestedClassesAndTraitsPercent(),
'crap' => '<abbr title="Change Risk Anti-Patterns (CRAP) Index">CRAP</abbr>',
]
);

$items .= $this->renderFunctionItems(
$node->getFunctions(),
$methodItemTemplate
);

$items .= $this->renderTraitOrClassItems(
$node->getTraits(),
$template,
$methodItemTemplate
);

$items .= $this->renderTraitOrClassItems(
$node->getClasses(),
$template,
$methodItemTemplate
);

return $items;
}

protected function renderTraitOrClassItems(array $items, \Text_Template $template, \Text_Template $methodItemTemplate): string
{
$buffer = '';

if (empty($items)) {
return $buffer;
}

foreach ($items as $name => $item) {
$numMethods = 0;
$numTestedMethods = 0;

foreach ($item['methods'] as $method) {
if ($method['executableLines'] > 0) {
$numMethods++;

if ($method['executedLines'] === $method['executableLines']) {
$numTestedMethods++;
}
}
}

if ($item['executableLines'] > 0) {
$numClasses = 1;
$numTestedClasses = $numTestedMethods == $numMethods ? 1 : 0;
$linesExecutedPercentAsString = Util::percent(
$item['executedLines'],
$item['executableLines'],
true
);
} else {
$numClasses = 'n/a';
$numTestedClasses = 'n/a';
$linesExecutedPercentAsString = 'n/a';
}

$buffer .= $this->renderItemTemplate(
$template,
[
'name' => $this->abbreviateClassName($name),
'numClasses' => $numClasses,
'numTestedClasses' => $numTestedClasses,
'numMethods' => $numMethods,
'numTestedMethods' => $numTestedMethods,
'linesExecutedPercent' => Util::percent(
$item['executedLines'],
$item['executableLines'],
false
),
'linesExecutedPercentAsString' => $linesExecutedPercentAsString,
'numExecutedLines' => $item['executedLines'],
'numExecutableLines' => $item['executableLines'],
'testedMethodsPercent' => Util::percent(
$numTestedMethods,
$numMethods
),
'testedMethodsPercentAsString' => Util::percent(
$numTestedMethods,
$numMethods,
true
),
'testedClassesPercent' => Util::percent(
$numTestedMethods == $numMethods ? 1 : 0,
1
),
'testedClassesPercentAsString' => Util::percent(
$numTestedMethods == $numMethods ? 1 : 0,
1,
true
),
'crap' => $item['crap'],
]
);

foreach ($item['methods'] as $method) {
$buffer .= $this->renderFunctionOrMethodItem(
$methodItemTemplate,
$method,
'&nbsp;'
);
}
}

return $buffer;
}

protected function renderFunctionItems(array $functions, \Text_Template $template): string
{
if (empty($functions)) {
return '';
}

$buffer = '';

foreach ($functions as $function) {
$buffer .= $this->renderFunctionOrMethodItem(
$template,
$function
);
}

return $buffer;
}

protected function renderFunctionOrMethodItem(\Text_Template $template, array $item, string $indent = ''): string
{
$numMethods = 0;
$numTestedMethods = 0;

if ($item['executableLines'] > 0) {
$numMethods = 1;

if ($item['executedLines'] === $item['executableLines']) {
$numTestedMethods = 1;
}
}

return $this->renderItemTemplate(
$template,
[
'name' => \sprintf(
'%s<a href="#%d"><abbr title="%s">%s</abbr></a>',
$indent,
$item['startLine'],
\htmlspecialchars($item['signature'], $this->htmlSpecialCharsFlags),
$item['functionName'] ?? $item['methodName']
),
'numMethods' => $numMethods,
'numTestedMethods' => $numTestedMethods,
'linesExecutedPercent' => Util::percent(
$item['executedLines'],
$item['executableLines']
),
'linesExecutedPercentAsString' => Util::percent(
$item['executedLines'],
$item['executableLines'],
true
),
'numExecutedLines' => $item['executedLines'],
'numExecutableLines' => $item['executableLines'],
'testedMethodsPercent' => Util::percent(
$numTestedMethods,
1
),
'testedMethodsPercentAsString' => Util::percent(
$numTestedMethods,
1,
true
),
'crap' => $item['crap'],
]
);
}

protected function renderSource(FileNode $node): string
{
$coverageData = $node->getCoverageData();
$testData = $node->getTestData();
$codeLines = $this->loadFile($node->getPath());
$lines = '';
$i = 1;

foreach ($codeLines as $line) {
$trClass = '';
$popoverContent = '';
$popoverTitle = '';

if (\array_key_exists($i, $coverageData)) {
$numTests = ($coverageData[$i] ? \count($coverageData[$i]) : 0);

if ($coverageData[$i] === null) {
$trClass = ' class="warning"';
} elseif ($numTests == 0) {
$trClass = ' class="danger"';
} else {
$lineCss = 'covered-by-large-tests';
$popoverContent = '<ul>';

if ($numTests > 1) {
$popoverTitle = $numTests . ' tests cover line ' . $i;
} else {
$popoverTitle = '1 test covers line ' . $i;
}

foreach ($coverageData[$i] as $test) {
if ($lineCss == 'covered-by-large-tests' && $testData[$test]['size'] == 'medium') {
$lineCss = 'covered-by-medium-tests';
} elseif ($testData[$test]['size'] == 'small') {
$lineCss = 'covered-by-small-tests';
}

switch ($testData[$test]['status']) {
case 0:
switch ($testData[$test]['size']) {
case 'small':
$testCSS = ' class="covered-by-small-tests"';

break;

case 'medium':
$testCSS = ' class="covered-by-medium-tests"';

break;

default:
$testCSS = ' class="covered-by-large-tests"';

break;
}

break;

case 1:
case 2:
$testCSS = ' class="warning"';

break;

case 3:
$testCSS = ' class="danger"';

break;

case 4:
$testCSS = ' class="danger"';

break;

default:
$testCSS = '';
}

$popoverContent .= \sprintf(
'<li%s>%s</li>',
$testCSS,
\htmlspecialchars($test, $this->htmlSpecialCharsFlags)
);
}

$popoverContent .= '</ul>';
$trClass = ' class="' . $lineCss . ' popin"';
}
}

$popover = '';

if (!empty($popoverTitle)) {
$popover = \sprintf(
' data-title="%s" data-content="%s" data-placement="top" data-html="true"',
$popoverTitle,
\htmlspecialchars($popoverContent, $this->htmlSpecialCharsFlags)
);
}

$lines .= \sprintf(
'     <tr%s><td%s><div align="right"><a name="%d"></a><a href="#%d">%d</a></div></td><td class="codeLine">%s</td></tr>' . "\n",
$trClass,
$popover,
$i,
$i,
$i,
$line
);

$i++;
}

return $lines;
}




protected function loadFile($file): array
{
$buffer = \file_get_contents($file);
$tokens = \token_get_all($buffer);
$result = [''];
$i = 0;
$stringFlag = false;
$fileEndsWithNewLine = \substr($buffer, -1) == "\n";

unset($buffer);

foreach ($tokens as $j => $token) {
if (\is_string($token)) {
if ($token === '"' && $tokens[$j - 1] !== '\\') {
$result[$i] .= \sprintf(
'<span class="string">%s</span>',
\htmlspecialchars($token, $this->htmlSpecialCharsFlags)
);

$stringFlag = !$stringFlag;
} else {
$result[$i] .= \sprintf(
'<span class="keyword">%s</span>',
\htmlspecialchars($token, $this->htmlSpecialCharsFlags)
);
}

continue;
}

[$token, $value] = $token;

$value = \str_replace(
["\t", ' '],
['&nbsp;&nbsp;&nbsp;&nbsp;', '&nbsp;'],
\htmlspecialchars($value, $this->htmlSpecialCharsFlags)
);

if ($value === "\n") {
$result[++$i] = '';
} else {
$lines = \explode("\n", $value);

foreach ($lines as $jj => $line) {
$line = \trim($line);

if ($line !== '') {
if ($stringFlag) {
$colour = 'string';
} else {
switch ($token) {
case \T_INLINE_HTML:
$colour = 'html';

break;

case \T_COMMENT:
case \T_DOC_COMMENT:
$colour = 'comment';

break;

case \T_ABSTRACT:
case \T_ARRAY:
case \T_AS:
case \T_BREAK:
case \T_CALLABLE:
case \T_CASE:
case \T_CATCH:
case \T_CLASS:
case \T_CLONE:
case \T_CONTINUE:
case \T_DEFAULT:
case \T_ECHO:
case \T_ELSE:
case \T_ELSEIF:
case \T_EMPTY:
case \T_ENDDECLARE:
case \T_ENDFOR:
case \T_ENDFOREACH:
case \T_ENDIF:
case \T_ENDSWITCH:
case \T_ENDWHILE:
case \T_EXIT:
case \T_EXTENDS:
case \T_FINAL:
case \T_FINALLY:
case \T_FOREACH:
case \T_FUNCTION:
case \T_GLOBAL:
case \T_IF:
case \T_IMPLEMENTS:
case \T_INCLUDE:
case \T_INCLUDE_ONCE:
case \T_INSTANCEOF:
case \T_INSTEADOF:
case \T_INTERFACE:
case \T_ISSET:
case \T_LOGICAL_AND:
case \T_LOGICAL_OR:
case \T_LOGICAL_XOR:
case \T_NAMESPACE:
case \T_NEW:
case \T_PRIVATE:
case \T_PROTECTED:
case \T_PUBLIC:
case \T_REQUIRE:
case \T_REQUIRE_ONCE:
case \T_RETURN:
case \T_STATIC:
case \T_THROW:
case \T_TRAIT:
case \T_TRY:
case \T_UNSET:
case \T_USE:
case \T_VAR:
case \T_WHILE:
case \T_YIELD:
$colour = 'keyword';

break;

default:
$colour = 'default';
}
}

$result[$i] .= \sprintf(
'<span class="%s">%s</span>',
$colour,
$line
);
}

if (isset($lines[$jj + 1])) {
$result[++$i] = '';
}
}
}
}

if ($fileEndsWithNewLine) {
unset($result[\count($result) - 1]);
}

return $result;
}

private function abbreviateClassName(string $className): string
{
$tmp = \explode('\\', $className);

if (\count($tmp) > 1) {
$className = \sprintf(
'<abbr title="%s">%s</abbr>',
$className,
\array_pop($tmp)
);
}

return $className;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report;

use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Node\File;
use SebastianBergmann\CodeCoverage\RuntimeException;




final class Clover
{



public function process(CodeCoverage $coverage, ?string $target = null, ?string $name = null): string
{
$xmlDocument = new \DOMDocument('1.0', 'UTF-8');
$xmlDocument->formatOutput = true;

$xmlCoverage = $xmlDocument->createElement('coverage');
$xmlCoverage->setAttribute('generated', (string) $_SERVER['REQUEST_TIME']);
$xmlDocument->appendChild($xmlCoverage);

$xmlProject = $xmlDocument->createElement('project');
$xmlProject->setAttribute('timestamp', (string) $_SERVER['REQUEST_TIME']);

if (\is_string($name)) {
$xmlProject->setAttribute('name', $name);
}

$xmlCoverage->appendChild($xmlProject);

$packages = [];
$report = $coverage->getReport();

foreach ($report as $item) {
if (!$item instanceof File) {
continue;
}



$xmlFile = $xmlDocument->createElement('file');
$xmlFile->setAttribute('name', $item->getPath());

$classes = $item->getClassesAndTraits();
$coverageData = $item->getCoverageData();
$lines = [];
$namespace = 'global';

foreach ($classes as $className => $class) {
$classStatements = 0;
$coveredClassStatements = 0;
$coveredMethods = 0;
$classMethods = 0;

foreach ($class['methods'] as $methodName => $method) {
if ($method['executableLines'] == 0) {
continue;
}

$classMethods++;
$classStatements += $method['executableLines'];
$coveredClassStatements += $method['executedLines'];

if ($method['coverage'] == 100) {
$coveredMethods++;
}

$methodCount = 0;

foreach (\range($method['startLine'], $method['endLine']) as $line) {
if (isset($coverageData[$line]) && ($coverageData[$line] !== null)) {
$methodCount = \max($methodCount, \count($coverageData[$line]));
}
}

$lines[$method['startLine']] = [
'ccn' => $method['ccn'],
'count' => $methodCount,
'crap' => $method['crap'],
'type' => 'method',
'visibility' => $method['visibility'],
'name' => $methodName,
];
}

if (!empty($class['package']['namespace'])) {
$namespace = $class['package']['namespace'];
}

$xmlClass = $xmlDocument->createElement('class');
$xmlClass->setAttribute('name', $className);
$xmlClass->setAttribute('namespace', $namespace);

if (!empty($class['package']['fullPackage'])) {
$xmlClass->setAttribute(
'fullPackage',
$class['package']['fullPackage']
);
}

if (!empty($class['package']['category'])) {
$xmlClass->setAttribute(
'category',
$class['package']['category']
);
}

if (!empty($class['package']['package'])) {
$xmlClass->setAttribute(
'package',
$class['package']['package']
);
}

if (!empty($class['package']['subpackage'])) {
$xmlClass->setAttribute(
'subpackage',
$class['package']['subpackage']
);
}

$xmlFile->appendChild($xmlClass);

$xmlMetrics = $xmlDocument->createElement('metrics');
$xmlMetrics->setAttribute('complexity', (string) $class['ccn']);
$xmlMetrics->setAttribute('methods', (string) $classMethods);
$xmlMetrics->setAttribute('coveredmethods', (string) $coveredMethods);
$xmlMetrics->setAttribute('conditionals', '0');
$xmlMetrics->setAttribute('coveredconditionals', '0');
$xmlMetrics->setAttribute('statements', (string) $classStatements);
$xmlMetrics->setAttribute('coveredstatements', (string) $coveredClassStatements);
$xmlMetrics->setAttribute('elements', (string) ($classMethods + $classStatements ));
$xmlMetrics->setAttribute('coveredelements', (string) ($coveredMethods + $coveredClassStatements ));
$xmlClass->appendChild($xmlMetrics);
}

foreach ($coverageData as $line => $data) {
if ($data === null || isset($lines[$line])) {
continue;
}

$lines[$line] = [
'count' => \count($data), 'type' => 'stmt',
];
}

\ksort($lines);

foreach ($lines as $line => $data) {
$xmlLine = $xmlDocument->createElement('line');
$xmlLine->setAttribute('num', (string) $line);
$xmlLine->setAttribute('type', $data['type']);

if (isset($data['name'])) {
$xmlLine->setAttribute('name', $data['name']);
}

if (isset($data['visibility'])) {
$xmlLine->setAttribute('visibility', $data['visibility']);
}

if (isset($data['ccn'])) {
$xmlLine->setAttribute('complexity', (string) $data['ccn']);
}

if (isset($data['crap'])) {
$xmlLine->setAttribute('crap', (string) $data['crap']);
}

$xmlLine->setAttribute('count', (string) $data['count']);
$xmlFile->appendChild($xmlLine);
}

$linesOfCode = $item->getLinesOfCode();

$xmlMetrics = $xmlDocument->createElement('metrics');
$xmlMetrics->setAttribute('loc', (string) $linesOfCode['loc']);
$xmlMetrics->setAttribute('ncloc', (string) $linesOfCode['ncloc']);
$xmlMetrics->setAttribute('classes', (string) $item->getNumClassesAndTraits());
$xmlMetrics->setAttribute('methods', (string) $item->getNumMethods());
$xmlMetrics->setAttribute('coveredmethods', (string) $item->getNumTestedMethods());
$xmlMetrics->setAttribute('conditionals', '0');
$xmlMetrics->setAttribute('coveredconditionals', '0');
$xmlMetrics->setAttribute('statements', (string) $item->getNumExecutableLines());
$xmlMetrics->setAttribute('coveredstatements', (string) $item->getNumExecutedLines());
$xmlMetrics->setAttribute('elements', (string) ($item->getNumMethods() + $item->getNumExecutableLines() ));
$xmlMetrics->setAttribute('coveredelements', (string) ($item->getNumTestedMethods() + $item->getNumExecutedLines() ));
$xmlFile->appendChild($xmlMetrics);

if ($namespace === 'global') {
$xmlProject->appendChild($xmlFile);
} else {
if (!isset($packages[$namespace])) {
$packages[$namespace] = $xmlDocument->createElement(
'package'
);

$packages[$namespace]->setAttribute('name', $namespace);
$xmlProject->appendChild($packages[$namespace]);
}

$packages[$namespace]->appendChild($xmlFile);
}
}

$linesOfCode = $report->getLinesOfCode();

$xmlMetrics = $xmlDocument->createElement('metrics');
$xmlMetrics->setAttribute('files', (string) \count($report));
$xmlMetrics->setAttribute('loc', (string) $linesOfCode['loc']);
$xmlMetrics->setAttribute('ncloc', (string) $linesOfCode['ncloc']);
$xmlMetrics->setAttribute('classes', (string) $report->getNumClassesAndTraits());
$xmlMetrics->setAttribute('methods', (string) $report->getNumMethods());
$xmlMetrics->setAttribute('coveredmethods', (string) $report->getNumTestedMethods());
$xmlMetrics->setAttribute('conditionals', '0');
$xmlMetrics->setAttribute('coveredconditionals', '0');
$xmlMetrics->setAttribute('statements', (string) $report->getNumExecutableLines());
$xmlMetrics->setAttribute('coveredstatements', (string) $report->getNumExecutedLines());
$xmlMetrics->setAttribute('elements', (string) ($report->getNumMethods() + $report->getNumExecutableLines() ));
$xmlMetrics->setAttribute('coveredelements', (string) ($report->getNumTestedMethods() + $report->getNumExecutedLines() ));
$xmlProject->appendChild($xmlMetrics);

$buffer = $xmlDocument->saveXML();

if ($target !== null) {
if (!$this->createDirectory(\dirname($target))) {
throw new \RuntimeException(\sprintf('Directory "%s" was not created', \dirname($target)));
}

if (@\file_put_contents($target, $buffer) === false) {
throw new RuntimeException(
\sprintf(
'Could not write to "%s',
$target
)
);
}
}

return $buffer;
}

private function createDirectory(string $directory): bool
{
return !(!\is_dir($directory) && !@\mkdir($directory, 0777, true) && !\is_dir($directory));
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage\Report;

use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Node\File;
use SebastianBergmann\CodeCoverage\RuntimeException;

final class Crap4j
{



private $threshold;

public function __construct(int $threshold = 30)
{
$this->threshold = $threshold;
}




public function process(CodeCoverage $coverage, ?string $target = null, ?string $name = null): string
{
$document = new \DOMDocument('1.0', 'UTF-8');
$document->formatOutput = true;

$root = $document->createElement('crap_result');
$document->appendChild($root);

$project = $document->createElement('project', \is_string($name) ? $name : '');
$root->appendChild($project);
$root->appendChild($document->createElement('timestamp', \date('Y-m-d H:i:s', $_SERVER['REQUEST_TIME'])));

$stats = $document->createElement('stats');
$methodsNode = $document->createElement('methods');

$report = $coverage->getReport();
unset($coverage);

$fullMethodCount = 0;
$fullCrapMethodCount = 0;
$fullCrapLoad = 0;
$fullCrap = 0;

foreach ($report as $item) {
$namespace = 'global';

if (!$item instanceof File) {
continue;
}

$file = $document->createElement('file');
$file->setAttribute('name', $item->getPath());

$classes = $item->getClassesAndTraits();

foreach ($classes as $className => $class) {
foreach ($class['methods'] as $methodName => $method) {
$crapLoad = $this->getCrapLoad($method['crap'], $method['ccn'], $method['coverage']);

$fullCrap += $method['crap'];
$fullCrapLoad += $crapLoad;
$fullMethodCount++;

if ($method['crap'] >= $this->threshold) {
$fullCrapMethodCount++;
}

$methodNode = $document->createElement('method');

if (!empty($class['package']['namespace'])) {
$namespace = $class['package']['namespace'];
}

$methodNode->appendChild($document->createElement('package', $namespace));
$methodNode->appendChild($document->createElement('className', $className));
$methodNode->appendChild($document->createElement('methodName', $methodName));
$methodNode->appendChild($document->createElement('methodSignature', \htmlspecialchars($method['signature'])));
$methodNode->appendChild($document->createElement('fullMethod', \htmlspecialchars($method['signature'])));
$methodNode->appendChild($document->createElement('crap', (string) $this->roundValue($method['crap'])));
$methodNode->appendChild($document->createElement('complexity', (string) $method['ccn']));
$methodNode->appendChild($document->createElement('coverage', (string) $this->roundValue($method['coverage'])));
$methodNode->appendChild($document->createElement('crapLoad', (string) \round($crapLoad)));

$methodsNode->appendChild($methodNode);
}
}
}

$stats->appendChild($document->createElement('name', 'Method Crap Stats'));
$stats->appendChild($document->createElement('methodCount', (string) $fullMethodCount));
$stats->appendChild($document->createElement('crapMethodCount', (string) $fullCrapMethodCount));
$stats->appendChild($document->createElement('crapLoad', (string) \round($fullCrapLoad)));
$stats->appendChild($document->createElement('totalCrap', (string) $fullCrap));

$crapMethodPercent = 0;

if ($fullMethodCount > 0) {
$crapMethodPercent = $this->roundValue((100 * $fullCrapMethodCount) / $fullMethodCount);
}

$stats->appendChild($document->createElement('crapMethodPercent', (string) $crapMethodPercent));

$root->appendChild($stats);
$root->appendChild($methodsNode);

$buffer = $document->saveXML();

if ($target !== null) {
if (!$this->createDirectory(\dirname($target))) {
throw new \RuntimeException(\sprintf('Directory "%s" was not created', \dirname($target)));
}

if (@\file_put_contents($target, $buffer) === false) {
throw new RuntimeException(
\sprintf(
'Could not write to "%s',
$target
)
);
}
}

return $buffer;
}






private function getCrapLoad($crapValue, $cyclomaticComplexity, $coveragePercent): float
{
$crapLoad = 0;

if ($crapValue >= $this->threshold) {
$crapLoad += $cyclomaticComplexity * (1.0 - $coveragePercent / 100);
$crapLoad += $cyclomaticComplexity / $this->threshold;
}

return $crapLoad;
}




private function roundValue($value): float
{
return \round($value, 2);
}

private function createDirectory(string $directory): bool
{
return !(!\is_dir($directory) && !@\mkdir($directory, 0777, true) && !\is_dir($directory));
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage;




final class CoveredCodeNotExecutedException extends RuntimeException
{
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage;




interface Exception
{
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage;




final class MissingCoversAnnotationException extends RuntimeException
{
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage;




final class UnintentionallyCoveredCodeException extends RuntimeException
{



private $unintentionallyCoveredUnits = [];

public function __construct(array $unintentionallyCoveredUnits)
{
$this->unintentionallyCoveredUnits = $unintentionallyCoveredUnits;

parent::__construct($this->toString());
}

public function getUnintentionallyCoveredUnits(): array
{
return $this->unintentionallyCoveredUnits;
}

private function toString(): string
{
$message = '';

foreach ($this->unintentionallyCoveredUnits as $unit) {
$message .= '- ' . $unit . "\n";
}

return $message;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage;

class RuntimeException extends \RuntimeException implements Exception
{
}
<?php declare(strict_types=1);








namespace SebastianBergmann\CodeCoverage;

final class InvalidArgumentException extends \InvalidArgumentException implements Exception
{







public static function create($argument, $type, $value = null): self
{
$stack = \debug_backtrace(0);

return new self(
\sprintf(
'Argument #%d%sof %s::%s() must be a %s',
$argument,
$value !== null ? ' (' . \gettype($value) . '#' . $value . ')' : ' (No Value) ',
$stack[1]['class'],
$stack[1]['function'],
$type
)
);
}
}
<?php declare(strict_types = 1);
namespace TheSeer\Tokenizer;

class TokenCollection implements \ArrayAccess, \Iterator, \Countable {


private $tokens = [];


private $pos;

public function addToken(Token $token): void {
$this->tokens[] = $token;
}

public function current(): Token {
return \current($this->tokens);
}

public function key(): int {
return \key($this->tokens);
}

public function next(): void {
\next($this->tokens);
$this->pos++;
}

public function valid(): bool {
return $this->count() > $this->pos;
}

public function rewind(): void {
\reset($this->tokens);
$this->pos = 0;
}

public function count(): int {
return \count($this->tokens);
}

public function offsetExists($offset): bool {
return isset($this->tokens[$offset]);
}




public function offsetGet($offset): Token {
if (!$this->offsetExists($offset)) {
throw new TokenCollectionException(
\sprintf('No Token at offest %s', $offset)
);
}

return $this->tokens[$offset];
}






public function offsetSet($offset, $value): void {
if (!\is_int($offset)) {
$type = \gettype($offset);

throw new TokenCollectionException(
\sprintf(
'Offset must be of type integer, %s given',
$type === 'object' ? \get_class($value) : $type
)
);
}

if (!$value instanceof Token) {
$type = \gettype($value);

throw new TokenCollectionException(
\sprintf(
'Value must be of type %s, %s given',
Token::class,
$type === 'object' ? \get_class($value) : $type
)
);
}
$this->tokens[$offset] = $value;
}

public function offsetUnset($offset): void {
unset($this->tokens[$offset]);
}
}
<?php declare(strict_types = 1);
namespace TheSeer\Tokenizer;

class Tokenizer {






private $map = [
'(' => 'T_OPEN_BRACKET',
')' => 'T_CLOSE_BRACKET',
'[' => 'T_OPEN_SQUARE',
']' => 'T_CLOSE_SQUARE',
'{' => 'T_OPEN_CURLY',
'}' => 'T_CLOSE_CURLY',
';' => 'T_SEMICOLON',
'.' => 'T_DOT',
',' => 'T_COMMA',
'=' => 'T_EQUAL',
'<' => 'T_LT',
'>' => 'T_GT',
'+' => 'T_PLUS',
'-' => 'T_MINUS',
'*' => 'T_MULT',
'/' => 'T_DIV',
'?' => 'T_QUESTION_MARK',
'!' => 'T_EXCLAMATION_MARK',
':' => 'T_COLON',
'"' => 'T_DOUBLE_QUOTES',
'@' => 'T_AT',
'&' => 'T_AMPERSAND',
'%' => 'T_PERCENT',
'|' => 'T_PIPE',
'$' => 'T_DOLLAR',
'^' => 'T_CARET',
'~' => 'T_TILDE',
'`' => 'T_BACKTICK'
];

public function parse(string $source): TokenCollection {
$result = new TokenCollection();

if ($source === '') {
return $result;
}

$tokens = \token_get_all($source);

$lastToken = new Token(
$tokens[0][2],
'Placeholder',
''
);

foreach ($tokens as $pos => $tok) {
if (\is_string($tok)) {
$token = new Token(
$lastToken->getLine(),
$this->map[$tok],
$tok
);
$result->addToken($token);
$lastToken = $token;

continue;
}

$line = $tok[2];
$values = \preg_split('/\R+/Uu', $tok[1]);

foreach ($values as $v) {
$token = new Token(
$line,
\token_name($tok[0]),
$v
);
$lastToken = $token;
$line++;

if ($v === '') {
continue;
}

$result->addToken($token);
}
}

return $this->fillBlanks($result, $lastToken->getLine());
}

private function fillBlanks(TokenCollection $tokens, int $maxLine): TokenCollection {
$prev = new Token(
0,
'Placeholder',
''
);

$final = new TokenCollection();

foreach ($tokens as $token) {
if ($prev === null) {
$final->addToken($token);
$prev = $token;

continue;
}

$gap = $token->getLine() - $prev->getLine();

while ($gap > 1) {
$linebreak = new Token(
$prev->getLine() + 1,
'T_WHITESPACE',
''
);
$final->addToken($linebreak);
$prev = $linebreak;
$gap--;
}

$final->addToken($token);
$prev = $token;
}

$gap = $maxLine - $prev->getLine();

while ($gap > 0) {
$linebreak = new Token(
$prev->getLine() + 1,
'T_WHITESPACE',
''
);
$final->addToken($linebreak);
$prev = $linebreak;
$gap--;
}

return $final;
}
}
<?php declare(strict_types = 1);
namespace TheSeer\Tokenizer;

class Exception extends \Exception {
}
<?php declare(strict_types = 1);
namespace TheSeer\Tokenizer;

class TokenCollectionException extends Exception {
}
<?php declare(strict_types = 1);
namespace TheSeer\Tokenizer;

use DOMDocument;

class XMLSerializer {


private $writer;


private $previousToken;


private $xmlns;






public function __construct(NamespaceUri $xmlns = null) {
if ($xmlns === null) {
$xmlns = new NamespaceUri('https://github.com/theseer/tokenizer');
}
$this->xmlns = $xmlns;
}

public function toDom(TokenCollection $tokens): DOMDocument {
$dom = new DOMDocument();
$dom->preserveWhiteSpace = false;
$dom->loadXML($this->toXML($tokens));

return $dom;
}

public function toXML(TokenCollection $tokens): string {
$this->writer = new \XMLWriter();
$this->writer->openMemory();
$this->writer->setIndent(true);
$this->writer->startDocument();
$this->writer->startElement('source');
$this->writer->writeAttribute('xmlns', $this->xmlns->asString());

if (\count($tokens) > 0) {
$this->writer->startElement('line');
$this->writer->writeAttribute('no', '1');

$this->previousToken = $tokens[0];

foreach ($tokens as $token) {
$this->addToken($token);
}
}

$this->writer->endElement();
$this->writer->endElement();
$this->writer->endDocument();

return $this->writer->outputMemory();
}

private function addToken(Token $token): void {
if ($this->previousToken->getLine() < $token->getLine()) {
$this->writer->endElement();

$this->writer->startElement('line');
$this->writer->writeAttribute('no', (string)$token->getLine());
$this->previousToken = $token;
}

if ($token->getValue() !== '') {
$this->writer->startElement('token');
$this->writer->writeAttribute('name', $token->getName());
$this->writer->writeRaw(\htmlspecialchars($token->getValue(), \ENT_NOQUOTES | \ENT_DISALLOWED | \ENT_XML1));
$this->writer->endElement();
}
}
}
<?php declare(strict_types = 1);
namespace TheSeer\Tokenizer;

class NamespaceUri {


private $value;

public function __construct(string $value) {
$this->ensureValidUri($value);
$this->value = $value;
}

public function asString(): string {
return $this->value;
}

private function ensureValidUri($value): void {
if (\strpos($value, ':') === false) {
throw new NamespaceUriException(
\sprintf("Namespace URI '%s' must contain at least one colon", $value)
);
}
}
}
<?php declare(strict_types = 1);
namespace TheSeer\Tokenizer;

class Token {


private $line;


private $name;


private $value;




public function __construct(int $line, string $name, string $value) {
$this->line = $line;
$this->name = $name;
$this->value = $value;
}

public function getLine(): int {
return $this->line;
}

public function getName(): string {
return $this->name;
}

public function getValue(): string {
return $this->value;
}
}
<?php declare(strict_types = 1);
namespace TheSeer\Tokenizer;

class NamespaceUriException extends Exception {
}
<?php



































namespace Hoa\Event;









interface Source
{
}
<?php



































namespace Hoa\Event;










class Listener
{





protected $_source = null;






protected $_callables = [];









public function __construct(Listenable $source, array $ids)
{
$this->_source = $source;
$this->addIds($ids);

return;
}







public function addIds(array $ids)
{
foreach ($ids as $id) {
$this->_callables[$id] = [];
}

return;
}









public function attach($listenerId, $callable)
{
if (false === $this->listenerExists($listenerId)) {
throw new Exception(
'Cannot listen %s because it is not defined.',
0,
$listenerId
);
}

$callable = xcallable($callable);
$this->_callables[$listenerId][$callable->getHash()] = $callable;

return $this;
}








public function detach($listenerId, $callable)
{
unset($this->_callables[$listenerId][xcallable($callable)->getHash()]);

return $this;
}







public function detachAll($listenerId)
{
unset($this->_callables[$listenerId]);

return $this;
}







public function listenerExists($listenerId)
{
return array_key_exists($listenerId, $this->_callables);
}









public function fire($listenerId, Bucket $data)
{
if (false === $this->listenerExists($listenerId)) {
throw new Exception(
'Cannot fire on %s because it is not defined.',
1,
$listenerId
);
}

$data->setSource($this->_source);
$out = [];

foreach ($this->_callables[$listenerId] as $callable) {
$out[] = $callable($data);
}

return $out;
}
}
<?php



































namespace Hoa\Event\Test\Unit;

use Hoa\Test;









class Source extends Test\Unit\Suite
{
public function case_interface()
{
$this
->when($result = new \Mock\Hoa\Event\Source())
->then
->object($result)
->isInstanceOf('Hoa\Event\Source');
}
}
<?php



































namespace Hoa\Event\Test\Unit;

use Hoa\Event as LUT;
use Hoa\Event\Listener as SUT;
use Hoa\Test;









class Listener extends Test\Unit\Suite
{
public function case_constructor()
{
$this
->given(
$source = new \Mock\Hoa\Event\Listenable(),
$ids = ['foo', 'bar', 'baz']
)
->when($result = new SUT($source, $ids))
->then
->object($result)
->isInstanceOf('Hoa\Event\Listener')
->boolean($result->listenerExists('foo'))
->isTrue()
->boolean($result->listenerExists('bar'))
->isTrue()
->boolean($result->listenerExists('baz'))
->isTrue();
}

public function case_attach()
{
$this
->given(
$source = new \Mock\Hoa\Event\Listenable(),
$listenerId = 'foo',
$listener = new SUT($source, ['foo', 'bar']),
$callable = function () {
return 42;
}
)
->when($result = $listener->attach($listenerId, $callable))
->then
->object($result)
->isIdenticalTo($listener)
->array($listener->fire($listenerId, new LUT\Bucket()))
->isEqualTo([42]);
}

public function case_attach_to_an_undefined_listener()
{
$this
->given(
$source = new \Mock\Hoa\Event\Listenable(),
$listenerId = 'bar',
$listener = new SUT($source, ['foo', 'baz']),
$callable = function () { }
)
->exception(function () use ($listener, $listenerId, $callable) {
$listener->attach($listenerId, $callable);
})
->isInstanceOf('Hoa\Event\Exception');
}

public function case_detach()
{
$this
->given(
$source = new \Mock\Hoa\Event\Listenable(),
$listenerId = 'foo',
$listener = new SUT($source, ['foo', 'bar']),
$callable = function () {
return 42;
},
$listener->attach($listenerId, $callable)
)
->when($result = $listener->detach($listenerId, $callable))
->then
->object($result)
->isIdenticalTo($listener)
->array($listener->fire($listenerId, new LUT\Bucket()))
->isEmpty();
}

public function case_detach_an_undefined_listener()
{
$this
->given(
$source = new \Mock\Hoa\Event\Listenable(),
$listenerId = 'bar',
$listener = new SUT($source, ['foo', 'baz']),
$callable = function () { }
)
->when($result = $listener->detach($listenerId, $callable))
->then
->object($result)
->isIdenticalTo($listener);
}

public function case_detach_all()
{
$this
->given(
$source = new \Mock\Hoa\Event\Listenable(),
$listenerId = 'foo',
$listener = new SUT($source, ['foo', 'bar'])
)
->when($result = $listener->detachAll($listenerId))
->then
->object($result)
->isIdenticalTo($listener)
->boolean($listener->listenerExists($listenerId))
->isFalse();
}

public function case_detach_all_with_an_undefined_listener()
{
$this
->given(
$source = new \Mock\Hoa\Event\Listenable(),
$listenerId = 'bar',
$listener = new SUT($source, ['foo', 'baz'])
)
->when($result = $listener->detachAll($listenerId))
->then
->object($result)
->isIdenticalTo($listener);
}

public function case_listener_exists()
{
$this
->given(
$source = new \Mock\Hoa\Event\Listenable(),
$ids = [],
$listener = new SUT($source, $ids)
)
->when($listener->addIds(['foo']))
->then
->boolean($listener->listenerExists('foo'))
->isTrue()
->boolean($listener->listenerExists('bar'))
->isFalse()

->when($listener->addIds(['bar']))
->then
->boolean($listener->listenerExists('bar'))
->isTrue();
}

public function case_fire()
{
$self = $this;

$this
->given(
$source = new \Mock\Hoa\Event\Listenable(),
$ids = ['foo', 'bar'],
$listener = new SUT($source, $ids),

$listenerId = 'foo',
$bucket = new LUT\Bucket(),
$listener->attach(
$listenerId,
function (LUT\Bucket $receivedBucket) use ($self, $bucket, $source, &$called) {
$called = true;

$self
->object($receivedBucket)
->isIdenticalTo($bucket)
->object($receivedBucket->getSource())
->isIdenticalTo($source);

return 42;
}
)
)
->when($result = $listener->fire($listenerId, $bucket))
->then
->array($result)
->isEqualTo([42])
->boolean($called)
->isTrue();
}

public function case_fire_an_undefined_listenerId()
{
$this
->given(
$source = new \Mock\Hoa\Event\Listenable(),
$ids = [],
$listener = new SUT($source, $ids)
)
->exception(function () use ($listener) {
$listener->fire('foo', new LUT\Bucket());
})
->isInstanceOf('Hoa\Event\Exception');
}
}
<?php



































namespace Hoa\Event\Test\Unit;

use Hoa\Event\Exception as SUT;
use Hoa\Test;









class Exception extends Test\Unit\Suite
{
public function case_hoa_exception()
{
$this
->when($result = new SUT('foo', 0))
->then
->object($result)
->isInstanceOf('Hoa\Exception\Exception');
}
}
<?php



































namespace Hoa\Event\Test\Unit;

use Hoa\Event as LUT;
use Hoa\Event\Bucket as SUT;
use Hoa\Test;









class Bucket extends Test\Unit\Suite
{
public function case_constructor()
{
$this
->when($result = new SUT('foo'))
->then
->object($result)
->isInstanceOf('Hoa\Event\Bucket')
->string($result->getData())
->isEqualTo('foo');
}

public function case_send()
{
$self = $this;

$this
->given(
$eventId = 'hoa://Event/Test',
$source = new \Mock\Hoa\Event\Source(),
LUT::register($eventId, $source),

$bucket = new SUT('foo'),

LUT::getEvent($eventId)->attach(
function (SUT $receivedBucket) use ($self, $bucket, &$called) {
$called = true;

$self
->object($receivedBucket)
->isIdenticalTo($bucket);
}
)
)
->when($result = $bucket->send($eventId, $source))
->then
->variable($result)
->isNull()
->boolean($called)
->isTrue();
}

public function case_set_source()
{
$this
->given(
$bucket = new SUT(),
$sourceA = new \Mock\Hoa\Event\Source()
)
->when($result = $bucket->setSource($sourceA))
->then
->variable($result)
->isNull()
->object($bucket->getSource())
->isIdenticalTo($sourceA)

->given($sourceB = new \Mock\Hoa\Event\Source())
->when($result = $bucket->setSource($sourceB))
->then
->object($result)
->isIdenticalTo($sourceA)
->object($bucket->getSource())
->isIdenticalTo($sourceB);
}

public function case_set_data()
{
$this
->given(
$bucket = new SUT(),
$datumA = 'foo'
)
->when($result = $bucket->setData($datumA))
->then
->variable($result)
->isNull()
->string($bucket->getData())
->isEqualTo($datumA)

->given($datumB = 'bar')
->when($result = $bucket->setData($datumB))
->then
->string($result)
->isEqualTo($datumA)
->string($bucket->getData())
->isEqualTo($datumB);
}
}
<?php



































namespace Hoa\Event\Test\Unit;

use Hoa\Event as LUT;
use Hoa\Event\Listens as SUT;
use Hoa\Test;









class Listens extends Test\Unit\Suite
{
public function case_set_listener()
{
$this
->given(
$listenable = new _Listenable(),
$listener = new LUT\Listener($listenable, ['foo'])
)
->when($result = $listenable->_setListener($listener))
->then
->variable($result)
->isNull();
}

public function case_get_listener()
{
$this
->given(
$listenable = new _Listenable(),
$listener = new LUT\Listener($listenable, ['foo']),
$listenable->_setListener($listener)
)
->when($result = $listenable->_getListener())
->then
->object($result)
->isIdenticalTo($listener);
}

public function case_on()
{
$this
->given(
$listenable = new _Listenable(),
$listener = new LUT\Listener($listenable, ['foo']),
$listenable->_setListener($listener),
$callable = function () use (&$called) {
$called = true;

return 42;
}
)
->when($result = $listenable->on('foo', $callable))
->then
->object($result)
->isIdenticalTo($listenable)

->when($listenable->doSomethingThatFires())
->then
->boolean($called)
->isTrue();
}

public function case_on_unregistered_listener()
{
$this
->given(
$listenable = new _Listenable(),
$listener = new LUT\Listener($listenable, ['foo']),
$listenable->_setListener($listener)
)
->exception(function () use ($listenable) {
$listenable->on('bar', null);
})
->isInstanceOf('Hoa\Event\Exception');
}
}

class _Listenable implements LUT\Listenable
{
use SUT;

public function _setListener(LUT\Listener $listener)
{
return $this->setListener($listener);
}

public function _getListener()
{
return $this->getListener();
}

public function doSomethingThatFires()
{
$this->getListener()->fire('foo', new LUT\Bucket('bar'));

return;
}
}
<?php



































namespace Hoa\Event\Test\Unit;

use Hoa\Test;









class Listenable extends Test\Unit\Suite
{
public function case_interface()
{
$this
->when($result = new \Mock\Hoa\Event\Listenable())
->then
->object($result)
->isInstanceOf('Hoa\Event\Listenable');
}
}
<?php



































namespace Hoa\Event\Test\Unit;

use Hoa\Event as LUT;
use Hoa\Event\Event as SUT;
use Hoa\Test;









class Event extends Test\Unit\Suite
{
public function case_multiton()
{
$this
->given($eventId = 'hoa://Event/Test')
->when($result = SUT::getEvent($eventId))
->then
->object($result)
->isInstanceOf('Hoa\Event\Event')
->object(SUT::getEvent($eventId))
->isIdenticalTo($result);
}

public function case_register_source_instance()
{
$this
->given(
$eventId = 'hoa://Event/Test',
$source = new \Mock\Hoa\Event\Source()
)
->when($result = SUT::register($eventId, $source))
->then
->variable($result)
->isNull()
->boolean(SUT::eventExists($eventId))
->isTrue();
}

public function case_register_source_name()
{
$this
->given(
$eventId = 'hoa://Event/Test',
$source = 'Mock\Hoa\Event\Source'
)
->when($result = SUT::register($eventId, $source))
->then
->variable($result)
->isNull()
->boolean(SUT::eventExists($eventId))
->isTrue();
}

public function case_register_redeclare()
{
$this
->given(
$eventId = 'hoa://Event/Test',
$source = new \Mock\Hoa\Event\Source(),
SUT::register($eventId, $source)
)
->exception(function () use ($eventId, $source) {
SUT::register($eventId, $source);
})
->isInstanceOf('Hoa\Event\Exception');
}

public function case_register_not_a_source_instance()
{
$this
->given(
$eventId = 'hoa://Event/Test',
$source = new \StdClass()
)
->exception(function () use ($eventId, $source) {
$result = SUT::register($eventId, $source);
})
->isInstanceOf('Hoa\Event\Exception');
}

public function case_register_not_a_source_name()
{
$this
->given(
$eventId = 'hoa://Event/Test',
$source = 'StdClass'
)
->exception(function () use ($eventId, $source) {
$result = SUT::register($eventId, $source);
})
->isInstanceOf('Hoa\Event\Exception');
}

public function case_unregister()
{
$this
->given(
$eventId = 'hoa://Event/Test',
$source = new \Mock\Hoa\Event\Source(),
SUT::register($eventId, $source)
)
->when($result = SUT::unregister($eventId))
->then
->boolean(SUT::eventExists($eventId))
->isFalse();
}

public function case_unregister_hard()
{
$this
->given(
$eventId = 'hoa://Event/Test',
$source = new \Mock\Hoa\Event\Source(),
SUT::register($eventId, $source),
$event = SUT::getEvent($eventId)
)
->when($result = SUT::unregister($eventId, true))
->then
->boolean(SUT::eventExists($eventId))
->isFalse()
->object(SUT::getEvent($eventId))
->isNotIdenticalTo($event);
}

public function case_unregister_not_registered()
{
$this
->given($eventId = 'hoa://Event/Test')
->when($result = SUT::unregister($eventId))
->then
->variable($result)
->isNull();
}

public function case_attach()
{
$this
->given(
$event = SUT::getEvent('hoa://Event/Test'),
$callable = function () { }
)
->when($result = $event->attach($callable))
->then
->object($result)
->isIdenticalTo($event)
->boolean($event->isListened())
->isTrue();
}

public function case_detach()
{
$this
->given(
$event = SUT::getEvent('hoa://Event/Test'),
$callable = function () { },
$event->attach($callable)
)
->when($result = $event->detach($callable))
->then
->object($result)
->isIdenticalTo($event)
->boolean($event->isListened())
->isFalse();
}

public function case_detach_unattached()
{
$this
->given(
$event = SUT::getEvent('hoa://Event/Test'),
$callable = function () { }
)
->when($result = $event->detach($callable))
->then
->object($result)
->isIdenticalTo($event)
->boolean($event->isListened())
->isFalse();
}

public function case_is_listened()
{
$this
->given($event = SUT::getEvent('hoa://Event/Test'))
->when($result = $event->isListened())
->then
->boolean($event->isListened())
->isFalse();
}

public function case_notify()
{
$self = $this;

$this
->given(
$eventId = 'hoa://Event/Test',
$source = new \Mock\Hoa\Event\Source(),
$bucket = new LUT\Bucket(),

SUT::register($eventId, $source),
SUT::getEvent($eventId)->attach(
function (LUT\Bucket $receivedBucket) use ($self, $source, $bucket, &$called) {
$called = true;

$this
->object($receivedBucket)
->isIdenticalTo($bucket)
->object($receivedBucket->getSource())
->isIdenticalTo($source);
}
)
)
->when($result = SUT::notify($eventId, $source, $bucket))
->then
->variable($result)
->isNull()
->boolean($called)
->isTrue();
}

public function case_notify_unregistered_event_id()
{
$this
->given(
$eventId = 'hoa://Event/Test',
$source = new \Mock\Hoa\Event\Source(),
$data = new LUT\Bucket()
)
->exception(function () use ($eventId, $source, $data) {
SUT::notify($eventId, $source, $data);
})
->isInstanceOf('Hoa\Event\Exception');
}

public function case_event_exists()
{
$this
->given(
$eventId = 'hoa://Event/Test',
$source = new \Mock\Hoa\Event\Source(),
SUT::register($eventId, $source)
)
->when($result = SUT::eventExists($eventId))
->then
->boolean($result)
->isTrue();
}

public function case_event_not_exists()
{
$this
->given($eventId = 'hoa://Event/Test')
->when($result = SUT::eventExists($eventId))
->then
->boolean($result)
->isFalse();
}
}
<?php



































namespace Hoa\Event;

use Hoa\Exception as HoaException;









class Exception extends HoaException
{
}
<?php



































namespace Hoa\Event;









class Bucket
{





protected $_source = null;






protected $_data = null;








public function __construct($data = null)
{
$this->setData($data);

return;
}








public function send($eventId, Source $source)
{
return Event::notify($eventId, $source, $this);
}







public function setSource(Source $source)
{
$old = $this->_source;
$this->_source = $source;

return $old;
}






public function getSource()
{
return $this->_source;
}







public function setData($data)
{
$old = $this->_data;
$this->_data = $data;

return $old;
}






public function getData()
{
return $this->_data;
}
}
<?php



































namespace Hoa\Event;









trait Listens
{





protected $_listener = null;










public function on($listenerId, $callable)
{
$listener = $this->getListener();

if (null === $listener) {
throw new Exception(
'Cannot attach a callable to the listener %s because ' .
'it has not been initialized yet.',
0,
get_class($this)
);
}

$listener->attach($listenerId, $callable);

return $this;
}







protected function setListener(Listener $listener)
{
$old = $this->_listener;
$this->_listener = $listener;

return $old;
}






protected function getListener()
{
return $this->_listener;
}
}
<?php



































namespace Hoa\Event;









interface Listenable extends Source
{







public function on($listenerId, $callable);
}
<?php



































namespace Hoa\Event;

use Hoa\Consistency;











class Event
{





const KEY_EVENT = 0;






const KEY_SOURCE = 1;







private static $_register = [];






protected $_callable = [];







private function __construct()
{
return;
}








public static function getEvent($eventId)
{
if (!isset(self::$_register[$eventId][self::KEY_EVENT])) {
self::$_register[$eventId] = [
self::KEY_EVENT => new self(),
self::KEY_SOURCE => null
];
}

return self::$_register[$eventId][self::KEY_EVENT];
}










public static function register($eventId, $source)
{
if (true === self::eventExists($eventId)) {
throw new Exception(
'Cannot redeclare an event with the same ID, i.e. the event ' .
'ID %s already exists.',
0,
$eventId
);
}

if (is_object($source) && !($source instanceof Source)) {
throw new Exception(
'The source must implement \Hoa\Event\Source ' .
'interface; given %s.',
1,
get_class($source)
);
} else {
$reflection = new \ReflectionClass($source);

if (false === $reflection->implementsInterface('\Hoa\Event\Source')) {
throw new Exception(
'The source must implement \Hoa\Event\Source ' .
'interface; given %s.',
2,
$source
);
}
}

if (!isset(self::$_register[$eventId][self::KEY_EVENT])) {
self::$_register[$eventId][self::KEY_EVENT] = new self();
}

self::$_register[$eventId][self::KEY_SOURCE] = $source;

return;
}









public static function unregister($eventId, $hard = false)
{
if (false !== $hard) {
unset(self::$_register[$eventId]);
} else {
self::$_register[$eventId][self::KEY_SOURCE] = null;
}

return;
}









public function attach($callable)
{
$callable = xcallable($callable);
$this->_callable[$callable->getHash()] = $callable;

return $this;
}








public function detach($callable)
{
unset($this->_callable[xcallable($callable)->getHash()]);

return $this;
}






public function isListened()
{
return !empty($this->_callable);
}










public static function notify($eventId, Source $source, Bucket $data)
{
if (false === self::eventExists($eventId)) {
throw new Exception(
'Event ID %s does not exist, cannot send notification.',
3,
$eventId
);
}

$data->setSource($source);
$event = self::getEvent($eventId);

foreach ($event->_callable as $callable) {
$callable($data);
}

return;
}







public static function eventExists($eventId)
{
return
array_key_exists($eventId, self::$_register) &&
self::$_register[$eventId][self::KEY_SOURCE] !== null;
}
}




Consistency::flexEntity('Hoa\Event\Event');
<?php



































namespace Hoa\Ustring;









class Search
{









public static function approximated($y, $x, $k)
{
$x = (string) $x;
$y = (string) $y;
$m = strlen($x);
$n = strlen($y);
$offset = [];
$L = [-1 => array_fill(-1, $n - $m + $k + 3, -2)];

for ($q = 0, $max = $k - 1; $q <= $max; ++$q) {
$L[$q][-$q - 1] = $L[$q][-$q - 2] = $q - 1;
}

for ($q = 0; $q <= $k; ++$q) {
for ($d = -$q, $max = $n - $m + $k - $q; $d <= $max; ++$d) {
$l = min(
max(
$L[$q - 1][$d - 1],
$L[$q - 1][$d ] + 1,
$L[$q - 1][$d + 1] + 1
),
$m - 1
);
$a = substr($x, $l + 1, $m - $l);
$b = substr($y, $l + 1 + $d, $n - $l - $d);
$L[$q][$d] = $l + static::lcp($a, $b);

if ($L[$q][$d] == $m - 1 ||
$d + $L[$q][$d] == $n - 1) {
$j = $m + $d;
$i = max(0, $j - $m);
$offset[$q][] = ['i' => $i, 'j' => $j, 'l' => $j - $i];
}
}
}

return empty($offset) ? $offset : $offset[$k];
}








public static function lcp($x, $y)
{
$max = min(strlen($x), strlen($y));
$i = 0;

while ($i < $max && $x[$i] == $y[$i]) {
++$i;
}

return $i;
}
}
<?php



































namespace Hoa\Ustring\Test\Unit;

use Hoa\Test;
use Hoa\Ustring as LUT;









class Issue extends Test\Unit\Suite implements Test\Decorrelated
{
public function case_github_26()
{
$this
->when($result = LUT::toCode(chr(160)))
->then
->integer($result)
->isEqualTo(0xa0);
}
}
<?php



































namespace Hoa\Ustring\Test\Unit;

use Hoa\Test;
use Hoa\Ustring as LUT;









class Search extends Test\Unit\Suite
{
public function case_approximated()
{
$this
->given(
$x = 'GATAA',
$y = 'CAGATAAGAGAA',
$k = 1
)
->when($result = LUT\Search::approximated($y, $x, $k))
->then
->array($result)
->isEqualTo([
0 => [
'i' => 1,
'j' => 6,
'l' => 5
],
1 => [
'i' => 2,
'j' => 7,
'l' => 5
],
2 => [
'i' => 3,
'j' => 8,
'l' => 5
],
3 => [
'i' => 7,
'j' => 12,
'l' => 5
]
]);
}
}
<?php



































namespace Hoa\Ustring\Test\Unit;

use Hoa\Test;
use Hoa\Ustring as LUT;









class Ustring extends Test\Unit\Suite
{
public function case_check_mbstring()
{
$this
->given($this->function->function_exists = true)
->then
->boolean(LUT::checkMbString())
->isTrue();
}

public function case_check_no_mbstring()
{
$this
->given(
$this->function->function_exists = function ($name) {
return 'mb_substr' !== $name;
}
)
->exception(function () {
new LUT();
})
->isInstanceOf('Hoa\Ustring\Exception');
}

public function case_append_ltr()
{
$this
->given($string = new LUT('je'))
->when($result = $string->append(' t\'aime'))
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('je t\'aime');
}

public function case_append_rtl()
{
$this
->given($string = new LUT('أ'))
->when($result = $string->append('حبك'))
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('أحبك');
}

public function case_prepend_ltr()
{
$this
->given($string = new LUT(' t\'aime'))
->when($result = $string->prepend('je'))
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('je t\'aime');
}

public function case_prepend_rtl()
{
$this
->given($string = new LUT('ك'))
->when($result = $string->prepend('أحب'))
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('أحبك');
}

public function case_pad_beginning_ltr()
{
$this
->given($string = new LUT('je t\'aime'))
->when($result = $string->pad(20, '👍 💩 😄 ❤️ ', LUT::BEGINNING))
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('👍 💩 😄 ❤️ 👍 je t\'aime');
}

public function case_pad_beginning_rtl()
{
$this
->given($string = new LUT('أحبك'))
->when($result = $string->pad(20, '👍 💩 😄 ❤️ ', LUT::BEGINNING))
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('👍 💩 😄 ❤️ 👍 💩 😄 ❤أحبك');
}

public function case_pad_end_ltr()
{
$this
->given($string = new LUT('je t\'aime'))
->when($result = $string->pad(20, '👍 💩 😄 ❤️ ', LUT::END))
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('je t\'aime👍 💩 😄 ❤️ 👍 ');
}

public function case_pad_end_rtl()
{
$this
->given($string = new LUT('أحبك'))
->when($result = $string->pad(20, '👍 💩 😄 ❤️ ', LUT::END))
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('أحبك👍 💩 😄 ❤️ 👍 💩 😄 ❤');
}

public function case_compare_no_collator()
{
$this
->given(
$this->function->class_exists = function ($name) {
return 'Collator' !== $name;
},
$string = new LUT('b')
)
->case_compare();
}

public function case_compare()
{
$this
->given($string = new LUT('b'))
->when($result = $string->compare('a'))
->then
->integer($result)
->isEqualTo(1)

->when($result = $string->compare('b'))
->then
->integer($result)
->isEqualTo(0)

->when($result = $string->compare('c'))
->then
->integer($result)
->isEqualTo(-1);
}

public function case_collator()
{
$this
->given(
$this->function->setlocale = 'fr_FR',
$collator = LUT::getCollator()
)
->when($result = $collator->getLocale(\Locale::VALID_LOCALE))
->then
->string($result)
->isEqualTo('fr');
}

public function case_safe_unsafe_pattern()
{
$this
->given($pattern = '/foo/i')
->when($result = LUT::safePattern($pattern))
->then
->string($result)
->isEqualto('/foo/iu');
}

public function case_safe_safe_pattern()
{
$this
->given($pattern = '/foo/ui')
->when($result = LUT::safePattern($pattern))
->then
->string($result)
->isEqualto('/foo/ui');
}

public function case_match_default()
{
$this
->given(
$pattern = '/💩/u',
$string = new LUT('foo 💩 bar')
)
->when($result = $string->match($pattern, $matches))
->then
->integer($result)
->isEqualTo(1)
->array($matches)
->isEqualTo([
0 => '💩'
]);
}

public function case_match_offset()
{
$this
->given(
$pattern = '/💩/u',
$string = new LUT('foo 💩 bar')
)
->when($result = $string->match($pattern, $matches, 0, 0))
->then
->integer($result)
->isEqualTo(1)
->array($matches)
->isEqualTo([0 => '💩'])

->when($result = $string->match($pattern, $matches, 0, 4))
->then
->integer($result)
->isEqualTo(1)
->array($matches)
->isEqualTo([0 => '💩'])

->when($result = $string->match($pattern, $matches, 0, 5))
->then
->integer($result)
->isEqualTo(0)
->array($matches)
->isEmpty();
}

public function case_match_with_offset()
{
$this
->given(
$pattern = '/💩/u',
$string = new LUT('foo 💩 bar')
)
->when($result = $string->match($pattern, $matches, $string::WITH_OFFSET))
->then
->integer($result)
->isEqualTo(1)
->array($matches)
->isEqualTo([
0 => [
0 => '💩',
1 => 4
]
]);
}

public function case_match_all_default()
{
$this
->given(
$pattern = '/💩/u',
$string = new LUT('foo 💩 bar 💩 baz')
)
->when($result = $string->match($pattern, $matches, 0, 0, true))
->then
->integer($result)
->isEqualTo(2)
->array($matches)
->isEqualTo([
0 => [
0 => '💩',
1 => '💩'
]
]);
}

public function case_match_all_with_offset()
{
$this
->given(
$pattern = '/💩/u',
$string = new LUT('foo 💩 bar 💩 baz')
)
->when($result = $string->match($pattern, $matches, $string::WITH_OFFSET, 0, true))
->then
->integer($result)
->isEqualTo(2)
->array($matches)
->isEqualTo([
0 => [
0 => [
0 => '💩',
1 => 4
],
1 => [
0 => '💩',
1 => 13
]
]
]);
}

public function case_match_all_grouped_by_pattern()
{
$this
->given(
$pattern = '/(💩)/u',
$string = new LUT('foo 💩 bar 💩 baz')
)
->when($result = $string->match($pattern, $matches, $string::GROUP_BY_PATTERN, 0, true))
->then
->integer($result)
->isEqualTo(2)
->array($matches)
->isEqualTo([
0 => [
0 => '💩',
1 => '💩'
],
1 => [
0 => '💩',
1 => '💩'
]
]);
}

public function case_match_all_grouped_by_tuple()
{
$this
->given(
$pattern = '/(💩)/u',
$string = new LUT('foo 💩 bar 💩 baz')
)
->when($result = $string->match($pattern, $matches, $string::GROUP_BY_TUPLE, 0, true))
->then
->integer($result)
->isEqualTo(2)
->array($matches)
->isEqualTo([
0 => [
0 => '💩',
1 => '💩'
],
1 => [
0 => '💩',
1 => '💩'
]
]);
}

public function case_replace()
{
$this
->given($string = new LUT('❤️ 💩 💩'))
->when($result = $string->replace('/💩/u', '😄'))
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('❤️ 😄 😄');
}

public function case_replace_limited()
{
$this
->given($string = new LUT('❤️ 💩 💩'))
->when($result = $string->replace('/💩/u', '😄', 1))
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('❤️ 😄 💩');
}

public function case_split_default()
{
$this
->given($string = new LUT('❤️💩❤️💩❤️'))
->when($result = $string->split('/💩/'))
->then
->array($result)
->isEqualTo([
0 => '❤️',
1 => '❤️',
2 => '❤️'
]);
}

public function case_split_default_limited()
{
$this
->given($string = new LUT('❤️💩❤️💩❤️'))
->when($result = $string->split('/💩/', 1))
->then
->array($result)
->isEqualTo([
0 => '❤️💩❤️💩❤️'
]);
}

public function case_split_with_delimiters()
{
$this
->given($string = new LUT('❤️💩❤️💩❤️'))
->when($result = $string->split('/💩/', -1, $string::WITH_DELIMITERS))
->then
->array($result)
->isEqualTo([
0 => '❤️',
1 => '❤️',
2 => '❤️'
]);
}

public function case_split_with_offset()
{
$this
->given($string = new LUT('❤️💩❤️💩❤️'))
->when($result = $string->split('/💩/', -1, $string::WITH_OFFSET))
->then
->array($result)
->isEqualTo([
0 => [
0 => '❤️',
1 => 0
],
1 => [
0 => '❤️',
1 => 10
],
2 => [
0 => '❤️',
1 => 20
]
]);
}

public function case_iterator_ltr()
{
$this
->given($string = new LUT('je t\'aime'))
->when($result = iterator_to_array($string))
->then
->array($result)
->isEqualTo([
'j',
'e',
' ',
't',
'\'',
'a',
'i',
'm',
'e'
]);
}

public function case_iterator_rtl()
{
$this
->given($string = new LUT('أحبك'))
->when($result = iterator_to_array($string))
->then
->array($result)
->isEqualTo([
'أ',
'ح',
'ب',
'ك'
]);
}

public function case_to_lower()
{
$this
->given($string = new LUT('Σ \'ΑΓΑΠΏ'))
->when($result = $string->toLowerCase())
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('σ \'αγαπώ')

->given($string = new LUT('JE T\'AIME'))
->when($result = $string->toLowerCase())
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('je t\'aime');
}

public function case_to_upper()
{
$this
->given($string = new LUT('σ \'αγαπώ'))
->when($result = $string->toUpperCase())
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('Σ \'ΑΓΑΠΏ')

->given($string = new LUT('je t\'aime'))
->when($result = $string->toUpperCase())
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('JE T\'AIME');
}

public function case_trim_default()
{
$this
->given($string = new LUT('💩💩❤️💩💩'))
->when($result = $string->trim('💩'))
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('❤️');
}

public function case_trim_beginning()
{
$this
->given($string = new LUT('💩💩❤️💩💩'))
->when($result = $string->trim('💩', $string::BEGINNING))
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('❤️💩💩');
}

public function case_trim_end()
{
$this
->given($string = new LUT('💩💩❤️💩💩'))
->when($result = $string->trim('💩', $string::END))
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('💩💩❤️');
}

public function case_offset_get_ltr()
{
$this
->given($string = new LUT('je t\'aime'))
->when($result = $string[0])
->then
->string($result)
->isEqualTo('j')

->when($result = $string[-1])
->then
->string($result)
->isEqualTo('e');
}

public function case_offset_get_rtl()
{
$this
->given($string = new LUT('أحبك'))
->when($result = $string[0])
->then
->string($result)
->isEqualTo('أ')

->when($result = $string[-1])
->then
->string($result)
->isEqualTo('ك');
}

public function case_offset_set()
{
$this
->given($string = new LUT('أحبﻙ'))
->when($string[-1] = 'ك')
->then
->string((string) $string)
->isEqualTo('أحبك');
}

public function case_offset_unset()
{
$this
->given($string = new LUT('أحبك😄'))
->when(function () use ($string) {
unset($string[-1]);
})
->then
->string((string) $string)
->isEqualTo('أحبك');
}

public function case_reduce()
{
$this
->given($string = new LUT('أحبك'))
->when($result = $string->reduce(0, 1))
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('أ');
}

public function case_count()
{
$this
->given($string = new LUT('je t\'aime'))
->when($result = count($string))
->then
->integer($result)
->isEqualTo(9)

->given($string = new LUT('أحبك'))
->when($result = count($string))
->then
->integer($result)
->isEqualTo(4)

->given($string = new LUT('💩'))
->when($result = count($string))
->then
->integer($result)
->isEqualTo(1);
}

public function case_byte_at()
{
$this
->given($string = new LUT('💩'))
->when($result = $string->getByteAt(0))
->then
->integer(ord($result))
->isEqualTo(0xf0)

->when($result = $string->getByteAt(1))
->then
->integer(ord($result))
->isEqualTo(0x9f)

->when($result = $string->getByteAt(2))
->then
->integer(ord($result))
->isEqualTo(0x92)

->when($result = $string->getByteAt(3))
->then
->integer(ord($result))
->isEqualTo(0xa9)

->when($result = $string->getByteAt(-1))
->then
->integer(ord($result))
->isEqualTo(0xa9);
}

public function case_bytes_length()
{
$this
->given($string = new LUT('💩'))
->when($result = $string->getBytesLength())
->then
->integer($result)
->isEqualTo(4);
}

public function case_get_width()
{
$this
->given($string = new LUT('💩'))
->when($result = $string->getWidth())
->then
->integer($result)
->isEqualTo(1)

->given($string = new LUT('習'))
->when($result = $string->getWidth())
->then
->integer($result)
->isEqualTo(2);
}

public function case_get_char_direction()
{
$this
->when($result = LUT::getCharDirection('A'))
->then
->integer($result)
->isEqualTo(LUT::LTR)

->when($result = LUT::getCharDirection('ا'))
->then
->integer($result)
->isEqualTo(LUT::RTL);
}

public function case_get_char_width()
{
$this
->given(
$data = [

 [0x0, 0],
[0x19, -1],
[0x7f, -1],
[0x9f, -1],


 [0xa0, 1],


 [0x300, 0], 
 [0x488, 0], 
 [0x600, 0], 
 [0xad, 1], 
 [0x1160, 0],
[0x11ff, 0],
[0x200b, 0],


 [0x1100, 2],
[0x2160, 1],
[0x3f60, 2],
[0x303f, 1],
[0x2329, 2],
[0xaed0, 2],
[0x232a, 2],
[0xffa4, 1],
[0xfe10, 2],
[0xfe30, 2],
[0xff00, 2],
[0xf900, 2]
]
)
->when(function () use ($data) {
foreach ($data as $datum) {
list($code, $width) = $datum;

$this
->when($result = LUT::getCharWidth(LUT::fromCode($code)))
->then
->integer($result)
->isEqualTo($width);
}
});
}

public function case_is_char_printable()
{
$this
->when($result = LUT::isCharPrintable(LUT::fromCode(0x7f)))
->then
->boolean($result)
->isFalse()

->when($result = LUT::isCharPrintable(LUT::fromCode(0xa0)))
->then
->boolean($result)
->isTrue()

->when($result = LUT::isCharPrintable(LUT::fromCode(0x1100)))
->then
->boolean($result)
->isTrue();
}

public function case_from_code()
{
$this

 ->when($result = LUT::fromCode(0x7e))
->then
->string($result)
->isEqualTo('~')


 ->when($result = LUT::fromCode(0xa7))
->then
->string($result)
->isEqualTo('§')


 ->when($result = LUT::fromCode(0x1207))
->then
->string($result)
->isEqualTo('ሇ')


 ->when($result = LUT::fromCode(0x1f4a9))
->then
->string($result)
->isEqualTo('💩');
}

public function case_to_code()
{
$this

 ->when($result = LUT::toCode('~'))
->then
->integer($result)
->isEqualTo(0x7e)


 ->when($result = LUT::toCode('§'))
->then
->integer($result)
->isEqualTo(0xa7)


 ->when($result = LUT::toCode('ሇ'))
->then
->integer($result)
->isEqualTo(0x1207)


 ->when($result = LUT::toCode('💩'))
->then
->integer($result)
->isEqualTo(0x1f4a9);
}

public function case_to_binary_code()
{
$this

 ->when($result = LUT::toBinaryCode('~'))
->then
->string($result)
->isEqualTo('01111110')


 ->when($result = LUT::toBinaryCode('§'))
->then
->string($result)
->isEqualTo('1100001010100111')


 ->when($result = LUT::toBinaryCode('ሇ'))
->then
->string($result)
->isEqualTo('111000011000100010000111')


 ->when($result = LUT::toBinaryCode('💩'))
->then
->string($result)
->isEqualTo('11110000100111111001001010101001');
}

public function case_transcode_no_iconv()
{
$this
->given(
$this->function->function_exists = function ($name) {
return 'iconv' !== $name;
}
)
->exception(function () {
LUT::transcode('foo', 'UTF-8');
})
->isInstanceOf('Hoa\Ustring\Exception');
}

public function case_transcode_and_isUtf8()
{
$this
->given($uΣ = 'Σ')
->when($Σ = LUT::transcode($uΣ, 'UTF-8', 'UTF-16'))
->then
->string($Σ)
->isNotEqualTo($uΣ)
->boolean(LUT::isUtf8($Σ))
->isFalse()

->when($Σ = LUT::transcode($Σ, 'UTF-16', 'UTF-8'))
->string($Σ)
->isEqualTo($uΣ)
->boolean(LUT::isUtf8($Σ))
->isTrue()
->boolean(LUT::isUtf8($uΣ))
->isTrue();
}

public function case_to_ascii_no_transliterator_no_normalizer()
{
$this
->given(
$this->function->class_exists = function ($name) {
return false === in_array($name, ['Transliterator', 'Normalizer']);
},
$string = new LUT('Un été brûlant sur la côte')
)
->exception(function () use ($string) {
$string->toAscii();
})
->isInstanceOf('Hoa\Ustring\Exception');
}

public function case_to_ascii_no_transliterator_no_normalizer_try()
{
$this
->given(
$this->function->class_exists = function ($name) {
return false === in_array($name, ['Transliterator', 'Normalizer']);
},
$string = new LUT('Un été brûlant sur la côte')
)
->when($result = $string->toAscii(true))
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('Un ete brulant sur la cote');
}

public function case_to_ascii_no_transliterator()
{
$this
->given(
$this->function->class_exists = function ($name) {
return 'Transliterator' !== $name;
},
$string = new LUT('Un été brûlant sur la côte')
)
->when($result = $string->toAscii())
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo('Un ete brulant sur la cote');
}

public function case_to_ascii()
{
$this
->given(
$strings = [
'Un été brûlant sur la côte'
=> 'Un ete brulant sur la cote',

'Αυτή είναι μια δοκιμή'
=> 'Aute einai mia dokime',

'أحبك'
=> 'ahbk',

'キャンパス'
=> 'kyanpasu',

'биологическом'
=> 'biologiceskom',

'정, 병호'
=> 'jeong, byeongho',

'ますだ, よしひこ'
=> 'masuda, yoshihiko',

'मोनिच'
=> 'monica',

'क्ष'
=> 'ksa',

'أحبك 😀'
=> 'ahbk (grinning face)',

'∀ i ∈ ℕ'
=> '(for all) i (element of) N'
]
)
->when(function () use ($strings) {
foreach ($strings as $original => $asciied) {
$this
->given($string = new LUT($original))
->when($result = $string->toAscii())
->then
->object($result)
->isIdenticalTo($string)
->string((string) $result)
->isEqualTo($asciied);
}
});
}

public function case_copy()
{
$this
->given($string = new LUT('foo'))
->when($result = $string->copy())
->then
->object($result)
->isEqualTo($string);
}

public function case_toString()
{
$this
->given($datum = $this->sample($this->realdom->regex('/\w{7,42}/')))
->when($result = new LUT($datum))
->then
->castToString($result)
->isEqualTo($datum);
}
}
<?php



































namespace Hoa\Ustring;

use Hoa\Exception as HoaException;









class Exception extends HoaException
{
}
<?php



































namespace Hoa\Ustring\Bin;

use Hoa\Console;
use Hoa\Ustring;









class Tocode extends Console\Dispatcher\Kit
{





protected $options = [
['base', Console\GetOption::REQUIRED_ARGUMENT, 'b'],
['help', Console\GetOption::NO_ARGUMENT, 'h'],
['help', Console\GetOption::NO_ARGUMENT, '?']
];








public function main()
{
$base = 16;

while (false !== $c = $this->getOption($v)) {
switch ($c) {
case 'b':
$base = intval($v);

break;

case '__ambiguous':
$this->resolveOptionAmbiguity($v);

break;

case 'h':
case '?':
default:
return $this->usage();
}
}

$this->parser->listInputs($char);

$code = base_convert((string) Ustring::toCode($char), 10, $base);

echo $code, "\n";

return;
}






public function usage()
{
echo
'Usage   : ustring:tocode <char>', "\n",
'Options :', "\n",
$this->makeUsageOptionsList([
'b' => 'Get the code in a specific base (16 by default).',
'help' => 'This help.'
]), "\n";

return;
}
}

__halt_compiler();
Transform a character into its code.
<?php



































namespace Hoa\Ustring\Bin;

use Hoa\Console;
use Hoa\Ustring;









class Fromcode extends Console\Dispatcher\Kit
{





protected $options = [
['base', Console\GetOption::REQUIRED_ARGUMENT, 'b'],
['help', Console\GetOption::NO_ARGUMENT, 'h'],
['help', Console\GetOption::NO_ARGUMENT, '?']
];








public function main()
{
$base = 16;

while (false !== $c = $this->getOption($v)) {
switch ($c) {
case 'b':
$base = intval($v);

break;

case '__ambiguous':
$this->resolveOptionAmbiguity($v);

break;

case 'h':
case '?':
default:
return $this->usage();
}
}

$this->parser->listInputs($code);

$char = Ustring::fromCode(base_convert($code, $base, 10));

echo $char;

return;
}






public function usage()
{
echo
'Usage   : ustring:fromcode <char>', "\n",
'Options :', "\n",
$this->makeUsageOptionsList([
'b' => 'Specify the base of the code (16 by default).',
'help' => 'This help.'
]), "\n";

return;
}
}

__halt_compiler();
Get a character from its code.
<?php



































namespace Hoa\Ustring;

use Hoa\Consistency;













class Ustring implements \ArrayAccess, \Countable, \IteratorAggregate
{





const LTR = 0;






const RTL = 1;






const BOM = 0xfeff;






const LRM = 0x200e;






const RLM = 0x200f;






const LRE = 0x202a;






const RLE = 0x202b;






const PDF = 0x202c;






const LRO = 0x202d;






const RLO = 0x202e;






const BEGINNING = 1;






const END = 2;






const WITHOUT_EMPTY = PREG_SPLIT_NO_EMPTY;







const WITH_DELIMITERS = PREG_SPLIT_DELIM_CAPTURE;






const WITH_OFFSET = 260; 
 






const GROUP_BY_PATTERN = PREG_PATTERN_ORDER;






const GROUP_BY_TUPLE = PREG_SET_ORDER;






protected $_string = null;






protected $_direction = null;






protected static $_collator = null;








public function __construct($string = null)
{
if (null !== $string) {
$this->append($string);
}

return;
}






public static function checkMbString()
{
return function_exists('mb_substr');
}






public static function checkIconv()
{
return function_exists('iconv');
}







public function append($substring)
{
$this->_string .= $substring;

return $this;
}







public function prepend($substring)
{
$this->_string = $substring . $this->_string;

return $this;
}










public function pad($length, $piece, $side = self::END)
{
$difference = $length - $this->count();

if (0 >= $difference) {
return $this;
}

$handle = null;

for ($i = $difference / mb_strlen($piece) - 1; $i >= 0; --$i) {
$handle .= $piece;
}

$handle .= mb_substr($piece, 0, $difference - mb_strlen($handle));

return
static::END === $side
? $this->append($handle)
: $this->prepend($handle);
}









public function compare($string)
{
if (null === $collator = static::getCollator()) {
return strcmp($this->_string, (string) $string);
}

return $collator->compare($this->_string, $string);
}






public static function getCollator()
{
if (false === class_exists('Collator')) {
return null;
}

if (null === static::$_collator) {
static::$_collator = new \Collator(setlocale(LC_COLLATE, null));
}

return static::$_collator;
}







public static function safePattern($pattern)
{
$delimiter = mb_substr($pattern, 0, 1);
$options = mb_substr(
mb_strrchr($pattern, $delimiter, false),
mb_strlen($delimiter)
);

if (false === strpos($options, 'u')) {
$pattern .= 'u';
}

return $pattern;
}














public function match(
$pattern,
&$matches = null,
$flags = 0,
$offset = 0,
$global = false
) {
$pattern = static::safePattern($pattern);

if (0 === $flags) {
if (true === $global) {
$flags = static::GROUP_BY_PATTERN;
}
} else {
$flags &= ~PREG_SPLIT_OFFSET_CAPTURE;
}


$offset = strlen(mb_substr($this->_string, 0, $offset));

if (true === $global) {
return preg_match_all(
$pattern,
$this->_string,
$matches,
$flags,
$offset
);
}

return preg_match($pattern, $this->_string, $matches, $flags, $offset);
}










public function replace($pattern, $replacement, $limit = -1)
{
$pattern = static::safePattern($pattern);

if (false === is_callable($replacement)) {
$this->_string = preg_replace(
$pattern,
$replacement,
$this->_string,
$limit
);
} else {
$this->_string = preg_replace_callback(
$pattern,
$replacement,
$this->_string,
$limit
);
}

return $this;
}










public function split(
$pattern,
$limit = -1,
$flags = self::WITHOUT_EMPTY
) {
return preg_split(
static::safePattern($pattern),
$this->_string,
$limit,
$flags
);
}






public function getIterator()
{
return new \ArrayIterator(preg_split('#(?<!^)(?!$)#u', $this->_string));
}






public function toLowerCase()
{
$this->_string = mb_strtolower($this->_string);

return $this;
}






public function toUpperCase()
{
$this->_string = mb_strtoupper($this->_string);

return $this;
}










public function toAscii($try = false)
{
if (0 === preg_match('#[\x80-\xff]#', $this->_string)) {
return $this;
}

$string = $this->_string;
$transId =
'Any-Latin; ' .
'[\p{S}] Name; ' .
'Latin-ASCII';

if (null !== $transliterator = static::getTransliterator($transId)) {
$this->_string = preg_replace_callback(
'#\\\N\{([A-Z ]+)\}#u',
function (array $matches) {
return '(' . strtolower($matches[1]) . ')';
},
$transliterator->transliterate($string)
);

return $this;
}

if (false === class_exists('Normalizer')) {
if (false === $try) {
throw new Exception(
'%s needs the class Normalizer to work properly, ' .
'or you can force a try by using %1$s(true).',
0,
__METHOD__
);
}

$string = static::transcode($string, 'UTF-8', 'ASCII//IGNORE//TRANSLIT');
$this->_string = preg_replace('#(?:[\'"`^](\w))#u', '\1', $string);

return $this;
}

$string = \Normalizer::normalize($string, \Normalizer::NFKD);
$string = preg_replace('#\p{Mn}+#u', '', $string);
$this->_string = static::transcode($string, 'UTF-8', 'ASCII//IGNORE//TRANSLIT');

return $this;
}











public function transliterate($identifier, $start = 0, $end = null)
{
if (null === $transliterator = static::getTransliterator($identifier)) {
throw new Exception(
'%s needs the class Transliterator to work properly.',
1,
__METHOD__
);
}

$this->_string = $transliterator->transliterate($this->_string, $start, $end);

return $this;
}








public static function getTransliterator($identifier)
{
if (false === class_exists('Transliterator')) {
return null;
}

return \Transliterator::create($identifier);
}









public function trim($regex = '\s', $side = 3 )
{
$regex = '(?:' . $regex . ')+';
$handle = null;

if (0 !== ($side & static::BEGINNING)) {
$handle .= '(^' . $regex . ')';
}

if (0 !== ($side & static::END)) {
if (null !== $handle) {
$handle .= '|';
}

$handle .= '(' . $regex . '$)';
}

$this->_string = preg_replace('#' . $handle . '#u', '', $this->_string);
$this->_direction = null;

return $this;
}







protected function computeOffset($offset)
{
$length = mb_strlen($this->_string);

if (0 > $offset) {
$offset = -$offset % $length;

if (0 !== $offset) {
$offset = $length - $offset;
}
} elseif ($offset >= $length) {
$offset %= $length;
}

return $offset;
}







public function offsetGet($offset)
{
return mb_substr($this->_string, $this->computeOffset($offset), 1);
}








public function offsetSet($offset, $value)
{
$head = null;
$offset = $this->computeOffset($offset);

if (0 < $offset) {
$head = mb_substr($this->_string, 0, $offset);
}

$tail = mb_substr($this->_string, $offset + 1);
$this->_string = $head . $value . $tail;
$this->_direction = null;

return $this;
}







public function offsetUnset($offset)
{
return $this->offsetSet($offset, null);
}






public function offsetExists($offset)
{
return true;
}








public function reduce($start, $length = null)
{
$this->_string = mb_substr($this->_string, $start, $length);

return $this;
}






public function count()
{
return mb_strlen($this->_string);
}







public function getByteAt($offset)
{
$length = strlen($this->_string);

if (0 > $offset) {
$offset = -$offset % $length;

if (0 !== $offset) {
$offset = $length - $offset;
}
} elseif ($offset >= $length) {
$offset %= $length;
}

return $this->_string[$offset];
}






public function getBytesLength()
{
return strlen($this->_string);
}








public function getWidth()
{
return mb_strwidth($this->_string);
}








public function getDirection()
{
if (null === $this->_direction) {
if (null === $this->_string) {
$this->_direction = static::LTR;
} else {
$this->_direction = static::getCharDirection(
mb_substr($this->_string, 0, 1)
);
}
}

return $this->_direction;
}








public static function getCharDirection($char)
{
$c = static::toCode($char);

if (!(0x5be <= $c && 0x10b7f >= $c)) {
return static::LTR;
}

if (0x85e >= $c) {
if (0x5be === $c ||
0x5c0 === $c ||
0x5c3 === $c ||
0x5c6 === $c ||
(0x5d0 <= $c && 0x5ea >= $c) ||
(0x5f0 <= $c && 0x5f4 >= $c) ||
0x608 === $c ||
0x60b === $c ||
0x60d === $c ||
0x61b === $c ||
(0x61e <= $c && 0x64a >= $c) ||
(0x66d <= $c && 0x66f >= $c) ||
(0x671 <= $c && 0x6d5 >= $c) ||
(0x6e5 <= $c && 0x6e6 >= $c) ||
(0x6ee <= $c && 0x6ef >= $c) ||
(0x6fa <= $c && 0x70d >= $c) ||
0x710 === $c ||
(0x712 <= $c && 0x72f >= $c) ||
(0x74d <= $c && 0x7a5 >= $c) ||
0x7b1 === $c ||
(0x7c0 <= $c && 0x7ea >= $c) ||
(0x7f4 <= $c && 0x7f5 >= $c) ||
0x7fa === $c ||
(0x800 <= $c && 0x815 >= $c) ||
0x81a === $c ||
0x824 === $c ||
0x828 === $c ||
(0x830 <= $c && 0x83e >= $c) ||
(0x840 <= $c && 0x858 >= $c) ||
0x85e === $c) {
return static::RTL;
}
} elseif (0x200f === $c) {
return static::RTL;
} elseif (0xfb1d <= $c) {
if (0xfb1d === $c ||
(0xfb1f <= $c && 0xfb28 >= $c) ||
(0xfb2a <= $c && 0xfb36 >= $c) ||
(0xfb38 <= $c && 0xfb3c >= $c) ||
0xfb3e === $c ||
(0xfb40 <= $c && 0xfb41 >= $c) ||
(0xfb43 <= $c && 0xfb44 >= $c) ||
(0xfb46 <= $c && 0xfbc1 >= $c) ||
(0xfbd3 <= $c && 0xfd3d >= $c) ||
(0xfd50 <= $c && 0xfd8f >= $c) ||
(0xfd92 <= $c && 0xfdc7 >= $c) ||
(0xfdf0 <= $c && 0xfdfc >= $c) ||
(0xfe70 <= $c && 0xfe74 >= $c) ||
(0xfe76 <= $c && 0xfefc >= $c) ||
(0x10800 <= $c && 0x10805 >= $c) ||
0x10808 === $c ||
(0x1080a <= $c && 0x10835 >= $c) ||
(0x10837 <= $c && 0x10838 >= $c) ||
0x1083c === $c ||
(0x1083f <= $c && 0x10855 >= $c) ||
(0x10857 <= $c && 0x1085f >= $c) ||
(0x10900 <= $c && 0x1091b >= $c) ||
(0x10920 <= $c && 0x10939 >= $c) ||
0x1093f === $c ||
0x10a00 === $c ||
(0x10a10 <= $c && 0x10a13 >= $c) ||
(0x10a15 <= $c && 0x10a17 >= $c) ||
(0x10a19 <= $c && 0x10a33 >= $c) ||
(0x10a40 <= $c && 0x10a47 >= $c) ||
(0x10a50 <= $c && 0x10a58 >= $c) ||
(0x10a60 <= $c && 0x10a7f >= $c) ||
(0x10b00 <= $c && 0x10b35 >= $c) ||
(0x10b40 <= $c && 0x10b55 >= $c) ||
(0x10b58 <= $c && 0x10b72 >= $c) ||
(0x10b78 <= $c && 0x10b7f >= $c)) {
return static::RTL;
}
}

return static::LTR;
}
















public static function getCharWidth($char)
{
$char = (string) $char;
$c = static::toCode($char);


 if (0x0 === $c) {
return 0;
}

if (0x20 > $c || (0x7f <= $c && $c < 0xa0)) {
return -1;
}


 if (0xad !== $c &&
0 !== preg_match('#^[\p{Mn}\p{Me}\p{Cf}\x{1160}-\x{11ff}\x{200b}]#u', $char)) {
return 0;
}


 return 1 +
(0x1100 <= $c &&
(0x115f >= $c || 
 0x2329 === $c || 0x232a === $c ||
(0x2e80 <= $c && 0xa4cf >= $c &&
0x303f !== $c) || 
 (0xac00 <= $c && 0xd7a3 >= $c) || 
 (0xf900 <= $c && 0xfaff >= $c) || 
 (0xfe10 <= $c && 0xfe19 >= $c) || 
 (0xfe30 <= $c && 0xfe6f >= $c) || 
 (0xff00 <= $c && 0xff60 >= $c) || 
 (0xffe0 <= $c && 0xffe6 >= $c) ||
(0x20000 <= $c && 0x2fffd >= $c) ||
(0x30000 <= $c && 0x3fffd >= $c)));
}







public static function isCharPrintable($char)
{
return 1 <= static::getCharWidth($char);
}







public static function fromCode($code)
{
return mb_convert_encoding(
'&#x' . dechex($code) . ';',
'UTF-8',
'HTML-ENTITIES'
);
}







public static function toCode($char)
{
$char = (string) $char;
$code = ord($char[0]);
$bytes = 1;

if (!($code & 0x80)) { 
 return $code;
}

if (($code & 0xe0) === 0xc0) { 
 $bytes = 2;
$code = $code & ~0xc0;
} elseif (($code & 0xf0) == 0xe0) { 
 $bytes = 3;
$code = $code & ~0xe0;
} elseif (($code & 0xf8) === 0xf0) { 
 $bytes = 4;
$code = $code & ~0xf0;
}

for ($i = 2; $i <= $bytes; $i++) { 
 $code = ($code << 6) + (ord($char[$i - 1]) & ~0x80);
}

return $code;
}







public static function toBinaryCode($char)
{
$char = (string) $char;
$out = null;

for ($i = 0, $max = strlen($char); $i < $max; ++$i) {
$out .= vsprintf('%08b', ord($char[$i]));
}

return $out;
}










public static function transcode($string, $from, $to = 'UTF-8')
{
if (false === static::checkIconv()) {
throw new Exception(
'%s needs the iconv extension.',
2,
__CLASS__
);
}

return iconv($from, $to, $string);
}







public static function isUtf8($string)
{
return (bool) preg_match('##u', $string);
}






public function copy()
{
return clone $this;
}






public function __toString()
{
return $this->_string;
}
}




Consistency::flexEntity('Hoa\Ustring\Ustring');

if (false === Ustring::checkMbString()) {
throw new Exception(
'%s needs the mbstring extension.',
0,
__NAMESPACE__ . '\Ustring'
);
}
<?php



































namespace Hoa\Protocol;

use Hoa\Consistency;









class Protocol extends Node
{





const NO_RESOLUTION = '/hoa/flatland';






private static $_instance = null;






private static $_cache = [];







public function __construct()
{
$this->initialize();

return;
}







public static function getInstance()
{
if (null === static::$_instance) {
static::$_instance = new static();
}

return static::$_instance;
}






protected function initialize()
{
$root = dirname(dirname(__DIR__));
$cwd =
'cli' === PHP_SAPI
? dirname(realpath($_SERVER['argv'][0]))
: getcwd();

$this[] = new Node(
'Application',
$cwd . DS,
[
new Node('Public', 'Public' . DS)
]
);

$this[] = new Node(
'Data',
dirname($cwd) . DS,
[
new Node(
'Etc',
'Etc' . DS,
[
new Node('Configuration', 'Configuration' . DS),
new Node('Locale', 'Locale' . DS)
]
),
new Node('Lost+found', 'Lost+found' . DS),
new Node('Temporary', 'Temporary' . DS),
new Node(
'Variable',
'Variable' . DS,
[
new Node('Cache', 'Cache' . DS),
new Node('Database', 'Database' . DS),
new Node('Log', 'Log' . DS),
new Node('Private', 'Private' . DS),
new Node('Run', 'Run' . DS),
new Node('Test', 'Test' . DS)
]
)
]
);

$this[] = new Node\Library(
'Library',
$root . DS . 'Hoathis' . DS . RS .
$root . DS . 'Hoa' . DS
);

return;
}










public function resolve($path, $exists = true, $unfold = false)
{
if (substr($path, 0, 6) !== 'hoa://') {
if (true === is_dir($path)) {
$path = rtrim($path, '/\\');

if (0 === strlen($path)) {
$path = '/';
}
}

return $path;
}

if (isset(self::$_cache[$path])) {
$handle = self::$_cache[$path];
} else {
$out = $this->_resolve($path, $handle);


 if (!is_array($handle)) {
return $out;
}

$handle = array_values(array_unique($handle, SORT_REGULAR));

foreach ($handle as &$entry) {
if (true === is_dir($entry)) {
$entry = rtrim($entry, '/\\');

if (0 === strlen($entry)) {
$entry = '/';
}
}
}

self::$_cache[$path] = $handle;
}

if (true === $unfold) {
if (true !== $exists) {
return $handle;
}

$out = [];

foreach ($handle as $solution) {
if (file_exists($solution)) {
$out[] = $solution;
}
}

return $out;
}

if (true !== $exists) {
return $handle[0];
}

foreach ($handle as $solution) {
if (file_exists($solution)) {
return $solution;
}
}

return static::NO_RESOLUTION;
}






public static function clearCache()
{
self::$_cache = [];

return;
}
}




Consistency::flexEntity('Hoa\Protocol\Protocol');
<?php



































namespace Hoa\Protocol\Test\Unit;

use Hoa\Protocol\Protocol as SUT;
use Hoa\Test;









class Protocol extends Test\Unit\Suite
{
public function case_root_is_a_node()
{
$this
->when($result = SUT::getInstance())
->then
->object($result)
->isInstanceOf('Hoa\Protocol\Node');
}

public function case_default_tree()
{
$this
->when($result = SUT::getInstance())
->then
->object($result['Application'])->isInstanceOf('Hoa\Protocol\Node\Node')
->object($result['Application']['Public'])->isInstanceOf('Hoa\Protocol\Node\Node')
->object($result['Data'])->isInstanceOf('Hoa\Protocol\Node\Node')
->object($result['Data']['Etc'])->isInstanceOf('Hoa\Protocol\Node\Node')
->object($result['Data']['Etc']['Configuration'])->isInstanceOf('Hoa\Protocol\Node\Node')
->object($result['Data']['Etc']['Locale'])->isInstanceOf('Hoa\Protocol\Node\Node')
->object($result['Data']['Lost+found'])->isInstanceOf('Hoa\Protocol\Node\Node')
->object($result['Data']['Temporary'])->isInstanceOf('Hoa\Protocol\Node\Node')
->object($result['Data']['Variable'])->isInstanceOf('Hoa\Protocol\Node\Node')
->object($result['Data']['Variable']['Cache'])->isInstanceOf('Hoa\Protocol\Node\Node')
->object($result['Data']['Variable']['Database'])->isInstanceOf('Hoa\Protocol\Node\Node')
->object($result['Data']['Variable']['Log'])->isInstanceOf('Hoa\Protocol\Node\Node')
->object($result['Data']['Variable']['Private'])->isInstanceOf('Hoa\Protocol\Node\Node')
->object($result['Data']['Variable']['Run'])->isInstanceOf('Hoa\Protocol\Node\Node')
->object($result['Data']['Variable']['Test'])->isInstanceOf('Hoa\Protocol\Node\Node')
->object($result['Library'])->isInstanceOf('Hoa\Protocol\Node\Library')
->string($result['Library']->reach())
->isEqualTo(
dirname(dirname(dirname(dirname(__DIR__)))) . DS . 'hoathis' . DS .
RS .
dirname(dirname(dirname(dirname(__DIR__)))) . DS . 'hoa' . DS
);
}

public function case_resolve_not_a_hoa_path()
{
$this
->given($protocol = SUT::getInstance())
->when($result = $protocol->resolve('/foo/bar'))
->then
->string($result)
->isEqualTo('/foo/bar');
}

public function case_resolve_to_non_existing_resource()
{
$this
->given($protocol = SUT::getInstance())
->when($result = $protocol->resolve('hoa://Application/Foo/Bar'))
->then
->string($result)
->isEqualTo(SUT::NO_RESOLUTION);
}

public function case_resolve_does_not_test_if_exists()
{
$this
->given($protocol = SUT::getInstance())
->when($result = $protocol->resolve('hoa://Application/Foo/Bar', false))
->then
->string($result)
->isEqualTo('/Foo/Bar');
}

public function case_resolve_unfold_to_existing_resources()
{
$this
->given($protocol = SUT::getInstance())
->when($result = $protocol->resolve('hoa://Library', true, true))
->then
->array($result)
->contains(
dirname(dirname(dirname(dirname(__DIR__)))) . DS . 'hoa'
);
}

public function case_resolve_unfold_to_non_existing_resources()
{
$this
->given(
$parentHoaDirectory = dirname(dirname(dirname(dirname(__DIR__)))),
$protocol = SUT::getInstance()
)
->when($result = $protocol->resolve('hoa://Library', false, true))
->then
->array($result)
->isEqualTo([
$parentHoaDirectory . DS . 'hoathis',
$parentHoaDirectory . DS . 'hoa'
]);
}
}
<?php



































namespace Hoa\Protocol\Test\Unit;

use Hoa\Protocol as LUT;
use Hoa\Protocol\Wrapper as SUT;
use Hoa\Test;









class Wrapper extends Test\Unit\Suite
{
public function case_stream_cast_for_select()
{
$this
->given($wrapper = new SUT())
->when($result = $wrapper->stream_cast(STREAM_CAST_FOR_SELECT))
->then
->boolean($result)
->isFalse();
}

public function case_stream_cast_as_stream()
{
$this
->given($wrapper = new SUT())
->when($result = $wrapper->stream_cast(STREAM_CAST_AS_STREAM))
->then
->boolean($result)
->isFalse();
}

public function case_stream_close()
{
$this
->given(
$wrapper = new SUT(),
$this->openFile($wrapper)
)
->when($result = $wrapper->stream_close())
->then
->variable($result)
->isNull()
->variable($wrapper->getStream())
->isNull()
->variable($wrapper->getStreamName())
->isNull();
}

public function case_stream_not_eof()
{
$this
->given(
$wrapper = new SUT(),
$this->openFile($wrapper, 'foo'),
fseek($wrapper->getStream(), 0, SEEK_SET)
)
->when($result = $wrapper->stream_eof())
->then
->boolean($result)
->isFalse();
}

public function case_stream_eof()
{
$this
->given(
$this->function->feof = true,
$wrapper = new SUT()
)
->when($result = $wrapper->stream_eof())
->then
->boolean($result)
->isTrue();
}

public function case_stream_flush()
{
$this
->given(
$wrapper = new SUT(),
$this->openFile($wrapper)
)
->when($result = $wrapper->stream_flush())
->then
->boolean($result)
->isTrue();
}

public function _case_stream_xxx_lock($operation)
{
$this
->given(
$this->function->flock = function ($resource, $operation) use (&$_resource, &$_operation) {
$_resource = $resource;
$_operation = $operation;

if ($operation === LOCK_NB) {
return true;
}

return flock($resource, $operation);
},
$wrapper = new SUT(),
$this->openFile($wrapper)
)
->when($result = $wrapper->stream_lock($operation))
->then
->boolean($result)
->isTrue()
->resource($_resource)
->isStream()
->isIdenticalTo($wrapper->getStream())
->integer($_operation)
->isEqualTo($operation);
}

public function case_stream_shared_lock()
{
return $this->_case_stream_xxx_lock(LOCK_SH);
}

public function case_stream_exclusive_lock()
{
return $this->_case_stream_xxx_lock(LOCK_EX);
}

public function case_stream_release_lock()
{
return $this->_case_stream_xxx_lock(LOCK_UN);
}

public function case_stream_not_blocking_lock()
{
return $this->_case_stream_xxx_lock(LOCK_NB);
}

public function _case_metadata_touch_with_xxx_arguments($arguments, $path, $time, $atime)
{
$this
->given(
$this->function->touch = function ($path, $time, $atime) use (&$_path, &$_time, &$_atime) {
$_path = $path;
$_time = $time;
$_atime = $atime;

return true;
},
$wrapper = new SUT()
)
->when($result = $wrapper->stream_metadata($path, STREAM_META_TOUCH, $arguments))
->then
->boolean($result)
->isTrue()
->string($_path)
->isEqualTo($path)
->variable($_time)
->isEqualTo($time)
->variable($_atime)
->isEqualTo($atime);
}

public function case_metadata_touch_with_no_argument()
{
return $this->_case_metadata_touch_with_xxx_arguments([], 'foo', null, null);
}

public function case_metadata_touch_with_time()
{
return $this->_case_metadata_touch_with_xxx_arguments([42], 'foo', 42, null);
}

public function case_metadata_touch_with_time_and_atime()
{
return $this->_case_metadata_touch_with_xxx_arguments([42, 777], 'foo', 42, 777);
}

public function _case_metadata_owner_xxx($owner)
{
$this
->given(
$this->function->chown = function ($path, $user) use (&$_path, &$_user) {
$_path = $path;
$_user = $user;

return true;
},
$path = 'foo',
$user = 'gordon',
$wrapper = new SUT()
)
->when($result = $wrapper->stream_metadata('foo', $owner, $user))
->then
->boolean($result)
->isTrue()
->string($path)
->isEqualTo($_path)
->string($user)
->isEqualTo($_user);
}

public function case_metadata_owner()
{
return $this->_case_metadata_owner_xxx(STREAM_META_OWNER);
}

public function case_metadata_owner_name()
{
return $this->_case_metadata_owner_xxx(STREAM_META_OWNER_NAME);
}

public function _case_metadata_group_xxx($grp)
{
$this
->given(
$this->function->chgrp = function ($path, $group) use (&$_path, &$_group) {
$_path = $path;
$_group = $group;

return true;
},
$path = 'foo',
$group = 'root',
$wrapper = new SUT()
)
->when($result = $wrapper->stream_metadata('foo', $grp, $group))
->then
->boolean($result)
->isTrue()
->string($path)
->isEqualTo($_path)
->string($group)
->isEqualTo($_group);
}

public function case_metadata_group()
{
return $this->_case_metadata_group_xxx(STREAM_META_GROUP);
}

public function case_metadata_group_name()
{
return $this->_case_metadata_group_xxx(STREAM_META_GROUP_NAME);
}

public function case_metadata_access()
{
$this
->given(
$this->function->chmod = function ($path, $mode) use (&$_path, &$_mode) {
$_path = $path;
$_mode = $mode;

return true;
},
$path = 'foo',
$mode = 0755,
$wrapper = new SUT()
)
->when($result = $wrapper->stream_metadata('foo', STREAM_META_ACCESS, $mode))
->then
->boolean($result)
->isTrue()
->string($path)
->isEqualTo($_path)
->integer($mode)
->isEqualTo($_mode);
}

public function case_metadata_default()
{
$this
->given(
$option = 0,
$mode = 0,
$wrapper = new SUT()
)
->when($result = $wrapper->stream_metadata('foo', $option, $mode))
->then
->boolean($result)
->isFalse();
}

public function case_stream_open()
{
$this
->given(
$this->function->fopen = function ($path, $mode, $options) use (&$_path, &$_mode, &$_options, &$_openedPath) {
$_path = $path;
$_mode = $mode;
$_options = $options;

return fopen($path, $mode, $options);
},
$wrapper = new SUT(),
$path = 'hoa://Test/Vfs/Foo?type=file',
$mode = 'r',
$options = STREAM_USE_PATH
)
->when($result = $wrapper->stream_open($path, $mode, $options, $openedPath))
->then
->boolean($result)
->isTrue()
->string(SUT::realPath($path, true))
->isEqualTo($_path)
->string($mode)
->isEqualTo($_mode)
->integer($options)
->isEqualTo($_options & STREAM_USE_PATH)
->resource($openedPath)
->isStream()
->isIdenticalTo($wrapper->getStream())
->string($wrapper->getStreamName())
->isEqualTo('atoum://Foo');
}

public function case_stream_open_not_hoa_protocol()
{
$this
->given(
$wrapper = new SUT(),
$path = LUT::NO_RESOLUTION,
$mode = 'r',
$options = STREAM_USE_PATH
)
->when($result = $wrapper->stream_open($path, $mode, $options, $openedPath))
->then
->boolean($result)
->isFalse();
}

public function case_stream_open_not_a_resource()
{
$this
->given(
$this->function->fopen = function ($path, $mode, $options) use (&$_path, &$_mode, &$_options, &$_openedPath) {
$_path = $path;
$_mode = $mode;
$_options = $options;

return fopen($path, $mode, $options);
},
$this->function->is_resource = false,

$wrapper = new SUT(),
$path = 'hoa://Test/Vfs/Foo?type=file',
$mode = 'r',
$options = STREAM_USE_PATH
)
->when($result = $wrapper->stream_open($path, $mode, $options, $openedPath))
->then
->boolean($result)
->isFalse()
->string(SUT::realPath($path, true))
->isEqualTo($_path)
->string($mode)
->isEqualTo($_mode)
->integer($options)
->isEqualTo($_options & STREAM_USE_PATH)
->resource($openedPath)
->isStream();
}

public function case_stream_read()
{
$this
->given(
$this->function->fread = function ($resource, $count) use (&$_resource, &$_count) {
$_resource = $resource;
$_count = $count;

return fread($resource, $count);
},
$wrapper = new SUT(),
$count = 42,
$this->openFile($wrapper, str_repeat('@', $count))
)
->when($result = $wrapper->stream_read($count))
->then
->string($result)
->hasLength($count)
->resource($_resource)
->isStream()
->isIdenticalTo($wrapper->getStream())
->integer($_count)
->isEqualTo($count);
}

public function _case_stream_seek_xxx($offset, $whence)
{
return
$this
->given(
$this->function->fseek = function ($resource, $offset, $whence) use (&$_resource, &$_offset, &$_whence) {
$_resource = $resource;
$_offset = $offset;
$_whence = $whence;

return fseek($resource, $offset, $whence);
},
$wrapper = new SUT(),
$this->openFile($wrapper, 'foobar')
)
->when($result = $wrapper->stream_seek($offset, $whence))
->then
->boolean($result)
->isTrue()
->resource($_resource)
->isStream()
->isIdenticalTo($wrapper->getStream())
->integer($offset)
->isEqualTo($_offset)
->integer($whence)
->isEqualTo($_whence)
->integer(ftell($wrapper->getStream()));
}

public function case_stream_seek_set()
{
return
$this
->_case_stream_seek_xxx(3, SEEK_SET)
->isEqualTo(3);
}

public function case_stream_seek_current()
{
return
$this
->_case_stream_seek_xxx(4, SEEK_CUR)
->isEqualTo(4);
}

public function case_stream_seek_end()
{
return
$this
->_case_stream_seek_xxx(-4, SEEK_END)
->isEqualTo(2);
}

public function case_stream_stat()
{
$this
->given(
$this->function->fstat = function ($resource) use (&$_resource) {
$_resource = $resource;

return fstat($resource);
},
$wrapper = new SUT(),
$this->openFile($wrapper)
)
->when($result = $wrapper->stream_stat())
->then
->array($result)
->resource($_resource)
->isStream()
->isIdenticalTo($wrapper->getStream());
}

public function case_stream_tell()
{
$this
->given(
$this->function->ftell = function ($resource) use (&$_resource) {
$_resource = $resource;

return ftell($resource);
},
$wrapper = new SUT(),
$this->openFile($wrapper, 'foo'),
$wrapper->stream_seek(2)
)
->when($result = $wrapper->stream_tell())
->then
->integer($result)
->isEqualTo(2)
->resource($_resource)
->isStream()
->isIdenticalTo($wrapper->getStream());
}

public function case_stream_truncate()
{
$this
->given(
$this->function->ftruncate = function ($resource, $size) use (&$_resource, &$_size) {
$_resource = $resource;
$_size = $size;

return ftruncate($resource, $size);
},
$wrapper = new SUT(),
$this->openFile($wrapper, 'foobar'),
$size = 3
)
->when($result = $wrapper->stream_truncate($size))
->then
->boolean($result)
->isTrue()
->resource($_resource)
->isStream()
->isIdenticalTo($wrapper->getStream())
->integer($size)
->isEqualTo($_size)
->integer($wrapper->stream_tell())
->isEqualTo(0)
->let($wrapper->stream_seek(0, SEEK_END))
->integer($wrapper->stream_tell())
->isEqualTo(3);
}

public function case_stream_write()
{
$this
->given(
$this->function->fwrite = function ($resource, $data) use (&$_resource, &$_data) {
$_resource = $resource;
$_data = $data;

return fwrite($resource, $data);
},
$wrapper = new SUT(),
$wrapper->stream_open('hoa://Test/Vfs/Foo?type=file', 'wb+', STREAM_USE_PATH, $openedPath),
$data = 'foo'
)
->when($result = $wrapper->stream_write($data))
->then
->integer($result)
->isEqualTo(strlen($data))
->resource($_resource)
->isStream()
->isIdenticalTo($wrapper->getStream())
->string($_data)
->isEqualTo($data)
->let($wrapper->stream_seek(0))
->string($wrapper->stream_read(3))
->isEqualTo($data);
}

public function case_dir_closedir()
{
$this
->given(
$wrapper = new SUT(),
$this->openDirectory($wrapper)
)
->when($result = $wrapper->dir_closedir())
->then
->variable($result)
->isNull()
->variable($wrapper->getStream())
->isNull()
->variable($wrapper->getStreamName())
->isNull();
}

public function case_dir_opendir()
{
$this
->given(
$this->function->opendir = function ($path) use (&$_path) {
$_path = $path;

return opendir($path);
},
$wrapper = new SUT(),
$path = 'hoa://Test/Vfs/Bar?type=directory',
$options = 0
)
->when($result = $wrapper->dir_opendir($path, $options))
->then
->boolean($result)
->isTrue()
->string(SUT::realPath($path, true))
->isEqualTo($_path)
->resource($wrapper->getStream())
->isStream()
->string($wrapper->getStreamName())
->isEqualTo('atoum://Bar');
}

public function case_dir_opendir_not_a_resource()
{
$this
->given(
$this->function->opendir = function ($path) use (&$_path) {
$_path = $path;

return false;
},
$wrapper = new SUT(),
$path = 'hoa://Test/Vfs/Bar?type=directory',
$options = 0
)
->when($result = $wrapper->dir_opendir($path, $options))
->then
->boolean($result)
->isFalse()
->string(SUT::realPath($path, true))
->isEqualTo($_path)
->variable($wrapper->getStream())
->isNull()
->variable($wrapper->getStreamName())
->isNull();
}

public function case_dir_readdir()
{
$this
->given(
$this->function->readdir = function ($resource) use (&$_resource) {
$_resource = $resource;

return readdir($resource);
},
$wrapper = new SUT(),
$this->openDirectory($wrapper, ['Baz', 'Qux'])
)
->when($result = $wrapper->dir_readdir())
->then
->string($result)
->isEqualTo('Baz')
->resource($_resource)
->isIdenticalTo($wrapper->getStream());
}

public function case_dir_readdir_until_eod()
{
$this
->given(
$this->function->readdir = function ($resource) use (&$_resource) {
$_resource = $resource;

return readdir($resource);
},
$wrapper = new SUT(),
$this->openDirectory($wrapper, ['Baz', 'Qux'])
)
->when($result = $wrapper->dir_readdir())
->then
->string($result)
->isEqualTo('Baz')
->resource($_resource)
->isIdenticalTo($wrapper->getStream())

->when($result = $wrapper->dir_readdir())
->then
->string($result)
->isEqualTo('Qux')

->when($result = $wrapper->dir_readdir())
->then
->boolean($result)
->isFalse();
}

public function case_dir_rewinddir()
{
$this
->given(
$this->function->rewinddir = function ($resource) use (&$_resource) {
$_resource = $resource;

return rewinddir($resource);
},
$wrapper = new SUT(),
$this->openDirectory($wrapper, ['Baz']),
$wrapper->dir_readdir()
)
->when($result = $wrapper->dir_rewinddir())
->then
->variable($result)
->isNull()

->when($result = $wrapper->dir_readdir())
->then
->string($result)
->isEqualTo('Baz')
->resource($_resource)
->isIdenticalTo($wrapper->getStream());
}

public function case_dir_mkdir()
{
$this
->given(
$this->function->mkdir = function ($path, $mode, $options) use (&$_path, &$_mode, &$_options) {
$_path = $path;
$_mode = $mode;
$_options = $options;

return true;
},
$wrapper = new SUT(),
$this->openDirectory($wrapper),
$path = 'Baz',
$mode = 0755,
$options = STREAM_MKDIR_RECURSIVE
)
->when($result = $wrapper->mkdir($path, $mode, $options))
->then
->boolean($result)
->isTrue()
->string($_path)
->isEqualTo($path)
->integer($_mode)
->isEqualTo($_mode)
->integer($_options)
->isEqualTo($options | STREAM_MKDIR_RECURSIVE);
}

public function case_rename()
{
$this
->given(
$this->function->rename = function ($from, $to) use (&$_from, &$_to) {
$_to = $to;
$_from = $from;

return rename($from, $to);
},
$wrapper = new SUT(),
$this->openFile($wrapper),
$from = 'hoa://Test/Vfs/Foo?type=file',
$to = 'hoa://Test/Vfs/Oof?type=file'
)
->when($result = $wrapper->rename($from, $to))
->then
->boolean($result)
->isTrue()
->string($_from)
->isEqualTo(SUT::realPath($from))
->string($_to)
->isEqualTo(SUT::realPath($_to, false));
}

public function case_rmdir()
{
$this
->given(
$this->function->rmdir = function ($path) use (&$_path) {
$_path = $path;

return rmdir($path);
},
$wrapper = new SUT(),
$this->openDirectory($wrapper)
)
->when($result = $wrapper->rmdir('hoa://Test/Vfs/Bar?type=directory', 0))
->then
->boolean($result)
->isTrue();
}

public function case_rmdir_a_file()
{
$this
->given(
$wrapper = new SUT(),
$this->openFile($wrapper)
)
->when($result = $wrapper->rmdir('hoa://Test/Vfs/Foo?type=file', 0))
->then
->boolean($result)
->isFalse();
}

public function case_unlink()
{
$this
->given(
$wrapper = new SUT(),
$this->openFile($wrapper)
)
->when($result = $wrapper->unlink('hoa://Test/Vfs/Foo?type=file'))
->then
->boolean($result)
->isTrue();
}

public function case_rmdir_a_directory()
{
$this
->given(
$wrapper = new SUT(),
$this->openDirectory($wrapper)
)
->when($result = $wrapper->unlink('hoa://Test/Vfs/Bar?type=directory'))
->then
->boolean($result)
->isFalse();
}

public function case_url_stat()
{
$this
->given(
$this->function->stat = function ($path) use (&$_path) {
$_path = $path;

return stat($path);
},
$wrapper = new SUT(),
$this->openFile($wrapper),
$path = 'hoa://Test/Vfs/Foo?type=file'
)
->when($result = $wrapper->url_stat($path, 0))
->then
->let(
$keys = [
'dev',
'ino',
'mode',
'nlink',
'uid',
'gid',
'rdev',
'size',
'atime',
'mtime',
'ctime',
'blksize',
'blocks'
]
)
->array($result)
->hasSize(26)
->hasKeys($keys)
->hasKeys(array_keys($keys))
->string($_path)
->isEqualTo(SUT::realPath($path));
}

public function case_url_stat_not_hoa_protocol()
{
$this
->given(
$wrapper = new SUT(),
$path = LUT::NO_RESOLUTION
)
->when(function () use ($wrapper, $path) {
$wrapper->url_stat($path, 0);
})
->then
->error()
->exists();
}

protected function openFile(SUT $wrapper, $content = '')
{
$wrapper->stream_open('hoa://Test/Vfs/Foo?type=file', 'wb+', STREAM_USE_PATH, $openedPath);
fwrite($openedPath, $content, strlen($content));
fseek($openedPath, 0, SEEK_SET);

return $wrapper;
}

protected function openDirectory(SUT $wrapper, array $children = [])
{
$wrapper->dir_opendir('hoa://Test/Vfs/Bar?type=directory', 0);

foreach ($children as $child) {
resolve('hoa://Test/Vfs/Bar/' . $child . '?type=file');
}

return $wrapper;
}
}
<?php



































namespace Hoa\Protocol\Test\Unit;

use Hoa\Protocol\Exception as SUT;
use Hoa\Test;









class Exception extends Test\Unit\Suite
{
public function case_hoa_exception()
{
$this
->when($result = new SUT('foo', 0))
->then
->object($result)
->isInstanceOf('Hoa\Exception\Exception');
}
}
<?php



































namespace Hoa\Protocol\Test\Unit\Node;

use Hoa\Protocol\Node\Library as SUT;
use Hoa\Test;









class Library extends Test\Unit\Suite
{
public function case_reach_without_composer_without_a_queue()
{
$this
->given(
$this->constant->WITH_COMPOSER = false,
$node = new SUT('foo', 'bar')
)
->when($result = $node->reach())
->then
->string($result)
->isEqualTo('bar');
}

public function case_reach_without_composer_with_a_queue()
{
$this
->given(
$this->constant->WITH_COMPOSER = false,
$node = new SUT('foo', 'bar')
)
->when($result = $node->reach('baz'))
->then
->string($result)
->isEqualTo('baz');
}

public function case_reach_with_composer_without_a_queue_and_a_single_reach()
{
$this
->given(
$this->constant->WITH_COMPOSER = true,
$node = new SUT('foo', 'Bar' . DS . 'Baz' . DS . 'Qux' . DS)
)
->when($result = $node->reach())
->then
->string($result)
->isEqualTo('Bar' . DS . 'Baz' . DS . 'qux' . DS);
}

public function case_reach_with_composer_without_a_queue_and_a_multiple_reaches()
{
$this
->given(
$this->constant->WITH_COMPOSER = true,
$node = new SUT(
'foo',
'Bar' . DS . 'Baz' . DS . 'Qux' . DS . RS .
'Hello' . DS . 'Mister' . DS . 'Anderson' . DS
)
)
->when($result = $node->reach())
->then
->string($result)
->isEqualTo(
'Bar' . DS . 'Baz' . DS . 'qux' . DS . RS .
'Hello' . DS . 'Mister' . DS . 'anderson' . DS
);
}

public function case_reach_with_composer_with_a_simple_queue()
{
$this
->given(
$this->constant->WITH_COMPOSER = true,
$node = new SUT('foo', 'Bar' . DS . 'Baz' . DS . 'Qux' . DS)
)
->when($result = $node->reach('Hello'))
->then
->string($result)
->isEqualTo(
"\r" . 'Bar' . DS . 'Baz' . DS . 'Qux' . DS . 'hello' . RS .
"\r" . dirname(dirname(dirname(dirname(dirname(dirname(__DIR__))))))
);
}

public function case_reach_with_composer_with_a_queue()
{
$this
->given(
$this->constant->WITH_COMPOSER = true,
$node = new SUT('foo', 'Bar' . DS)
)
->when($result = $node->reach('Hello/Mister/Anderson'))
->then
->string($result)
->isEqualTo(
"\r" . 'Bar' . DS . 'hello' . DS . 'Mister' . DS . 'Anderson' . RS .
"\r" . dirname(dirname(dirname(dirname(dirname(dirname(__DIR__)))))) . DS . 'Mister' . DS . 'Anderson'
);
}
}
<?php



































namespace Hoa\Protocol\Test\Unit\Node;

use Hoa\Protocol as LUT;
use Hoa\Protocol\Node\Node as SUT;
use Hoa\Test;









class Node extends Test\Unit\Suite
{
public function case_implements()
{
$this
->when($result = new SUT())
->then
->object($result)
->isInstanceOf('ArrayAccess')
->isInstanceOf('IteratorAggregate');
}

public function case_empty_constructor()
{
$this
->when($result = new SUT())
->then
->variable($result->getName())
->isNull()
->array(iterator_to_array($result->getIterator()))
->isEmpty();
}

public function case_constructor_with_a_name()
{
$this
->given($name = 'foo')
->when($result = new SUT($name))
->then
->string($result->getName())
->isEqualTo($name)
->array(iterator_to_array($result->getIterator()))
->isEmpty();
}

public function case_constructor_with_a_name_and_children()
{
$this
->given(
$name = 'foo',
$children = [new SUT('bar'), new SUT('baz')]
)
->when($result = new SUT($name, '', $children))
->then
->string($result->getName())
->isEqualTo($name)
->array(iterator_to_array($result->getIterator()))
->hasSize(2);
}

public function case_offset_set()
{
$this
->given(
$root = new SUT(),
$name = 'foo',
$node = new SUT(),
$oldCountChildren = count(iterator_to_array($root->getIterator()))
)
->when($result = $root->offsetSet($name, $node))
->then
->integer(count(iterator_to_array($root->getIterator())))
->isEqualTo($oldCountChildren + 1)
->object($root[$name])
->isIdenticalTo($node);
}

public function case_offset_set_not_a_node()
{
$this
->given($root = new SUT())
->exception(function () use ($root) {
$root->offsetSet('foo', null);
})
->isInstanceOf('Hoa\Protocol\Exception');
}

public function case_offset_set_no_name()
{
$this
->given($root = new SUT())
->exception(function () use ($root) {
$root->offsetSet(null, new SUT());
})
->isInstanceOf('Hoa\Protocol\Exception');
}

public function case_offset_get()
{
$this
->given(
$root = new SUT(),
$child = new SUT(),
$root['foo'] = $child
)
->when($result = $root->offsetGet('foo'))
->then
->object($result)
->isIdenticalTo($child);
}

public function case_offset_get_an_unknown_name()
{
$this
->given($root = new SUT())
->exception(function () use ($root) {
$root->offsetGet('foo');
})
->isInstanceOf('Hoa\Protocol\Exception');
}

public function case_offset_exists()
{
$this
->given(
$root = new SUT(),
$child = new SUT(),
$root['foo'] = $child
)
->when($result = $root->offsetExists('foo'))
->then
->boolean($result)
->isTrue();
}

public function case_offset_not_exists()
{
$this
->given($root = new SUT())
->when($result = $root->offsetExists('foo'))
->then
->boolean($result)
->isFalse();
}

public function case_offset_unset()
{
$this
->given(
$root = new SUT(),
$child = new SUT(),
$root['foo'] = $child
)
->when($result = $root->offsetUnset('foo'))
->then
->boolean($root->offsetExists('foo'))
->isFalse();
}

public function case_reach()
{
$this
->given(
$reach = 'bar',
$node = new SUT('foo', $reach)
)
->when($result = $node->reach())
->then
->string($result)
->isEqualTo($reach);
}

public function case_reach_with_a_queue()
{
$this
->given(
$queue = 'baz',
$node = new SUT('foo', 'bar')
)
->when($result = $node->reach('baz'))
->then
->string($result)
->isEqualTo($queue);
}

public function case_reach_id()
{
$this
->given($node = new SUT())
->exception(function () use ($node) {
$node->reachId('foo');
})
->isInstanceOf('Hoa\Protocol\Exception');
}

public function case_set_reach()
{
$this
->given(
$reach = 'bar',
$node = new SUT('foo', $reach)
)
->when($result = $node->setReach('baz'))
->then
->string($result)
->isEqualTo($reach)
->string($node->reach())
->isEqualTo('baz');
}

public function case_get_name()
{
$this
->given(
$name = 'foo',
$node = new SUT($name)
)
->when($result = $node->getName())
->then
->string($result)
->isEqualTo($name);
}

public function case_get_iterator()
{
$this
->given(
$childA = new SUT('bar'),
$childB = new SUT('baz'),
$children = [$childA, $childB]
)
->when($result = new SUT('foo', '', $children))
->then
->object($result->getIterator())
->isInstanceOf('ArrayIterator')
->array(iterator_to_array($result->getIterator()))
->isEqualTo([
'bar' => $childA,
'baz' => $childB
]);
}

public function case_get_root()
{
$this
->when($result = SUT::getRoot())
->then
->object($result)
->isIdenticalTo(LUT::getInstance());
}

public function case_to_string_as_leaf()
{
$this
->given($node = new SUT('foo'))
->when($result = $node->__toString())
->then
->string($result)
->isEqualTo('foo' . "\n");
}

public function case_to_string_as_node()
{
$this
->given(
$node = new SUT('foo'),
$node[] = new SUT('bar'),
$node[] = new SUT('baz')
)
->when($result = $node->__toString())
->then
->string($result)
->isEqualTo(
'foo' . "\n" .
'  bar' . "\n" .
'  baz' . "\n"
);
}
}
<?php



































namespace Hoa\Protocol
{









class Wrapper
{





private $_stream = null;






private $_streamName = null;






public $context = null;











public static function realPath($path, $exists = true)
{
return Node::getRoot()->resolve($path, $exists);
}










public function stream_cast($castAs)
{
return false;
}









public function stream_close()
{
if (true === @fclose($this->getStream())) {
$this->_stream = null;
$this->_streamName = null;
}

return;
}








public function stream_eof()
{
return feof($this->getStream());
}









public function stream_flush()
{
return fflush($this->getStream());
}
















public function stream_lock($operation)
{
return flock($this->getStream(), $operation);
}


















public function stream_metadata($path, $option, $values)
{
$path = static::realPath($path, false);

switch ($option) {
case STREAM_META_TOUCH:
$arity = count($values);

if (0 === $arity) {
$out = touch($path);
} elseif (1 === $arity) {
$out = touch($path, $values[0]);
} else {
$out = touch($path, $values[0], $values[1]);
}

break;

case STREAM_META_OWNER_NAME:
case STREAM_META_OWNER:
$out = chown($path, $values);

break;

case STREAM_META_GROUP_NAME:
case STREAM_META_GROUP:
$out = chgrp($path, $values);

break;

case STREAM_META_ACCESS:
$out = chmod($path, $values);

break;

default:
$out = false;
}

return $out;
}




























public function stream_open($path, $mode, $options, &$openedPath)
{
$path = static::realPath($path, 'r' === $mode[0]);

if (Protocol::NO_RESOLUTION === $path) {
return false;
}

if (null === $this->context) {
$openedPath = fopen($path, $mode, $options & STREAM_USE_PATH);
} else {
$openedPath = fopen(
$path,
$mode,
$options & STREAM_USE_PATH,
$this->context
);
}

if (false === is_resource($openedPath)) {
return false;
}

$this->_stream = $openedPath;
$this->_streamName = $path;

return true;
}









public function stream_read($count)
{
return fread($this->getStream(), $count);
}

















public function stream_seek($offset, $whence = SEEK_SET)
{
return 0 === fseek($this->getStream(), $offset, $whence);
}







public function stream_stat()
{
return fstat($this->getStream());
}







public function stream_tell()
{
return ftell($this->getStream());
}







public function stream_truncate($size)
{
return ftruncate($this->getStream(), $size);
}








public function stream_write($data)
{
return fwrite($this->getStream(), $data);
}









public function dir_closedir()
{
closedir($this->getStream());
$this->_stream = null;
$this->_streamName = null;

return;
}










public function dir_opendir($path, $options)
{
$path = static::realPath($path);
$handle = null;

if (null === $this->context) {
$handle = @opendir($path);
} else {
$handle = @opendir($path, $this->context);
}

if (false === $handle) {
return false;
}

$this->_stream = $handle;
$this->_streamName = $path;

return true;
}







public function dir_readdir()
{
return readdir($this->getStream());
}










public function dir_rewinddir()
{
return rewinddir($this->getStream());
}










public function mkdir($path, $mode, $options)
{
if (null === $this->context) {
return mkdir(
static::realPath($path, false),
$mode,
$options | STREAM_MKDIR_RECURSIVE
);
}

return mkdir(
static::realPath($path, false),
$mode,
$options | STREAM_MKDIR_RECURSIVE,
$this->context
);
}










public function rename($from, $to)
{
if (null === $this->context) {
return rename(static::realPath($from), static::realPath($to, false));
}

return rename(
static::realPath($from),
static::realPath($to, false),
$this->context
);
}










public function rmdir($path, $options)
{
if (null === $this->context) {
return rmdir(static::realPath($path));
}

return rmdir(static::realPath($path), $this->context);
}








public function unlink($path)
{
if (null === $this->context) {
return unlink(static::realPath($path));
}

return unlink(static::realPath($path), $this->context);
}

























public function url_stat($path, $flags)
{
$path = static::realPath($path);

if (Protocol::NO_RESOLUTION === $path) {
if ($flags & STREAM_URL_STAT_QUIET) {
return 0;
} else {
return trigger_error(
'Path ' . $path . ' cannot be resolved.',
E_WARNING
);
}
}

if ($flags & STREAM_URL_STAT_LINK) {
return @lstat($path);
}

return @stat($path);
}






public function getStream()
{
return $this->_stream;
}






public function getStreamName()
{
return $this->_streamName;
}
}




stream_wrapper_register('hoa', Wrapper::class);

}

namespace
{










if (!function_exists('resolve')) {
function resolve($path, $exists = true, $unfold = false)
{
return Hoa\Protocol::getInstance()->resolve($path, $exists, $unfold);
}
}

}
<?php



































namespace Hoa\Protocol;

use Hoa\Exception as HoaException;









class Exception extends HoaException
{
}
<?php



































namespace Hoa\Protocol\Bin;

use Hoa\Console;
use Hoa\Protocol;









class Resolve extends Console\Dispatcher\Kit
{





protected $options = [
['exists', Console\GetOption::NO_ARGUMENT, 'E'],
['unfold', Console\GetOption::NO_ARGUMENT, 'u'],
['tree', Console\GetOption::NO_ARGUMENT, 't'],
['no-verbose', Console\GetOption::NO_ARGUMENT, 'V'],
['help', Console\GetOption::NO_ARGUMENT, 'h'],
['help', Console\GetOption::NO_ARGUMENT, '?']
];








public function main()
{
$exists = true;
$unfold = false;
$tree = false;
$verbose = Console::isDirect(STDOUT);

while (false !== $c = $this->getOption($v)) {
switch ($c) {
case 'E':
$exists = false;

break;

case 'u':
$unfold = true;

break;

case 't':
$tree = true;

break;

case 'V':
$verbose = false;

break;

case 'h':
case '?':
return $this->usage();

case '__ambiguous':
$this->resolveOptionAmbiguity($v);

break;
}
}

$this->parser->listInputs($path);

if (null === $path) {
return $this->usage();
}

if (true === $tree) {
$protocol = Protocol::getInstance();
$foo = substr($path, 0, 6);

if ('hoa://' !== $foo) {
return;
}

$path = substr($path, 6);
$current = $protocol;

foreach (explode('/', $path) as $component) {
if (!isset($current[$component])) {
break;
}

$current = $current[$component];
}

echo $current;

return;
}

if (true === $verbose) {
echo
Console\Cursor::colorize('foreground(yellow)'),
$path,
Console\Cursor::colorize('normal'),
' is equivalent to:', "\n";
}

$resolved = resolve($path, $exists, $unfold);

foreach ((array) $resolved as $r) {
echo $r, "\n";
}

return;
}






public function usage()
{
echo
'Usage   : protocol:resolve <options> path', "\n",
'Options :', "\n",
$this->makeUsageOptionsList([
'E' => 'Do not check if the resolution result exists.',
'u' => 'Unfold all possible results.',
't' => 'Print the tree from the path.',
'V' => 'No-verbose, i.e. be as quiet as possible, just print ' .
'essential information.',
'help' => 'This help.'
]), "\n";

return;
}
}

__halt_compiler();
Resolve `hoa://` paths.
<?php



































namespace Hoa\Protocol\Node;









class Library extends Node
{







public function reach($queue = null)
{
if (!WITH_COMPOSER) {
return parent::reach($queue);
}

if (!empty($queue)) {
$head = $queue;

if (false !== $pos = strpos($queue, '/')) {
$head = substr($head, 0, $pos);
$queue = DIRECTORY_SEPARATOR . substr($queue, $pos + 1);
} else {
$queue = null;
}

$out = [];

foreach (explode(RS, $this->_reach) as $part) {
$out[] = "\r" . $part . strtolower($head) . $queue;
}

$out[] = "\r" . dirname(dirname(dirname(dirname(__DIR__)))) . $queue;

return implode(RS, $out);
}

$out = [];

foreach (explode(RS, $this->_reach) as $part) {
$pos = strrpos(rtrim($part, DIRECTORY_SEPARATOR), DIRECTORY_SEPARATOR) + 1;
$head = substr($part, 0, $pos);
$tail = substr($part, $pos);
$out[] = $head . strtolower($tail);
}

$this->_reach = implode(RS, $out);

return parent::reach($queue);
}
}
<?php



































namespace Hoa\Protocol\Node;

use Hoa\Consistency;
use Hoa\Protocol;









class Node implements \ArrayAccess, \IteratorAggregate
{





protected $_name = null;






protected $_reach = null;






private $_children = [];













public function __construct($name = null, $reach = null, array $children = [])
{
if (null !== $name) {
$this->_name = $name;
}

if (null !== $reach) {
$this->_reach = $reach;
}

foreach ($children as $child) {
$this[] = $child;
}

return;
}










public function offsetSet($name, $node)
{
if (!($node instanceof self)) {
throw new Protocol\Exception(
'Protocol node must extend %s.',
0,
__CLASS__
);
}

if (empty($name)) {
$name = $node->getName();
}

if (empty($name)) {
throw new Protocol\Exception(
'Cannot add a node to the `hoa://` protocol without a name.',
1
);
}

$this->_children[$name] = $node;

return;
}








public function offsetGet($name)
{
if (!isset($this[$name])) {
throw new Protocol\Exception(
'Node %s does not exist.',
2,
$name
);
}

return $this->_children[$name];
}







public function offsetExists($name)
{
return true === array_key_exists($name, $this->_children);
}







public function offsetUnset($name)
{
unset($this->_children[$name]);

return;
}










protected function _resolve($path, &$accumulator, $id = null)
{
if (substr($path, 0, 6) == 'hoa://') {
$path = substr($path, 6);
}

if (empty($path)) {
return null;
}

if (null === $accumulator) {
$accumulator = [];
$posId = strpos($path, '#');

if (false !== $posId) {
$id = substr($path, $posId + 1);
$path = substr($path, 0, $posId);
} else {
$id = null;
}
}

$path = trim($path, '/');
$pos = strpos($path, '/');

if (false !== $pos) {
$next = substr($path, 0, $pos);
} else {
$next = $path;
}

if (isset($this[$next])) {
if (false === $pos) {
if (null === $id) {
$this->_resolveChoice($this[$next]->reach(), $accumulator);

return true;
}

$accumulator = null;

return $this[$next]->reachId($id);
}

$tnext = $this[$next];
$this->_resolveChoice($tnext->reach(), $accumulator);

return $tnext->_resolve(substr($path, $pos + 1), $accumulator, $id);
}

$this->_resolveChoice($this->reach($path), $accumulator);

return true;
}








protected function _resolveChoice($reach, array &$accumulator)
{
if (empty($accumulator)) {
$accumulator = explode(RS, $reach);

return;
}

if (false === strpos($reach, RS)) {
if (false !== $pos = strrpos($reach, "\r")) {
$reach = substr($reach, $pos + 1);

foreach ($accumulator as &$entry) {
$entry = null;
}
}

foreach ($accumulator as &$entry) {
$entry .= $reach;
}

return;
}

$choices = explode(RS, $reach);
$ref = $accumulator;
$accumulator = [];

foreach ($choices as $choice) {
if (false !== $pos = strrpos($choice, "\r")) {
$choice = substr($choice, $pos + 1);

foreach ($ref as $entry) {
$accumulator[] = $choice;
}
} else {
foreach ($ref as $entry) {
$accumulator[] = $entry . $choice;
}
}
}

unset($ref);

return;
}









public function reach($queue = null)
{
return empty($queue) ? $this->_reach : $queue;
}









public function reachId($id)
{
throw new Protocol\Exception(
'The node %s has no ID support (tried to reach #%s).',
4,
[$this->getName(), $id]
);
}







public function setReach($reach)
{
$old = $this->_reach;
$this->_reach = $reach;

return $old;
}






public function getName()
{
return $this->_name;
}






protected function getReach()
{
return $this->_reach;
}






public function getIterator()
{
return new \ArrayIterator($this->_children);
}






public static function getRoot()
{
return Protocol::getInstance();
}






public function __toString()
{
static $i = 0;

$out = str_repeat('  ', $i) . $this->getName() . "\n";

foreach ($this as $node) {
++$i;
$out .= $node;
--$i;
}

return $out;
}
}




Consistency::flexEntity('Hoa\Protocol\Node\Node');
<?php



































namespace Hoa\Stream\Test\Integration\Filter;

use Hoa\Stream as LUT;
use Hoa\Stream\Filter as SUT;
use Hoa\Test;









class LateComputed extends Test\Integration\Suite
{
public function case_custom_late_computed_filter()
{
$this
->given(
$name = 'custom',
SUT::register($name, CustomFilter::class),

$filename = 'hoa://Test/Vfs/Foo?type=file',
$content = 'Hello, World!',
file_put_contents($filename, $content),
$stream = fopen($filename, 'r')
)
->when(
SUT::append($stream, $name),
$result = stream_get_contents($stream)
)
->then
->string($result)
->isEqualTo(
strtolower($content) . ' ' .
strlen($content)
);
}
}

class CustomFilter extends LUT\Filter\LateComputed
{
protected function compute()
{
$this->_buffer =
strtolower($this->_buffer) . ' ' .
strlen($this->_buffer); 

return;
}
}
<?php



































namespace Hoa\Stream\Test\Integration\Filter;

use Hoa\Stream\Filter as SUT;
use Hoa\Test;









class Filter extends Test\Integration\Suite
{
public function case_append()
{
$this
->given(
$filename = 'hoa://Test/Vfs/Foo?type=file',
$content = 'Hello, World!',
file_put_contents($filename, $content),
$stream = fopen($filename, 'r'),
$name = 'string.toupper'
)
->when(
SUT::append($stream, $name),
$result = stream_get_contents($stream)
)
->then
->string($result)
->isEqualTo(strtoupper($content));
}

public function case_prepend()
{
$this
->given(
$filename = 'hoa://Test/Vfs/Foo?type=file',
$content = 'Hello, World!',
file_put_contents($filename, $content),
$stream = fopen($filename, 'r'),
$name = 'string.toupper'
)
->when(
SUT::prepend($stream, $name),
$result = stream_get_contents($stream)
)
->then
->string($result)
->isEqualTo(strtoupper($content));
}

public function case_append_append()
{
$this
->given(
$filename = 'hoa://Test/Vfs/Foo?type=file',
$content = 'Hello, World!',
file_put_contents($filename, $content),
$stream = fopen($filename, 'r'),
$name1 = 'string.toupper',
$name2 = 'string.tolower'
)
->when(
SUT::append($stream, $name1),
SUT::append($stream, $name2),
$result = stream_get_contents($stream)
)
->then
->string($result)
->isEqualTo(strtolower($content));
}

public function case_append_prepend()
{
$this
->given(
$filename = 'hoa://Test/Vfs/Foo?type=file',
$content = 'Hello, World!',
file_put_contents($filename, $content),
$stream = fopen($filename, 'r'),
$name1 = 'string.toupper',
$name2 = 'string.tolower'
)
->when(
SUT::append($stream, $name1),
SUT::prepend($stream, $name2),
$result = stream_get_contents($stream)
)
->then
->string($result)
->isEqualTo(strtoupper($content));
}

public function case_prepend_prepend()
{
$this
->given(
$filename = 'hoa://Test/Vfs/Foo?type=file',
$content = 'Hello, World!',
file_put_contents($filename, $content),
$stream = fopen($filename, 'r'),
$name1 = 'string.toupper',
$name2 = 'string.tolower'
)
->when(
SUT::prepend($stream, $name1),
SUT::prepend($stream, $name2),
$result = stream_get_contents($stream)
)
->then
->string($result)
->isEqualTo(strtoupper($content));
}

public function case_append_1000_filters()
{
$this
->given(
$filename = 'hoa://Test/Vfs/Foo?type=file',
$content = 'Hello, World!',
file_put_contents($filename, $content),
$stream = fopen($filename, 'r'),
$name = 'string.toupper'
)
->when(function () use ($stream, $name) {
for ($i = 1000; $i >= 0; --$i) {
$this->resource(SUT::prepend($stream, $name));
}
})
->when($result = stream_get_contents($stream))
->then
->string($result)
->isEqualTo(strtoupper($content));
}
}
<?php



































namespace Hoa\Stream\Test\Integration;

use Hoa\Event;
use Hoa\Stream as LUT;
use Hoa\Test;









class Stream extends Test\Integration\Suite
{
public function case_notifications()
{
$self = $this;

$this
->given(
$port = mt_rand(10000, 12000),
exec(
sprintf(
'php -S 127.0.0.1:%d -t %s > /dev/null 2>&1 & echo $! && sleep 0.2',
$port,
dirname(__DIR__) . DS . 'Fixtures'
),
$outputs
),
$pid = $outputs[0],
$stream = new SUT('http://127.0.0.1:' . $port, null, true),

$stream->on(
'connect',
function (Event\Bucket $bucket) use ($self, &$connectCalled) {
$connectCalled = true;
$data = $bucket->getData();

$self
->array($data)
->isEqualTo([
'code' => 0,
'severity' => 0,
'message' => null,
'transferred' => 0,
'max' => 0
]);
}
),
$stream->on(
'mimetype',
function (Event\Bucket $bucket) use ($self, &$mimetypeCalled) {
$mimetypeCalled = true;
$data = $bucket->getData();

$self
->array($data)
->isEqualTo([
'code' => 0,
'severity' => 0,
'message' => 'text/html; charset=UTF-8',
'transferred' => 0,
'max' => 0
]);
}
),
$stream->on(
'size',
function (Event\Bucket $bucket) use ($self, &$sizeCalled) {
$sizeCalled = true;
$data = $bucket->getData();

$self
->array($data)
->isEqualTo([
'code' => 0,
'severity' => 0,
'message' => 'Content-Length: 14',
'transferred' => 0,
'max' => 14
]);
}
),
$stream->on(
'progress',
function (Event\Bucket $bucket) use ($self, &$progressCalled) {
$progressCalled = true;
$data = $bucket->getData();

$self
->array($data)
->isEqualTo([
'code' => 0,
'severity' => 0,
'message' => null,
'transferred' => 0,
'max' => 14
]);
}
)
)
->when($stream->open())
->then
->boolean($connectCalled)
->isTrue()
->boolean($mimetypeCalled)
->isTrue()
->boolean($sizeCalled)
->isTrue()
->boolean($progressCalled)
->isTrue()
->let(!empty($pid) && exec('kill ' . $pid));
}
}

class SUT extends LUT\Stream
{
protected function &_open($streamName, LUT\Context $context = null)
{
if (null === $context) {
$out = fopen($streamName, 'rb');
} else {
$out = fopen($streamName, 'rb', false, $context->getContext());
}

return $out;
}

protected function _close()
{
return fclose($this->getStream());
}
}
<?php



































namespace Hoa\Stream\Test\Unit;

use Hoa\Exception as HoaException;
use Hoa\Stream\Exception as SUT;
use Hoa\Test;









class Exception extends Test\Unit\Suite
{
public function case_hoa_exception()
{
$this
->when($result = new SUT('foo', 0))
->then
->object($result)
->isInstanceOf(HoaException::class);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\Wrapper\IWrapper;

use Hoa\Stream as LUT;
use Hoa\Stream\Wrapper\IWrapper\IWrapper as SUT;
use Hoa\Test;









class IWrapper extends Test\Unit\Suite
{
public function case_is_a_valid_interface()
{
$this
->when($result = new \Mock\Hoa\Stream\Wrapper\IWrapper\IWrapper())
->then
->object($result)
->isInstanceOf(SUT::class)
->isInstanceOf(LUT\Wrapper\IWrapper\File::class)
->isInstanceOf(LUT\Wrapper\IWrapper\Stream::class);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\Wrapper\IWrapper;

use Hoa\Stream\Wrapper\IWrapper\Stream as SUT;
use Hoa\Test;









class Stream extends Test\Unit\Suite
{
public function case_is_a_valid_interface()
{
$this
->when($result = new \Mock\Hoa\Stream\Wrapper\IWrapper\Stream())
->then
->object($result)
->isInstanceOf(SUT::class);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\Wrapper\IWrapper;

use Hoa\Stream\Wrapper\IWrapper\File as SUT;
use Hoa\Test;









class File extends Test\Unit\Suite
{
public function case_is_a_valid_interface()
{
$this
->when($result = new \Mock\Hoa\Stream\Wrapper\IWrapper\File())
->then
->object($result)
->isInstanceOf(SUT::class);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\Wrapper;

use Hoa\Stream as LUT;
use Hoa\Stream\Wrapper\Wrapper as SUT;
use Hoa\Test;









class Wrapper extends Test\Unit\Suite
{
public function case_register()
{
$this
->given($oldIsRegistered = SUT::isRegistered('foo'))
->when($result = SUT::register('foo', 'StdClass'))
->then
->boolean($result)
->isTrue()
->boolean($oldIsRegistered)
->isFalse()
->boolean(SUT::isRegistered('foo'))
->isTrue();
}

public function case_register_already_registered()
{
$this
->exception(function () {
SUT::register('php', 'ClassName');
})
->isInstanceOf(LUT\Exception::class)
->hasMessage('The protocol php is already registered.');
}

public function case_register_implementation_does_not_exist()
{
$this
->exception(function () {
SUT::register('foo', 'ClassName');
})
->isInstanceOf(LUT\Exception::class)
->hasMessage(
'Cannot use the ClassName class for the implementation ' .
'of the foo protocol because it is not found.'
);
}

public function case_unregister()
{
$this
->given(
SUT::register('foo', 'StdClass'),
$oldIsRegistered = SUT::isRegistered('foo')
)
->when($result = SUT::unregister('foo'))
->then
->boolean($result)
->isTrue()
->boolean($oldIsRegistered)
->isTrue()
->boolean(SUT::isRegistered('foo'))
->isFalse();
}

public function case_unregister_unregistered_protocol()
{
$this
->when($result = SUT::unregister('foo'))
->then
->boolean($result)
->isFalse();
}

public function case_restore_registered_protocol()
{
$this
->when($result = SUT::restore('php'))
->then
->boolean($result)
->isTrue();
}

public function case_restore_unregistered_protocol()
{
$this
->when($result = SUT::restore('foo'))
->then
->boolean($result)
->isFalse();
}

public function case_is_registered()
{
$this
->when($result = SUT::isRegistered('php'))
->then
->boolean($result)
->isTrue();
}

public function case_is_not_registered()
{
$this
->when($result = SUT::isRegistered('foo'))
->then
->boolean($result)
->isFalse();
}

public function case_get_registered()
{
$this
->when($result = SUT::getRegistered())
->then
->array($result)
->containsValues([
'https',
'php',
'file',
'glob',
'data',
'http',
'hoa'
]);
}

public function case_get_registered_dynamically()
{
$this
->given($oldCount = count(SUT::getRegistered()))
->when(
SUT::register('foo', \StdClass::class),
$result = SUT::getRegistered()
)
->then
->integer(count($result))
->isEqualTo($oldCount + 1)

->when(
SUT::unregister('foo'),
$result = SUT::getRegistered()
)
->then
->integer(count($result))
->isEqualTo($oldCount);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\Wrapper;

use Hoa\Stream as LUT;
use Hoa\Stream\Wrapper\Exception as SUT;
use Hoa\Test;









class Exception extends Test\Unit\Suite
{
public function case_hoa_exception()
{
$this
->when($result = new SUT('foo', 0))
->then
->object($result)
->isInstanceOf(LUT\Exception::class);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\IStream;

use Hoa\Stream as LUT;
use Hoa\Stream\IStream\Statable as SUT;
use Hoa\Test;









class Statable extends Test\Unit\Suite
{
public function case_is_a_valid_interface()
{
$this
->when($result = new \Mock\Hoa\Stream\IStream\Statable())
->then
->object($result)
->isInstanceOf(SUT::class)
->isInstanceOf(LUT\IStream\Stream::class);
}

public function case_constants()
{
$this
->when($result = SUT::SIZE_UNDEFINED)
->then
->integer($result)
->isEqualTo(-1);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\IStream;

use Hoa\Stream as LUT;
use Hoa\Stream\IStream\Touchable as SUT;
use Hoa\Test;









class Touchable extends Test\Unit\Suite
{
public function case_is_a_valid_interface()
{
$this
->when($result = new \Mock\Hoa\Stream\IStream\Touchable())
->then
->object($result)
->isInstanceOf(SUT::class)
->isInstanceOf(LUT\IStream\Stream::class);
}

public function case_constants()
{
$this
->when($result = SUT::OVERWRITE)
->then
->boolean($result)
->isEqualTo(true)

->when($result = SUT::DO_NOT_OVERWRITE)
->then
->boolean($result)
->isEqualTo(false)

->when($result = SUT::MAKE_DIRECTORY)
->then
->boolean($result)
->isEqualTo(true)

->when($result = SUT::DO_NOT_MAKE_DIRECTORY)
->then
->boolean($result)
->isEqualTo(false);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\IStream;

use Hoa\Stream as LUT;
use Hoa\Stream\IStream\In as SUT;
use Hoa\Test;









class In extends Test\Unit\Suite
{
public function case_is_a_valid_interface()
{
$this
->when($result = new \Mock\Hoa\Stream\IStream\In())
->then
->object($result)
->isInstanceOf(SUT::class)
->isInstanceOf(LUT\IStream\Stream::class);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\IStream;

use Hoa\Stream as LUT;
use Hoa\Stream\IStream\Structural as SUT;
use Hoa\Test;









class Structural extends Test\Unit\Suite
{
public function case_is_a_valid_interface()
{
$this
->when($result = new \Mock\Hoa\Stream\IStream\Structural())
->then
->object($result)
->isInstanceOf(SUT::class)
->isInstanceOf(LUT\IStream\Stream::class);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\IStream;

use Hoa\Stream as LUT;
use Hoa\Stream\IStream\Out as SUT;
use Hoa\Test;









class Out extends Test\Unit\Suite
{
public function case_is_a_valid_interface()
{
$this
->when($result = new \Mock\Hoa\Stream\IStream\Out())
->then
->object($result)
->isInstanceOf(SUT::class)
->isInstanceOf(LUT\IStream\Stream::class);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\IStream;

use Hoa\Stream as LUT;
use Hoa\Stream\IStream\Pointable as SUT;
use Hoa\Test;









class Pointable extends Test\Unit\Suite
{
public function case_is_a_valid_interface()
{
$this
->when($result = new \Mock\Hoa\Stream\IStream\Pointable())
->then
->object($result)
->isInstanceOf(SUT::class)
->isInstanceOf(LUT\IStream\Stream::class);
}

public function case_constants()
{
$this
->when($result = SUT::SEEK_SET)
->then
->integer($result)
->isEqualTo(SEEK_SET)

->when($result = SUT::SEEK_CURRENT)
->then
->integer($result)
->isEqualTo(SEEK_CUR)

->when($result = SUT::SEEK_END)
->then
->integer($result)
->isEqualTo(SEEK_END);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\IStream;

use Hoa\Stream\IStream\Stream as SUT;
use Hoa\Test;









class Stream extends Test\Unit\Suite
{
public function case_is_a_valid_interface()
{
$this
->when($result = new \Mock\Hoa\Stream\IStream\Stream())
->then
->object($result)
->isInstanceOf(SUT::class);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\IStream;

use Hoa\Stream as LUT;
use Hoa\Stream\IStream\Bufferable as SUT;
use Hoa\Test;









class Bufferable extends Test\Unit\Suite
{
public function case_is_a_valid_interface()
{
$this
->when($result = new \Mock\Hoa\Stream\IStream\Bufferable())
->then
->object($result)
->isInstanceOf(SUT::class)
->isInstanceOf(LUT\IStream\Stream::class);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\IStream;

use Hoa\Stream as LUT;
use Hoa\Stream\IStream\Lockable as SUT;
use Hoa\Test;









class Lockable extends Test\Unit\Suite
{
public function case_is_a_valid_interface()
{
$this
->when($result = new \Mock\Hoa\Stream\IStream\Lockable())
->then
->object($result)
->isInstanceOf(SUT::class)
->isInstanceOf(LUT\IStream\Stream::class);
}

public function case_constants()
{
$this
->when($result = SUT::LOCK_SHARED)
->then
->integer($result)
->isEqualTo(LOCK_SH)

->when($result = SUT::LOCK_EXCLUSIVE)
->then
->integer($result)
->isEqualTo(LOCK_EX)

->when($result = SUT::LOCK_RELEASE)
->then
->integer($result)
->isEqualTo(LOCK_UN)

->when($result = SUT::LOCK_NO_BLOCK)
->then
->integer($result)
->isEqualTo(LOCK_NB);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\IStream;

use Hoa\Stream as LUT;
use Hoa\Stream\IStream\Pathable as SUT;
use Hoa\Test;









class Pathable extends Test\Unit\Suite
{
public function case_is_a_valid_interface()
{
$this
->when($result = new \Mock\Hoa\Stream\IStream\Pathable())
->then
->object($result)
->isInstanceOf(SUT::class)
->isInstanceOf(LUT\IStream\Stream::class);
}
}
<?php



































namespace Hoa\Stream\Test\Unit;

use Hoa\Stream\Bucket as SUT;
use Hoa\Test;









class Bucket extends Test\Unit\Suite
{
public function case_constants()
{
$this
->boolean(SUT::IS_A_BRIGADE)
->isTrue()
->boolean(SUT::IS_A_STREAM)
->isFalse();
}

public function case_construct_a_brigade()
{
$this
->given($brigade = 'foo')
->when($result = new SUT($brigade, SUT::IS_A_BRIGADE))
->then
->boolean($result->getType())
->isEqualTo(SUT::IS_A_BRIGADE)
->variable($result->getBrigade())
->isIdenticalTo($brigade)
->isIdenticalTo('foo');
}

public function case_construct_a_stream()
{
$this
->given(
$stream = fopen(__FILE__, 'r'),
$buffer = 'bar'
)
->when($result = new SUT($stream, SUT::IS_A_STREAM, $buffer))
->then
->boolean($result->getType())
->isEqualTo(SUT::IS_A_STREAM)
->let($bucket = $this->invoke($result)->getBucket())
->object($bucket)
->isInstanceOf(\StdClass::class)
->resource($bucket->bucket)
->string($bucket->data)
->isEqualTo($buffer)
->integer($bucket->datalen)
->isEqualTo(strlen($buffer))
->object($result->getBrigade())
->isIdenticalTo($bucket);
}

public function case_eob()
{
$this
->given(
$stream = fopen(__FILE__, 'r'),
$bucket = new SUT($stream, SUT::IS_A_STREAM)
)
->when($result = $bucket->eob())
->then
->boolean($result)
->isTrue();
}

public function case_set_data()
{
$this
->given(
$stream = fopen(__FILE__, 'r'),
$oldBuffer = 'bar',
$bucket = new SUT($stream, SUT::IS_A_STREAM, $oldBuffer),
$buffer = 'bazqux'
)
->when($result = $bucket->setData('bazqux'))
->then
->string($result)
->isEqualTo($oldBuffer)
->let($_bucket = $this->invoke($bucket)->getBucket())
->object($_bucket)
->isInstanceOf(\StdClass::class)
->resource($_bucket->bucket)
->string($_bucket->data)
->isEqualTo($buffer)
->integer($_bucket->datalen)
->isEqualTo(strlen($buffer))
->object($bucket->getBrigade())
->isIdenticalTo($_bucket);
}

public function case_get_data()
{
$this
->given(
$stream = fopen(__FILE__, 'r'),
$buffer = 'bar',
$bucket = new SUT($stream, SUT::IS_A_STREAM, $buffer)
)
->when($result = $bucket->getData())
->then
->string($result)
->isEqualTo($buffer)
->isEqualTo($this->invoke($bucket)->getBucket()->data);
}

public function case_get_length()
{
$this
->given(
$stream = fopen(__FILE__, 'r'),
$buffer = 'bar',
$bucket = new SUT($stream, SUT::IS_A_STREAM, $buffer)
)
->when($result = $bucket->getLength())
->then
->integer($result)
->isEqualTo(strlen($buffer))
->isEqualTo($this->invoke($bucket)->getBucket()->datalen);
}
}
<?php



































namespace Hoa\Stream\Test\Unit;

use Hoa\Stream as LUT;
use Hoa\Stream\Context as SUT;
use Hoa\Test;









class Context extends Test\Unit\Suite
{
public function case_get_instance_with_empty_id()
{
$this
->exception(function () {
SUT::getInstance(null);
})
->isInstanceOf(LUT\Exception::class);
}

public function case_get_new_instance()
{
$this
->when($result = SUT::getInstance('foo'))
->then
->object($result)
->isInstanceOf(SUT::class);
}

public function case_get_new_instances()
{
$this
->when($result = SUT::getInstance('foo'))
->then
->object($result)
->isNotIdenticalTo(SUT::getInstance('bar'));
}

public function case_get_same_instance()
{
$this
->when($result = SUT::getInstance('foo'))
->then
->object($result)
->isIdenticalTo(SUT::getInstance('foo'));
}

public function case_get_id()
{
$this
->given(
$id = 'foo',
$context = SUT::getInstance($id)
)
->when($result = $context->getId())
->then
->string($result)
->isEqualTo($id);
}

public function case_context_exists()
{
$this
->given(
$id = 'foo',
SUT::getInstance($id)
)
->when($result = SUT::contextExists($id))
->then
->boolean($result)
->isTrue();
}

public function case_context_does_not_exist()
{
$this
->when($result = SUT::contextExists('foo'))
->then
->boolean($result)
->isFalse();
}

public function case_set_options()
{
$this
->given(
$context = SUT::getInstance('foo'),
$options = ['bar' => ['baz' => 'qux']]
)
->when($result = $context->setOptions($options))
->then
->boolean($result)
->isTrue();
}

public function case_get_options()
{
$this
->given(
$context = SUT::getInstance('foo'),
$options = ['bar' => ['baz' => 'qux']],
$context->setOptions($options)
)
->when($result = $context->getOptions())
->then
->array($result)
->isEqualTo($options);
}

public function case_set_parameters()
{
$this
->given(
$context = SUT::getInstance('foo'),
$parameters = [
'notificaion' => 'callback',
'options' => ['bar' => ['baz' => 'qux']]
]
)
->when($result = $context->setParameters($parameters))
->then
->boolean($result)
->isTrue();
}

public function case_get_parameters()
{
$this
->given(
$context = SUT::getInstance('foo'),
$parameters = [
'notification' => 'callback',
'options' => ['bar' => ['baz' => 'qux']]
],
$context->setParameters($parameters)
)
->when($result = $context->getParameters())
->then
->array($result)
->isEqualTo($parameters);
}

public function case_get_context()
{
$this
->given($context = SUT::getInstance('foo'))
->when($result = $context->getContext())
->then
->resource($result)
->isStreamContext();
}
}
<?php



































namespace Hoa\Stream\Test\Unit\Filter;

use Hoa\Stream as LUT;
use Hoa\Stream\Filter\Exception as SUT;
use Hoa\Test;









class Exception extends Test\Unit\Suite
{
public function case_exception()
{
$this
->when($result = new SUT('foo', 0))
->then
->object($result)
->isInstanceOf(LUT\Exception::class);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\Filter;

use Hoa\Stream as LUT;
use Hoa\Stream\Filter as SUT;
use Hoa\Test;









class Filter extends Test\Unit\Suite
{
public function case_constants()
{
$this
->boolean(SUT::OVERWRITE)
->isTrue()
->boolean(SUT::DO_NOT_OVERWRITE)
->isFalse()
->integer(SUT::READ)
->isEqualTo(STREAM_FILTER_READ)
->integer(SUT::WRITE)
->isEqualTo(STREAM_FILTER_WRITE)
->integer(SUT::READ_AND_WRITE)
->isEqualTo(STREAM_FILTER_ALL);
}

public function case_register()
{
$this
->when($result = SUT::register('foo', \StdClass::class))
->then
->boolean($result)
->isTrue();
}

public function case_register_already_registered_do_not_overwrite()
{
$this
->given(
$name = 'foo',
$class = \StdClass::class,
SUT::register($name, $class)
)
->exception(function () use ($name, $class) {
SUT::register($name, $class);
})
->isInstanceOf(LUT\Filter\Exception::class)
->hasMessage('Filter foo is already registered.');
}

public function case_register_already_registered_do_overwrite()
{
$this
->given(
$name = 'foo',
SUT::register($name, \StdClass::class),
new \Mock\StdClass() 
 )
->when($result = SUT::register($name, \Mock\StdClass::class, SUT::OVERWRITE))
->then
->boolean($result)
->isFalse();
}

public function case_register_empty_name()
{
$this
->exception(function () {
SUT::register('', \StdClass::class);
})
->isInstanceOf(LUT\Filter\Exception::class)
->hasMessage(
'Filter name cannot be empty ' .
'(implementation class is StdClass).'
);
}

public function case_register_unknown_class()
{
$this
->exception(function () {
SUT::register('foo', '42Foo');
})
->isInstanceOf(LUT\Filter\Exception::class)
->hasMessage(
'Cannot register the 42Foo class for the filter foo ' .
'because it does not exist.'
);
}

public function case_append()
{
$this
->given(
$stream = fopen('hoa://Test/Vfs/Foo?type=file', 'r'),
$name = 'string.toupper'
)
->when($result = SUT::append($stream, $name))
->then
->resource($result)
->isStreamFilter();
}

public function case_prepend()
{
$this
->given(
$stream = fopen('hoa://Test/Vfs/Foo?type=file', 'r'),
$name = 'string.toupper'
)
->when($result = SUT::prepend($stream, $name))
->then
->resource($result)
->isStreamFilter();
}

public function case_remove()
{
$this
->given(
$stream = fopen('hoa://Test/Vfs/Foo?type=file', 'r'),
$name = 'string.toupper',
$filter = SUT::append($stream, $name)
)
->when($result = SUT::remove($filter))
->then
->boolean($result)
->isTrue();
}

public function case_remove_by_name()
{
$this
->given(
$stream = fopen('hoa://Test/Vfs/Foo?type=file', 'r'),
$name = 'string.toupper',
$filter = SUT::append($stream, $name)
)
->when($result = SUT::remove($name))
->then
->boolean($result)
->isTrue();
}

public function case_remove_unknown()
{
$this
->exception(function () {
SUT::remove('foo');
})
->isInstanceOf(LUT\Filter\Exception::class)
->hasMessage(
'Cannot remove the stream filter foo ' .
'because no resource was found with this name.'
);
}

public function case_is_registered()
{
$this
->when($result = SUT::isRegistered('string.toupper'))
->then
->boolean($result)
->isTrue();
}

public function case_is_not_registered()
{
$this
->when($result = SUT::isRegistered('foo'))
->then
->boolean($result)
->isFalse();
}

public function case_get_registered()
{
$this
->when($result = SUT::getRegistered())
->then
->array($result)
->containsValues([
'string.rot13',
'string.toupper',
'string.tolower',
'string.strip_tags',
'consumed',
'dechunk'
]);
}
}
<?php



































namespace Hoa\Stream\Test\Unit\Filter;

use Hoa\Stream as LUT;
use Mock\Hoa\Stream\Filter\Basic as SUT;
use Hoa\Test;









class Basic extends Test\Unit\Suite
{
public function case_constants()
{
$this
->integer(SUT::PASS_ON)
->isEqualTo(PSFS_PASS_ON)
->integer(SUT::FEED_ME)
->isEqualTo(PSFS_FEED_ME)
->integer(SUT::FATAL_ERROR)
->isEqualTo(PSFS_ERR_FATAL)
->integer(SUT::FLAG_NORMAL)
->isEqualTo(PSFS_FLAG_NORMAL)
->integer(SUT::FLAG_FLUSH_INC)
->isEqualTo(PSFS_FLAG_FLUSH_INC)
->integer(SUT::FLAG_FLUSH_CLOSE)
->isEqualTo(PSFS_FLAG_FLUSH_CLOSE);
}

public function case_is_a_php_filter()
{
$this
->when($result = new SUT())
->then
->object($result)
->isInstanceOf(\php_user_filter::class);
}

public function case_interfaces()
{
$this
->when($result = new SUT())
->then
->object($result)
->isInstanceOf(LUT\IStream\Stream::class);
}

public function case_set_name()
{
$this
->given($filter = new SUT())
->when($result = $filter->setName('foo'))
->then
->string($result)
->isEqualTo('');
}

public function case_get_name()
{
$this
->given(
$filter = new SUT(),
$name = 'foo',
$filter->setName($name)
)
->when($result = $filter->getName())
->then
->string($result)
->isEqualTo($name);
}

public function case_set_parameters()
{
$this
->given($filter = new SUT())
->when($result = $filter->setParameters(['foo', 'bar', 'baz']))
->then
->string($result)
->isEqualTo('');
}

public function case_get_parameters()
{
$this
->given(
$filter = new SUT(),
$parameters = ['foo', 'bar', 'baz'],
$filter->setParameters($parameters)
)
->when($result = $filter->getParameters())
->then
->array($result)
->isEqualTo($parameters);
}

public function case_get_stream()
{
$this
->given($filter = new SUT())
->when($result = $filter->getStream())
->then
->variable($result)
->isNull(); 
 }
}
<?php



































namespace Hoa\Stream\Test\Unit;

use Hoa\Event;
use Hoa\Stream as LUT;
use Hoa\Test;









class Stream extends Test\Unit\Suite
{
public function case_interfaces()
{
$this
->when($result = new SUT(__FILE__))
->then
->object($result)
->isInstanceOf(LUT\IStream\Stream::class)
->isInstanceOf(Event\Listenable::class);
}

public function case_constants()
{
$this
->integer(SUT::NAME)
->isEqualTo(0)
->integer(SUT::HANDLER)
->isEqualTo(1)
->integer(SUT::RESOURCE)
->isEqualTo(2)
->integer(SUT::CONTEXT)
->isEqualTo(3);
}

public function case_construct()
{
$this
->given($name = __FILE__)
->when($result = new SUT($name))
->then
->string($result->getStreamName())
->isEqualTo($name)
->boolean($this->invoke($result)->hasBeenDeferred())
->isFalse()
->let($listener = $this->invoke($result)->getListener())
->object($listener)
->isInstanceOf(Event\Listener::class)
->boolean($listener->listenerExists('authrequire'))
->isTrue()
->boolean($listener->listenerExists('authresult'))
->isTrue()
->boolean($listener->listenerExists('complete'))
->isTrue()
->boolean($listener->listenerExists('connect'))
->isTrue()
->boolean($listener->listenerExists('failure'))
->isTrue()
->boolean($listener->listenerExists('mimetype'))
->isTrue()
->boolean($listener->listenerExists('progress'))
->isTrue()
->boolean($listener->listenerExists('redirect'))
->isTrue()
->boolean($listener->listenerExists('resolve'))
->isTrue()
->boolean($listener->listenerExists('size'))
->isTrue()
->boolean(Event::eventExists('hoa://Event/Stream/' . $name))
->isTrue()
->boolean(Event::eventExists('hoa://Event/Stream/' . $name . ':close-before'))
->isTrue();
}

public function case_construct_with_a_context()
{
$this
->given(
$name = __FILE__,
$contextName = 'foo',
LUT\Context::getInstance($contextName)
)
->when($result = new SUT($name, $contextName))
->then
->string($result->getStreamName())
->isEqualTo($name)
->boolean($this->invoke($result)->hasBeenDeferred())
->isFalse()
->object($this->invoke($result)->getListener())
->isInstanceOf(Event\Listener::class);
}

public function case_construct_with_deferred_opening()
{
$this
->given($name = __FILE__)
->when($result = new SUT($name, null, true))
->then
->boolean($this->invoke($result)->hasBeenDeferred())
->isTrue()
->boolean($result->isOpened())
->isFalse()
->variable($result->getStreamName())
->isNull();
}

public function case_open()
{
$this
->given(
$name = __FILE__,
$stream = new SUT($name, null, true)
)
->when($result = $stream->open())
->then
->object($result)
->isIdenticalTo($stream)
->boolean($this->invoke($result)->hasBeenDeferred())
->isTrue()
->boolean($result->isOpened())
->isTrue()
->string($result->getStreamName())
->isEqualTo($name)
->integer($result->getStreamBufferSize())
->isEqualTo(SUT::DEFAULT_BUFFER_SIZE);
}

public function case_close()
{
$this
->given(
$name = __FILE__,
$stream = new SUT($name),
$resource = $stream->getStream(),
$context = $stream->getStreamContext()
)
->when($result = $stream->close())
->then
->variable($result)
->isNull()
->boolean($stream->isOpened())
->isFalse()
->variable(SUT::getStreamHandler($stream))
->isNull()
->variable($stream->getStreamName())
->isEqualTo($name)
->variable($stream->getStream())
->isEqualTo($resource)
->variable($stream->getStreamContext())
->isEqualTo($context)
->boolean(Event::eventExists('hoa://Event/Stream/' . $name))
->isFalse()
->boolean(Event::eventExists('hoa://Event/Stream/' . $name . ':close-before'))
->isFalse();
}

public function case_close_more_than_once()
{
$this
->given(
$name = __FILE__,
$stream = new SUT($name),
$close1 = $stream->close()
)
->when($result = $stream->close())
->then
->variable($result)
->isIdenticalTo($close1);
}

public function case_open_close_open()
{
$this
->given(
$name = __FILE__,
$stream = new SUT($name, null, true),
$stream->open(),
$resource = $stream->getStream(),
$context = $stream->getStreamContext(),
$handler = SUT::getStreamHandler($stream),

$this->function->stream_set_write_buffer = 0,

$stream->setStreamBuffer(42),
$stream->close()
)
->when($result = $stream->open())
->then
->string($result->getStreamName())
->isEqualTo($name)
->resource($result->getStream())
->isNotEqualTo($resource)
->object($handler)
->isIdenticalTo($result)
->object($this->invoke($stream)->getListener())
->isInstanceOf(Event\Listener::class)
->boolean(Event::eventExists('hoa://Event/Stream/' . $name))
->isTrue()
->boolean(Event::eventExists('hoa://Event/Stream/' . $name . ':close-before'))
->isTrue()
->integer($stream->getStreamBufferSize())
->isEqualTo(SUT::DEFAULT_BUFFER_SIZE);
}

public function case_close_event_close_before()
{
$self = $this;

$this
->given(
$name = 'hoa://Test/Vfs/Foo?type=file',
$stream = new SUT($name),
Event::getEvent('hoa://Event/Stream/' . $name . ':close-before')->attach(
function (Event\Bucket $bucket) use ($self, &$called) {
$called = true;

$self
->variable($bucket->getData())
->isNull()
->boolean($bucket->getSource()->isOpened())
->isTrue();
}
)
)
->when($result = $stream->close())
->then
->boolean($called)
->isTrue();
}

public function case_get_stream_name()
{
$this
->given(
$name = __FILE__,
$stream = new SUT($name)
)
->when($result = $stream->getStreamName())
->then
->string($result)
->isEqualTo($name);
}

public function case_get_stream()
{
$this
->given(
$name = __FILE__,
$stream = new SUT($name)
)
->when($result = $stream->getStream())
->then
->resource($result)
->isStream($name);
}

public function case_get_stream_context()
{
$this
->given(
$name = __FILE__,
$contextName = 'foo',
$context = LUT\Context::getInstance($contextName),
$stream = new SUT($name, $contextName)
)
->when($result = $stream->getStreamContext())
->then
->object($result)
->isIdenticalTo($context);
}

public function case_get_stream_context_with_no_context_given()
{
$this
->given(
$name = __FILE__,
$stream = new SUT($name)
)
->when($result = $stream->getStreamContext())
->then
->variable($result)
->isNull();
}

public function case_get_stream_handler()
{
$this
->given(
$name = __FILE__,
$stream = new SUT($name)
)
->when($result = SUT::getStreamHandler($name))
->then
->object($result)
->isIdenticalTo($result);
}

public function case_get_stream_handler_of_unknown_stream()
{
$this
->when($result = SUT::getStreamHandler('foo'))
->then
->variable($result)
->isNull();
}

public function case__set_stream()
{
$this
->given(
$stream = new SUT(__FILE__),
$oldStream = $stream->getStream(),
$newStream = fopen('php://memory', 'rb')
)
->when($result = $stream->_setStream($newStream))
->then
->resource($result)
->isIdenticalTo($oldStream)
->isStream()
->resource($stream->getStream())
->isStream()
->isIdenticalTo($newStream);
}

public function case__set_stream_invalid_resource()
{
$this
->given($stream = new SUT(__FILE__))
->exception(function () use ($stream) {
$stream->_setStream(true);
})
->isInstanceOf(LUT\Exception::class);
}

public function case__set_stream_unknown_resource()
{
$this
->given(
$stream = new SUT(__FILE__),
$oldStream = $stream->getStream(),
$newStream = fopen('php://memory', 'rb'),
$this->function->is_resource = false,
$this->function->gettype = 'resource',
$this->function->get_resource_type = 'Unknown'
)
->when($result = $stream->_setStream($newStream))
->then
->resource($result)
->isIdenticalTo($oldStream)
->isStream()
->resource($stream->getStream())
->isStream()
->isIdenticalTo($newStream);
}

public function case_is_opened()
{
$this
->given($stream = new SUT(__FILE__))
->when($result = $stream->isOpened())
->then
->boolean($result)
->isTrue();
}

public function case_is_not_opened()
{
$this
->given($stream = new SUT(__FILE__, null, true))
->when($result = $stream->isOpened())
->then
->boolean($result)
->isFalse()

->when(
$stream->open(),
$result = $stream->isOpened()
)
->then
->boolean($result)
->isTrue();
}

public function case_set_stream_timeout()
{
$self = $this;

$this
->given(
$stream = new SUT(__FILE__),

$this->function->stream_set_timeout = function ($_stream, $_seconds, $_microseconds) use ($self, $stream, &$called) {
$called = true;

$self
->resource($_stream)
->isIdenticalTo($stream->getStream())
->integer($_seconds)
->isEqualTo(7)
->integer($_microseconds)
->isEqualTo(42);

return true;
}
)
->when($result = $stream->setStreamTimeout(7, 42))
->then
->boolean($result)
->isTrue()
->boolean($called)
->isTrue();
}

public function case_has_been_deferred()
{
$this
->given($stream = new SUT(__FILE__, null, true))
->when($result = $this->invoke($stream)->hasBeenDeferred())
->then
->boolean($result)
->isTrue();
}

public function case_has_not_been_deferred()
{
$this
->given($stream = new SUT(__FILE__))
->when($result = $this->invoke($stream)->hasBeenDeferred())
->then
->boolean($result)
->isFalse();
}

public function case_has_timed_out()
{
$this
->given(
$stream = new SUT(__FILE__),
$this->function->stream_get_meta_data = [
'timed_out' => true
]
)
->when($result = $stream->hasTimedOut())
->then
->boolean($result)
->isTrue();
}

public function case_has_not_timed_out()
{
$this
->given(
$stream = new SUT(__FILE__),
$this->function->stream_get_meta_data = [
'timed_out' => false
]
)
->when($result = $stream->hasTimedOut())
->then
->boolean($result)
->isFalse();
}

public function case_set_stream_blocking()
{
$self = $this;

$this
->given(
$stream = new SUT(__FILE__),

$this->function->stream_set_blocking = function ($_stream, $_mode) use ($self, $stream, &$called) {
$called = true;

$self
->resource($_stream)
->isIdenticalTo($stream->getStream())
->integer($_mode)
->isEqualTo(1);

return true;
}
)
->when($result = $stream->setStreamBlocking(true))
->then
->boolean($result)
->isTrue()
->boolean($called)
->isTrue();
}

public function case_get_default_stream_buffer_size()
{
$self = $this;

$this
->given($stream = new SUT(__FILE__))
->when($result = $stream->getStreamBufferSize())
->then
->integer($result)
->isEqualTo(8192);
}

public function case_set_stream_buffer()
{
$self = $this;

$this
->given(
$stream = new SUT(__FILE__),

$this->function->stream_set_write_buffer = function ($_stream, $_buffer) use ($self, $stream, &$called) {
$called = true;

$self
->resource($_stream)
->isIdenticalTo($stream->getStream())
->integer($_buffer)
->isEqualTo(42);

return 0;
}
)
->when($result = $stream->setStreamBuffer(42))
->then
->boolean($result)
->isTrue()
->boolean($called)
->isTrue()
->integer($stream->getStreamBufferSize())
->isEqualTo(42);
}

public function case_set_stream_buffer_fail()
{
$self = $this;

$this
->given(
$stream = new SUT(__FILE__),
$oldStreamBufferSize = $stream->getStreamBufferSize(),

$this->function->stream_set_write_buffer = function ($_stream, $_buffer) use ($self, $stream, &$called) {
$called = true;

$self
->resource($_stream)
->isIdenticalTo($stream->getStream())
->integer($_buffer)
->isEqualTo(42);

return 1;
}
)
->when($result = $stream->setStreamBuffer(42))
->then
->boolean($result)
->isFalse()
->boolean($called)
->isTrue()
->integer($stream->getStreamBufferSize())
->isEqualTo($oldStreamBufferSize);
}

public function case_disable_stream_buffer()
{
$self = $this;

$this
->given(
$stream = new SUT(__FILE__),

$this->function->stream_set_write_buffer = function ($_stream, $_buffer) use ($self, $stream, &$called) {
$called = true;

$self
->resource($_stream)
->isIdenticalTo($stream->getStream())
->integer($_buffer)
->isEqualTo(0);

return 0;
}
)
->when($result = $stream->disableStreamBuffer())
->then
->boolean($result)
->isTrue()
->boolean($called)
->isTrue()
->integer($stream->getStreamBufferSize())
->isEqualTo(0);
}

public function case_get_stream_wrapper_name_with_no_wrapper()
{
$this
->given($stream = new SUT(__FILE__))
->when($result = $stream->getStreamWrapperName())
->then
->string($result)
->isEqualTo('file');
}

public function case_get_stream_wrapper_name()
{
$this
->given($stream = new SUT('hoa://Test/Vfs/Foo?type=file'))
->when($result = $stream->getStreamWrapperName())
->then
->string($result)
->isEqualTo('hoa');
}

public function case_get_stream_meta_data()
{
$this
->given($stream = new SUT(__FILE__))
->when($result = $stream->getStreamMetaData())
->then
->array($result)
->isEqualTo([
'timed_out' => false,
'blocked' => true,
'eof' => false,
'wrapper_type' => 'plainfile',
'stream_type' => 'STDIO',
'mode' => 'rb',
'unread_bytes' => 0,
'seekable' => true,
'uri' => __FILE__
]);
}

public function case_is_borrowing()
{
$this
->given(
$streamA1 = new SUT(__FILE__),
$streamA2 = new SUT(__FILE__)
)
->when($result = $streamA2->isBorrowing())
->then
->boolean($result)
->isTrue()
->boolean($streamA1->isBorrowing())
->isFalse();
}

public function case_is_not_borrowing()
{
$this
->given($stream = new SUT(__FILE__))
->when($result = $stream->isBorrowing())
->then
->boolean($result)
->isFalse();
}

public function case_shutdown_destructor()
{
$this
->given(
$stream = new \Mock\Hoa\Stream\Test\Unit\SUTWithPublicClose(__FILE__),
$this->calling($stream)->_close = function () use (&$called) {
$called = true;
}
)
->when($result = SUT::_Hoa_Stream())
->then
->boolean($called)
->isTrue();
}

public function case_destruct_an_opened_stream()
{
$this
->given(
$stream = new \Mock\Hoa\Stream\Test\Unit\SUTWithPublicClose(__FILE__),
$this->calling($stream)->_close = function () use (&$called) {
$called = true;
}
)
->when($result = $stream->__destruct())
->then
->boolean($called)
->isTrue();
}

public function case_destruct_a_deferred_stream()
{
$this
->given(
$stream = new \Mock\Hoa\Stream\Test\Unit\SUTWithPublicClose(__FILE__, null, true),
$this->calling($stream)->_close = function () use (&$called) {
$called = true;
}
)
->when($result = $stream->__destruct())
->then
->variable($called)
->isNull();
}

public function case_protocol_reach_id()
{
$this
->given(
$name = 'hoa://Test/Vfs/Foo?type=file',
$stream = new SUT($name)
)
->when($result = resolve('hoa://Library/Stream#' . $name))
->then
->object($result)
->isIdenticalTo($stream);
}

public function case_protocol_reach_unknown_id()
{
$this
->given($name = 'hoa://Test/Vfs/Foo?type=file')
->when($result = resolve('hoa://Library/Stream#' . $name))
->then
->variable($result)
->isNull();
}
}

class SUT extends LUT\Stream
{
protected function &_open($streamName, LUT\Context $context = null)
{
if (null === $context) {
$out = fopen($streamName, 'rb');
} else {
$out = fopen($streamName, 'rb', false, $context->getContext());
}

return $out;
}

protected function _close()
{
return fclose($this->getStream());
}
}

class SUTWithPublicClose extends SUT
{
public function _close()
{
return parent::_close();
}
}
<?php



































namespace Hoa\Stream\Test\Unit;

use Mock\Hoa\Stream\Composite as SUT;
use Hoa\Test;









class Composite extends Test\Unit\Suite
{
public function case_set_stream()
{
$this
->given(
$stream = new \StdClass(),
$composite = new SUT()
)
->when($result = $this->invoke($composite)->setStream($stream))
->then
->variable($result)
->isNull();
}

public function case_get_stream()
{
$this
->given(
$stream = new \StdClass(),
$composite = new SUT(),
$this->invoke($composite)->setStream($stream)
)
->when($result = $composite->getStream())
->then
->object($result)
->isIdenticalTo($stream);
}

public function case_set_inner_stream()
{
$this
->given(
$innerStream = new \Mock\Hoa\Stream(__FILE__),
$composite = new SUT()
)
->when($result = $this->invoke($composite)->setInnerStream($innerStream))
->then
->variable($result)
->isNull();
}

public function case_get_inner_stream()
{
$this
->given(
$innerStream = new \Mock\Hoa\Stream(__FILE__),
$composite = new SUT(),
$this->invoke($composite)->setInnerStream($innerStream)
)
->when($result = $composite->getInnerStream())
->then
->object($result)
->isIdenticalTo($innerStream);
}
}
<?php



































namespace Hoa\Stream;

use Hoa\Exception as HoaException;









class Exception extends HoaException
{
}
<?php



































namespace Hoa\Stream\Wrapper\IWrapper;

use Hoa\Consistency;









interface IWrapper extends File, Stream
{





public function __construct();
}




Consistency::flexEntity('Hoa\Stream\Wrapper\IWrapper\IWrapper');
<?php



































namespace Hoa\Stream\Wrapper\IWrapper;









interface Stream
{









public function stream_cast($castAs);









public function stream_close();







public function stream_eof();









public function stream_flush();
















public function stream_lock($operation);


















public function stream_metadata($path, $option, $value);




























public function stream_open($path, $mode, $options, &$openedPath);









public function stream_read($count);

















public function stream_seek($offset, $whence = SEEK_SET);
































public function stream_set_option($option, $arg1, $arg2);







public function stream_stat();







public function stream_tell();







public function stream_truncate($size);








public function stream_write($data);
}
<?php



































namespace Hoa\Stream\Wrapper\IWrapper;









interface File
{








public function dir_closedir();









public function dir_opendir($path, $options);







public function dir_readdir();










public function dir_rewinddir();










public function mkdir($path, $mode, $options);










public function rename($from, $to);









public function rmdir($path, $options);








public function unlink($path);

























public function url_stat($path, $flags);
}
<?php



































namespace Hoa\Stream\Wrapper;

use Hoa\Consistency;









class Wrapper
{











public static function register($protocol, $className, $flags = 0)
{
if (true === self::isRegistered($protocol)) {
throw new Exception(
'The protocol %s is already registered.',
0,
$protocol
);
}

if (false === class_exists($className)) {
throw new Exception(
'Cannot use the %s class for the implementation of ' .
'the %s protocol because it is not found.',
1,
[$className, $protocol]
);
}

return stream_wrapper_register($protocol, $className, $flags);
}







public static function unregister($protocol)
{

 
 
 return @stream_wrapper_unregister($protocol);
}







public static function restore($protocol)
{

 
 
 return @stream_wrapper_restore($protocol);
}







public static function isRegistered($protocol)
{
return in_array($protocol, self::getRegistered());
}






public static function getRegistered()
{
return stream_get_wrappers();
}
}




Consistency::flexEntity('Hoa\Stream\Wrapper\Wrapper');
<?php



































namespace Hoa\Stream\Wrapper;

use Hoa\Stream;









class Exception extends Stream\Exception
{
}
<?php



































namespace Hoa\Stream\IStream;









interface Statable extends Stream
{





const SIZE_UNDEFINED = -1;






public function getSize();






public function getStatistic();






public function getATime();






public function getCTime();






public function getMTime();






public function getGroup();






public function getOwner();






public function getPermissions();






public function isReadable();






public function isWritable();






public function isExecutable();






public function clearStatisticCache();






public static function clearAllStatisticCaches();
}
<?php



































namespace Hoa\Stream\IStream;









interface Touchable extends Stream
{





const OVERWRITE = true;






const DO_NOT_OVERWRITE = false;






const MAKE_DIRECTORY = true;






const DO_NOT_MAKE_DIRECTORY = false;











public function touch($time = -1, $atime = -1);










public function copy($to, $force = self::DO_NOT_OVERWRITE);












public function move(
$name,
$force = self::DO_NOT_OVERWRITE,
$mkdir = self::DO_NOT_MAKE_DIRECTORY
);






public function delete();







public function changeGroup($group);







public function changeMode($mode);







public function changeOwner($user);








public static function umask($umask = null);
}
<?php



































namespace Hoa\Stream\IStream;









interface In extends Stream
{





public function eof();







public function read($length);







public function readString($length);







public function readCharacter();






public function readBoolean();







public function readInteger($length = 1);







public function readFloat($length = 1);









public function readArray($argument = null);






public function readLine();







public function readAll($offset = 0);







public function scanf($format);
}
<?php



































namespace Hoa\Stream\IStream;









interface Structural extends Stream
{





public function selectRoot();






public function selectAnyElements();







public function selectElements($E = null);







public function selectDescendantElements($F = null);







public function selectChildElements($F = null);







public function selectAdjacentSiblingElement($F);







public function selectSiblingElements($F = null);







public function querySelector($query);







public function querySelectorAll($query);
}
<?php



































namespace Hoa\Stream\IStream;









interface Out extends Stream
{







public function write($string, $length);







public function writeString($string);







public function writeCharacter($character);







public function writeBoolean($boolean);







public function writeInteger($integer);







public function writeFloat($float);







public function writeArray(array $array);







public function writeLine($line);







public function writeAll($string);







public function truncate($size);
}
<?php



































namespace Hoa\Stream\IStream;









interface Pointable extends Stream
{





const SEEK_SET = SEEK_SET;






const SEEK_CURRENT = SEEK_CUR;






const SEEK_END = SEEK_END;








public function rewind();








public function seek($offset, $whence = self::SEEK_SET);






public function tell();
}
<?php



































namespace Hoa\Stream\IStream;









interface Stream
{





public function getStream();
}
<?php



































namespace Hoa\Stream\IStream;











interface Bufferable extends Stream
{








public function newBuffer($callable = null, $size = null);






public function flush();






public function deleteBuffer();






public function getBufferLevel();






public function getBufferSize();
}
<?php



































namespace Hoa\Stream\IStream;









interface Lockable extends Stream
{





const LOCK_SHARED = LOCK_SH;






const LOCK_EXCLUSIVE = LOCK_EX;






const LOCK_RELEASE = LOCK_UN;






const LOCK_NO_BLOCK = LOCK_NB;










public function lock($operation);
}
<?php



































namespace Hoa\Stream\IStream;









interface Pathable extends Stream
{





public function getBasename();






public function getDirname();
}
<?php



































namespace Hoa\Stream;









class Bucket
{





const IS_A_BRIGADE = true;






const IS_A_STREAM = false;






protected $_type = null;






protected $_brigade = null;






protected $_bucket = null;













public function __construct(&$brigade, $is = self::IS_A_BRIGADE, $buffer = '')
{
$this->setType($is);

if (self::IS_A_BRIGADE === $this->getType()) {
$this->setBrigade($brigade);
} else {
$this->setBucket(stream_bucket_new($brigade, $buffer));
$bucket = $this->getBucket();
$this->setBrigade($bucket);
}

return;
}







public function eob()
{
$this->_bucket = null;

return false == $this->getBucket();
}







public function append(Bucket $bucket)
{
stream_bucket_append($this->getBrigade(), $bucket->getBucket());

return;
}







public function prepend(Bucket $bucket)
{
stream_bucket_prepend($this->getBrigade(), $bucket->getBucket());

return;
}







protected function setType($type)
{
$old = $this->_type;
$this->_type = $type;

return $old;
}






public function getType()
{
return $this->_type;
}







public function setData($data)
{
$old = $this->getBucket()->data;
$this->getBucket()->data = $data;
$this->getBucket()->datalen = strlen($this->getBucket()->data);

return $old;
}






public function getData()
{
if (null === $this->getBucket()) {
return null;
}

return $this->getBucket()->data;
}






public function getLength()
{
if (null === $this->getBucket()) {
return 0;
}

return $this->getBucket()->datalen;
}







protected function setBrigade(&$brigade)
{
$old = $this->_brigade;
$this->_brigade = $brigade;

return $old;
}






public function getBrigade()
{
return $this->_brigade;
}







protected function setBucket($bucket)
{
$old = $this->_bucket;
$this->_bucket = $bucket;

return $old;
}






protected function getBucket()
{
if (null === $this->_bucket && self::IS_A_BRIGADE === $this->getType()) {
$this->_bucket = stream_bucket_make_writeable($this->getBrigade());
}

return $this->_bucket;
}
}
<?php



































namespace Hoa\Stream;









class Context
{





protected $_id = null;






protected static $_instances = [];







protected function __construct($id)
{
$this->_id = $id;
$this->_context = stream_context_create();

return;
}








public static function getInstance($id)
{
if (empty($id)) {
throw new Exception('Context ID must not be null.', 0);
}

if (false === static::contextExists($id)) {
static::$_instances[$id] = new static($id);
}

return static::$_instances[$id];
}






public function getId()
{
return $this->_id;
}







public static function contextExists($id)
{
return array_key_exists($id, static::$_instances);
}








public function setOptions(array $options)
{
return stream_context_set_option($this->getContext(), $options);
}








public function setParameters(array $parameters)
{
return stream_context_set_params($this->getContext(), $parameters);
}






public function getOptions()
{
return stream_context_get_options($this->getContext());
}






public function getParameters()
{
return stream_context_get_params($this->getContext());
}






public function getContext()
{
return $this->_context;
}
}
<?php



































namespace Hoa\Stream\Filter;

use Hoa\Stream;









abstract class LateComputed extends Basic
{





protected $_buffer = null;
























public function filter($in, $out, &$consumed, $closing)
{
$return = self::FEED_ME;
$iBucket = new Stream\Bucket($in);

while (false === $iBucket->eob()) {
$this->_buffer .= $iBucket->getData();
$consumed += $iBucket->getLength();
}

if (null !== $consumed) {
$return = self::PASS_ON;
}

if (true === $closing) {
$stream = $this->getStream();
$this->compute();
$bucket = new Stream\Bucket(
$stream,
Stream\Bucket::IS_A_STREAM,
$this->_buffer
);
$oBucket = new Stream\Bucket($out);
$oBucket->append($bucket);

$return = self::PASS_ON;
$this->_buffer = null;
}

return $return;
}






abstract protected function compute();
}
<?php



































namespace Hoa\Stream\Filter;

use Hoa\Stream;









class Exception extends Stream\Exception
{
}
<?php



































namespace Hoa\Stream\Filter;

use Hoa\Consistency;
use Hoa\Stream;









abstract class Filter extends Stream
{





const OVERWRITE = true;






const DO_NOT_OVERWRITE = false;






const READ = STREAM_FILTER_READ;






const WRITE = STREAM_FILTER_WRITE;






const READ_AND_WRITE = STREAM_FILTER_ALL;






protected static $_resources = [];













public static function register(
$name,
$class,
$overwrite = self::DO_NOT_OVERWRITE
) {
if ($overwrite === self::DO_NOT_OVERWRITE &&
true === self::isRegistered($name)) {
throw new Exception('Filter %s is already registered.', 0, $name);
}

if (is_object($class)) {
$class = get_class($class);
}

if (empty($name)) {
throw new Exception(
'Filter name cannot be empty (implementation class is %s).',
1,
$class
);
}

if (false === class_exists($class, false)) {
throw new Exception(
'Cannot register the %s class for the filter %s ' .
'because it does not exist.',
2,
[$class, $name]
);
}

return stream_filter_register($name, $class);
}













public static function append(
$stream,
$name,
$mode = self::READ,
$parameters = null
) {
if ($stream instanceof Stream) {
$stream = $stream->getStream();
}

if (null === $parameters) {
return self::$_resources[$name] = stream_filter_append(
$stream,
$name,
$mode
);
}

return self::$_resources[$name] = stream_filter_append(
$stream,
$name,
$mode,
$parameters
);
}













public static function prepend(
$stream,
$name,
$mode = self::READ, $parameters = null
) {
if ($stream instanceof Stream) {
$stream = $stream->getStream();
}

if (null === $parameters) {
return self::$_resources[$name] = stream_filter_prepend(
$stream,
$name,
$mode
);
}

return self::$_resources[$name] = stream_filter_prepend(
$stream,
$name,
$mode,
$parameters
);
}








public static function remove($streamFilter)
{
if (!is_resource($streamFilter)) {
if (isset(self::$_resources[$streamFilter])) {
$streamFilter = self::$_resources[$streamFilter];
} else {
throw new Exception(
'Cannot remove the stream filter %s because no resource was ' .
'found with this name.',
3,
$streamFilter
);
}
}

return stream_filter_remove($streamFilter);
}







public static function isRegistered($name)
{
return in_array($name, self::getRegistered());
}






public static function getRegistered()
{
return stream_get_filters();
}
}




Consistency::flexEntity('Hoa\Stream\Filter\Filter');
<?php



































namespace Hoa\Stream\Filter;

use Hoa\Stream;










abstract class Basic extends \php_user_filter implements Stream\IStream\Stream
{






const PASS_ON = PSFS_PASS_ON;







const FEED_ME = PSFS_FEED_ME;






const FATAL_ERROR = PSFS_ERR_FATAL;






const FLAG_NORMAL = PSFS_FLAG_NORMAL;






const FLAG_FLUSH_INC = PSFS_FLAG_FLUSH_INC;






const FLAG_FLUSH_CLOSE = PSFS_FLAG_FLUSH_CLOSE;
























public function filter($in, $out, &$consumed, $closing)
{
$iBucket = new Stream\Bucket($in);
$oBucket = new Stream\Bucket($out);

while (false === $iBucket->eob()) {
$consumed += $iBucket->getLength();
$oBucket->append($iBucket);
}

unset($iBucket);
unset($oBucket);

return self::PASS_ON;
}






public function onCreate()
{
return true;
}







public function onClose()
{
return;
}







public function setName($name)
{
$old = $this->filtername;
$this->filtername = $name;

return $old;
}







public function setParameters($parameters)
{
$old = $this->params;
$this->params = $parameters;

return $old;
}






public function getName()
{
return $this->filtername;
}






public function getParameters()
{
return $this->params;
}








public function getStream()
{
return isset($this->stream) ? $this->stream : null;
}
}
<?php



































namespace Hoa\Stream;

use Hoa\Consistency;
use Hoa\Event;
use Hoa\Protocol;









abstract class Stream implements IStream\Stream, Event\Listenable
{
use Event\Listens;






const NAME = 0;






const HANDLER = 1;






const RESOURCE = 2;






const CONTEXT = 3;






const DEFAULT_BUFFER_SIZE = 8192;






protected $_bucket = [];






private static $_register = [];






protected $_bufferSize = self::DEFAULT_BUFFER_SIZE;






protected $_streamName = null;






protected $_context = null;






protected $_hasBeenDeferred = false;






protected $_borrowing = false;













public function __construct($streamName, $context = null, $wait = false)
{
$this->_streamName = $streamName;
$this->_context = $context;
$this->_hasBeenDeferred = $wait;
$this->setListener(
new Event\Listener(
$this,
[
'authrequire',
'authresult',
'complete',
'connect',
'failure',
'mimetype',
'progress',
'redirect',
'resolve',
'size'
]
)
);

if (true === $wait) {
return;
}

$this->open();

return;
}













final private static function &_getStream(
$streamName,
Stream $handler,
$context = null
) {
$name = md5($streamName);

if (null !== $context) {
if (false === Context::contextExists($context)) {
throw new Exception(
'Context %s was not previously declared, cannot retrieve ' .
'this context.',
0,
$context
);
}

$context = Context::getInstance($context);
}

if (!isset(self::$_register[$name])) {
self::$_register[$name] = [
self::NAME => $streamName,
self::HANDLER => $handler,
self::RESOURCE => $handler->_open($streamName, $context),
self::CONTEXT => $context
];
Event::register(
'hoa://Event/Stream/' . $streamName,
$handler
);

 Event::register(
'hoa://Event/Stream/' . $streamName . ':close-before',
$handler
);
} else {
$handler->_borrowing = true;
}

if (null === self::$_register[$name][self::RESOURCE]) {
self::$_register[$name][self::RESOURCE]
= $handler->_open($streamName, $context);
}

return self::$_register[$name];
}











abstract protected function &_open($streamName, Context $context = null);








abstract protected function _close();







final public function open()
{
$context = $this->_context;

if (true === $this->hasBeenDeferred()) {
if (null === $context) {
$handle = Context::getInstance(uniqid());
$handle->setParameters([
'notification' => [$this, '_notify']
]);
$context = $handle->getId();
} elseif (true === Context::contextExists($context)) {
$handle = Context::getInstance($context);
$parameters = $handle->getParameters();

if (!isset($parameters['notification'])) {
$handle->setParameters([
'notification' => [$this, '_notify']
]);
}
}
}

$this->_bufferSize = self::DEFAULT_BUFFER_SIZE;
$this->_bucket = self::_getStream(
$this->_streamName,
$this,
$context
);

return $this;
}






final public function close()
{
$streamName = $this->getStreamName();
$name = md5($streamName);

if (!isset(self::$_register[$name])) {
return;
}

Event::notify(
'hoa://Event/Stream/' . $streamName . ':close-before',
$this,
new Event\Bucket()
);

if (false === $this->_close()) {
return;
}

unset(self::$_register[$name]);
$this->_bucket[self::HANDLER] = null;
Event::unregister(
'hoa://Event/Stream/' . $streamName
);
Event::unregister(
'hoa://Event/Stream/' . $streamName . ':close-before'
);

return;
}






public function getStreamName()
{
if (empty($this->_bucket)) {
return null;
}

return $this->_bucket[self::NAME];
}






public function getStream()
{
if (empty($this->_bucket)) {
return null;
}

return $this->_bucket[self::RESOURCE];
}






public function getStreamContext()
{
if (empty($this->_bucket)) {
return null;
}

return $this->_bucket[self::CONTEXT];
}







public static function getStreamHandler($streamName)
{
$name = md5($streamName);

if (!isset(self::$_register[$name])) {
return null;
}

return self::$_register[$name][self::HANDLER];
}










public function _setStream($stream)
{
if (false === is_resource($stream) &&
('resource' !== gettype($stream) ||
'Unknown' !== get_resource_type($stream))) {
throw new Exception(
'Try to change the stream resource with an invalid one; ' .
'given %s.',
1,
gettype($stream)
);
}

$old = $this->_bucket[self::RESOURCE];
$this->_bucket[self::RESOURCE] = $stream;

return $old;
}






public function isOpened()
{
return is_resource($this->getStream());
}








public function setStreamTimeout($seconds, $microseconds = 0)
{
return stream_set_timeout($this->getStream(), $seconds, $microseconds);
}




protected function hasBeenDeferred()
{
return $this->_hasBeenDeferred;
}








public function hasTimedOut()
{
$metaData = $this->getStreamMetaData();

return true === $metaData['timed_out'];
}







public function setStreamBlocking($mode)
{
return stream_set_blocking($this->getStream(), (int) $mode);
}















public function setStreamBuffer($buffer)
{

 $out = 0 === stream_set_write_buffer($this->getStream(), $buffer);

if (true === $out) {
$this->_bufferSize = $buffer;
}

return $out;
}







public function disableStreamBuffer()
{
return $this->setStreamBuffer(0);
}






public function getStreamBufferSize()
{
return $this->_bufferSize;
}






public function getStreamWrapperName()
{
if (false === $pos = strpos($this->getStreamName(), '://')) {
return 'file';
}

return substr($this->getStreamName(), 0, $pos);
}






public function getStreamMetaData()
{
return stream_get_meta_data($this->getStream());
}






public function isBorrowing()
{
return $this->_borrowing;
}















public function _notify(
$ncode,
$severity,
$message,
$code,
$transferred,
$max
) {
static $_map = [
STREAM_NOTIFY_AUTH_REQUIRED => 'authrequire',
STREAM_NOTIFY_AUTH_RESULT => 'authresult',
STREAM_NOTIFY_COMPLETED => 'complete',
STREAM_NOTIFY_CONNECT => 'connect',
STREAM_NOTIFY_FAILURE => 'failure',
STREAM_NOTIFY_MIME_TYPE_IS => 'mimetype',
STREAM_NOTIFY_PROGRESS => 'progress',
STREAM_NOTIFY_REDIRECTED => 'redirect',
STREAM_NOTIFY_RESOLVE => 'resolve',
STREAM_NOTIFY_FILE_SIZE_IS => 'size'
];

$this->getListener()->fire($_map[$ncode], new Event\Bucket([
'code' => $code,
'severity' => $severity,
'message' => $message,
'transferred' => $transferred,
'max' => $max
]));

return;
}










final public static function _Hoa_Stream()
{
foreach (self::$_register as $entry) {
$entry[self::HANDLER]->close();
}

return;
}






public function __toString()
{
return $this->getStreamName();
}






public function __destruct()
{
if (false === $this->isOpened()) {
return;
}

$this->close();

return;
}
}









class _Protocol extends Protocol\Node
{





protected $_name = 'Stream';









public function reachId($id)
{
return Stream::getStreamHandler($id);
}
}




Consistency::flexEntity('Hoa\Stream\Stream');




Consistency::registerShutdownFunction(xcallable('Hoa\Stream\Stream::_Hoa_Stream'));





$protocol = Protocol::getInstance();
$protocol['Library'][] = new _Protocol();
<?php



































namespace Hoa\Stream;









abstract class Composite
{





protected $_stream = null;






protected $_innerStream = null;









protected function setStream($stream)
{
$old = $this->_stream;
$this->_stream = $stream;

return $old;
}






public function getStream()
{
return $this->_stream;
}







protected function setInnerStream(Stream $innerStream)
{
$old = $this->_innerStream;
$this->_innerStream = $innerStream;

return $old;
}






public function getInnerStream()
{
return $this->_innerStream;
}
}
<?php



































namespace Hoa\Exception;











class Idle extends \Exception
{





protected $_tmpArguments = null;






protected $_arguments = null;






protected $_trace = null;






protected $_previous = null;






protected $_rawMessage = null;














public function __construct(
$message,
$code = 0,
$arguments = [],
\Exception $previous = null
) {
$this->_tmpArguments = $arguments;
parent::__construct($message, $code, $previous);
$this->_rawMessage = $message;
$this->message = @vsprintf($message, $this->getArguments());

return;
}







public function getBacktrace()
{
if (null === $this->_trace) {
$this->_trace = $this->getTrace();
}

return $this->_trace;
}







public function getPreviousThrow()
{
if (null === $this->_previous) {
$this->_previous = $this->getPrevious();
}

return $this->_previous;
}






public function getArguments()
{
if (null === $this->_arguments) {
$arguments = $this->_tmpArguments;

if (!is_array($arguments)) {
$arguments = [$arguments];
}

foreach ($arguments as &$value) {
if (null === $value) {
$value = '(null)';
}
}

$this->_arguments = $arguments;
unset($this->_tmpArguments);
}

return $this->_arguments;
}






public function getRawMessage()
{
return $this->_rawMessage;
}






public function getFormattedMessage()
{
return $this->getMessage();
}






public function getFrom()
{
$trace = $this->getBacktrace();
$from = '{main}';

if (!empty($trace)) {
$t = $trace[0];
$from = '';

if (isset($t['class'])) {
$from .= $t['class'] . '::';
}

if (isset($t['function'])) {
$from .= $t['function'] . '()';
}
}

return $from;
}







public function raise($previous = false)
{
$message = $this->getFormattedMessage();
$trace = $this->getBacktrace();
$file = '/dev/null';
$line = -1;
$pre = $this->getFrom();

if (!empty($trace)) {
$file = isset($trace['file']) ? $trace['file'] : null;
$line = isset($trace['line']) ? $trace['line'] : null;
}

$pre .= ': ';

try {
$out =
$pre . '(' . $this->getCode() . ') ' . $message . "\n" .
'in ' . $this->getFile() . ' at line ' .
$this->getLine() . '.';
} catch (\Exception $e) {
$out =
$pre . '(' . $this->getCode() . ') ' . $message . "\n" .
'in ' . $file . ' around line ' . $line . '.';
}

if (true === $previous &&
null !== $previous = $this->getPreviousThrow()) {
$out .=
"\n\n" . '    ⬇' . "\n\n" .
'Nested exception (' . get_class($previous) . '):' . "\n" .
($previous instanceof self
? $previous->raise(true)
: $previous->getMessage());
}

return $out;
}








public static function uncaught($exception)
{
if (!($exception instanceof self)) {
throw $exception;
}

while (0 < ob_get_level()) {
ob_end_flush();
}

echo
'Uncaught exception (' . get_class($exception) . '):' . "\n" .
$exception->raise(true);

return;
}






public function __toString()
{
return $this->raise();
}








public static function enableUncaughtHandler($enable = true)
{
if (false === $enable) {
return restore_exception_handler();
}

return set_exception_handler(function ($exception) {
return self::uncaught($exception);
});
}
}
<?php



































namespace Hoa\Exception\Test\Unit;

use Hoa\Exception\Idle as SUT;
use Hoa\Test;









class Idle extends Test\Unit\Suite
{
public function case_is_a_real_exception()
{
$this
->when($result = new SUT('foo'))
->then
->object($result)
->isInstanceOf('Exception');
}

public function case_get_backtrace()
{
$this
->given($exception = new SUT('foo'))
->when($result = $exception->getBacktrace())
->then
->array($result)
->hasKey(0)
->array($result[0])
->hasKey('file')
->hasKey('line')
->hasKey('function')
->hasKey('class')
->hasKey('type')
->hasKey('args');
}

public function case_get_previous_throw()
{
$this
->given(
$previous = new SUT('previous'),
$exception = new SUT('foo', 0, [], $previous)
)
->when($result = $exception->getPreviousThrow())
->then
->object($result)
->isIdenticalTo($previous);
}

public function case_get_arguments()
{
$this
->given($exception = new SUT('foo', 0, ['arg', 42, null]))
->when($result = $exception->getArguments())
->then
->array($result)
->isEqualTo(['arg', 42, '(null)']);
}

public function case_get_arguments_from_a_string()
{
$this
->given($exception = new SUT('foo', 0, 'arg'))
->when($result = $exception->getArguments())
->then
->array($result)
->isEqualTo(['arg']);
}

public function case_get_raw_message()
{
$this
->given(
$message = 'foo %s',
$exception = new SUT($message)
)
->when($result = $exception->getRawMessage())
->then
->string($result)
->isEqualTo($message);
}

public function case_get_formatted_message()
{
$this
->given(
$message = 'foo %s',
$exception = new SUT($message, 0, 'bar')
)
->when($result = $exception->getFormattedMessage())
->then
->string($result)
->isEqualTo($exception->getMessage())
->isEqualTo('foo bar');
}

public function case_get_from_object()
{
$this
->given($exception = new SUT('foo'))
->when($result = $exception->getFrom())
->then
->string($result)
->isEqualTo(__METHOD__ . '()');
}

public function case_raise()
{
$this
->given($exception = new SUT('foo'), $line = __LINE__)
->when($result = $exception->raise())
->then
->string($result)
->isEqualTo(
__METHOD__ . '(): (0) foo' . "\n" .
'in ' . __FILE__ . ' at line ' . $line . '.'
);
}

public function case_raise_with_previous()
{
$this
->given(
$previous = new SUT('previous'), $previousLine = __LINE__,
$exception = new SUT('foo', 0, [], $previous), $line = __LINE__
)
->when($result = $exception->raise(true))
->then
->string($result)
->isEqualTo(
__METHOD__ . '(): (0) foo' . "\n" .
'in ' . __FILE__ . ' at line ' . $line . '.' . "\n\n" .
'    ⬇' . "\n\n" .
'Nested exception (' . get_class($previous) . '):' . "\n" .
__METHOD__ . '(): (0) previous' . "\n" .
'in ' . __FILE__ . ' at line ' . $previousLine . '.'
);
}

public function case_uncaught()
{
$this
->given(
$this->function->ob_get_level = 0,
$exception = new SUT('foo'), $line = __LINE__
)
->when($result = SUT::uncaught($exception))
->then
->variable($result)
->isNull()
->output
->isEqualTo(
'Uncaught exception (' . get_class($exception) . '):' . "\n" .
__METHOD__ . '(): (0) foo' . "\n" .
'in ' . __FILE__ . ' at line ' . $line . '.'
);
}

public function case_uncaught_not_Hoa()
{
$this
->exception(function () {
SUT::uncaught(new \Exception('foo'));
})
->isInstanceOf('Exception')
->output
->isEmpty();
}

public function case_to_string()
{
$this
->given($exception = new SUT('foo'))
->when($result = $exception->__toString())
->then
->string($result)
->isEqualTo($exception->raise());
}

public function case_disable_uncaught_handler()
{
$this
->given(
$this->function->restore_exception_handler = function () use (&$called) {
$called = true;

return null;
}
)
->when($result = SUT::enableUncaughtHandler(false))
->then
->variable($result)
->isNull()
->boolean($called)
->isTrue();
}

public function case_enable_uncaught_handler()
{
$self = $this;

$this
->given(
$this->function->set_exception_handler = function ($handler) use ($self, &$called) {
$called = true;

$self
->object($handler)
->isInstanceOf('Closure')
->let($reflection = new \ReflectionObject($handler))
->array($invokeParameters = $reflection->getMethod('__invoke')->getParameters())
->hasSize(1)
->string($invokeParameters[0]->getName())
->isEqualTo('exception');

return null;
}
)
->when($result = SUT::enableUncaughtHandler())
->then
->variable($result)
->isNull()
->boolean($called)
->isTrue();
}
}
<?php



































namespace Hoa\Exception\Test\Unit;

use Hoa\Event;
use Hoa\Exception\Exception as SUT;
use Hoa\Test;









class Exception extends Test\Unit\Suite
{
public function case_is_an_idle_exception()
{
$this
->when($result = new SUT('foo'))
->then
->object($result)
->isInstanceOf('Hoa\Exception\Idle');
}

public function case_event_is_registered()
{
$this
->given(new SUT('foo'))
->when($result = Event::eventExists('hoa://Event/Exception'))
->then
->boolean($result)
->isTrue();
}

public function case_event_is_sent()
{
$self = $this;

$this
->given(
Event::getEvent('hoa://Event/Exception')->attach(
function (Event\Bucket $bucket) use ($self, &$called) {
$called = true;

$self
->object($bucket->getSource())
->isInstanceOf('Hoa\Exception\Exception')
->string($bucket->getSource()->getMessage())
->isEqualTo('foo')
->object($bucket->getData())
->isIdenticalTo($bucket->getSource());
}
)
)
->when(new SUT('foo'))
->then
->boolean($called)
->isTrue();
}
}
<?php



































namespace Hoa\Exception\Test\Unit;

use Hoa\Exception\Group as SUT;
use Hoa\Test;









class Group extends Test\Unit\Suite
{
public function case_is_an_exception_arrayaccess_iteratoraggregate_countable()
{
$this
->when($result = new SUT('foo'))
->then
->object($result)
->isInstanceOf('Hoa\Exception\Exception')
->isInstanceOf('ArrayAccess')
->isInstanceOf('IteratorAggregate')
->isInstanceOf('Countable');
}

public function case_constructor()
{
$this
->given(
$message = 'foo %s %d %s',
$code = 7,
$arguments = ['arg', 42, null],
$previous = new SUT('previous')
)
->when($result = new SUT($message, $code, $arguments, $previous), $line = __LINE__)
->then
->string($result->getMessage())
->isEqualTo('foo arg 42 (null)')
->integer($result->getCode())
->isEqualTo(7)
->array($result->getArguments())
->isEqualTo(['arg', 42, '(null)'])
->object($result->getPreviousThrow())
->isIdenticalTo($previous)
->boolean($result->hasUncommittedExceptions())
->isFalse();
}

public function case_raise_zero_exception()
{
$this
->given($group = new SUT('foo'), $line = __LINE__)
->when($result = $group->raise())
->then
->string($result)
->isEqualTo(
__METHOD__ . '(): (0) foo' . "\n" .
'in ' . __FILE__ . ' at line ' . $line . '.'
);
}

public function case_raise_one_exception()
{
$this
->given(
$exception1 = new SUT('bar'), $barLine = __LINE__,
$group = new SUT('foo'), $fooLine = __LINE__,
$group[] = $exception1
)
->when($result = $group->raise())
->then
->string($result)
->isEqualTo(
__METHOD__ . '(): (0) foo' . "\n" .
'in ' . __FILE__ . ' at line ' . $fooLine . '.' . "\n\n" .
'Contains the following exceptions:' . "\n\n" .
'  • ' . __METHOD__ . '(): (0) bar' . "\n" .
'    in ' . __FILE__ . ' at line ' . $barLine . '.'
);
}

public function case_raise_more_exceptions()
{
$this
->given(
$exception1 = new SUT('bar'), $barLine = __LINE__,
$exception2 = new SUT('baz'), $bazLine = __LINE__,
$group = new SUT('foo'), $fooLine = __LINE__,
$group[] = $exception1,
$group[] = $exception2
)
->when($result = $group->raise())
->then
->string($result)
->isEqualTo(
__METHOD__ . '(): (0) foo' . "\n" .
'in ' . __FILE__ . ' at line ' . $fooLine . '.' . "\n\n" .
'Contains the following exceptions:' . "\n\n" .
'  • ' . __METHOD__ . '(): (0) bar' . "\n" .
'    in ' . __FILE__ . ' at line ' . $barLine . '.' . "\n\n" .
'  • ' . __METHOD__ . '(): (0) baz' . "\n" .
'    in ' . __FILE__ . ' at line ' . $bazLine . '.'
);
}

public function case_begin_transaction()
{
$this
->given(
$group = new SUT('foo'),
$oldStackSize = $group->getStackSize()
)
->when(
$result = $group->beginTransaction(),
$stackSize = $group->getStackSize()
)
->then
->integer($oldStackSize)
->isEqualTo(1)
->object($result)
->isIdenticalTo($group)
->integer($stackSize)
->isEqualTo($oldStackSize + 1);
}

public function case_rollback_transaction_with_an_empty_stack()
{
$this
->given(
$group = new SUT('foo'),
$oldStackSize = $group->getStackSize()
)
->when(
$result = $group->rollbackTransaction(),
$stackSize = $group->getStackSize()
)
->then
->integer($oldStackSize)
->isEqualTo(1)
->object($result)
->isIdenticalTo($group)
->integer($stackSize)
->isEqualTo($oldStackSize);
}

public function case_rollback_transaction()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$group->beginTransaction(),
$oldStackSize = $group->getStackSize(),
$group->rollbackTransaction()
)
->when(
$result = $group->rollbackTransaction(),
$stackSize = $group->getStackSize()
)
->then
->integer($oldStackSize)
->isEqualTo(3)
->object($result)
->isIdenticalTo($group)
->integer($stackSize)
->isEqualTo($oldStackSize - 2);
}

public function case_commit_transaction_with_an_empty_stack()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$oldCount = count($group),
$oldStackSize = $group->getStackSize()
)
->when(
$result = $group->commitTransaction(),
$count = count($group),
$stackSize = $group->getStackSize()
)
->then
->integer($oldCount)
->isEqualTo(0)
->integer($oldStackSize)
->isEqualTo(2)
->object($result)
->isIdenticalTo($group)
->integer($count)
->isEqualTo($oldCount)
->integer($stackSize)
->isEqualTo($oldStackSize - 1);
}

public function case_commit_transaction()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$exception1 = new SUT('bar'),
$exception2 = new SUT('baz'),
$group[] = $exception1,
$group[] = $exception2,
$oldCount = count($group),
$oldStackSize = $group->getStackSize()
)
->when(
$result = $group->commitTransaction(),
$count = count($group),
$stackSize = $group->getStackSize()
)
->then
->integer($oldCount)
->isEqualTo(0)
->integer($oldStackSize)
->isEqualTo(2)
->object($result)
->isIdenticalTo($group)
->integer($count)
->isEqualTo($oldCount + 2)
->integer($stackSize)
->isEqualTo($oldStackSize - 1)
->array(iterator_to_array($group->getIterator()))
->isEqualTo([
0 => $exception1,
1 => $exception2
]);
}

public function case_has_uncommitted_exceptions()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$group[] = new SUT('bar')
)
->when($result = $group->hasUncommittedExceptions())
->then
->boolean($result)
->isTrue();
}

public function case_has_no_uncommitted_exceptions()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction()
)
->when($result = $group->hasUncommittedExceptions())
->then
->boolean($result)
->isFalse();
}

public function case_has_no_uncommitted_exceptions_with_empty_stack()
{
$this
->given(
$group = new SUT('foo'),
$group[] = new SUT('bar')
)
->when($result = $group->hasUncommittedExceptions())
->then
->boolean($result)
->isFalse();
}

public function case_offset_exists_with_no_uncommited_exceptions()
{
$this
->given(
$group = new SUT('foo'),
$group['bar'] = new SUT('bar')
)
->when($result = $group->offsetExists('bar'))
->then
->boolean($result)
->isTrue();
}

public function case_offset_does_not_exist_with_no_uncommited_exceptions()
{
$this
->given(
$group = new SUT('foo'),
$group['bar'] = new SUT('bar')
)
->when($result = $group->offsetExists('baz'))
->then
->boolean($result)
->isFalse();
}

public function case_offset_exists()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$group->beginTransaction(),
$group['bar'] = new SUT('bar')
)
->when($result = $group->offsetExists('bar'))
->then
->boolean($result)
->isTrue();
}

public function case_offset_does_not_exist()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$group->beginTransaction(),
$group['bar'] = new SUT('bar')
)
->when($result = $group->offsetExists('baz'))
->then
->boolean($result)
->isFalse();
}

public function case_offset_get_with_no_uncommited_exceptions()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar'),
$group['bar'] = $exception1
)
->when($result = $group->offsetGet('bar'))
->then
->object($result)
->isIdenticalTo($exception1);
}

public function case_offset_get_does_not_exist_with_no_uncommited_exceptions()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar'),
$group['bar'] = $exception1
)
->when($result = $group->offsetGet('baz'))
->then
->variable($result)
->isNull();
}

public function case_offset_get()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$group->beginTransaction(),
$exception1 = new SUT('bar'),
$group['bar'] = $exception1
)
->when($result = $group->offsetGet('bar'))
->then
->object($result)
->isIdenticalTo($exception1);
}

public function case_offset_get_does_not_exist()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$group->beginTransaction(),
$exception1 = new SUT('bar'),
$group['bar'] = $exception1
)
->when($result = $group->offsetGet('baz'))
->then
->variable($result)
->isNull();
}

public function case_offset_set_not_an_exception()
{
$this
->given($group = new SUT('foo'))
->when($group->offsetSet('bar', new \StdClass()))
->then
->boolean($group->offsetExists('bar'))
->isFalse();
}

public function case_offset_set()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar')
)
->when($result = $group->offsetExists('bar'))
->then
->boolean($result)
->isFalse()

->when($group->offsetSet('bar', $exception1))
->then
->boolean($group->offsetExists('bar'))
->isTrue()
->object($group->offsetGet('bar'))
->isIdenticalTo($exception1);
}

public function case_offset_set_with_a_null_index()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar')
)
->when($group->offsetSet(null, $exception1))
->then
->boolean($group->offsetExists(0))
->isTrue()
->object($group->offsetGet(0))
->isIdenticalTo($exception1);
}

public function case_offset_set_with_an_integer_index()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar')
)
->when($group->offsetSet(42, $exception1))
->then
->boolean($group->offsetExists(42))
->isFalse()
->boolean($group->offsetExists(0))
->isTrue()
->object($group->offsetGet(0))
->isIdenticalTo($exception1);
}

public function case_offset_unset_with_no_uncommited_exceptions()
{
$this
->given(
$group = new SUT('foo'),
$group['bar'] = new SUT('bar')
)
->when($group->offsetUnset('bar'))
->then
->boolean($group->offsetExists('bar'))
->isFalse();
}

public function case_offset_unset_does_not_exist_with_no_uncommited_exceptions()
{
$this
->given($group = new SUT('foo'))
->when($group->offsetUnset('bar'))
->then
->boolean($group->offsetExists('bar'))
->isFalse();
}

public function case_offset_unset()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$group->beginTransaction(),
$group['bar'] = new SUT('bar')
)
->when($result = $group->offsetUnset('bar'))
->then
->boolean($group->offsetExists('bar'))
->isFalse();
}

public function case_offset_unset_does_not_exist()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$group->beginTransaction()
)
->when($result = $group->offsetUnset('bar'))
->then
->boolean($group->offsetExists('bar'))
->isFalse();
}

public function case_get_exceptions()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar'),
$exception2 = new SUT('baz'),
$group['bar'] = $exception1,
$group->beginTransaction(),
$group['baz'] = $exception2
)
->when($result = $group->getExceptions())
->then
->object($result)
->isInstanceOf('ArrayObject')
->object($result['bar'])
->isIdenticalTo($exception1);
}

public function case_get_iterator()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar'),
$group['bar'] = $exception1
)
->when($result = $group->getIterator())
->then
->object($result)
->isInstanceOf('ArrayIterator')
->array(iterator_to_array($result))
->isEqualTo([
'bar' => $exception1
]);
}

public function case_count()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar'),
$exception2 = new SUT('baz'),
$group['bar'] = $exception1,
$group->beginTransaction(),
$group['baz'] = $exception2
)
->when($result = count($group))
->then
->integer($result)
->isEqualTo(1);
}

public function get_get_stack_size()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar'),
$exception2 = new SUT('baz'),
$group['bar'] = $exception1,
$group->beginTransaction(),
$group['baz'] = $exception2
)
->when($result = $group->getStackSize())
->then
->integer($result)
->isEqualTo(2);
}
}
<?php



































namespace Hoa\Exception\Test\Unit;

use Hoa\Exception\Error as SUT;
use Hoa\Test;









class Error extends Test\Unit\Suite
{
public function case_is_an_exception()
{
$this
->when($result = new SUT('foo', 42, '/hoa/flatland', 153))
->then
->object($result)
->isInstanceOf('Hoa\Exception\Exception');
}

public function case_get_message()
{
$this
->given($exception = new SUT('foo', 42, '/hoa/flatland', 153))
->when($result = $exception->raise())
->then
->string($result)
->isEqualTo(
'{main}: (42) foo' . "\n" .
'in /hoa/flatland at line 153.'
);
}

public function case_disable_error_handler()
{
$this
->given(
$this->function->restore_error_handler = function () use (&$called) {
$called = true;

return null;
}
)
->when($result = SUT::enableErrorHandler(false))
->then
->variable($result)
->isNull()
->boolean($called)
->isTrue();
}

public function case_enable_error_handler()
{
$self = $this;

$this
->given(
$this->function->set_error_handler = function ($handler) use ($self, &$called) {
$called = true;

$self
->object($handler)
->isInstanceOf('Closure')
->let($reflection = new \ReflectionObject($handler))
->array($invokeParameters = $reflection->getMethod('__invoke')->getParameters())
->hasSize(5)
->string($invokeParameters[0]->getName())
->isEqualTo('no')
->string($invokeParameters[1]->getName())
->isEqualTo('str')
->string($invokeParameters[2]->getName())
->isEqualTo('file')
->boolean($invokeParameters[2]->isOptional())
->isTrue()
->string($invokeParameters[3]->getName())
->isEqualTo('line')
->boolean($invokeParameters[3]->isOptional())
->isTrue()
->string($invokeParameters[4]->getName())
->isEqualTo('ctx')
->boolean($invokeParameters[4]->isOptional())
->isTrue();

return null;
}
)
->when($result = SUT::enableErrorHandler())
->then
->variable($result)
->isNull()
->boolean($called)
->isTrue();
}

public function case_error_handler()
{
$this
->given(SUT::enableErrorHandler())
->exception(function () {
++$i;
})
->isInstanceOf('Hoa\Exception\Error')
->hasMessage('Undefined variable: i');
}
}
<?php



































namespace Hoa\Exception;

use Hoa\Consistency;
use Hoa\Event;









class Exception extends Idle implements Event\Source
{











public function __construct(
$message,
$code = 0,
$arguments = [],
$previous = null
) {
parent::__construct($message, $code, $arguments, $previous);

if (false === Event::eventExists('hoa://Event/Exception')) {
Event::register('hoa://Event/Exception', __CLASS__);
}

$this->send();

return;
}






public function send()
{
Event::notify(
'hoa://Event/Exception',
$this,
new Event\Bucket($this)
);

return;
}
}




Consistency::flexEntity('Hoa\Exception\Exception');
<?php



































namespace Hoa\Exception;









class Group extends Exception implements \ArrayAccess, \IteratorAggregate, \Countable
{





protected $_group = null;











public function __construct(
$message,
$code = 0,
$arguments = [],
\Exception $previous = null
) {
parent::__construct($message, $code, $arguments, $previous);
$this->_group = new \SplStack();
$this->beginTransaction();

return;
}







public function raise($previous = false)
{
$out = parent::raise($previous);

if (0 >= count($this)) {
return $out;
}

$out .= "\n\n" . 'Contains the following exceptions:';

foreach ($this as $exception) {
$out .=
"\n\n" . '  • ' .
str_replace(
"\n",
"\n" . '    ',
$exception->raise($previous)
);
}

return $out;
}






public function beginTransaction()
{
$this->_group->push(new \ArrayObject());

return $this;
}






public function rollbackTransaction()
{
if (1 >= count($this->_group)) {
return $this;
}

$this->_group->pop();

return $this;
}






public function commitTransaction()
{
if (false === $this->hasUncommittedExceptions()) {
$this->_group->pop();

return $this;
}

foreach ($this->_group->pop() as $index => $exception) {
$this[$index] = $exception;
}

return $this;
}






public function hasUncommittedExceptions()
{
return
1 < count($this->_group) &&
0 < count($this->_group->top());
}







public function offsetExists($index)
{
foreach ($this->_group as $group) {
if (isset($group[$index])) {
return true;
}
}

return false;
}







public function offsetGet($index)
{
foreach ($this->_group as $group) {
if (isset($group[$index])) {
return $group[$index];
}
}

return null;
}








public function offsetSet($index, $exception)
{
if (!($exception instanceof \Exception)) {
return null;
}

$group = $this->_group->top();

if (null === $index ||
true === is_int($index)) {
$group[] = $exception;
} else {
$group[$index] = $exception;
}

return;
}







public function offsetUnset($index)
{
foreach ($this->_group as $group) {
if (isset($group[$index])) {
unset($group[$index]);
}
}

return;
}






public function getExceptions()
{
return $this->_group->bottom();
}






public function getIterator()
{
return $this->getExceptions()->getIterator();
}






public function count()
{
return count($this->getExceptions());
}






public function getStackSize()
{
return count($this->_group);
}
}
<?php



































namespace Hoa\Exception;









class Error extends Exception
{









public function __construct(
$message,
$code,
$file,
$line,
array $trace = []
) {
$this->file = $file;
$this->line = $line;
$this->_trace = $trace;

parent::__construct($message, $code);

return;
}







public static function enableErrorHandler($enable = true)
{
if (false === $enable) {
return restore_error_handler();
}

return set_error_handler(
function ($no, $str, $file = null, $line = null, $ctx = null) {
if (0 === ($no & error_reporting())) {
return;
}

$trace = debug_backtrace();
array_shift($trace);
array_shift($trace);

throw new Error($str, $no, $file, $line, $trace);
}
);
}
}
<?php



































namespace Hoa\File;

use Hoa\Stream;









abstract class Generic
extends Stream
implements Stream\IStream\Pathable,
Stream\IStream\Statable,
Stream\IStream\Touchable
{





protected $_mode = null;








public function getBasename()
{
return basename($this->getStreamName());
}






public function getDirname()
{
return dirname($this->getStreamName());
}






public function getSize()
{
if (false === $this->getStatistic()) {
return false;
}

return filesize($this->getStreamName());
}






public function getStatistic()
{
return fstat($this->getStream());
}






public function getATime()
{
return fileatime($this->getStreamName());
}






public function getCTime()
{
return filectime($this->getStreamName());
}






public function getMTime()
{
return filemtime($this->getStreamName());
}






public function getGroup()
{
return filegroup($this->getStreamName());
}






public function getOwner()
{
return fileowner($this->getStreamName());
}






public function getPermissions()
{
return fileperms($this->getStreamName());
}















public function getReadablePermissions()
{
$p = $this->getPermissions();

if (($p & 0xC000) == 0xC000) {
$out = 's';
} elseif (($p & 0xA000) == 0xA000) {
$out = 'l';
} elseif (($p & 0x8000) == 0x8000) {
$out = '-';
} elseif (($p & 0x6000) == 0x6000) {
$out = 'b';
} elseif (($p & 0x4000) == 0x4000) {
$out = 'd';
} elseif (($p & 0x2000) == 0x2000) {
$out = 'c';
} elseif (($p & 0x1000) == 0x1000) {
$out = 'p';
} else {
$out = 'u';
}

$out .=
(($p & 0x0100) ? 'r' : '-') .
(($p & 0x0080) ? 'w' : '-') .
(($p & 0x0040) ?
(($p & 0x0800) ? 's' : 'x') :
(($p & 0x0800) ? 'S' : '-')) .
(($p & 0x0020) ? 'r' : '-') .
(($p & 0x0010) ? 'w' : '-') .
(($p & 0x0008) ?
(($p & 0x0400) ? 's' : 'x') :
(($p & 0x0400) ? 'S' : '-')) .
(($p & 0x0004) ? 'r' : '-') .
(($p & 0x0002) ? 'w' : '-') .
(($p & 0x0001) ?
(($p & 0x0200) ? 't' : 'x') :
(($p & 0x0200) ? 'T' : '-'));

return $out;
}






public function isReadable()
{
return is_readable($this->getStreamName());
}






public function isWritable()
{
return is_writable($this->getStreamName());
}






public function isExecutable()
{
return is_executable($this->getStreamName());
}






public function clearStatisticCache()
{
clearstatcache(true, $this->getStreamName());

return;
}






public static function clearAllStatisticCaches()
{
clearstatcache();

return;
}









public function touch($time = -1, $atime = -1)
{
if ($time == -1) {
$time = time();
}

if ($atime == -1) {
$atime = $time;
}

return touch($this->getStreamName(), $time, $atime);
}











public function copy($to, $force = Stream\IStream\Touchable::DO_NOT_OVERWRITE)
{
$from = $this->getStreamName();

if ($force === Stream\IStream\Touchable::DO_NOT_OVERWRITE &&
true === file_exists($to)) {
return true;
}

if (null === $this->getStreamContext()) {
return @copy($from, $to);
}

return @copy($from, $to, $this->getStreamContext()->getContext());
}














public function move(
$name,
$force = Stream\IStream\Touchable::DO_NOT_OVERWRITE,
$mkdir = Stream\IStream\Touchable::DO_NOT_MAKE_DIRECTORY
) {
$from = $this->getStreamName();

if ($force === Stream\IStream\Touchable::DO_NOT_OVERWRITE &&
true === file_exists($name)) {
return false;
}

if (Stream\IStream\Touchable::MAKE_DIRECTORY === $mkdir) {
Directory::create(
dirname($name),
Directory::MODE_CREATE_RECURSIVE
);
}

if (null === $this->getStreamContext()) {
return @rename($from, $name);
}

return @rename($from, $name, $this->getStreamContext()->getContext());
}






public function delete()
{
if (null === $this->getStreamContext()) {
return @unlink($this->getStreamName());
}

return @unlink(
$this->getStreamName(),
$this->getStreamContext()->getContext()
);
}







public function changeGroup($group)
{
return chgrp($this->getStreamName(), $group);
}







public function changeMode($mode)
{
return chmod($this->getStreamName(), $mode);
}







public function changeOwner($user)
{
return chown($this->getStreamName(), $user);
}








public static function umask($umask = null)
{
if (null === $umask) {
return umask();
}

return umask($umask);
}






public function isFile()
{
return is_file($this->getStreamName());
}






public function isLink()
{
return is_link($this->getStreamName());
}






public function isDirectory()
{
return is_dir($this->getStreamName());
}






public function isSocket()
{
return filetype($this->getStreamName()) == 'socket';
}






public function isFIFOPipe()
{
return filetype($this->getStreamName()) == 'fifo';
}






public function isCharacterSpecial()
{
return filetype($this->getStreamName()) == 'char';
}






public function isBlockSpecial()
{
return filetype($this->getStreamName()) == 'block';
}






public function isUnknown()
{
return filetype($this->getStreamName()) == 'unknown';
}








protected function setMode($mode)
{
$old = $this->_mode;
$this->_mode = $mode;

return $old;
}






public function getMode()
{
return $this->_mode;
}






public function getINode()
{
return fileinode($this->getStreamName());
}






public static function isCaseSensitive()
{
return !(
file_exists(mb_strtolower(__FILE__)) &&
file_exists(mb_strtoupper(__FILE__))
);
}






public function getRealPath()
{
if (false === $out = realpath($this->getStreamName())) {
return $this->getStreamName();
}

return $out;
}






public function getExtension()
{
return pathinfo(
$this->getStreamName(),
PATHINFO_EXTENSION
);
}






public function getFilename()
{
$file = basename($this->getStreamName());

if (defined('PATHINFO_FILENAME')) {
return pathinfo($file, PATHINFO_FILENAME);
}

if (strstr($file, '.')) {
return substr($file, 0, strrpos($file, '.'));
}

return $file;
}
}
<?php



































namespace Hoa\File;

use Hoa\Stream;









class Directory extends Generic
{





const MODE_READ = 'rb';







const MODE_CREATE = 'xb';







const MODE_CREATE_RECURSIVE = 'xrb';












public function __construct(
$streamName,
$mode = self::MODE_READ,
$context = null,
$wait = false
) {
$this->setMode($mode);
parent::__construct($streamName, $context, $wait);

return;
}










protected function &_open($streamName, Stream\Context $context = null)
{
if (false === is_dir($streamName)) {
if ($this->getMode() == self::MODE_READ) {
throw new Exception\FileDoesNotExist(
'Directory %s does not exist.',
0,
$streamName
);
} else {
self::create(
$streamName,
$this->getMode(),
null !== $context
? $context->getContext()
: null
);
}
}

$out = null;

return $out;
}






protected function _close()
{
return true;
}











public function copy($to, $force = Stream\IStream\Touchable::DO_NOT_OVERWRITE)
{
if (empty($to)) {
throw new Exception(
'The destination path (to copy) is empty.',
1
);
}

$from = $this->getStreamName();
$fromLength = strlen($from) + 1;
$finder = new Finder();
$finder->in($from);

self::create($to, self::MODE_CREATE_RECURSIVE);

foreach ($finder as $file) {
$relative = substr($file->getPathname(), $fromLength);
$_to = $to . DS . $relative;

if (true === $file->isDir()) {
self::create($_to, self::MODE_CREATE);

continue;
}


 
 
 
 
 $handle = null;

if (true === $file->isFile()) {
$handle = new Read($file->getPathname());
} elseif (true === $file->isDir()) {
$handle = new Directory($file->getPathName());
} elseif (true === $file->isLink()) {
$handle = new Link\Read($file->getPathName());
}

if (null !== $handle) {
$handle->copy($_to, $force);
$handle->close();
}
}

return true;
}






public function delete()
{
$from = $this->getStreamName();
$finder = new Finder();
$finder->in($from)
->childFirst();

foreach ($finder as $file) {
$file->open()->delete();
$file->close();
}

if (null === $this->getStreamContext()) {
return @rmdir($from);
}

return @rmdir($from, $this->getStreamContext()->getContext());
}












public static function create(
$name,
$mode = self::MODE_CREATE_RECURSIVE,
$context = null
) {
if (true === is_dir($name)) {
return true;
}

if (empty($name)) {
return false;
}

if (null !== $context) {
if (false === Stream\Context::contextExists($context)) {
throw new Exception(
'Context %s was not previously declared, cannot retrieve ' .
'this context.',
2,
$context
);
} else {
$context = Stream\Context::getInstance($context);
}
}

if (null === $context) {
return @mkdir(
$name,
0755,
self::MODE_CREATE_RECURSIVE === $mode
);
}

return @mkdir(
$name,
0755,
self::MODE_CREATE_RECURSIVE === $mode,
$context->getContext()
);
}
}
<?php



































namespace Hoa\File;

use Hoa\Iterator;









class SplFileInfo extends Iterator\SplFileInfo
{





protected $_stream = null;









public function open()
{
if (true === $this->isFile()) {
return $this->_stream = new ReadWrite($this->getPathname());
} elseif (true === $this->isDir()) {
return $this->_stream = new Directory($this->getPathname());
} elseif (true === $this->isLink()) {
return $this->_stream = new Link\ReadWrite($this->getPathname());
}

throw new Exception('%s has an unknown type.', 0, $this->getPathname());
}






public function close()
{
if (null === $this->_stream) {
return;
}

return $this->_stream->close();
}






public function __destruct()
{
$this->close();

return;
}
}
<?php



































namespace Hoa\File;

use Hoa\Iterator;









class Finder implements Iterator\Aggregate
{





protected $_splFileInfo = 'Hoa\File\SplFileInfo';






protected $_paths = [];






protected $_maxDepth = -1;






protected $_filters = [];






protected $_flags = -1;






protected $_types = [];






protected $_first = -1;






protected $_sorts = [];







public function __construct()
{
$this->_flags = Iterator\FileSystem::KEY_AS_PATHNAME
| Iterator\FileSystem::CURRENT_AS_FILEINFO
| Iterator\FileSystem::SKIP_DOTS;
$this->_first = Iterator\Recursive\Iterator::SELF_FIRST;

return;
}







public function in($paths)
{
if (!is_array($paths)) {
$paths = [$paths];
}

foreach ($paths as $path) {
if (1 === preg_match('/[\*\?\[\]]/', $path)) {
$iterator = new Iterator\CallbackFilter(
new Iterator\Glob(rtrim($path, DS)),
function ($current) {
return $current->isDir();
}
);

foreach ($iterator as $fileInfo) {
$this->_paths[] = $fileInfo->getPathname();
}
} else {
$this->_paths[] = $path;
}
}

return $this;
}







public function maxDepth($depth)
{
$this->_maxDepth = $depth;

return $this;
}






public function files()
{
$this->_types[] = 'file';

return $this;
}






public function directories()
{
$this->_types[] = 'dir';

return $this;
}






public function links()
{
$this->_types[] = 'link';

return $this;
}







public function followSymlinks($flag = true)
{
if (true === $flag) {
$this->_flags ^= Iterator\FileSystem::FOLLOW_SYMLINKS;
} else {
$this->_flags |= Iterator\FileSystem::FOLLOW_SYMLINKS;
}

return $this;
}









public function name($regex)
{
$this->_filters[] = function (\SplFileInfo $current) use ($regex) {
return 0 !== preg_match($regex, $current->getBasename());
};

return $this;
}









public function notIn($regex)
{
$this->_filters[] = function (\SplFileInfo $current) use ($regex) {
foreach (explode(DS, $current->getPathname()) as $part) {
if (0 !== preg_match($regex, $part)) {
return false;
}
}

return true;
};

return $this;
}















public function size($size)
{
if (0 === preg_match('#^(<|<=|>|>=|=)\s*(\d+)\s*((?:[KMGTPEZY])b)?$#', $size, $matches)) {
return $this;
}

$number = floatval($matches[2]);
$unit = isset($matches[3]) ? $matches[3] : 'b';
$operator = $matches[1];

switch ($unit) {

case 'b':
break;


 case 'Kb':
$number <<= 10;

break;


 case 'Mb':
$number <<= 20;

break;


 case 'Gb':
$number <<= 30;

break;


 case 'Tb':
$number *= 1099511627776;

break;


 case 'Pb':
$number *= pow(1024, 5);

break;


 case 'Eb':
$number *= pow(1024, 6);

break;


 case 'Zb':
$number *= pow(1024, 7);

break;


 case 'Yb':
$number *= pow(1024, 8);

break;
}

$filter = null;

switch ($operator) {
case '<':
$filter = function (\SplFileInfo $current) use ($number) {
return $current->getSize() < $number;
};

break;

case '<=':
$filter = function (\SplFileInfo $current) use ($number) {
return $current->getSize() <= $number;
};

break;

case '>':
$filter = function (\SplFileInfo $current) use ($number) {
return $current->getSize() > $number;
};

break;

case '>=':
$filter = function (\SplFileInfo $current) use ($number) {
return $current->getSize() >= $number;
};

break;

case '=':
$filter = function (\SplFileInfo $current) use ($number) {
return $current->getSize() === $number;
};

break;
}

$this->_filters[] = $filter;

return $this;
}







public function dots($flag = true)
{
if (true === $flag) {
$this->_flags ^= Iterator\FileSystem::SKIP_DOTS;
} else {
$this->_flags |= Iterator\FileSystem::SKIP_DOTS;
}

return $this;
}







public function owner($owner)
{
$this->_filters[] = function (\SplFileInfo $current) use ($owner) {
return $current->getOwner() === $owner;
};

return $this;
}















protected function formatDate($date, &$operator)
{
$operator = -1;

if (0 === preg_match('#\bago\b#', $date)) {
$date .= ' ago';
}

if (0 !== preg_match('#^(since|until)\b(.+)$#', $date, $matches)) {
$time = strtotime($matches[2]);

if ('until' === $matches[1]) {
$operator = 1;
}
} else {
$time = strtotime($date);
}

return $time;
}









public function changed($date)
{
$time = $this->formatDate($date, $operator);

if (-1 === $operator) {
$this->_filters[] = function (\SplFileInfo $current) use ($time) {
return $current->getCTime() >= $time;
};
} else {
$this->_filters[] = function (\SplFileInfo $current) use ($time) {
return $current->getCTime() < $time;
};
}

return $this;
}









public function modified($date)
{
$time = $this->formatDate($date, $operator);

if (-1 === $operator) {
$this->_filters[] = function (\SplFileInfo $current) use ($time) {
return $current->getMTime() >= $time;
};
} else {
$this->_filters[] = function (\SplFileInfo $current) use ($time) {
return $current->getMTime() < $time;
};
}

return $this;
}














public function filter($callback)
{
$this->_filters[] = $callback;

return $this;
}











public function sortByName($locale = 'root')
{
if (true === class_exists('Collator', false)) {
$collator = new \Collator($locale);

$this->_sorts[] = function (\SplFileInfo $a, \SplFileInfo $b) use ($collator) {
return $collator->compare($a->getPathname(), $b->getPathname());
};
} else {
$this->_sorts[] = function (\SplFileInfo $a, \SplFileInfo $b) {
return strcmp($a->getPathname(), $b->getPathname());
};
}

return $this;
}








public function sortBySize()
{
$this->_sorts[] = function (\SplFileInfo $a, \SplFileInfo $b) {
return $a->getSize() < $b->getSize();
};

return $this;
}














public function sort($callable)
{
$this->_sorts[] = $callable;

return $this;
}






public function childFirst()
{
$this->_first = Iterator\Recursive\Iterator::CHILD_FIRST;

return $this;
}






public function getIterator()
{
$_iterator = new Iterator\Append();
$types = $this->getTypes();

if (!empty($types)) {
$this->_filters[] = function (\SplFileInfo $current) use ($types) {
return in_array($current->getType(), $types);
};
}

$maxDepth = $this->getMaxDepth();
$splFileInfo = $this->getSplFileInfo();

foreach ($this->getPaths() as $path) {
if (1 == $maxDepth) {
$iterator = new Iterator\IteratorIterator(
new Iterator\Recursive\Directory(
$path,
$this->getFlags(),
$splFileInfo
),
$this->getFirst()
);
} else {
$iterator = new Iterator\Recursive\Iterator(
new Iterator\Recursive\Directory(
$path,
$this->getFlags(),
$splFileInfo
),
$this->getFirst()
);

if (1 < $maxDepth) {
$iterator->setMaxDepth($maxDepth - 1);
}
}

$_iterator->append($iterator);
}

foreach ($this->getFilters() as $filter) {
$_iterator = new Iterator\CallbackFilter(
$_iterator,
$filter
);
}

$sorts = $this->getSorts();

if (empty($sorts)) {
return $_iterator;
}

$array = iterator_to_array($_iterator);

foreach ($sorts as $sort) {
uasort($array, $sort);
}

return new Iterator\Map($array);
}







public function setSplFileInfo($splFileInfo)
{
$old = $this->_splFileInfo;
$this->_splFileInfo = $splFileInfo;

return $old;
}






public function getSplFileInfo()
{
return $this->_splFileInfo;
}






protected function getPaths()
{
return $this->_paths;
}






public function getMaxDepth()
{
return $this->_maxDepth;
}






public function getTypes()
{
return $this->_types;
}






protected function getFilters()
{
return $this->_filters;
}






protected function getSorts()
{
return $this->_sorts;
}






public function getFlags()
{
return $this->_flags;
}






public function getFirst()
{
return $this->_first;
}
}
<?php



































namespace Hoa\File;

use Hoa\Stream;









class Read extends File implements Stream\IStream\In
{









public function __construct(
$streamName,
$mode = parent::MODE_READ,
$context = null,
$wait = false
) {
parent::__construct($streamName, $mode, $context, $wait);

return;
}










protected function &_open($streamName, Stream\Context $context = null)
{
static $createModes = [
parent::MODE_READ
];

if (!in_array($this->getMode(), $createModes)) {
throw new Exception(
'Open mode are not supported; given %d. Only %s are supported.',
0,
[$this->getMode(), implode(', ', $createModes)]
);
}

preg_match('#^(\w+)://#', $streamName, $match);

if (((isset($match[1]) && $match[1] == 'file') || !isset($match[1])) &&
!file_exists($streamName)) {
throw new Exception\FileDoesNotExist(
'File %s does not exist.',
1,
$streamName
);
}

$out = parent::_open($streamName, $context);

return $out;
}






public function eof()
{
return feof($this->getStream());
}








public function read($length)
{
if (0 > $length) {
throw new Exception(
'Length must be greater than 0, given %d.',
2,
$length
);
}

return fread($this->getStream(), $length);
}







public function readString($length)
{
return $this->read($length);
}






public function readCharacter()
{
return fgetc($this->getStream());
}






public function readBoolean()
{
return (bool) $this->read(1);
}







public function readInteger($length = 1)
{
return (int) $this->read($length);
}







public function readFloat($length = 1)
{
return (float) $this->read($length);
}








public function readArray($format = null)
{
return $this->scanf($format);
}






public function readLine()
{
return fgets($this->getStream());
}







public function readAll($offset = 0)
{
return stream_get_contents($this->getStream(), -1, $offset);
}







public function scanf($format)
{
return fscanf($this->getStream(), $format);
}
}
<?php



































namespace Hoa\File;

use Hoa\Event;









class Watcher extends Finder implements Event\Listenable
{
use Event\Listens;






protected $_latency = 1;








public function __construct($latency = null)
{
parent::__construct();

$this->setListener(
new Event\Listener(
$this,
[
'new',
'modify',
'move'
]
)
);

if (null !== $latency) {
$this->setLatency($latency);
}

return;
}











public function run()
{
$iterator = $this->getIterator();
$previous = iterator_to_array($iterator);
$current = $previous;

while (true) {
foreach ($current as $name => $c) {
if (!isset($previous[$name])) {
$this->getListener()->fire(
'new',
new Event\Bucket([
'file' => $c
])
);

continue;
}

if (null === $c->getHash()) {
unset($current[$name]);

continue;
}

if ($previous[$name]->getHash() != $c->getHash()) {
$this->getListener()->fire(
'modify',
new Event\Bucket([
'file' => $c
])
);
}

unset($previous[$name]);
}

foreach ($previous as $p) {
$this->getListener()->fire(
'move',
new Event\Bucket([
'file' => $p
])
);
}

usleep($this->getLatency() * 1000000);

$previous = $current;
$current = iterator_to_array($iterator);
}

return;
}







public function setLatency($latency)
{
$old = $this->_latency;
$this->_latency = $latency;

return $old;
}






public function getLatency()
{
return $this->_latency;
}
}
<?php



































namespace Hoa\File;

use Hoa\Stream;









class ReadWrite
extends File
implements Stream\IStream\In,
Stream\IStream\Out
{









public function __construct(
$streamName,
$mode = parent::MODE_APPEND_READ_WRITE,
$context = null,
$wait = false
) {
parent::__construct($streamName, $mode, $context, $wait);

return;
}










protected function &_open($streamName, Stream\Context $context = null)
{
static $createModes = [
parent::MODE_READ_WRITE,
parent::MODE_TRUNCATE_READ_WRITE,
parent::MODE_APPEND_READ_WRITE,
parent::MODE_CREATE_READ_WRITE
];

if (!in_array($this->getMode(), $createModes)) {
throw new Exception(
'Open mode are not supported; given %d. Only %s are supported.',
0,
[$this->getMode(), implode(', ', $createModes)]
);
}

preg_match('#^(\w+)://#', $streamName, $match);

if (((isset($match[1]) && $match[1] == 'file') || !isset($match[1])) &&
!file_exists($streamName) &&
parent::MODE_READ_WRITE == $this->getMode()) {
throw new Exception\FileDoesNotExist(
'File %s does not exist.',
1,
$streamName
);
}

$out = parent::_open($streamName, $context);

return $out;
}






public function eof()
{
return feof($this->getStream());
}








public function read($length)
{
if (0 > $length) {
throw new Exception(
'Length must be greater than 0, given %d.',
2,
$length
);
}

return fread($this->getStream(), $length);
}







public function readString($length)
{
return $this->read($length);
}






public function readCharacter()
{
return fgetc($this->getStream());
}






public function readBoolean()
{
return (bool) $this->read(1);
}







public function readInteger($length = 1)
{
return (int) $this->read($length);
}







public function readFloat($length = 1)
{
return (float) $this->read($length);
}








public function readArray($format = null)
{
return $this->scanf($format);
}






public function readLine()
{
return fgets($this->getStream());
}







public function readAll($offset = 0)
{
return stream_get_contents($this->getStream(), -1, $offset);
}







public function scanf($format)
{
return fscanf($this->getStream(), $format);
}









public function write($string, $length)
{
if (0 > $length) {
throw new Exception(
'Length must be greater than 0, given %d.',
3,
$length
);
}

return fwrite($this->getStream(), $string, $length);
}







public function writeString($string)
{
$string = (string) $string;

return $this->write($string, strlen($string));
}







public function writeCharacter($char)
{
return $this->write((string) $char[0], 1);
}







public function writeBoolean($boolean)
{
return $this->write((string) (bool) $boolean, 1);
}







public function writeInteger($integer)
{
$integer = (string) (int) $integer;

return $this->write($integer, strlen($integer));
}







public function writeFloat($float)
{
$float = (string) (float) $float;

return $this->write($float, strlen($float));
}







public function writeArray(array $array)
{
$array = var_export($array, true);

return $this->write($array, strlen($array));
}







public function writeLine($line)
{
if (false === $n = strpos($line, "\n")) {
return $this->write($line . "\n", strlen($line) + 1);
}

++$n;

return $this->write(substr($line, 0, $n), $n);
}







public function writeAll($string)
{
return $this->write($string, strlen($string));
}







public function truncate($size)
{
return ftruncate($this->getStream(), $size);
}
}
<?php



































namespace Hoa\File;

use Hoa\Stream;









class Write extends File implements Stream\IStream\Out
{









public function __construct(
$streamName,
$mode = parent::MODE_APPEND_WRITE,
$context = null,
$wait = false
) {
parent::__construct($streamName, $mode, $context, $wait);

return;
}










protected function &_open($streamName, Stream\Context $context = null)
{
static $createModes = [
parent::MODE_TRUNCATE_WRITE,
parent::MODE_APPEND_WRITE,
parent::MODE_CREATE_WRITE
];

if (!in_array($this->getMode(), $createModes)) {
throw new Exception(
'Open mode are not supported; given %d. Only %s are supported.',
0,
[$this->getMode(), implode(', ', $createModes)]
);
}

preg_match('#^(\w+)://#', $streamName, $match);

if (((isset($match[1]) && $match[1] == 'file') || !isset($match[1])) &&
!file_exists($streamName) &&
parent::MODE_TRUNCATE_WRITE == $this->getMode()) {
throw new Exception\FileDoesNotExist(
'File %s does not exist.',
1,
$streamName
);
}

$out = parent::_open($streamName, $context);

return $out;
}









public function write($string, $length)
{
if (0 > $length) {
throw new Exception(
'Length must be greater than 0, given %d.',
2,
$length
);
}

return fwrite($this->getStream(), $string, $length);
}







public function writeString($string)
{
$string = (string) $string;

return $this->write($string, strlen($string));
}







public function writeCharacter($char)
{
return $this->write((string) $char[0], 1);
}







public function writeBoolean($boolean)
{
return $this->write((string) (bool) $boolean, 1);
}







public function writeInteger($integer)
{
$integer = (string) (int) $integer;

return $this->write($integer, strlen($integer));
}







public function writeFloat($float)
{
$float = (string) (float) $float;

return $this->write($float, strlen($float));
}







public function writeArray(array $array)
{
$array = var_export($array, true);

return $this->write($array, strlen($array));
}







public function writeLine($line)
{
if (false === $n = strpos($line, "\n")) {
return $this->write($line . "\n", strlen($line) + 1);
}

++$n;

return $this->write(substr($line, 0, $n), $n);
}







public function writeAll($string)
{
return $this->write($string, strlen($string));
}







public function truncate($size)
{
return ftruncate($this->getStream(), $size);
}
}
<?php



































namespace Hoa\File\Temporary;

use Hoa\File;
use Hoa\Stream;









class Read extends Temporary implements Stream\IStream\In
{









public function __construct(
$streamName,
$mode = parent::MODE_READ,
$context = null,
$wait = false
) {
parent::__construct($streamName, $mode, $context, $wait);

return;
}










protected function &_open($streamName, Stream\Context $context = null)
{
static $createModes = [
parent::MODE_READ
];

if (!in_array($this->getMode(), $createModes)) {
throw new File\Exception(
'Open mode are not supported; given %d. Only %s are supported.',
0,
[$this->getMode(), implode(', ', $createModes)]
);
}

preg_match('#^(\w+)://#', $streamName, $match);

if (((isset($match[1]) && $match[1] == 'file') || !isset($match[1])) &&
!file_exists($streamName)) {
throw new File\Exception\FileDoesNotExist(
'File %s does not exist.',
1,
$streamName
);
}

$out = parent::_open($streamName, $context);

return $out;
}






public function eof()
{
return feof($this->getStream());
}








public function read($length)
{
if (0 > $length) {
throw new File\Exception(
'Length must be greater than 0, given %d.',
2,
$length
);
}

return fread($this->getStream(), $length);
}







public function readString($length)
{
return $this->read($length);
}






public function readCharacter()
{
return fgetc($this->getStream());
}






public function readBoolean()
{
return (bool) $this->read(1);
}







public function readInteger($length = 1)
{
return (int) $this->read($length);
}







public function readFloat($length = 1)
{
return (float) $this->read($length);
}








public function readArray($format = null)
{
return $this->scanf($format);
}






public function readLine()
{
return fgets($this->getStream());
}







public function readAll($offset = 0)
{
return stream_get_contents($this->getStream(), -1, $offset);
}







public function scanf($format)
{
return fscanf($this->getStream(), $format);
}
}
<?php



































namespace Hoa\File\Temporary;

use Hoa\File;
use Hoa\Stream;









class ReadWrite
extends Temporary
implements Stream\IStream\In,
Stream\IStream\Out
{









public function __construct(
$streamName,
$mode = parent::MODE_APPEND_READ_WRITE,
$context = null,
$wait = false
) {
parent::__construct($streamName, $mode, $context, $wait);

return;
}










protected function &_open($streamName, Stream\Context $context = null)
{
static $createModes = [
parent::MODE_READ_WRITE,
parent::MODE_TRUNCATE_READ_WRITE,
parent::MODE_APPEND_READ_WRITE,
parent::MODE_CREATE_READ_WRITE
];

if (!in_array($this->getMode(), $createModes)) {
throw new File\Exception(
'Open mode are not supported; given %d. Only %s are supported.',
0,
[$this->getMode(), implode(', ', $createModes)]
);
}

preg_match('#^(\w+)://#', $streamName, $match);

if (((isset($match[1]) && $match[1] == 'file') || !isset($match[1])) &&
!file_exists($streamName) &&
parent::MODE_READ_WRITE == $this->getMode()) {
throw new File\Exception\FileDoesNotExist(
'File %s does not exist.',
1,
$streamName
);
}

$out = parent::_open($streamName, $context);

return $out;
}






public function eof()
{
return feof($this->getStream());
}








public function read($length)
{
if (0 > $length) {
throw new File\Exception(
'Length must be greater than 0, given %d.',
2,
$length
);
}

return fread($this->getStream(), $length);
}







public function readString($length)
{
return $this->read($length);
}






public function readCharacter()
{
return fgetc($this->getStream());
}






public function readBoolean()
{
return (bool) $this->read(1);
}







public function readInteger($length = 1)
{
return (int) $this->read($length);
}







public function readFloat($length = 1)
{
return (float) $this->read($length);
}








public function readArray($format = null)
{
return $this->scanf($format);
}






public function readLine()
{
return fgets($this->getStream());
}







public function readAll($offset = 0)
{
return stream_get_contents($this->getStream(), -1, $offset);
}







public function scanf($format)
{
return fscanf($this->getStream(), $format);
}









public function write($string, $length)
{
if (0 > $length) {
throw new File\Exception(
'Length must be greater than 0, given %d.',
3,
$length
);
}

return fwrite($this->getStream(), $string, $length);
}







public function writeString($string)
{
$string = (string) $string;

return $this->write($string, strlen($string));
}







public function writeCharacter($char)
{
return $this->write((string) $char[0], 1);
}







public function writeBoolean($boolean)
{
return $this->write((string) (bool) $boolean, 1);
}







public function writeInteger($integer)
{
$integer = (string) (int) $integer;

return $this->write($integer, strlen($integer));
}







public function writeFloat($float)
{
$float = (string) (float) $float;

return $this->write($float, strlen($float));
}







public function writeArray(array $array)
{
$array = var_export($array, true);

return $this->write($array, strlen($array));
}







public function writeLine($line)
{
if (false === $n = strpos($line, "\n")) {
return $this->write($line . "\n", strlen($line) + 1);
}

++$n;

return $this->write(substr($line, 0, $n), $n);
}







public function writeAll($string)
{
return $this->write($string, strlen($string));
}







public function truncate($size)
{
return ftruncate($this->getStream(), $size);
}
}
<?php



































namespace Hoa\File\Temporary;

use Hoa\File;
use Hoa\Stream;









class Write extends Temporary implements Stream\IStream\Out
{









public function __construct(
$streamName,
$mode = parent::MODE_APPEND_WRITE,
$context = null,
$wait = false
) {
parent::__construct($streamName, $mode, $context, $wait);

return;
}










protected function &_open($streamName, Stream\Context $context = null)
{
static $createModes = [
parent::MODE_TRUNCATE_WRITE,
parent::MODE_APPEND_WRITE,
parent::MODE_CREATE_WRITE
];

if (!in_array($this->getMode(), $createModes)) {
throw new File\Exception(
'Open mode are not supported; given %d. Only %s are supported.',
0,
[$this->getMode(), implode(', ', $createModes)]
);
}

preg_match('#^(\w+)://#', $streamName, $match);

if (((isset($match[1]) && $match[1] == 'file') || !isset($match[1])) &&
!file_exists($streamName)) {
throw new File\Exception\FileDoesNotExist(
'File %s does not exist.',
1,
$streamName
);
}

$out = parent::_open($streamName, $context);

return $out;
}









public function write($string, $length)
{
if (0 > $length) {
throw new File\Exception(
'Length must be greater than 0, given %d.',
2,
$length
);
}

return fwrite($this->getStream(), $string, $length);
}







public function writeString($string)
{
$string = (string) $string;

return $this->write($string, strlen($string));
}







public function writeCharacter($char)
{
return $this->write((string) $char[0], 1);
}







public function writeBoolean($boolean)
{
return $this->write((string) (bool) $boolean, 1);
}







public function writeInteger($integer)
{
$integer = (string) (int) $integer;

return $this->write($integer, strlen($integer));
}







public function writeFloat($float)
{
$float = (string) (float) $float;

return $this->write($float, strlen($float));
}







public function writeArray(array $array)
{
$array = var_export($array, true);

return $this->write($array, strlen($array));
}







public function writeLine($line)
{
if (false === $n = strpos($line, "\n")) {
return $this->write($line . "\n", strlen($line) + 1);
}

++$n;

return $this->write(substr($line, 0, $n), $n);
}







public function writeAll($string)
{
return $this->write($string, strlen($string));
}







public function truncate($size)
{
return ftruncate($this->getStream(), $size);
}
}
<?php



































namespace Hoa\File\Temporary;

use Hoa\Consistency;
use Hoa\File;
use Hoa\Stream;









class Temporary extends File
{





private static $_i = 0;













public function __construct(
$streamName,
$mode,
$context = null,
$wait = false
) {
if (null === $streamName) {
$streamName = 'hoa://Library/File/Temporary.php#' . self::$_i++;
}

parent::__construct($streamName, $mode, $context, $wait);

return;
}










protected function &_open($streamName, Stream\Context $context = null)
{
if (false === $out = @tmpfile()) {
throw new File\Exception(
'Failed to open a temporary stream.',
0
);
}

return $out;
}














public static function create($directory = null, $prefix = '__hoa_')
{
if (null === $directory ||
false === is_dir($directory)) {
$directory = static::getTemporaryDirectory();
}

return tempnam($directory, $prefix);
}






public static function getTemporaryDirectory()
{
return sys_get_temp_dir();
}
}




Consistency::flexEntity('Hoa\File\Temporary\Temporary');
<?php



































namespace Hoa\File\Link;

use Hoa\File;
use Hoa\Stream;









class Read extends Link implements Stream\IStream\In
{









public function __construct(
$streamName,
$mode = parent::MODE_READ,
$context = null,
$wait = false
) {
parent::__construct($streamName, $mode, $context, $wait);

return;
}










protected function &_open($streamName, Stream\Context $context = null)
{
static $createModes = [
parent::MODE_READ
];

if (!in_array($this->getMode(), $createModes)) {
throw new File\Exception(
'Open mode are not supported; given %d. Only %s are supported.',
0,
[$this->getMode(), implode(', ', $createModes)]
);
}

preg_match('#^(\w+)://#', $streamName, $match);

if (((isset($match[1]) && $match[1] == 'file') || !isset($match[1])) &&
!file_exists($streamName)) {
throw new File\Exception\FileDoesNotExist(
'File %s does not exist.',
1,
$streamName
);
}

$out = parent::_open($streamName, $context);

return $out;
}






public function eof()
{
return feof($this->getStream());
}








public function read($length)
{
if (0 > $length) {
throw new File\Exception(
'Length must be greater than 0, given %d.',
2,
$length
);
}

return fread($this->getStream(), $length);
}







public function readString($length)
{
return $this->read($length);
}






public function readCharacter()
{
return fgetc($this->getStream());
}






public function readBoolean()
{
return (bool) $this->read(1);
}







public function readInteger($length = 1)
{
return (int) $this->read($length);
}







public function readFloat($length = 1)
{
return (float) $this->read($length);
}








public function readArray($format = null)
{
return $this->scanf($format);
}






public function readLine()
{
return fgets($this->getStream());
}







public function readAll($offset = 0)
{
return stream_get_contents($this->getStream(), -1, $offset);
}







public function scanf($format)
{
return fscanf($this->getStream(), $format);
}
}
<?php



































namespace Hoa\File\Link;

use Hoa\File;
use Hoa\Stream;









class ReadWrite
extends Link
implements Stream\IStream\In,
Stream\IStream\Out
{









public function __construct(
$streamName,
$mode = parent::MODE_APPEND_READ_WRITE,
$context = null,
$wait = false
) {
parent::__construct($streamName, $mode, $context, $wait);

return;
}










protected function &_open($streamName, Stream\Context $context = null)
{
static $createModes = [
parent::MODE_READ_WRITE,
parent::MODE_TRUNCATE_READ_WRITE,
parent::MODE_APPEND_READ_WRITE,
parent::MODE_CREATE_READ_WRITE
];

if (!in_array($this->getMode(), $createModes)) {
throw new File\Exception(
'Open mode are not supported; given %d. Only %s are supported.',
0,
[$this->getMode(), implode(', ', $createModes)]
);
}

preg_match('#^(\w+)://#', $streamName, $match);

if (((isset($match[1]) && $match[1] == 'file') || !isset($match[1])) &&
!file_exists($streamName) &&
parent::MODE_READ_WRITE == $this->getMode()) {
throw new File\Exception\FileDoesNotExist(
'File %s does not exist.',
1,
$streamName
);
}

$out = parent::_open($streamName, $context);

return $out;
}






public function eof()
{
return feof($this->getStream());
}








public function read($length)
{
if (0 > $length) {
throw new File\Exception(
'Length must be greater than 0, given %d.',
2,
$length
);
}

return fread($this->getStream(), $length);
}







public function readString($length)
{
return $this->read($length);
}






public function readCharacter()
{
return fgetc($this->getStream());
}






public function readBoolean()
{
return (bool) $this->read(1);
}







public function readInteger($length = 1)
{
return (int) $this->read($length);
}







public function readFloat($length = 1)
{
return (float) $this->read($length);
}








public function readArray($format = null)
{
return $this->scanf($format);
}






public function readLine()
{
return fgets($this->getStream());
}







public function readAll($offset = 0)
{
return stream_get_contents($this->getStream(), -1, $offset);
}







public function scanf($format)
{
return fscanf($this->getStream(), $format);
}









public function write($string, $length)
{
if (0 > $length) {
throw new File\Exception(
'Length must be greater than 0, given %d.',
3,
$length
);
}

return fwrite($this->getStream(), $string, $length);
}







public function writeString($string)
{
$string = (string) $string;

return $this->write($string, strlen($string));
}







public function writeCharacter($char)
{
return $this->write((string) $char[0], 1);
}







public function writeBoolean($boolean)
{
return $this->write((string) (bool) $boolean, 1);
}







public function writeInteger($integer)
{
$integer = (string) (int) $integer;

return $this->write($integer, strlen($integer));
}







public function writeFloat($float)
{
$float = (string) (float) $float;

return $this->write($float, strlen($float));
}







public function writeArray(array $array)
{
$array = var_export($array, true);

return $this->write($array, strlen($array));
}







public function writeLine($line)
{
if (false === $n = strpos($line, "\n")) {
return $this->write($line . "\n", strlen($line) + 1);
}

++$n;

return $this->write(substr($line, 0, $n), $n);
}







public function writeAll($string)
{
return $this->write($string, strlen($string));
}







public function truncate($size)
{
return ftruncate($this->getStream(), $size);
}
}
<?php



































namespace Hoa\File\Link;

use Hoa\File;
use Hoa\Stream;








class Write extends Link implements Stream\IStream\Out
{









public function __construct(
$streamName,
$mode = parent::MODE_APPEND_WRITE,
$context = null,
$wait = false
) {
parent::__construct($streamName, $mode, $context, $wait);

return;
}










protected function &_open($streamName, Stream\Context $context = null)
{
static $createModes = [
parent::MODE_TRUNCATE_WRITE,
parent::MODE_APPEND_WRITE,
parent::MODE_CREATE_WRITE
];

if (!in_array($this->getMode(), $createModes)) {
throw new File\Exception(
'Open mode are not supported; given %d. Only %s are supported.',
0,
[$this->getMode(), implode(', ', $createModes)]
);
}

preg_match('#^(\w+)://#', $streamName, $match);

if (((isset($match[1]) && $match[1] == 'file') || !isset($match[1])) &&
!file_exists($streamName)) {
throw new File\Exception\FileDoesNotExist(
'File %s does not exist.',
1,
$streamName
);
}

$out = parent::_open($streamName, $context);

return $out;
}









public function write($string, $length)
{
if (0 > $length) {
throw new File\Exception(
'Length must be greater than 0, given %d.',
2,
$length
);
}

return fwrite($this->getStream(), $string, $length);
}







public function writeString($string)
{
$string = (string) $string;

return $this->write($string, strlen($string));
}







public function writeCharacter($char)
{
return $this->write((string) $char[0], 1);
}







public function writeBoolean($boolean)
{
return $this->write((string) (bool) $boolean, 1);
}







public function writeInteger($integer)
{
$integer = (string) (int) $integer;

return $this->write($integer, strlen($integer));
}







public function writeFloat($float)
{
$float = (string) (float) $float;

return $this->write($float, strlen($float));
}







public function writeArray(array $array)
{
$array = var_export($array, true);

return $this->write($array, strlen($array));
}







public function writeLine($line)
{
if (false === $n = strpos($line, "\n")) {
return $this->write($line . "\n", strlen($line) + 1);
}

++$n;

return $this->write(substr($line, 0, $n), $n);
}







public function writeAll($string)
{
return $this->write($string, strlen($string));
}







public function truncate($size)
{
return ftruncate($this->getStream(), $size);
}
}
<?php



































namespace Hoa\File\Link;

use Hoa\Consistency;
use Hoa\File;









class Link extends File
{











public function __construct(
$streamName,
$mode,
$context = null,
$wait = false
) {
if (!is_link($streamName)) {
throw new File\Exception(
'File %s is not a link.',
0,
$streamName
);
}

parent::__construct($streamName, $mode, $context, $wait);

return;
}






public function getStatistic()
{
return lstat($this->getStreamName());
}







public function changeGroup($group)
{
return lchgrp($this->getStreamName(), $group);
}







public function changeOwner($user)
{
return lchown($this->getStreamName(), $user);
}






public function getPermissions()
{
return 41453; 
 }







public function getTarget()
{
$target = dirname($this->getStreamName()) . DS .
$this->getTargetName();
$context = null !== $this->getStreamContext()
? $this->getStreamContext()->getCurrentId()
: null;

if (true === is_link($target)) {
return new ReadWrite(
$target,
File::MODE_APPEND_READ_WRITE,
$context
);
} elseif (true === is_file($target)) {
return new File\ReadWrite(
$target,
File::MODE_APPEND_READ_WRITE,
$context
);
} elseif (true === is_dir($target)) {
return new File\Directory(
$target,
File::MODE_READ,
$context
);
}

throw new File\Exception(
'Cannot find an appropriated object that matches with ' .
'path %s when defining it.',
1,
$target
);
}






public function getTargetName()
{
return readlink($this->getStreamName());
}








public static function create($name, $target)
{
if (false != linkinfo($name)) {
return true;
}

return symlink($target, $name);
}
}




Consistency::flexEntity('Hoa\File\Link\Link');
<?php



































namespace Hoa\File\Exception;

use Hoa\Consistency;
use Hoa\Exception as HoaException;









class Exception extends HoaException
{
}




Consistency::flexEntity('Hoa\File\Exception\Exception');
<?php



































namespace Hoa\File\Exception;









class FileDoesNotExist extends Exception
{
}
<?php



































namespace Hoa\File;

use Hoa\Consistency;
use Hoa\Stream;









abstract class File
extends Generic
implements Stream\IStream\Bufferable,
Stream\IStream\Lockable,
Stream\IStream\Pointable
{






const MODE_READ = 'rb';







const MODE_READ_WRITE = 'r+b';








const MODE_TRUNCATE_WRITE = 'wb';








const MODE_TRUNCATE_READ_WRITE = 'w+b';







const MODE_APPEND_WRITE = 'ab';







const MODE_APPEND_READ_WRITE = 'a+b';










const MODE_CREATE_WRITE = 'xb';










const MODE_CREATE_READ_WRITE = 'x+b';














public function __construct(
$streamName,
$mode,
$context = null,
$wait = false
) {
$this->setMode($mode);

switch ($streamName) {

case '0':
$streamName = 'php://stdin';

break;

case '1':
$streamName = 'php://stdout';

break;

case '2':
$streamName = 'php://stderr';

break;

default:
if (true === ctype_digit($streamName)) {
if (PHP_VERSION_ID >= 50306) {
$streamName = 'php://fd/' . $streamName;
} else {
throw new Exception(
'You need PHP5.3.6 to use a file descriptor ' .
'other than 0, 1 or 2 (tried %d with PHP%s).',
0,
[$streamName, PHP_VERSION]
);
}
}
}

parent::__construct($streamName, $context, $wait);

return;
}










protected function &_open($streamName, Stream\Context $context = null)
{
if (substr($streamName, 0, 4) == 'file' &&
false === is_dir(dirname($streamName))) {
throw new Exception(
'Directory %s does not exist. Could not open file %s.',
1,
[dirname($streamName), basename($streamName)]
);
}

if (null === $context) {
if (false === $out = @fopen($streamName, $this->getMode(), true)) {
throw new Exception(
'Failed to open stream %s.',
2,
$streamName
);
}

return $out;
}

$out = @fopen(
$streamName,
$this->getMode(),
true,
$context->getContext()
);

if (false === $out) {
throw new Exception(
'Failed to open stream %s.',
3,
$streamName
);
}

return $out;
}






protected function _close()
{
return @fclose($this->getStream());
}









public function newBuffer($callable = null, $size = null)
{
$this->setStreamBuffer($size);



return 1;
}






public function flush()
{
return fflush($this->getStream());
}






public function deleteBuffer()
{
return $this->disableStreamBuffer();
}






public function getBufferLevel()
{
return 1;
}






public function getBufferSize()
{
return $this->getStreamBufferSize();
}








public function lock($operation)
{
return flock($this->getStream(), $operation);
}






public function rewind()
{
return rewind($this->getStream());
}









public function seek($offset, $whence = Stream\IStream\Pointable::SEEK_SET)
{
return fseek($this->getStream(), $offset, $whence);
}






public function tell()
{
$stream = $this->getStream();

if (null === $stream) {
return 0;
}

return ftell($stream);
}








public static function create($name, $dummy)
{
if (file_exists($name)) {
return true;
}

return touch($name);
}
}




Consistency::flexEntity('Hoa\File\File');
<?php



































namespace Hoa\Console;

use Hoa\Consistency;









class Console
{





const IS_FIFO = 0;






const IS_CHARACTER = 1;






const IS_DIRECTORY = 2;






const IS_BLOCK = 3;






const IS_REGULAR = 4;






const IS_LINK = 5;






const IS_SOCKET = 6;






const IS_WHITEOUT = 7;






private static $_advanced = null;






private static $_old = null;






protected static $_mode = [];






protected static $_input = null;






protected static $_output = null;






protected static $_tput = null;









public static function advancedInteraction($force = false)
{
if (null !== self::$_advanced) {
return self::$_advanced;
}

if (OS_WIN) {
return self::$_advanced = false;
}

if (false === $force &&
true === defined('STDIN') &&
false === self::isDirect(STDIN)) {
return self::$_advanced = false;
}

self::$_old = Processus::execute('stty -g < /dev/tty', false);
Processus::execute('stty -echo -icanon min 1 time 0 < /dev/tty', false);

return self::$_advanced = true;
}






public static function restoreInteraction()
{
if (null === self::$_old) {
return;
}

Processus::execute('stty ' . self::$_old . ' < /dev/tty', false);

return;
}








public static function getMode($pipe = STDIN)
{
$_pipe = (int) $pipe;

if (isset(self::$_mode[$_pipe])) {
return self::$_mode[$_pipe];
}

$stat = fstat($pipe);

switch ($stat['mode'] & 0170000) {

 case 0010000:
$mode = self::IS_FIFO;

break;


 case 0020000:
$mode = self::IS_CHARACTER;

break;


 case 0040000:
$mode = self::IS_DIRECTORY;

break;


 case 0060000:
$mode = self::IS_BLOCK;

break;


 case 0100000:
$mode = self::IS_REGULAR;

break;


 case 0120000:
$mode = self::IS_LINK;

break;


 case 0140000:
$mode = self::IS_SOCKET;

break;


 case 0160000:
$mode = self::IS_WHITEOUT;

break;

default:
$mode = -1;
}

return self::$_mode[$_pipe] = $mode;
}











public static function isDirect($pipe)
{
return self::IS_CHARACTER === self::getMode($pipe);
}










public static function isPipe($pipe)
{
return self::IS_FIFO === self::getMode($pipe);
}










public static function isRedirection($pipe)
{
$mode = self::getMode($pipe);

return
self::IS_REGULAR === $mode ||
self::IS_DIRECTORY === $mode ||
self::IS_LINK === $mode ||
self::IS_SOCKET === $mode ||
self::IS_BLOCK === $mode;
}







public static function setInput(Input $input)
{
$old = static::$_input;
static::$_input = $input;

return $old;
}






public static function getInput()
{
if (null === static::$_input) {
static::$_input = new Input();
}

return static::$_input;
}







public static function setOutput(Output $output)
{
$old = static::$_output;
static::$_output = $output;

return $old;
}






public static function getOutput()
{
if (null === static::$_output) {
static::$_output = new Output();
}

return static::$_output;
}







public static function setTput(Tput $tput)
{
$old = static::$_tput;
static::$_tput = $tput;

return $old;
}






public static function getTput()
{
if (null === static::$_tput) {
static::$_tput = new Tput();
}

return static::$_tput;
}






public static function isTmuxRunning()
{
return isset($_SERVER['TMUX']);
}
}




Consistency::registerShutdownFunction(xcallable('Hoa\Console\Console::restoreInteraction'));




Consistency::flexEntity('Hoa\Console\Console');
<?php



































namespace Hoa\Console\Test\Unit;

use Hoa\Console as LUT;
use Hoa\Console\Console as SUT;
use Hoa\Test;









class Console extends Test\Unit\Suite
{
public function case_get_mode_fifo()
{
return $this->_case_get_mode_xxx(0010000, SUT::IS_FIFO);
}

public function case_get_mode_character()
{
return $this->_case_get_mode_xxx(0020000, SUT::IS_CHARACTER);
}

public function case_get_mode_directory()
{
return $this->_case_get_mode_xxx(0040000, SUT::IS_DIRECTORY);
}

public function case_get_mode_block()
{
return $this->_case_get_mode_xxx(0060000, SUT::IS_BLOCK);
}

public function case_get_mode_regular()
{
return $this->_case_get_mode_xxx(0100000, SUT::IS_REGULAR);
}

public function case_get_mode_link()
{
return $this->_case_get_mode_xxx(0120000, SUT::IS_LINK);
}

public function case_get_mode_socket()
{
return $this->_case_get_mode_xxx(0140000, SUT::IS_SOCKET);
}

public function case_get_mode_whiteout()
{
return $this->_case_get_mode_xxx(0160000, SUT::IS_WHITEOUT);
}

public function case_get_mode_unknown()
{
return $this->_case_get_mode_xxx(0170000, -1);
}

protected function _case_get_mode_xxx($mask, $expect)
{
$this
->given($this->function->fstat = ['mode' => $mask & 0170000])
->when($result = SUT::getMode(null))
->then
->integer($result)
->isEqualTo($expect);
}

public function case_set_input()
{
$this
->given($input = new LUT\Input())
->when($result = SUT::setInput($input))
->then
->variable($result)
->isNull()
->object(SUT::getInput())
->isIdenticalTo($input);
}

public function case_get_input()
{
$this
->when($result = SUT::getInput())
->then
->object($result)
->isInstanceOf('Hoa\Console\Input')
->isIdenticalTo(SUT::getInput());
}

public function case_set_output()
{
$this
->given($output = new LUT\Output())
->when($result = SUT::setOutput($output))
->then
->variable($result)
->isNull()
->object(SUT::getOutput())
->isIdenticalTo($output);
}

public function case_get_output()
{
$this
->when($result = SUT::getOutput())
->then
->object($result)
->isInstanceOf('Hoa\Console\Output')
->isIdenticalTo(SUT::getOutput());
}

public function case_set_tput()
{
$this
->given($tput = new LUT\Tput('hoa://Library/Console/Terminfo/78/xterm'))
->when($result = SUT::setTput($tput))
->then
->variable($result)
->isNull()
->object(SUT::getTput())
->isIdenticalTo($tput);
}

public function case_get_tput()
{
$this
->when($result = SUT::getTput())
->then
->object($result)
->isInstanceOf('Hoa\Console\Tput')
->isIdenticalTo(SUT::getTput());
}

public function case_is_tmux_running()
{
$this
->given($_SERVER['TMUX'] = 'foo')
->when($result = SUT::isTmuxRunning())
->then
->boolean($result)
->isTrue();
}

public function case_is_not_tmux_running()
{
unset($_SERVER['TMUX']);

$this
->when($result = SUT::isTmuxRunning())
->then
->boolean($result)
->isFalse();
}
}
<?php



































namespace Hoa\Console\Test\Unit;

use Hoa\Console as LUT;
use Hoa\Console\Mouse as SUT;
use Hoa\Event;
use Hoa\File;
use Hoa\Test;









class Mouse extends Test\Unit\Suite
{
public function beforeTestMethod($methodName)
{
parent::beforeTestMethod($methodName);
LUT::setTput(new LUT\Tput('hoa://Library/Console/Terminfo/78/xterm-256color'));

return;
}

public function case_get_instance()
{
$this
->when($result = SUT::getInstance())
->then
->object($result)
->isIdenticalTo(SUT::getInstance());
}

public function case_track_button_left()
{
return $this->_case_track(
7,
42,
SUT::BUTTON_LEFT,
'mousedown',
[
'x' => 7,
'y' => 42,
'button' => 'left',
'shift' => false,
'meta' => false,
'ctrl' => false
]
);
}

public function case_track_button_middle()
{
return $this->_case_track(
7,
42,
SUT::BUTTON_MIDDLE,
'mousedown',
[
'x' => 7,
'y' => 42,
'button' => 'middle',
'shift' => false,
'meta' => false,
'ctrl' => false
]
);
}

public function case_track_button_right()
{
return $this->_case_track(
7,
42,
SUT::BUTTON_RIGHT,
'mousedown',
[
'x' => 7,
'y' => 42,
'button' => 'right',
'shift' => false,
'meta' => false,
'ctrl' => false
]
);
}

public function case_track_button_release()
{
return $this->_case_track(
7,
42,
SUT::BUTTON_RELEASE,
'mouseup',
[
'x' => 7,
'y' => 42,
'button' => null,
'shift' => false,
'meta' => false,
'ctrl' => false
]
);
}

public function case_track_wheelup()
{
return $this->_case_track(
7,
42,
SUT::WHEEL_UP,
'wheelup',
[
'x' => 7,
'y' => 42,
'button' => null,
'shift' => false,
'meta' => false,
'ctrl' => false
]
);
}

public function case_track_wheeldown()
{
return $this->_case_track(
7,
42,
SUT::WHEEL_DOWN,
'wheeldown',
[
'x' => 7,
'y' => 42,
'button' => null,
'shift' => false,
'meta' => false,
'ctrl' => false
]
);
}

public function _case_track($x, $y, $pointerActionCode, $listenerName, array $listenerData)
{
$this
->given(
$self = $this,
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll(
"\033[M" .
chr(($pointerActionCode + 32) & ~28) .
chr($x + 32) .
chr($y + 32)
),
$file->rewind(),
$input = LUT::setInput(new LUT\Input($file)),

$this->function->stream_select = function () {
static $i = 1;

if (1 === $i) {
return $i--;
}

return false;
},

SUT::getInstance()->on(
$listenerName,
function (Event\Bucket $bucket) use (&$_listenerData) {
$_listenerData = $bucket->getData();

return;
}
)
)
->when(SUT::track())
->then
->output
->isEqualTo(

 "\033[1;2'z" .
"\033[?1000h" .
"\033[?1003h" .


 "\033[?1003l" .
"\033[?1000l"
)
->array($_listenerData)
->isEqualTo($listenerData);
}

public function case_untrack_when_not_tracked()
{
$this
->when($result = SUT::untrack())
->then
->variable($result)
->isNull()
->output
->isEmpty();
}
}
<?php



































namespace Hoa\Console\Test\Unit;

use Hoa\Console\Input as SUT;
use Hoa\File;
use Hoa\Test;









class Input extends Test\Unit\Suite
{
public function case_is_a_stream()
{
$this
->when($result = new SUT())
->then
->object($result)
->isInstanceOf('Hoa\Stream\IStream\In');
}

public function case_eof()
{
$this
->given(
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$input = new SUT($file)
)
->when($result = $input->eof())
->then
->boolean($result)
->isEqualTo($file->eof());
}

public function case_read()
{
$this
->given(
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll('foobar'),
$file->rewind(),
$input = new SUT($file)
)
->when($result = $input->read(3))
->then
->string($result)
->isEqualTo('foo');
}

public function case_read_string()
{
$this
->given(
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll('foobar'),
$file->rewind(),
$input = new SUT($file)
)
->when($result = $input->readString(3))
->then
->string($result)
->isEqualTo('foo');
}

public function case_read_character()
{
$this
->given(
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll('foobar'),
$file->rewind(),
$input = new SUT($file)
)
->when($result = $input->readCharacter(1))
->then
->string($result)
->isEqualTo('f');
}

public function case_read_boolean_true()
{
$this
->given(
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll('1'),
$file->rewind(),
$input = new SUT($file)
)
->when($result = $input->readBoolean())
->then
->boolean($result)
->isTrue();
}

public function case_read_boolean_false()
{
$this
->given(
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll('0'),
$file->rewind(),
$input = new SUT($file)
)
->when($result = $input->readBoolean())
->then
->boolean($result)
->isFalse();
}

public function case_read_integer()
{
$this
->given(
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll('42'),
$file->rewind(),
$input = new SUT($file)
)
->when($result = $input->readInteger(2))
->then
->integer($result)
->isEqualTo(42);
}

public function case_read_float()
{
$this
->given(
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll('4.2'),
$file->rewind(),
$input = new SUT($file)
)
->when($result = $input->readFloat(3))
->then
->float($result)
->isEqualTo(4.2);
}

public function case_read_array()
{
$this
->given(
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll('foo bar'),
$file->rewind(),
$input = new SUT($file)
)
->when($result = $input->readArray('%s %s'))
->then
->array($result)
->isEqualTo([
0 => 'foo',
1 => 'bar'
]);
}

public function case_read_line()
{
$this
->given(
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll('foo' . "\n" . 'bar'),
$file->rewind(),
$input = new SUT($file)
)
->when($result = $input->readLine())
->then
->string($result)
->isEqualTo('foo' . "\n");
}

public function case_read_all()
{
$this
->given(
$content = '4.2foo' . "\n" . 'bar',
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll($content),
$file->rewind(),
$input = new SUT($file)
)
->when($result = $input->readAll())
->then
->string($result)
->isEqualTo($content);
}

public function case_scanf()
{
$this
->given(
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll('foo 42' . "\n" . 'bar 153'),
$file->rewind(),
$input = new SUT($file)
)
->when($result = $input->scanf('%s %d'))
->then
->array($result)
->isEqualTo([
0 => 'foo',
1 => 42
])

->when($result = $input->scanf('%s %d'))
->then
->array($result)
->isEqualTo([
0 => 'bar',
1 => 153
]);
}
}
<?php



































namespace Hoa\Console\Test\Unit;

use Hoa\Console\Tput as SUT;
use Hoa\Test;









class Tput extends Test\Unit\Suite
{
public function case_get_term_from_environment()
{
$this
->given($_SERVER['TERM'] = 'foo')
->when($result = SUT::getTerm())
->then
->string($result)
->isEqualTo('foo');
}

public function case_get_unknown_term_on_windows()
{
unset($_SERVER['TERM']);

$this
->given($this->constant->OS_WIN = true)
->when($result = SUT::getTerm())
->then
->string($result)
->isEqualTo('windows-ansi');
}

public function case_get_unknown_term()
{
unset($_SERVER['TERM']);

$this
->given($this->constant->OS_WIN = false)
->when($result = SUT::getTerm())
->then
->string($result)
->isEqualTo('xterm');
}

public function case_unknown_file_when_parsing()
{
$this
->exception(function () {
new SUT('/hoa/flatland');
})
->isInstanceOf('Hoa\Console\Exception');
}

public function case_all_informations()
{
$this
->given($tput = new SUT('hoa://Library/Console/Terminfo/78/xterm'))
->when($result = $tput->getInformations())
->then
->array($result)
->isIdenticalTo([
'file' => 'hoa://Library/Console/Terminfo/78/xterm',
'headers' => [
'data_size' => 3258,
'header_size' => 12,
'magic_number' => 282,
'names_size' => 48,
'bool_count' => 38,
'number_count' => 15,
'string_count' => 413,
'string_table_size' => 1388
],
'name' => 'xterm',
'description' => 'xterm terminal emulator (X Window System)',
'booleans' => [
'auto_left_margin' => false,
'auto_right_margin' => true,
'no_esc_ctlc' => false,
'ceol_standout_glitch' => false,
'eat_newline_glitch' => true,
'erase_overstrike' => false,
'generic_type' => false,
'hard_copy' => false,
'meta_key' => true,
'status_line' => false,
'insert_null_glitch' => false,
'memory_above' => false,
'memory_below' => false,
'move_insert_mode' => true,
'move_standout_mode' => true,
'over_strike' => false,
'status_line_esc_ok' => false,
'dest_tabs_magic_smso' => false,
'tilde_glitch' => false,
'transparent_underline' => false,
'xon_xoff' => false,
'needs_xon_xoff' => false,
'prtr_silent' => true,
'hard_cursor' => false,
'non_rev_rmcup' => false,
'no_pad_char' => true,
'non_dest_scroll_region' => false,
'can_change' => false,
'back_color_erase' => true,
'hue_lightness_saturation' => false,
'col_addr_glitch' => false,
'cr_cancels_micro_mode' => false,
'print_wheel' => false,
'row_addr_glitch' => false,
'semi_auto_right_margin' => false,
'cpi_changes_res' => false,
'lpi_changes_res' => false,
'backspaces_with_bs' => true
],
'numbers' => [
'columns' => 80,
'init_tabs' => 8,
'lines' => 24,
'lines_of_memory' => -1,
'magic_cookie_glitch' => -1,
'padding_baud_rate' => -1,
'virtual_terminal' => -1,
'width_status_line' => -1,
'num_labels' => -1,
'label_height' => -1,
'label_width' => -1,
'max_attributes' => -1,
'maximum_windows' => -1,
'max_colors' => 8,
'max_pairs' => 64
],
'strings' => [
'back_tab' => '[Z',
'bell' => '',
'carriage_return' => '',
'change_scroll_region' => '[%i%p1%d;%p2%dr',
'clear_all_tabs' => '[3g',
'clear_screen' => '[H[2J',
'clr_eol' => '[K',
'clr_eos' => '[J',
'column_address' => '[%i%p1%dG',
'cursor_address' => '[%i%p1%d;%p2%dH',
'cursor_down' => "\n",
'cursor_home' => '[H',
'cursor_invisible' => '[?25l',
'cursor_left' => '',
'cursor_normal' => '[?12l[?25h',
'cursor_right' => '[C',
'cursor_up' => '[A',
'cursor_visible' => '[?12;25h',
'delete_character' => '[P',
'delete_line' => '[M',
'enter_alt_charset_mode' => '(0',
'enter_blink_mode' => '[5m',
'enter_bold_mode' => '[1m',
'enter_ca_mode' => '[?1049h',
'enter_insert_mode' => '[4h',
'enter_secure_mode' => '[8m',
'enter_reverse_mode' => '[7m',
'enter_standout_mode' => '[7m',
'enter_underline_mode' => '[4m',
'erase_chars' => '[%p1%dX',
'exit_alt_charset_mode' => '(B',
'exit_attribute_mode' => '(B[m',
'exit_ca_mode' => '[?1049l',
'exit_insert_mode' => '[4l',
'exit_standout_mode' => '[27m',
'exit_underline_mode' => '[24m',
'flash_screen' => '[?5h$<100/>[?5l',
'init_2string' => '[!p[?3;4l[4l>',
'insert_line' => '[L',
'key_backspace' => '',
'key_dc' => '[3~',
'key_down' => 'OB',
'key_f1' => 'OP',
'key_f10' => '[21~',
'key_f2' => 'OQ',
'key_f3' => 'OR',
'key_f4' => 'OS',
'key_f5' => '[15~',
'key_f6' => '[17~',
'key_f7' => '[18~',
'key_f8' => '[19~',
'key_f9' => '[20~',
'key_home' => 'OH',
'key_ic' => '[2~',
'key_left' => 'OD',
'key_npage' => '[6~',
'key_ppage' => '[5~',
'key_right' => 'OC',
'key_sf' => '[1;2B',
'key_sr' => '[1;2A',
'key_up' => 'OA',
'keypad_local' => '[?1l>',
'keypad_xmit' => '[?1h=',
'meta_off' => '[?1034l',
'meta_on' => '[?1034h',
'parm_dch' => '[%p1%dP',
'parm_delete_line' => '[%p1%dM',
'parm_down_cursor' => '[%p1%dB',
'parm_ich' => '[%p1%d@',
'parm_index' => '[%p1%dS',
'parm_insert_line' => '[%p1%dL',
'parm_left_cursor' => '[%p1%dD',
'parm_right_cursor' => '[%p1%dC',
'parm_rindex' => '[%p1%dT',
'parm_up_cursor' => '[%p1%dA',
'print_screen' => '[i',
'prtr_off' => '[4i',
'prtr_on' => '[5i',
'reset_1string' => 'c',
'reset_2string' => '[!p[?3;4l[4l>',
'restore_cursor' => '8',
'row_address' => '[%i%p1%dd',
'save_cursor' => '7',
'scroll_forward' => "\n",
'scroll_reverse' => 'M',
'set_attributes' => '%?%p9%t(0%e(B%;[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m',
'set_tab' => 'H',
'tab' => '	',
'key_b2' => 'OE',
'acs_chars' => '``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~',
'key_btab' => '[Z',
'enter_am_mode' => '[?7h',
'exit_am_mode' => '[?7l',
'key_end' => 'OF',
'key_enter' => 'OM',
'key_sdc' => '[3;2~',
'key_send' => '[1;2F',
'key_shome' => '[1;2H',
'key_sic' => '[2;2~',
'key_sleft' => '[1;2D',
'key_snext' => '[6;2~',
'key_sprevious' => '[5;2~',
'key_sright' => '[1;2C',
'key_f11' => '[23~',
'key_f12' => '[24~',
'key_f13' => '[1;2P',
'key_f14' => '[1;2Q',
'key_f15' => '[1;2R',
'key_f16' => '[1;2S',
'key_f17' => '[15;2~',
'key_f18' => '[17;2~',
'key_f19' => '[18;2~',
'key_f20' => '[19;2~',
'key_f21' => '[20;2~',
'key_f22' => '[21;2~',
'key_f23' => '[23;2~',
'key_f24' => '[24;2~',
'key_f25' => '[1;5P',
'key_f26' => '[1;5Q',
'key_f27' => '[1;5R',
'key_f28' => '[1;5S',
'key_f29' => '[15;5~',
'key_f30' => '[17;5~',
'key_f31' => '[18;5~',
'key_f32' => '[19;5~',
'key_f33' => '[20;5~',
'key_f34' => '[21;5~',
'key_f35' => '[23;5~',
'key_f36' => '[24;5~',
'key_f37' => '[1;6P',
'key_f38' => '[1;6Q',
'key_f39' => '[1;6R',
'key_f40' => '[1;6S',
'key_f41' => '[15;6~',
'key_f42' => '[17;6~',
'key_f43' => '[18;6~',
'key_f44' => '[19;6~',
'key_f45' => '[20;6~',
'key_f46' => '[21;6~',
'key_f47' => '[23;6~',
'key_f48' => '[24;6~',
'key_f49' => '[1;3P',
'key_f50' => '[1;3Q',
'key_f51' => '[1;3R',
'key_f52' => '[1;3S',
'key_f53' => '[15;3~',
'key_f54' => '[17;3~',
'key_f55' => '[18;3~',
'key_f56' => '[19;3~',
'key_f57' => '[20;3~',
'key_f58' => '[21;3~',
'key_f59' => '[23;3~',
'key_f60' => '[24;3~',
'key_f61' => '[1;4P',
'key_f62' => '[1;4Q',
'key_f63' => '[1;4R',
'clr_bol' => '[1K',
'user6' => '[%i%d;%dR',
'user7' => '[6n',
'user8' => '[?1;2c',
'user9' => '[c',
'orig_pair' => '[39;49m',
'set_foreground' => '[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m',
'set_background' => '[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m',
'key_mouse' => '[M',
'set_a_foreground' => '[3%p1%dm',
'set_a_background' => '[4%p1%dm',
'memory_lock' => 'l',
'memory_unlock' => 'm'
]
]);
}

public function case_has()
{
$this
->given($tput = new SUT('hoa://Library/Console/Terminfo/78/xterm'))
->when($result = $tput->has('auto_left_margin'))
->then
->boolean($result)
->isFalse()

->when($result = $tput->has('auto_right_margin'))
->then
->boolean($result)
->isTrue();
}

public function case_has_unknown_boolean()
{
$this
->given($tput = new SUT('hoa://Library/Console/Terminfo/78/xterm'))
->when($result = $tput->has('💩'))
->then
->boolean($result)
->isFalse();
}

public function case_count()
{
$this
->given($tput = new SUT('hoa://Library/Console/Terminfo/78/xterm'))
->when($result = $tput->count('columns'))
->then
->integer($result)
->isEqualTo(80);
}

public function case_count_unknown_integer()
{
$this
->given($tput = new SUT('hoa://Library/Console/Terminfo/78/xterm'))
->when($result = $tput->count('💩'))
->then
->integer($result)
->isEqualTo(0);
}

public function case_get()
{
$this
->given($tput = new SUT('hoa://Library/Console/Terminfo/78/xterm'))
->when($result = $tput->get('cursor_down'))
->then
->string($result)
->isEqualTo("\n");
}

public function case_get_unknown_string()
{
$this
->given($tput = new SUT('hoa://Library/Console/Terminfo/78/xterm'))
->when($result = $tput->get('💩'))
->then
->variable($result)
->isNull();
}
}
<?php



































namespace Hoa\Console\Test\Unit;

use Hoa\Console\Output as SUT;
use Hoa\Test;









class Output extends Test\Unit\Suite
{
public function case_is_a_stream()
{
$this
->when($result = new SUT())
->then
->object($result)
->isInstanceOf('Hoa\Stream\IStream\Out');
}

public function case_write()
{
$this
->given($output = new SUT())
->when($output->write('foobar', 3))
->then
->output
->isIdenticalTo('foo');
}

public function case_write_string()
{
$this
->given($output = new SUT())
->when($output->writeString(123))
->then
->output
->isIdenticalTo('123');
}

public function case_write_character()
{
$this
->given($output = new SUT())
->when($output->writeCharacter('foo'))
->then
->output
->isIdenticalTo('f');
}

public function case_write_boolean_true()
{
$this
->given($output = new SUT())
->when($output->writeBoolean(true))
->then
->output
->isIdenticalTo('1');
}

public function case_write_boolean_false()
{
$this
->given($output = new SUT())
->when($output->writeBoolean(false))
->then
->output
->isIdenticalTo('0');
}

public function case_write_integer()
{
$this
->given($output = new SUT())
->when($output->writeInteger(-42))
->then
->output
->isIdenticalTo('-42');
}

public function case_write_float()
{
$this
->given($output = new SUT())
->when($output->writeFloat(-4.2))
->then
->output
->isIdenticalTo('-4.2');
}

public function case_write_array()
{
$this
->given($output = new SUT())
->when($output->writeArray(['foo' => 'bar']))
->then
->output
->isIdenticalTo(
'array (' . "\n" .
'  \'foo\' => \'bar\',' . "\n" .
')'
);
}

public function case_write_line_no_newline()
{
$this
->given($output = new SUT())
->when($output->writeLine('foo'))
->then
->output
->isIdenticalTo('foo' . "\n");
}

public function case_write_line_with_newline()
{
$this
->given($output = new SUT())
->when($output->writeLine('foo' . "\n"))
->then
->output
->isIdenticalTo('foo' . "\n");
}

public function case_write_line_with_newlines()
{
$this
->given($output = new SUT())
->when($output->writeLine('foo' . "\n" . 'bar' . "\n"))
->then
->output
->isIdenticalTo('foo' . "\n");
}

public function case_write_all()
{
$this
->given($output = new SUT())
->when($output->writeAll('foobar'))
->then
->output
->isIdenticalTo('foobar');
}

public function case_truncate()
{
$this
->given($output = new SUT())
->when($result = $output->truncate(42))
->then
->boolean($result)
->isFalse();
}

public function case_default_multiplexer_consideration()
{
$this
->given($output = new SUT())
->when($result = $output->isMultiplexerConsidered())
->then
->boolean($result)
->isFalse();
}

public function case_consider_multiplexer()
{
$this
->given($output = new SUT())
->when(
$output->considerMultiplexer(true),
$result = $output->isMultiplexerConsidered()
)
->then
->boolean($result)
->isTrue();
}
}
<?php



































namespace Hoa\Console\Test\Unit;

use Hoa\Console as LUT;
use Hoa\Console\Window as SUT;
use Hoa\File;
use Hoa\Test;









class Window extends Test\Unit\Suite
{
public function beforeTestMethod($methodName)
{
parent::beforeTestMethod($methodName);
LUT::setTput(new LUT\Tput('hoa://Library/Console/Terminfo/78/xterm-256color'));

return;
}

public function case_get_instance()
{
$this
->when($result = SUT::getInstance())
->then
->object($result)
->isIdenticalTo(SUT::getInstance());
}

public function case_set_size()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::setSize(7, 42))
->then
->output
->isEqualTo("\033[8;42;7t");
}

public function case_set_size_on_windows()
{
$this
->given($this->constant->OS_WIN = true)
->when(SUT::setSize(7, 42))
->then
->output
->isEmpty();
}

public function case_move_to()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::moveTo(7, 42))
->then
->output
->isEqualTo("\033[3;7;42t");
}

public function case_move_to_on_windows()
{
$this
->given($this->constant->OS_WIN = true)
->when(SUT::moveTo(7, 42))
->then
->output
->isEmpty();
}

public function case_get_position()
{
$this
->given(
$this->constant->OS_WIN = false,

$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll("\033[3;7;42t"),
$file->rewind(),
$input = LUT::setInput(new LUT\Input($file))
)
->when($result = SUT::getPosition())
->then
->output
->isEqualTo("\033[13t")
->array($result)
->isEqualTo([
'x' => 7,
'y' => 42
]);
}

public function case_get_position_on_windows()
{
$this
->given($this->constant->OS_WIN = true)
->when($result = SUT::getPosition())
->then
->variable($result)
->isNull()
->output
->isEmpty();
}

public function case_scroll_u()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::scroll('u'))
->then
->output
->isEqualTo("\033[1S");
}

public function case_scroll_up()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::scroll('up'))
->then
->output
->isEqualTo("\033[1S");
}

public function case_scroll_d()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::scroll('d'))
->then
->output
->isEqualTo("\033[1T");
}

public function case_scroll_down()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::scroll('d'))
->then
->output
->isEqualTo("\033[1T");
}

public function case_scroll_u_d_up_down()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::scroll('u d up down'))
->then
->output
->isEqualTo("\033[2S\033[2T");
}

public function case_scroll_up_repeated()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::scroll('up', 3))
->then
->output
->isEqualTo("\033[3S");
}

public function case_scroll_on_windows()
{
$this
->given($this->constant->OS_WIN = true)
->when(SUT::scroll('u'))
->then
->output
->isEmpty();
}

public function case_minimize()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::minimize())
->then
->output
->isEqualTo("\033[2t");
}

public function case_minimize_on_windows()
{
$this
->given($this->constant->OS_WIN = true)
->when(SUT::minimize())
->then
->output
->isEmpty();
}

public function case_restore()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::restore())
->then
->output
->isEqualTo("\033[1t");
}

public function case_restore_on_windows()
{
$this
->given($this->constant->OS_WIN = true)
->when(SUT::restore())
->then
->output
->isEmpty();
}

public function case_raise()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::raise())
->then
->output
->isEqualTo("\033[5t");
}

public function case_raise_on_windows()
{
$this
->given($this->constant->OS_WIN = true)
->when(SUT::raise())
->then
->output
->isEmpty();
}

public function case_lower()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::lower())
->then
->output
->isEqualTo("\033[6t");
}

public function case_lower_on_windows()
{
$this
->given($this->constant->OS_WIN = true)
->when(SUT::lower())
->then
->output
->isEmpty();
}

public function case_set_title()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::setTitle('foobar 😄'))
->then
->output
->isEqualTo("\033]0;foobar 😄\033\\");
}

public function case_set_title_on_windows()
{
$this
->given($this->constant->OS_WIN = true)
->when(SUT::setTitle('foobar 😄'))
->then
->output
->isEmpty();
}

public function case_get_title()
{
$this
->given(
$this->constant->OS_WIN = false,

$title = 'hello 🌍',
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll("\033]l" . $title . "\033\\"),
$file->rewind(),
$input = LUT::setInput(new LUT\Input($file)),
$this->function->stream_select = function () {
return 1;
}
)
->when($result = SUT::getTitle())
->then
->output
->isEqualTo("\033[21t")
->string($result)
->isEqualTo($title);
}

public function case_get_title_on_windows()
{
$this
->given($this->constant->OS_WIN = true)
->when($result = SUT::getTitle())
->then
->variable($result)
->isNull()
->output
->isEmpty();
}

public function case_get_title_timed_out()
{
$this
->given(
$this->function->stream_select = function () {
return 0;
}
)
->when($result = SUT::getTitle())
->then
->output
->isEqualTo("\033[21t")
->variable($result)
->isNull();
}

public function case_get_label()
{
$this
->given(
$this->constant->OS_WIN = false,

$label = 'hello 🌍',
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll("\033]L" . $label . "\033\\"),
$file->rewind(),
$input = LUT::setInput(new LUT\Input($file)),
$this->function->stream_select = function () {
return 1;
}
)
->when($result = SUT::getLabel())
->then
->output
->isEqualTo("\033[20t")
->string($result)
->isEqualTo($label);
}

public function case_get_label_timed_out()
{
$this
->given(
$this->function->stream_select = function () {
return 0;
}
)
->when($result = SUT::getLabel())
->then
->output
->isEqualTo("\033[20t")
->variable($result)
->isNull();
}

public function case_get_label_on_windows()
{
$this
->given($this->constant->OS_WIN = true)
->when($result = SUT::getLabel())
->then
->variable($result)
->isNull()
->output
->isEmpty();
}

public function case_refresh()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::refresh())
->then
->output
->isEqualTo("\033[7t");
}

public function case_refresh_on_windows()
{
$this
->given($this->constant->OS_WIN = true)
->when(SUT::refresh())
->then
->output
->isEmpty();
}

public function case_copy()
{
unset($_SERVER['TMUX']);

$this
->given($this->constant->OS_WIN = false)
->when(SUT::copy('bla'))
->then
->output
->isEqualTo("\033]52;;" . base64_encode('bla') . "\033\\");
}

public function case_copy_on_tmux()
{
$this
->given(
$_SERVER['TMUX'] = 'foo',
$this->constant->OS_WIN = false
)
->when(SUT::copy('bla'))
->then
->output
->isEqualTo(
"\033Ptmux;" .
"\033\033]52;;" . base64_encode('bla') . "\033\033\\" .
"\033\\"
);
}

public function case_copy_on_windows()
{
$this
->given($this->constant->OS_WIN = true)
->when(SUT::copy('bla'))
->then
->output
->isEmpty();
}
}
<?php



































namespace Hoa\Console\Test\Unit;

use Hoa\Console as LUT;
use Hoa\Console\GetOption as SUT;
use Hoa\Test;









class GetOption extends Test\Unit\Suite
{
public function case_empty()
{
$this
->given(
$parser = new LUT\Parser(),
$parser->parse(''),

$options = new SUT([], $parser)
)
->when($result = $options->getOption($value))
->then
->boolean($options->isPipetteEmpty())
->isTrue()
->boolean($result)
->isFalse()
->variable($value)
->isNull();
}

public function case_one_entry()
{
$this
->given(
$parser = new LUT\Parser(),
$parser->parse('--foo'),

$options = new SUT(
[
['foo', SUT::NO_ARGUMENT, 'f']
],
$parser
)
)
->when($result = $options->getOption($value))
->then
->boolean($options->isPipetteEmpty())
->isFalse()
->string($result)
->isEqualTo('f')
->boolean($value)
->isTrue()

->when($result = $options->getOption($value))
->boolean($options->isPipetteEmpty())
->isFalse()
->boolean($result)
->isFalse()
->variable($value)
->isNull();
}

public function case_more_entries()
{
$this
->given(
$parser = new LUT\Parser(),
$parser->parse('--foo --bar baz'),

$options = new SUT(
[
['foo', SUT::NO_ARGUMENT, 'f'],
['bar', SUT::REQUIRED_ARGUMENT, 'b']
],
$parser
)
)
->when($result = $options->getOption($value))
->then
->boolean($options->isPipetteEmpty())
->isFalse()
->string($result)
->isEqualTo('f')
->boolean($value)
->isTrue()

->when($result = $options->getOption($value))
->then
->boolean($options->isPipetteEmpty())
->isFalse()
->string($result)
->isEqualTo('b')
->string($value)
->isEqualTo('baz')

->when($result = $options->getOption($value))
->then
->boolean($options->isPipetteEmpty())
->isFalse()
->boolean($result)
->isFalse()
->variable($value)
->isNull();
}

public function case_ambiguous()
{
$this
->given(
$parser = new LUT\Parser(),
$parser->parse('--baz'),

$options = new SUT(
[
['foo', SUT::NO_ARGUMENT, 'f'],
['bar', SUT::REQUIRED_ARGUMENT, 'b']
],
$parser
)
)
->when($result = $options->getOption($value))
->then
->boolean($options->isPipetteEmpty())
->isFalse()
->string($result)
->isEqualTo('__ambiguous')
->array($value)
->isEqualTo([
'solutions' => ['bar'],
'value' => true,
'option' => 'baz'
]);
}

public function case_resolve_option_ambiguity_no_solution()
{
$this
->given(
$parser = new LUT\Parser(),
$parser->parse(''),

$options = new SUT([], $parser),

$solutions = [
'solutions' => [],
'value' => true,
'option' => 'baz'
]
)
->exception(function () use ($options, $solutions) {
$options->resolveOptionAmbiguity($solutions);
})
->isInstanceOf('Hoa\Console\Exception');
}

public function case_resolve_option_ambiguity()
{
$this
->given(
$parser = new LUT\Parser(),
$parser->parse('--baz'),

$options = new SUT(
[
['bar', SUT::NO_ARGUMENT, 'b']
],
$parser
)
)
->when($result = $options->getOption($value))
->then
->string($result)
->isEqualTo('__ambiguous')
->array($value)
->isEqualTo([
'solutions' => ['bar'],
'value' => true,
'option' => 'baz'
])

->when($result = $options->resolveOptionAmbiguity($value))
->then
->variable($result)
->isNull()

->when($result = $options->getOption($value))
->then
->string($result)
->isEqualTo('b')
->boolean($value)
->isEqualTo(true);
}
}
<?php



































namespace Hoa\Console\Test\Unit;

use Hoa\Console\Parser as SUT;
use Hoa\Test;









class Parser extends Test\Unit\Suite
{
public function case_short_options()
{
return $this->_case(
'-a -b -c',
['a' => true, 'b' => true, 'c' => true]
);
}

public function case_single_dashed_short_options()
{
return $this->_case(
'-abc',
['a' => true, 'b' => true, 'c' => true]
);
}

public function case_long_options()
{
return $this->_case(
'--foo --bar --b-a-z',
['foo' => true, 'bar' => true, 'b-a-z' => true]
);
}

public function case_boolean_switches()
{
return $this->_case(
'-a -a --foo --foo --bar --bar --bar',
['a' => false, 'foo' => false, 'bar' => true]
);
}

public function case_valued_switches_equal_simple()
{
return $this->_case(
'-a=foo --long=bar',
['a' => 'foo', 'long' => 'bar']
);
}

public function case_valued_switches_equal_with_escaped_space()
{
return $this->_case(
'-a=fo\ o --long=b\ a\ r',
['a' => 'fo o', 'long' => 'b a r']
);
}

public function case_valued_switches_equal_double_quoted()
{
return $this->_case(
'-a="fo\"o" --long="b\"a\'r"',
['a' => 'fo"o', 'long' => 'b"a\'r']
);
}

public function case_valued_switches_equal_single_quoted()
{
return $this->_case(
'-a=\'fo\\\'"o\' --long=\'b\\\'a"r\'',
['a' => 'fo\'"o', 'long' => 'b\'a"r']
);
}

public function case_valued_switches_space_simple()
{
return $this->_case(
'-a foo --long bar',
['a' => 'foo', 'long' => 'bar']
);
}

public function case_valued_switches_space_with_escaped_space()
{
return $this->_case(
'-a fo\ o --long b\ a\ r',
['a' => 'fo o', 'long' => 'b a r']
);
}

public function case_valued_switches_space_double_quoted()
{
return $this->_case(
'-a "fo\"o" --long "b\"a\'r"',
['a' => 'fo"o', 'long' => 'b"a\'r']
);
}

public function case_valued_switches_space_single_quoted()
{
return $this->_case(
'-a \'fo\\\'"o\' --long \'b\\\'a"r\'',
['a' => 'fo\'"o', 'long' => 'b\'a"r']
);
}

public function case_valued_switch_equal_negative_value()
{
return $this->_case(
'-a=-foo --long=-bar',
['a' => '-foo', 'long' => '-bar']
);
}

public function case_special_valued_switch()
{
return $this->_case(
'-a f,o,o --long b,a,r',
['a' => 'f,o,o', 'long' => 'b,a,r']
);
}

public function case_input_associated_to_a_short_option()
{
return $this->_case(
'-a input',
['a' => 'input']
);
}

public function case_double_dashes_input()
{
return $this->_case(
'-a --long bar -- inputA inputB',
['a' => true, 'long' => 'bar'],
['inputA', 'inputB']
);
}

public function case_simple_input()
{
return $this->_case(
'inputA inputB',
[],
['inputA', 'inputB']
);
}

public function case_valued_switch_followed_by_an_input()
{
return $this->_case(
'-a foo --long bar inputA inputB',
['a' => 'foo', 'long' => 'bar'],
['inputA', 'inputB']
);
}

public function case_unordered()
{
return $this->_case(
'inputA -a foo inputB --long bar inputC',
['a' => 'foo', 'long' => 'bar'],
['inputA', 'inputB', 'inputC']
);
}

protected function _case($command, array $switches, array $inputs = [])
{
$this
->given($parser = new SUT())
->when($result = $parser->parse($command))
->then
->variable($result)
->isNull()
->array($parser->getSwitches())
->isIdenticalTo($switches)
->array($parser->getInputs())
->isIdenticalTo($inputs);
}

public function case_state_is_reset()
{
$this
->given($parser = new SUT())
->when($result = $parser->parse('--foo=bar baz'))
->then
->variable($result)
->isNull()
->array($parser->getSwitches())
->isIdenticalTo(['foo' => 'bar'])
->array($parser->getInputs())
->isIdenticalTo(['baz'])

->when($result = $parser->parse('--bar=baz qux'))
->variable($result)
->isNull()
->array($parser->getSwitches())
->isIdenticalTo(['bar' => 'baz'])
->array($parser->getInputs())
->isIdenticalTo(['qux']);
}

public function case_parse_special_value_list()
{
$this
->given($parser = new SUT())
->when($result = $parser->parseSpecialValue('foo,bar,baz'))
->then
->array($result)
->isIdenticalTo([
'foo',
'bar',
'baz'
]);
}

public function case_parse_special_value_list_with_keywords()
{
$this
->given($parser = new SUT())
->when($result = $parser->parseSpecialValue('foo,bar,QUX', ['QUX' => 'baz']))
->then
->array($result)
->isIdenticalTo([
'foo',
'bar',
'baz'
]);
}

public function case_parse_special_value_list_with_range()
{
$this
->given($parser = new SUT())
->when($result = $parser->parseSpecialValue('foo,bar,1:3'))
->then
->array($result)
->isIdenticalTo([
1,
2,
3,
'foo',
'bar'
]);
}

public function case_set_long_only()
{
$this
->given($parser = new SUT())
->when(
$parser->setLongOnly(true),
$result = $parser->parse('-abc')
)
->then
->boolean($parser->getLongOnly())
->isTrue()
->variable($result)
->isNull()
->array($parser->getSwitches())
->isIdenticalTo([
'abc' => true,
])
->array($parser->getInputs())
->isEmpty();
}
}
<?php



































namespace Hoa\Console\Test\Unit\Readline;

use Hoa\Console as LUT;
use Hoa\Console\Readline\Password as SUT;
use Hoa\Test;









class Password extends Test\Unit\Suite
{
public function case_ensure_hidden()
{
$this
->when($result = SUT::STATE_CONTINUE)
->then
->integer($result)
->isEqualTo(
LUT\Readline::STATE_CONTINUE |
LUT\Readline::STATE_NO_ECHO
);
}
}
<?php



































namespace Hoa\Console\Test\Unit\Readline\Autocompleter;

use Hoa\Console\Readline\Autocompleter\Aggregate as SUT;
use Hoa\Test;









class Aggregate extends Test\Unit\Suite
{
public function case_get_word_definition()
{
$this
->given($autocompleter = new SUT([]))
->when($result = $autocompleter->getWordDefinition())
->then
->string($result)
->isEqualTo('.*');
}

public function case_constructor()
{
$this
->given(
$autocompleterA = new \Mock\Hoa\Console\Readline\Autocompleter\Autocompleter(),
$autocompleterB = new \Mock\Hoa\Console\Readline\Autocompleter\Autocompleter()
)
->when($result = new SUT([$autocompleterA, $autocompleterB]))
->then
->object($result)
->isInstanceOf('Hoa\Console\Readline\Autocompleter\Autocompleter')
->let($autocompleters = $result->getAutocompleters())
->object($autocompleters)
->isInstanceOf('ArrayObject')
->integer(count($autocompleters))
->isEqualTo(2)
->object($autocompleters[0])
->isIdenticalTo($autocompleterA)
->object($autocompleters[1])
->isIdenticalTo($autocompleterB);
}

public function case_complete_no_solution()
{
$this
->given(
$autocompleterA = new \Mock\Hoa\Console\Readline\Autocompleter\Autocompleter(),
$autocompleterA->getWordDefinition = function () {
return 'aaa';
},

$autocompleterB = new \Mock\Hoa\Console\Readline\Autocompleter\Autocompleter(),
$autocompleterB->getWordDefinition = function () {
return 'bbb';
},

$autocompleter = new SUT([$autocompleterA, $autocompleterB]),
$prefix = 'ccc'
)
->when($result = $autocompleter->complete($prefix))
->then
->variable($result)
->isNull()
->string($prefix)
->isEqualTo('ccc');
}

public function case_complete_one_solution_first_autocompleter()
{
$self = $this;

$this
->given(
$autocompleterA = new \Mock\Hoa\Console\Readline\Autocompleter\Autocompleter(),
$this->calling($autocompleterA)->getWordDefinition = function () {
return 'aaa';
},
$this->calling($autocompleterA)->complete = function ($prefix) use ($self) {
$self
->string($prefix)
->isEqualTo('aaa');

return 'AAA';
},

$autocompleterB = new \Mock\Hoa\Console\Readline\Autocompleter\Autocompleter(),
$this->calling($autocompleterB)->getWordDefinition = function () {
return 'bbb';
},
$this->calling($autocompleterB)->complete = function ($prefix) use ($self) {
$self->fail('Bad autocompleter called.');
},

$autocompleter = new SUT([$autocompleterA, $autocompleterB]),
$prefix = 'aaa'
)
->when($result = $autocompleter->complete($prefix))
->then
->string($result)
->isEqualTo('AAA')
->string($prefix)
->isEqualTo('aaa');
}

public function case_complete_one_solution_second_autocompleter()
{
$self = $this;

$this
->given(
$autocompleterA = new \Mock\Hoa\Console\Readline\Autocompleter\Autocompleter(),
$this->calling($autocompleterA)->getWordDefinition = function () {
return 'aaa';
},
$this->calling($autocompleterA)->complete = function ($prefix) use ($self) {
$self->fail('Bad autocompleter called.');
},

$autocompleterB = new \Mock\Hoa\Console\Readline\Autocompleter\Autocompleter(),
$this->calling($autocompleterB)->getWordDefinition = function () {
return 'bbb';
},
$this->calling($autocompleterB)->complete = function ($prefix) use ($self) {
$self
->string($prefix)
->isEqualTo('bbb');

return 'BBB';
},

$autocompleter = new SUT([$autocompleterA, $autocompleterB]),
$prefix = 'bbb'
)
->when($result = $autocompleter->complete($prefix))
->then
->string($result)
->isEqualTo('BBB')
->string($prefix)
->isEqualTo('bbb');
}
}
<?php



































namespace Hoa\Console\Test\Unit\Readline\Autocompleter;

use Hoa\Console\Readline\Autocompleter\Word as SUT;
use Hoa\Test;









class Word extends Test\Unit\Suite
{
public function case_constructor()
{
$this
->given($words = ['foo', 'bar', 'baz', 'qux'])
->when($result = new SUT($words))
->then
->object($result)
->isInstanceOf('Hoa\Console\Readline\Autocompleter\Autocompleter')
->array($result->getWords())
->isEqualTo($words);
}

public function case_complete_no_solution()
{
$this
->given(
$autocompleter = new SUT(['foo', 'bar']),
$prefix = 'q'
)
->when($result = $autocompleter->complete($prefix))
->then
->variable($result)
->isNull()
->string($prefix)
->isEqualTo('q');
}

public function case_complete_one_solution()
{
$this
->given(
$autocompleter = new SUT(['foo', 'bar']),
$prefix = 'f'
)
->when($result = $autocompleter->complete($prefix))
->then
->string($result)
->isEqualTo('foo')
->string($prefix)
->isEqualTo('f');
}

public function case_complete_with_smallest_prefix()
{
$this
->given(
$autocompleter = new SUT(['foo', 'bar', 'baz', 'qux']),
$prefix = 'b'
)
->when($result = $autocompleter->complete($prefix))
->then
->array($result)
->isEqualTo(['bar', 'baz'])
->string($prefix)
->isEqualTo('b');
}

public function case_complete_with_longer_prefix()
{
$this
->given(
$autocompleter = new SUT(['bara', 'barb', 'baza']),
$prefix = 'bar'
)
->when($result = $autocompleter->complete($prefix))
->then
->array($result)
->isEqualTo(['bara', 'barb'])
->string($prefix)
->isEqualTo('bar');
}

public function case_get_word_definition()
{
$this
->given($autocompleter = new SUT([]))
->when($result = $autocompleter->getWordDefinition())
->then
->string($result)
->isEqualTo('\b\w+');
}

public function case_set_words()
{
$this
->given(
$words = ['foo', 'bar', 'baz', 'qux'],
$autocompleter = new SUT([])
)
->when($result = $autocompleter->setWords($words))
->then
->array($result)
->isEmpty();
}

public function case_get_words()
{
$this
->given(
$words = ['foo', 'bar', 'baz', 'qux'],
$autocompleter = new SUT($words)
)
->when($result = $autocompleter->getWords())
->then
->array($result)
->isEqualTo($words);
}
}
<?php



































namespace Hoa\Console\Test\Unit\Readline\Autocompleter;

use Hoa\Console\Readline\Autocompleter\Path as SUT;
use Hoa\Test;









class Path extends Test\Unit\Suite
{
public function case_get_word_definition()
{
$this
->given($autocompleter = new SUT())
->when($result = $autocompleter->getWordDefinition())
->then
->string($result)
->isEqualTo('/?[\w\d\\_\-\.]+(/[\w\d\\_\-\.]*)*');
}

public function case_constructor()
{
$this
->given(
$root = 'foo',
$iteratorFactory = function () {
return 42;
}
)
->when($result = new SUT($root, $iteratorFactory))
->then
->object($result)
->isInstanceOf('Hoa\Console\Readline\Autocompleter\Autocompleter')
->string($result->getRoot())
->isEqualTo($root)
->object($result->getIteratorFactory())
->isIdenticalTo($iteratorFactory);
}

public function case_complete_no_solution()
{
$this
->given(
resolve('hoa://Test/Vfs/Root?type=directory'),
resolve('hoa://Test/Vfs/Root/Foo?type=file'),
resolve('hoa://Test/Vfs/Root/Bar?type=file'),

$autocompleter = new SUT('hoa://Test/Vfs/Root'),
$prefix = 'Q'
)
->when($result = $autocompleter->complete($prefix))
->then
->variable($result)
->isNull()
->string($prefix)
->isEqualTo('Q');
}

public function case_complete_one_solution()
{
$this
->given(
resolve('hoa://Test/Vfs/Root?type=directory'),
resolve('hoa://Test/Vfs/Root/Foo?type=file'),
resolve('hoa://Test/Vfs/Root/Bar?type=file'),

$autocompleter = new SUT('hoa://Test/Vfs/Root'),
$prefix = 'F'
)
->when($result = $autocompleter->complete($prefix))
->then
->string($result)
->isEqualTo('Foo')
->string($prefix)
->isEqualTo('F');
}

public function case_complete_with_smallest_prefix()
{
$this
->given(
resolve('hoa://Test/Vfs/Root?type=directory'),
resolve('hoa://Test/Vfs/Root/Foo?type=file'),
resolve('hoa://Test/Vfs/Root/Bar?type=file'),
resolve('hoa://Test/Vfs/Root/Baz?type=file'),
resolve('hoa://Test/Vfs/Root/Qux?type=file'),

$autocompleter = new SUT('hoa://Test/Vfs/Root'),
$prefix = 'B'
)
->when($result = $autocompleter->complete($prefix))
->then
->array($result)
->isEqualTo(['Bar', 'Baz'])
->string($prefix)
->isEqualTo('B');
}

public function case_complete_with_longer_prefix()
{
$this
->given(
resolve('hoa://Test/Vfs/Root?type=directory'),
resolve('hoa://Test/Vfs/Root/Bara?type=file'),
resolve('hoa://Test/Vfs/Root/Barb?type=file'),
resolve('hoa://Test/Vfs/Root/Baza?type=file'),

$autocompleter = new SUT('hoa://Test/Vfs/Root'),
$prefix = 'Bar'
)
->when($result = $autocompleter->complete($prefix))
->then
->array($result)
->isEqualTo(['Bara', 'Barb'])
->string($prefix)
->isEqualTo('Bar');
}

public function case_set_root()
{
$this
->given($autocompleter = new SUT())
->when($result = $autocompleter->setRoot('foo'))
->then
->variable($result)
->isNull()

->when($result = $autocompleter->setRoot('bar'))
->then
->string($result)
->isEqualTo('foo');
}

public function case_get_root()
{
$this
->given(
$autocompleter = new SUT(),
$autocompleter->setRoot('foo')
)
->when($result = $autocompleter->getRoot())
->then
->string($result)
->isEqualTo('foo');
}

public function case_set_iterator_factory()
{
$this
->given($autocompleter = new SUT())
->when(
$result = $autocompleter->setIteratorFactory(function () {
return 42;
})
)
->then
->variable($result)
->isNull()

->when(
$result = $autocompleter->setIteratorFactory(function () {
return 43;
})
)
->then
->integer($result())
->isEqualTo(42);
}

public function case_get_iterator_factory()
{
$this
->given(
$autocompleter = new SUT(),
$autocompleter->setIteratorFactory(function () {
return 42;
})
)
->when(function () use (&$result, $autocompleter) {
$result = $autocompleter->getIteratorFactory();
})
->then
->integer($result())
->isEqualTo(42);
}

public function case_get_default_iterator_factory()
{
$this
->when(function () use (&$result) {
$result = SUT::getDefaultIteratorFactory();
})
->then
->object($result)
->isInstanceOf('Closure')
->object($result(__DIR__))
->isInstanceOf('DirectoryIterator');
}
}
<?php



































namespace Hoa\Console\Test\Unit;

use Hoa\Console as LUT;
use Hoa\Console\Cursor as SUT;
use Hoa\File;
use Hoa\Test;









class Cursor extends Test\Unit\Suite
{
public function beforeTestMethod($methodName)
{
parent::beforeTestMethod($methodName);
LUT::setTput(new LUT\Tput('hoa://Library/Console/Terminfo/78/xterm-256color'));

return;
}

public function case_move_u()
{
$this
->when(SUT::move('u'))
->then
->output
->isEqualTo("\033[1A");
}

public function case_move_up()
{
$this
->when(SUT::move('up'))
->then
->output
->isEqualTo("\033[1A");
}

public function case_move_↑()
{
$this
->when(SUT::move('↑'))
->then
->output
->isEqualTo("\033[1A");
}

public function case_move_↑_repeated()
{
$this
->when(SUT::move('↑', 42))
->then
->output
->isEqualTo("\033[42A");
}

public function case_move_r()
{
$this
->when(SUT::move('r'))
->then
->output
->isEqualTo("\033[1C");
}

public function case_move_right()
{
$this
->when(SUT::move('right'))
->then
->output
->isEqualTo("\033[1C");
}

public function case_move_→()
{
$this
->when(SUT::move('→'))
->then
->output
->isEqualTo("\033[1C");
}

public function case_move_→_repeated()
{
$this
->when(SUT::move('→', 42))
->then
->output
->isEqualTo("\033[42C");
}

public function case_move_d()
{
$this
->when(SUT::move('d'))
->then
->output
->isEqualTo("\033[1B");
}

public function case_move_down()
{
$this
->when(SUT::move('down'))
->then
->output
->isEqualTo("\033[1B");
}

public function case_move_↓()
{
$this
->when(SUT::move('↓'))
->then
->output
->isEqualTo("\033[1B");
}

public function case_move_↓_repeated()
{
$this
->when(SUT::move('↓', 42))
->then
->output
->isEqualTo("\033[42B");
}

public function case_move_l()
{
$this
->when(SUT::move('l'))
->then
->output
->isEqualTo("\033[1D");
}

public function case_move_left()
{
$this
->when(SUT::move('left'))
->then
->output
->isEqualTo("\033[1D");
}

public function case_move_←()
{
$this
->when(SUT::move('←'))
->then
->output
->isEqualTo("\033[1D");
}

public function case_move_←_repeated()
{
$this
->when(SUT::move('←', 42))
->then
->output
->isEqualTo("\033[42D");
}

public function case_move_sequence()
{
$this
->when(SUT::move('↑ → ↓ ←'))
->then
->output
->isEqualTo("\033[1A\033[1C\033[1B\033[1D");
}

public function case_move_to_x_y()
{
$this
->when(SUT::moveTo(7, 42))
->then
->output
->isEqualTo("\033[42;7H");
}

public function case_move_to_x()
{
$this
->given(
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll("\033[42;7R"),
$file->rewind(),
$input = LUT::setInput(new LUT\Input($file))
)
->when(SUT::moveTo(153))
->then
->output
->isEqualTo("\033[6n\033[42;153H");
}

public function case_move_to_y()
{
$this
->given(
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll("\033[42;7R"),
$file->rewind(),
$input = LUT::setInput(new LUT\Input($file))
)
->when(SUT::moveTo(null, 153))
->then
->output
->isEqualTo("\033[6n\033[153;7H");
}

public function case_get_position()
{
$this
->given(
$file = new File\ReadWrite('hoa://Test/Vfs/Input?type=file'),
$file->writeAll("\033[42;7R"),
$file->rewind(),
$input = LUT::setInput(new LUT\Input($file))
)
->when($result = SUT::getPosition())
->then
->output
->isEqualTo("\033[6n")
->array($result)
->isEqualTo([
'x' => 7,
'y' => 42
]);
}

public function case_save()
{
$this
->when(SUT::save())
->then
->output
->isEqualTo("\0337");
}

public function case_restore()
{
$this
->when(SUT::restore())
->then
->output
->isEqualTo("\0338");
}

public function case_clear_a()
{
$this
->when(SUT::clear('a'))
->then
->output
->isEqualTo("\033[H\033[2J\033[1;1H");
}

public function case_clear_all()
{
$this
->when(SUT::clear('all'))
->then
->output
->isEqualTo("\033[H\033[2J\033[1;1H");
}

public function case_clear_↕()
{
$this
->when(SUT::clear('↕'))
->then
->output
->isEqualTo("\033[H\033[2J\033[1;1H");
}

public function case_clear_u()
{
$this
->when(SUT::clear('u'))
->then
->output
->isEqualTo("\033[1J");
}

public function case_clear_up()
{
$this
->when(SUT::clear('up'))
->then
->output
->isEqualTo("\033[1J");
}

public function case_clear_↑()
{
$this
->when(SUT::clear('↑'))
->then
->output
->isEqualTo("\033[1J");
}

public function case_clear_r()
{
$this
->when(SUT::clear('r'))
->then
->output
->isEqualTo("\033[K");
}

public function case_clear_right()
{
$this
->when(SUT::clear('right'))
->then
->output
->isEqualTo("\033[K");
}

public function case_clear_→()
{
$this
->when(SUT::clear('→'))
->then
->output
->isEqualTo("\033[K");
}

public function case_clear_d()
{
$this
->when(SUT::clear('d'))
->then
->output
->isEqualTo("\033[J");
}

public function case_clear_down()
{
$this
->when(SUT::clear('down'))
->then
->output
->isEqualTo("\033[J");
}

public function case_clear_↓()
{
$this
->when(SUT::clear('↓'))
->then
->output
->isEqualTo("\033[J");
}

public function case_clear_l()
{
$this
->when(SUT::clear('l'))
->then
->output
->isEqualTo("\033[1K");
}

public function case_clear_left()
{
$this
->when(SUT::clear('left'))
->then
->output
->isEqualTo("\033[1K");
}

public function case_clear_←()
{
$this
->when(SUT::clear('←'))
->then
->output
->isEqualTo("\033[1K");
}

public function case_clear_line()
{
$this
->when(SUT::clear('line'))
->then
->output
->isEqualTo("\r\033[K");
}

public function case_clear_↔()
{
$this
->when(SUT::clear('↔'))
->then
->output
->isEqualTo("\r\033[K");
}

public function case_hide()
{
$this
->when(SUT::hide())
->then
->output
->isEqualTo("\033[?25l");
}

public function case_show()
{
$this
->when(SUT::show())
->then
->output
->isEqualTo("\033[?12;25h");
}

public function case_colorize_n()
{
$this
->when(SUT::colorize('n'))
->then
->output
->isEqualTo("\033[0m");
}

public function case_colorize_normal()
{
$this
->when(SUT::colorize('normal'))
->then
->output
->isEqualTo("\033[0m");
}

public function case_colorize_normal_repeated()
{
$this
->when(SUT::colorize('n normal'))
->then
->output
->isEqualTo("\033[0;0m");
}

public function case_colorize_b()
{
$this
->when(SUT::colorize('b'))
->then
->output
->isEqualTo("\033[1m");
}

public function case_colorize_bold()
{
$this
->when(SUT::colorize('bold'))
->then
->output
->isEqualTo("\033[1m");
}

public function case_colorize_u()
{
$this
->when(SUT::colorize('u'))
->then
->output
->isEqualTo("\033[4m");
}

public function case_colorize_underlined()
{
$this
->when(SUT::colorize('underlined'))
->then
->output
->isEqualTo("\033[4m");
}

public function case_colorize_bl()
{
$this
->when(SUT::colorize('bl'))
->then
->output
->isEqualTo("\033[5m");
}

public function case_colorize_blink()
{
$this
->when(SUT::colorize('blink'))
->then
->output
->isEqualTo("\033[5m");
}

public function case_colorize_i()
{
$this
->when(SUT::colorize('i'))
->then
->output
->isEqualTo("\033[7m");
}

public function case_colorize_inverse()
{
$this
->when(SUT::colorize('inverse'))
->then
->output
->isEqualTo("\033[7m");
}

public function case_colorize_not_b()
{
$this
->when(SUT::colorize('!b'))
->then
->output
->isEqualTo("\033[22m");
}

public function case_colorize_not_bold()
{
$this
->when(SUT::colorize('!bold'))
->then
->output
->isEqualTo("\033[22m");
}

public function case_colorize_not_u()
{
$this
->when(SUT::colorize('!u'))
->then
->output
->isEqualTo("\033[24m");
}

public function case_colorize_not_underlined()
{
$this
->when(SUT::colorize('!underlined'))
->then
->output
->isEqualTo("\033[24m");
}

public function case_colorize_not_bl()
{
$this
->when(SUT::colorize('!bl'))
->then
->output
->isEqualTo("\033[25m");
}

public function case_colorize_not_blink()
{
$this
->when(SUT::colorize('!blink'))
->then
->output
->isEqualTo("\033[25m");
}

public function case_colorize_not_i()
{
$this
->when(SUT::colorize('!i'))
->then
->output
->isEqualTo("\033[27m");
}

public function case_colorize_not_inverse()
{
$this
->when(SUT::colorize('!inverse'))
->then
->output
->isEqualTo("\033[27m");
}

public function case_colorize_fg_black()
{
$this
->when(SUT::colorize('fg(black)'))
->then
->output
->isEqualTo("\033[30m");
}

public function case_colorize_foreground_black()
{
$this
->when(SUT::colorize('foreground(black)'))
->then
->output
->isEqualTo("\033[30m");
}

public function case_colorize_fg_red()
{
$this
->when(SUT::colorize('fg(red)'))
->then
->output
->isEqualTo("\033[31m");
}

public function case_colorize_fg_green()
{
$this
->when(SUT::colorize('fg(green)'))
->then
->output
->isEqualTo("\033[32m");
}

public function case_colorize_fg_yellow()
{
$this
->when(SUT::colorize('fg(yellow)'))
->then
->output
->isEqualTo("\033[33m");
}

public function case_colorize_fg_blue()
{
$this
->when(SUT::colorize('fg(blue)'))
->then
->output
->isEqualTo("\033[34m");
}

public function case_colorize_fg_magenta()
{
$this
->when(SUT::colorize('fg(magenta)'))
->then
->output
->isEqualTo("\033[35m");
}

public function case_colorize_fg_cyan()
{
$this
->when(SUT::colorize('fg(cyan)'))
->then
->output
->isEqualTo("\033[36m");
}

public function case_colorize_fg_white()
{
$this
->when(SUT::colorize('fg(white)'))
->then
->output
->isEqualTo("\033[37m");
}

public function case_colorize_fg_default()
{
$this
->when(SUT::colorize('fg(default)'))
->then
->output
->isEqualTo("\033[39m");
}

public function case_colorize_bg_black()
{
$this
->when(SUT::colorize('bg(black)'))
->then
->output
->isEqualTo("\033[40m");
}

public function case_colorize_background_black()
{
$this
->when(SUT::colorize('background(black)'))
->then
->output
->isEqualTo("\033[40m");
}

public function case_colorize_bg_red()
{
$this
->when(SUT::colorize('bg(red)'))
->then
->output
->isEqualTo("\033[41m");
}

public function case_colorize_bg_green()
{
$this
->when(SUT::colorize('bg(green)'))
->then
->output
->isEqualTo("\033[42m");
}

public function case_colorize_bg_yellow()
{
$this
->when(SUT::colorize('bg(yellow)'))
->then
->output
->isEqualTo("\033[43m");
}

public function case_colorize_bg_blue()
{
$this
->when(SUT::colorize('bg(blue)'))
->then
->output
->isEqualTo("\033[44m");
}

public function case_colorize_bg_magenta()
{
$this
->when(SUT::colorize('bg(magenta)'))
->then
->output
->isEqualTo("\033[45m");
}

public function case_colorize_bg_cyan()
{
$this
->when(SUT::colorize('bg(cyan)'))
->then
->output
->isEqualTo("\033[46m");
}

public function case_colorize_bg_white()
{
$this
->when(SUT::colorize('bg(white)'))
->then
->output
->isEqualTo("\033[47m");
}

public function case_colorize_bg_default()
{
$this
->when(SUT::colorize('bg(default)'))
->then
->output
->isEqualTo("\033[49m");
}

public function case_colorize_foreground_ff0066()
{
$this
->when(SUT::colorize('foreground(#ff0066)'))
->then
->output
->isEqualTo("\033[38;5;197m");
}

public function case_colorize_background_ff0066()
{
$this
->when(SUT::colorize('background(#ff0066)'))
->then
->output
->isEqualTo("\033[48;5;197m");
}

public function case_colorize_foreground_color_index()
{
$this
->when(SUT::colorize('foreground(42)'))
->then
->output
->isEqualTo("\033[38;5;42m");
}

public function case_change_color()
{
$this
->when(SUT::changeColor(35, 0xff0066))
->then
->output
->isEqualTo("\033]4;35;ff0066\033\\");
}

public function case_set_style_b()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::setStyle('b'))
->then
->output
->isEqualTo("\033[1 q");
}

public function case_set_style_block()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::setStyle('block'))
->then
->output
->isEqualTo("\033[1 q");
}

public function case_set_style_▋()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::setStyle('▋'))
->then
->output
->isEqualTo("\033[1 q");
}

public function case_set_style_block_no_blink()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::setStyle('block', false))
->then
->output
->isEqualTo("\033[2 q");
}

public function case_set_style_u()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::setStyle('u'))
->then
->output
->isEqualTo("\033[2 q");
}

public function case_set_style_underline()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::setStyle('underline'))
->then
->output
->isEqualTo("\033[2 q");
}

public function case_set_style__()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::setStyle('_'))
->then
->output
->isEqualTo("\033[2 q");
}

public function case_set_style_underline_no_blink()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::setStyle('underline', false))
->then
->output
->isEqualTo("\033[3 q");
}

public function case_set_style_v()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::setStyle('v'))
->then
->output
->isEqualTo("\033[5 q");
}

public function case_set_style_vertical()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::setStyle('vertical'))
->then
->output
->isEqualTo("\033[5 q");
}

public function case_set_style_pipe()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::setStyle('|'))
->then
->output
->isEqualTo("\033[5 q");
}

public function case_set_style_vertical_no_blink()
{
$this
->given($this->constant->OS_WIN = false)
->when(SUT::setStyle('vertical', false))
->then
->output
->isEqualTo("\033[6 q");
}

public function case_set_style_on_windows()
{
$this
->given($this->constant->OS_WIN = true)
->when(SUT::setStyle('b'))
->then
->output
->isEmpty();
}

public function case_bip()
{
$this
->when(SUT::bip())
->then
->output
->isEqualTo("\007");
}
}
<?php



































namespace Hoa\Console;

use Hoa\Exception as HoaException;









class Exception extends HoaException
{
}
<?php



































namespace Hoa\Console;

use Hoa\Consistency;
use Hoa\Event;









class Mouse implements Event\Listenable
{
use Event\Listens;






const BUTTON_LEFT = 0;






const BUTTON_MIDDLE = 1;






const BUTTON_RIGHT = 2;






const BUTTON_RELEASE = 3;






const WHEEL_UP = 64;






const WHEEL_DOWN = 65;






protected static $_instance = null;






protected static $_enabled = false;







private function __construct()
{
$this->setListener(
new Event\Listener(
$this,
[
'mouseup',
'mousedown',
'wheelup',
'wheeldown',
]
)
);

return;
}






public static function getInstance()
{
if (null === static::$_instance) {
static::$_instance = new static();
}

return static::$_instance;
}






public static function track()
{
if (true === static::$_enabled) {
return;
}

static::$_enabled = true;

Console::getOutput()->writeAll(
"\033[1;2'z" .
"\033[?1000h" .
"\033[?1003h"
);

$instance = static::getInstance();
$bucket = [
'x' => 0,
'y' => 0,
'button' => null,
'shift' => false,
'meta' => false,
'ctrl' => false
];
$input = Console::getInput();
$read = [$input->getStream()->getStream()];

while (true) {
if (false === @stream_select($read, $write, $except, 30)) {
static::untrack();

break;
}

$string = $input->readCharacter();

if ("\033" !== $string) {
continue;
}

$char = $input->readCharacter();

if ('[' !== $char) {
continue;
}

$char = $input->readCharacter();

if ('M' !== $char) {
continue;
}

$data = $input->read(3);
$cb = ord($data[0]);
$cx = ord($data[1]) - 32;
$cy = ord($data[2]) - 32;

$bucket['x'] = $cx;
$bucket['y'] = $cy;
$bucket['shift'] = 0 !== ($cb & 4);
$bucket['meta'] = 0 !== ($cb & 8);
$bucket['ctrl'] = 0 !== ($cb & 16);

$cb = ($cb | 28) ^ 28; 
 $cb -= 32;

switch ($cb) {
case static::WHEEL_UP:
$instance->getListener()->fire(
'wheelup',
new Event\Bucket($bucket)
);

break;

case static::WHEEL_DOWN:
$instance->getListener()->fire(
'wheeldown',
new Event\Bucket($bucket)
);

break;

case static::BUTTON_RELEASE:
$instance->getListener()->fire(
'mouseup',
new Event\Bucket($bucket)
);
$bucket['button'] = null;

break;

default:
if (static::BUTTON_LEFT === $cb) {
$bucket['button'] = 'left';
} elseif (static::BUTTON_MIDDLE === $cb) {
$bucket['button'] = 'middle';
} elseif (static::BUTTON_RIGHT === $cb) {
$bucket['button'] = 'right';
} else {

 continue 2;
}

$instance->getListener()->fire(
'mousedown',
new Event\Bucket($bucket)
);
}
}

return;
}






public static function untrack()
{
if (false === static::$_enabled) {
return;
}

Console::getOutput()->writeAll(
"\033[?1003l" .
"\033[?1000l"
);

static::$_enabled = false;

return;
}
}




Console::advancedInteraction();




Consistency::registerShutdownFunction(xcallable('Hoa\Console\Mouse::untrack'));
<?php



































namespace Hoa\Console\Bin;

use Hoa\Console;









class Termcap extends Console\Dispatcher\Kit
{





protected $options = [
['terminal', Console\GetOption::NO_ARGUMENT, 't'],
['file', Console\GetOption::NO_ARGUMENT, 'f'],
['has', Console\GetOption::REQUIRED_ARGUMENT, 'H'],
['count', Console\GetOption::REQUIRED_ARGUMENT, 'c'],
['get', Console\GetOption::REQUIRED_ARGUMENT, 'g'],
['booleans', Console\GetOption::NO_ARGUMENT, 'b'],
['numbers', Console\GetOption::NO_ARGUMENT, 'n'],
['strings', Console\GetOption::NO_ARGUMENT, 's'],
['help', Console\GetOption::NO_ARGUMENT, 'h'],
['help', Console\GetOption::NO_ARGUMENT, '?']
];








public function main()
{
$tput = Console::getTput();

while (false !== $c = $this->getOption($v)) {
switch ($c) {
case 't':
echo $tput->getTerm();

return;

case 'f':
echo $tput->getTerminfo();

return;

case 'H':
echo $tput->has($v) ? 1 : 0;

return;

case 'c':
echo $tput->count($v);

return;

case 'g':
echo $tput->get($v);

return;

case 'b':
$informations = $tput->getInformations();
static::format($informations['booleans']);

return;

case 'n':
$informations = $tput->getInformations();
static::format($informations['numbers']);

return;

case 's':
$informations = $tput->getInformations();
static::format($informations['strings']);

return;

case '__ambiguous':
$this->resolveOptionAmbiguity($v);

break;

case 'h':
case '?':
default:
return $this->usage();
}
}

return $this->usage();
}






public function usage()
{
echo
'Usage   : console:termcap', "\n",
'Options :', "\n",
$this->makeUsageOptionsList([
't' => 'Get terminal name.',
'f' => 'Get path to the terminfo file.',
'H' => 'Get value of a boolean capability.',
'c' => 'Get value of a number capability.',
'g' => 'Get value of a string capability.',
'b' => 'Get all boolean capabilites.',
'n' => 'Get all number capabilites.',
's' => 'Get all string capabilites.',
'help' => 'This help.'
]), "\n",
'Examples:', "\n",
'    $ hoa console:termcap --count max_colors', "\n",
'    $ TERM=vt200 hoa console:termcap --has back_color_erase', "\n";

return;
}







public static function format(array $data)
{
$max = 0;

foreach ($data as $key => $_) {
if ($max < ($handle = strlen($key))) {
$max = $handle;
}
}

$format = '%-' . ($max + 1) . 's: %s' . "\n";

foreach ($data as $key => $value) {
printf(
$format,
$key,
is_bool($value)
? ($value ? 'true' : 'false')
: (is_string($value)
? str_replace(
[
"\033",
"\n",
ord(0xa),
"\r",
"\b",
"\f",
"\0"
],
[
'\e',
'\n',
'\l',
'\r',
'\b',
'\f',
'\0'
],
$value
)
: $value)
);
}

return;
}
}

__halt_compiler();
Terminal capabilities.
<?php



































namespace Hoa\Console;

use Hoa\File;
use Hoa\Stream;











class Input implements Stream\IStream\In
{





protected $_input = null;








public function __construct(Stream\IStream\In $input = null)
{
if (null === $input) {
if (defined('STDIN') &&
false !== @stream_get_meta_data(STDIN)) {
$input = new File\Read('php://stdin');
} else {
$input = new File\Read('/dev/tty');
}
}

$this->_input = $input;

return;
}






public function getStream()
{
return $this->_input;
}






public function eof()
{
return $this->_input->eof();
}







public function read($length)
{
return $this->_input->read($length);
}







public function readString($length)
{
return $this->_input->readString($length);
}






public function readCharacter()
{
return $this->_input->readCharacter();
}






public function readBoolean()
{
return $this->_input->readBoolean();
}







public function readInteger($length = 1)
{
return $this->_input->readInteger($length);
}







public function readFloat($length = 1)
{
return $this->_input->readFloat($length);
}









public function readArray($argument = null)
{
return $this->_input->readArray($argument);
}






public function readLine()
{
return $this->_input->readLine();
}







public function readAll($offset = 0)
{
return $this->_input->readAll($offset);
}







public function scanf($format)
{
return $this->_input->scanf($format);
}
}
<?php



































namespace Hoa\Console;












class Tput
{





protected static $_booleans = [
'auto_left_margin',
'auto_right_margin',
'no_esc_ctlc',
'ceol_standout_glitch',
'eat_newline_glitch',
'erase_overstrike',
'generic_type',
'hard_copy',
'meta_key', 
 'status_line', 
 'insert_null_glitch',
'memory_above',
'memory_below',
'move_insert_mode',
'move_standout_mode',
'over_strike',
'status_line_esc_ok',
'dest_tabs_magic_smso',
'tilde_glitch',
'transparent_underline',
'xon_xoff',
'needs_xon_xoff',
'prtr_silent',
'hard_cursor',
'non_rev_rmcup',
'no_pad_char',
'non_dest_scroll_region',
'can_change',
'back_color_erase',
'hue_lightness_saturation',
'col_addr_glitch',
'cr_cancels_micro_mode',
'print_wheel', 
 'row_addr_glitch',
'semi_auto_right_margin',
'cpi_changes_res',
'lpi_changes_res',

 'backspaces_with_bs',
'crt_no_scrolling',
'no_correctly_working_cr',
'gnu_meta_key', 
 'linefeed_is_newline',
'hardware_tabs', 
 'return_does_clr_eol'
];






protected static $_numbers = [
'columns',
'init_tabs',
'lines',
'lines_of_memory',
'magic_cookie_glitch',
'padding_baud_rate',
'virtual_terminal',
'width_status_line',
'num_labels',
'label_height',
'label_width',
'max_attributes',
'maximum_windows',
'max_colors',
'max_pairs',
'no_color_video',
'buffer_capacity',
'dot_vert_spacing',
'dot_horz_spacing',
'max_micro_address',
'max_micro_jump',
'micro_col_size',
'micro_line_size',
'number_of_pins',
'output_res_char',
'output_res_line',
'output_res_horz_inch',
'output_res_vert_inch',
'print_rate',
'wide_char_size',
'buttons',
'bit_image_entwining',
'bit_image_type',

 'magic_cookie_glitch_ul',
'carriage_return_delay',
'new_line_delay',
'backspace_delay',
'horizontal_tab_delay',
'number_of_function_keys'
];






protected static $_strings = [
'back_tab',
'bell',
'carriage_return',
'change_scroll_region',
'clear_all_tabs',
'clear_screen',
'clr_eol',
'clr_eos',
'column_address',
'command_character',
'cursor_address',
'cursor_down',
'cursor_home',
'cursor_invisible',
'cursor_left',
'cursor_mem_address',
'cursor_normal',
'cursor_right',
'cursor_to_ll',
'cursor_up',
'cursor_visible',
'delete_character',
'delete_line',
'dis_status_line',
'down_half_line',
'enter_alt_charset_mode',
'enter_blink_mode',
'enter_bold_mode',
'enter_ca_mode',
'enter_delete_mode',
'enter_dim_mode',
'enter_insert_mode',
'enter_secure_mode',
'enter_protected_mode',
'enter_reverse_mode',
'enter_standout_mode',
'enter_underline_mode',
'erase_chars',
'exit_alt_charset_mode',
'exit_attribute_mode',
'exit_ca_mode',
'exit_delete_mode',
'exit_insert_mode',
'exit_standout_mode',
'exit_underline_mode',
'flash_screen',
'form_feed',
'from_status_line',
'init_1string',
'init_2string',
'init_3string',
'init_file',
'insert_character',
'insert_line',
'insert_padding',
'key_backspace',
'key_catab',
'key_clear',
'key_ctab',
'key_dc',
'key_dl',
'key_down',
'key_eic',
'key_eol',
'key_eos',
'key_f0',
'key_f1',
'key_f10',
'key_f2',
'key_f3',
'key_f4',
'key_f5',
'key_f6',
'key_f7',
'key_f8',
'key_f9',
'key_home',
'key_ic',
'key_il',
'key_left',
'key_ll',
'key_npage',
'key_ppage',
'key_right',
'key_sf',
'key_sr',
'key_stab',
'key_up',
'keypad_local',
'keypad_xmit',
'lab_f0',
'lab_f1',
'lab_f10',
'lab_f2',
'lab_f3',
'lab_f4',
'lab_f5',
'lab_f6',
'lab_f7',
'lab_f8',
'lab_f9',
'meta_off',
'meta_on',
'newline',
'pad_char',
'parm_dch',
'parm_delete_line',
'parm_down_cursor',
'parm_ich',
'parm_index',
'parm_insert_line',
'parm_left_cursor',
'parm_right_cursor',
'parm_rindex',
'parm_up_cursor',
'pkey_key',
'pkey_local',
'pkey_xmit',
'print_screen',
'prtr_off',
'prtr_on',
'repeat_char',
'reset_1string',
'reset_2string',
'reset_3string',
'reset_file',
'restore_cursor',
'row_address',
'save_cursor',
'scroll_forward',
'scroll_reverse',
'set_attributes',
'set_tab',
'set_window',
'tab',
'to_status_line',
'underline_char',
'up_half_line',
'init_prog',
'key_a1',
'key_a3',
'key_b2',
'key_c1',
'key_c3',
'prtr_non',
'char_padding',
'acs_chars',
'plab_norm',
'key_btab',
'enter_xon_mode',
'exit_xon_mode',
'enter_am_mode',
'exit_am_mode',
'xon_character',
'xoff_character',
'ena_acs',
'label_on',
'label_off',
'key_beg',
'key_cancel',
'key_close',
'key_command',
'key_copy',
'key_create',
'key_end',
'key_enter',
'key_exit',
'key_find',
'key_help',
'key_mark',
'key_message',
'key_move',
'key_next',
'key_open',
'key_options',
'key_previous',
'key_print',
'key_redo',
'key_reference',
'key_refresh',
'key_replace',
'key_restart',
'key_resume',
'key_save',
'key_suspend',
'key_undo',
'key_sbeg',
'key_scancel',
'key_scommand',
'key_scopy',
'key_screate',
'key_sdc',
'key_sdl',
'key_select',
'key_send',
'key_seol',
'key_sexit',
'key_sfind',
'key_shelp',
'key_shome',
'key_sic',
'key_sleft',
'key_smessage',
'key_smove',
'key_snext',
'key_soptions',
'key_sprevious',
'key_sprint',
'key_sredo',
'key_sreplace',
'key_sright',
'key_srsume',
'key_ssave',
'key_ssuspend',
'key_sundo',
'req_for_input',
'key_f11',
'key_f12',
'key_f13',
'key_f14',
'key_f15',
'key_f16',
'key_f17',
'key_f18',
'key_f19',
'key_f20',
'key_f21',
'key_f22',
'key_f23',
'key_f24',
'key_f25',
'key_f26',
'key_f27',
'key_f28',
'key_f29',
'key_f30',
'key_f31',
'key_f32',
'key_f33',
'key_f34',
'key_f35',
'key_f36',
'key_f37',
'key_f38',
'key_f39',
'key_f40',
'key_f41',
'key_f42',
'key_f43',
'key_f44',
'key_f45',
'key_f46',
'key_f47',
'key_f48',
'key_f49',
'key_f50',
'key_f51',
'key_f52',
'key_f53',
'key_f54',
'key_f55',
'key_f56',
'key_f57',
'key_f58',
'key_f59',
'key_f60',
'key_f61',
'key_f62',
'key_f63',
'clr_bol',
'clear_margins',
'set_left_margin',
'set_right_margin',
'label_format',
'set_clock',
'display_clock',
'remove_clock',
'create_window',
'goto_window',
'hangup',
'dial_phone',
'quick_dial',
'tone',
'pulse',
'flash_hook',
'fixed_pause',
'wait_tone',
'user0',
'user1',
'user2',
'user3',
'user4',
'user5',
'user6',
'user7',
'user8',
'user9',
'orig_pair',
'orig_colors',
'initialize_color',
'initialize_pair',
'set_color_pair',
'set_foreground',
'set_background',
'change_char_pitch',
'change_line_pitch',
'change_res_horz',
'change_res_vert',
'define_char',
'enter_doublewide_mode',
'enter_draft_quality',
'enter_italics_mode',
'enter_leftward_mode',
'enter_micro_mode',
'enter_near_letter_quality',
'enter_normal_quality',
'enter_shadow_mode',
'enter_subscript_mode',
'enter_superscript_mode',
'enter_upward_mode',
'exit_doublewide_mode',
'exit_italics_mode',
'exit_leftward_mode',
'exit_micro_mode',
'exit_shadow_mode',
'exit_subscript_mode',
'exit_superscript_mode',
'exit_upward_mode',
'micro_column_address',
'micro_down',
'micro_left',
'micro_right',
'micro_row_address',
'micro_up',
'order_of_pins',
'parm_down_micro',
'parm_left_micro',
'parm_right_micro',
'parm_up_micro',
'select_char_set',
'set_bottom_margin',
'set_bottom_margin_parm',
'set_left_margin_parm',
'set_right_margin_parm',
'set_top_margin',
'set_top_margin_parm',
'start_bit_image',
'start_char_set_def',
'stop_bit_image',
'stop_char_set_def',
'subscript_characters',
'superscript_characters',
'these_cause_cr',
'zero_motion',
'char_set_names',
'key_mouse',
'mouse_info',
'req_mouse_pos',
'get_mouse',
'set_a_foreground',
'set_a_background',
'pkey_plab',
'device_type',
'code_set_init',
'set0_des_seq',
'set1_des_seq',
'set2_des_seq',
'set3_des_seq',
'set_lr_margin',
'set_tb_margin',
'bit_image_repeat',
'bit_image_newline',
'bit_image_carriage_return',
'color_names',
'define_bit_image_region',
'end_bit_image_region',
'set_color_band',
'set_page_length',
'display_pc_char',
'enter_pc_charset_mode',
'exit_pc_charset_mode',
'enter_scancode_mode',
'exit_scancode_mode',
'pc_term_options',
'scancode_escape',
'alt_scancode_esc',
'enter_horizontal_hl_mode',
'enter_left_hl_mode',
'enter_low_hl_mode',
'enter_right_hl_mode',
'enter_top_hl_mode',
'enter_vertical_hl_mode',
'set_a_attributes',
'set_pglen_inch',

 'termcap_init2',
'termcap_reset',
'linefeed_if_not_lf',
'backspace_if_not_bs',
'other_non_function_keys',
'arrow_key_map',
'acs_ulcorner',
'acs_llcorner',
'acs_urcorner',
'acs_lrcorner',
'acs_ltee',
'acs_rtee',
'acs_btee',
'acs_ttee',
'acs_hline',
'acs_vline',
'acs_plus',
'memory_lock',
'memory_unlock',
'box_chars_1'
];






protected $_informations = [];








public function __construct($terminfo = null)
{
if (null === $terminfo) {
$terminfo = static::getTerminfo();
}

$this->parse($terminfo);

return;
}








protected function parse($terminfo)
{
if (!file_exists($terminfo)) {
throw new Exception(
'Terminfo file %s does not exist.',
0,
$terminfo
);
}

$data = file_get_contents($terminfo);
$length = strlen($data);
$out = ['file' => $terminfo];

$headers = [
'data_size' => $length,
'header_size' => 12,
'magic_number' => (ord($data[ 1]) << 8) | ord($data[ 0]),
'names_size' => (ord($data[ 3]) << 8) | ord($data[ 2]),
'bool_count' => (ord($data[ 5]) << 8) | ord($data[ 4]),
'number_count' => (ord($data[ 7]) << 8) | ord($data[ 6]),
'string_count' => (ord($data[ 9]) << 8) | ord($data[ 8]),
'string_table_size' => (ord($data[11]) << 8) | ord($data[10]),
];
$out['headers'] = $headers;



 $i = $headers['header_size'];
$nameAndDescription = explode('|', substr($data, $i, $headers['names_size'] - 1));
$out['name'] = $nameAndDescription[0];
$out['description'] = $nameAndDescription[1];


 $i += $headers['names_size'];
$booleans = [];
$booleanNames = &static::$_booleans;

for (
$e = 0, $max = $i + $headers['bool_count'];
$i < $max;
++$e, ++$i
) {
$booleans[$booleanNames[$e]] = 1 === ord($data[$i]);
}

$out['booleans'] = $booleans;


 if (1 === ($i % 2)) {
++$i;
}

$numbers = [];
$numberNames = &static::$_numbers;

for (
$e = 0, $max = $i + $headers['number_count'] * 2;
$i < $max;
++$e, $i += 2
) {
$name = $numberNames[$e];
$data_i0 = ord($data[$i ]);
$data_i1 = ord($data[$i + 1]);

if ($data_i1 === 255 && $data_i0 === 255) {
$numbers[$name] = -1;
} else {
$numbers[$name] = ($data_i1 << 8) | $data_i0;
}
}

$out['numbers'] = $numbers;


 $strings = [];
$stringNames = &static::$_strings;
$ii = $i + $headers['string_count'] * 2;

for (
$e = 0, $max = $ii;
$i < $max;
++$e, $i += 2
) {
$name = $stringNames[$e];
$data_i0 = ord($data[$i ]);
$data_i1 = ord($data[$i + 1]);

if ($data_i1 === 255 && $data_i0 === 255) {
continue;
}

$a = ($data_i1 << 8) | $data_i0;
$strings[$name] = $a;

if (65534 === $a) {
continue;
}

$b = $ii + $a;
$c = $b;

while ($c < $length && ord($data[$c])) {
$c++;
}

$value = substr($data, $b, $c - $b);
$strings[$name] = false !== $value ? $value : null;
}

$out['strings'] = $strings;

return $this->_informations = $out;
}






public function getInformations()
{
return $this->_informations;
}







public function has($boolean)
{
if (!isset($this->_informations['booleans'][$boolean])) {
return false;
}

return $this->_informations['booleans'][$boolean];
}







public function count($number)
{
if (!isset($this->_informations['numbers'][$number])) {
return 0;
}

return $this->_informations['numbers'][$number];
}







public function get($string)
{
if (!isset($this->_informations['strings'][$string])) {
return null;
}

return $this->_informations['strings'][$string];
}






public static function getTerm()
{
return
isset($_SERVER['TERM']) && !empty($_SERVER['TERM'])
? $_SERVER['TERM']
: (OS_WIN ? 'windows-ansi' : 'xterm');
}







public static function getTerminfo($term = null)
{
$paths = [];

if (isset($_SERVER['TERMINFO'])) {
$paths[] = $_SERVER['TERMINFO'];
}

if (isset($_SERVER['HOME'])) {
$paths[] = $_SERVER['HOME'] . DS . '.terminfo';
}

if (isset($_SERVER['TERMINFO_DIRS'])) {
foreach (explode(':', $_SERVER['TERMINFO_DIRS']) as $path) {
$paths[] = $path;
}
}

$paths[] = '/usr/share/terminfo';
$paths[] = '/usr/share/lib/terminfo';
$paths[] = '/lib/terminfo';
$paths[] = '/usr/lib/terminfo';
$paths[] = '/usr/local/share/terminfo';
$paths[] = '/usr/local/share/lib/terminfo';
$paths[] = '/usr/local/lib/terminfo';
$paths[] = '/usr/local/ncurses/lib/terminfo';
$paths[] = 'hoa://Library/Console/Terminfo';

$term = $term ?: static::getTerm();
$fileHexa = dechex(ord($term[0])) . DS . $term;
$fileAlpha = $term[0] . DS . $term;
$pathname = null;

foreach ($paths as $path) {
if (file_exists($_ = $path . DS . $fileHexa) ||
file_exists($_ = $path . DS . $fileAlpha)) {
$pathname = $_;

break;
}
}

if (null === $pathname && 'xterm' !== $term) {
return static::getTerminfo('xterm');
}

return $pathname;
}
}
<?php



































namespace Hoa\Console\Chrome;

use Hoa\Console;









class Editor
{








public static function open($file = '', $editor = null)
{
if (null === $editor) {
if (isset($_SERVER['EDITOR'])) {
$editor = $_SERVER['EDITOR'];
} else {
$editor = 'vi';
}
}

if (!empty($file)) {
$file = escapeshellarg($file);
}

return Console\Processus::execute(
$editor . ' ' . $file . ' > `tty` < `tty`',
false
);
}
}
<?php



































namespace Hoa\Console\Chrome;

use Hoa\Console;









class Text
{





const ALIGN_LEFT = 0;






const ALIGN_RIGHT = 1;






const ALIGN_CENTER = 2;












public static function colorize(
$text,
$attributesBefore,
$attributesAfter = 'normal'
) {
ob_start();
Console\Cursor::colorize($attributesBefore);
Console::getOutput()->writeAll($text);
Console\Cursor::colorize($attributesAfter);
$out = ob_get_contents();
ob_end_clean();

return $out;
}





























public static function columnize(
array $line,
$alignement = self::ALIGN_LEFT,
$horizontalPadding = 2,
$verticalPadding = 0,
$separator = null
) {
if (empty($line)) {
return '';
}

$separator = explode('|', $separator);
$nbColumn = 0;
$nbLine = count($line);
$xtraWidth = 2 * ($verticalPadding + 2); 


 foreach ($line as $key => &$column) {
if (!is_array($column)) {
$column = [$column];
}

$handle = count($column);
$handle > $nbColumn and $nbColumn = $handle;
}

$xtraWidth += $horizontalPadding * $nbColumn;


 $columnWidth = array_fill(0, $nbColumn, 0);

for ($e = 0; $e < $nbColumn; $e++) {
for ($i = 0; $i < $nbLine; $i++) {
if (!isset($line[$i][$e])) {
continue;
}

$handle = self::getMaxLineWidth($line[$i][$e]);
$handle > $columnWidth[$e] and $columnWidth[$e] = $handle;
}
}


 
 $window = Console\Window::getSize();
$envWindow = $window['x'];

while ($envWindow <= ($cWidthSum = $xtraWidth + array_sum($columnWidth))) {
$diff = $cWidthSum - $envWindow;
$max = max($columnWidth) - $xtraWidth;
$newWidth = $max - $diff;
$i = array_search(max($columnWidth), $columnWidth);
$columnWidth[$i] = $newWidth;

foreach ($line as $key => &$c) {
if (isset($c[$i])) {
$c[$i] = self::wordwrap($c[$i], $newWidth);
}
}
}


 $columnWidth = array_map(
function ($x) use ($horizontalPadding) {
return $x + 2 * $horizontalPadding;
},
$columnWidth
);


 
 $newLine = [];
foreach ($line as $key => $plpl) {
$i = self::getMaxLineNumber($plpl);
while ($i-- >= 0) {
$newLine[] = array_fill(0, $nbColumn, null);
}
}

$yek = 0;
foreach ($line as $key => $col) {
foreach ($col as $kkey => $value) {
if (false === strpos($value, "\n")) {
$newLine[$yek][$kkey] = $value;

continue;
}

foreach (explode("\n", $value) as $foo => $oof) {
$newLine[$yek + $foo][$kkey] = $oof;
}
}

$i = self::getMaxLineNumber($col);
$i > 0 and $yek += $i;
$yek++;
}


 foreach ($newLine as $key => $col) {
foreach ($col as $kkey => $value) {
if (isset($separator[$kkey])) {
$newLine[$key][$kkey] =
$separator[$kkey] .
str_replace(
"\n",
"\n" . $separator[$kkey],
$value
);
}
}
}

$line = $newLine;
unset($newLine);


 foreach ($line as $key => &$column) {
$handle = count($column);

if ($nbColumn - $handle > 0) {
$column += array_fill($handle, $nbColumn - $handle, null);
}
}


 $out = null;
$dash = $alignement === self::ALIGN_LEFT ? '-' : '';
foreach ($line as $key => $handle) {
$format = null;

foreach ($handle as $i => $hand) {
if (preg_match_all('#(\\e\[[0-9]+m)#', $hand, $match)) {
$a = $columnWidth[$i];

foreach ($match as $m) {
$a += strlen($m[1]);
}

$format .= '%' . $dash . ($a + floor(count($match) / 2)) . 's';
} else {
$format .= '%' . $dash . $columnWidth[$i] . 's';
}
}

$format .= str_repeat("\n", $verticalPadding + 1);

array_unshift($handle, $format);
$out .= call_user_func_array('sprintf', $handle);
}

return $out;
}









public static function align(
$text,
$alignement = self::ALIGN_LEFT,
$width = null
) {
if (null === $width) {
$window = Console\Window::getSize();
$width = $window['x'];
}

$out = null;

switch ($alignement) {
case self::ALIGN_LEFT:
$out .= sprintf('%-' . $width . 's', self::wordwrap($text, $width));

break;

case self::ALIGN_CENTER:
foreach (explode("\n", self::wordwrap($text, $width)) as $key => $value) {
$out .= str_repeat(' ', ceil(($width - strlen($value)) / 2)) .
$value . "\n";
}

break;

case self::ALIGN_RIGHT:
default:
foreach (explode("\n", self::wordwrap($text, $width)) as $key => $value) {
$out .= sprintf('%' . $width . 's' . "\n", $value);
}

break;
}

return $out;
}







protected static function getMaxLineWidth($lines)
{
if (!is_array($lines)) {
$lines = [$lines];
}

$width = 0;

foreach ($lines as $foo => $line) {
foreach (explode("\n", $line) as $fooo => $lin) {
$lin = preg_replace('#\\e\[[0-9]+m#', '', $lin);
strlen($lin) > $width and $width = strlen($lin);
}
}

return $width;
}







protected static function getMaxLineNumber($lines)
{
if (!is_array($lines)) {
$lines = [$lines];
}

$number = 0;

foreach ($lines as $foo => $line) {
substr_count($line, "\n") > $number and
$number = substr_count($line, "\n");
}

return $number;
}









public static function wordwrap($text, $width = null, $break = "\n")
{
if (null === $width) {
$window = Console\Window::getSize();
$width = $window['x'];
}

return wordwrap($text, $width, $break, true);
}








public static function underline($text, $pattern = '*')
{
$text = explode("\n", $text);
$card = strlen($pattern);

foreach ($text as $key => &$value) {
$i = -1;
$max = strlen($value);
while ($value{++$i} == ' ' && $i < $max);

$underline =
str_repeat(' ', $i) .
str_repeat($pattern, strlen(trim($value)) / $card) .
str_repeat(' ', strlen($value) - $i - strlen(trim($value)));

$value .= "\n" . $underline;
}

return implode("\n", $text);
}
}
<?php



































namespace Hoa\Console\Chrome;

use Hoa\Console;









class Exception extends Console\Exception
{
}
<?php



































namespace Hoa\Console\Chrome;

use Hoa\Console;












class Pager
{





const LESS = 'less';






const MORE = 'more';










public static function less($output, $mode)
{
return self::pager($output, $mode, self::LESS);
}








public static function more($output, $mode)
{
return self::pager($output, $mode, self::MORE);
}









public static function pager($output, $mode, $type = null)
{
static $process = null;

if ($mode & PHP_OUTPUT_HANDLER_START) {
$pager
= null !== $type
? Console\Processus::locate($type)
: (isset($_ENV['PAGER']) ? $_ENV['PAGER'] : null);

if (null === $pager) {
return $output;
}

$process = new Console\Processus(
$pager,
null,
[['pipe', 'r']]
);
$process->open();
}

$process->writeAll($output);

if ($mode & PHP_OUTPUT_HANDLER_FINAL) {
$process->close();
}

return null;
}
}
<?php



































namespace Hoa\Console;

use Hoa\Stream;










class Output implements Stream\IStream\Out
{





protected $_considerMultiplexer = false;






protected $_output = null;








public function __construct(Stream\IStream\Out $output = null)
{
$this->_output = $output;

return;
}






public function getStream()
{
return $this->_output;
}









public function write($string, $length)
{
if (0 > $length) {
throw new Exception(
'Length must be greater than 0, given %d.',
0,
$length
);
}

$out = substr($string, 0, $length);

if (true === $this->isMultiplexerConsidered()) {
if (true === Console::isTmuxRunning()) {
$out =
"\033Ptmux;" .
str_replace("\033", "\033\033", $out) .
"\033\\";
}

$length = strlen($out);
}

if (null === $this->_output) {
echo $out;
} else {
$this->_output->write($out, $length);
}
}







public function writeString($string)
{
$string = (string) $string;

return $this->write($string, strlen($string));
}







public function writeCharacter($character)
{
return $this->write((string) $character[0], 1);
}







public function writeBoolean($boolean)
{
return $this->write(((bool) $boolean) ? '1' : '0', 1);
}







public function writeInteger($integer)
{
$integer = (string) (int) $integer;

return $this->write($integer, strlen($integer));
}







public function writeFloat($float)
{
$float = (string) (float) $float;

return $this->write($float, strlen($float));
}







public function writeArray(array $array)
{
$array = var_export($array, true);

return $this->write($array, strlen($array));
}







public function writeLine($line)
{
if (false === $n = strpos($line, "\n")) {
return $this->write($line . "\n", strlen($line) + 1);
}

++$n;

return $this->write(substr($line, 0, $n), $n);
}







public function writeAll($string)
{
return $this->write($string, strlen($string));
}







public function truncate($size)
{
return false;
}







public function considerMultiplexer($consider)
{
$old = $this->_considerMultiplexer;
$this->_considerMultiplexer = $consider;

return $old;
}






public function isMultiplexerConsidered()
{
return $this->_considerMultiplexer;
}
}
<?php



































namespace Hoa\Console;

use Hoa\Event;













class Window implements Event\Source
{





private static $_instance = null;









private function __construct()
{
Event::register(
'hoa://Event/Console/Window:resize',
$this
);

return;
}






public static function getInstance()
{
if (null === static::$_instance) {
static::$_instance = new static();
}

return static::$_instance;
}








public static function setSize($x, $y)
{
if (OS_WIN) {
return;
}

Console::getOutput()->writeAll("\033[8;" . $y . ";" . $x . "t");

return;
}






public static function getSize()
{
if (OS_WIN) {
$modecon = explode("\n", ltrim(Processus::execute('mode con')));

$_y = trim($modecon[2]);
preg_match('#[^:]+:\s*([0-9]+)#', $_y, $matches);
$y = (int) $matches[1];

$_x = trim($modecon[3]);
preg_match('#[^:]+:\s*([0-9]+)#', $_x, $matches);
$x = (int) $matches[1];

return [
'x' => $x,
'y' => $y
];
}

$term = '';

if (isset($_SERVER['TERM'])) {
$term = 'TERM="' . $_SERVER['TERM'] . '" ';
}

$command = $term . 'tput cols && ' . $term . 'tput lines';
$tput = Processus::execute($command, false);

if (!empty($tput)) {
list($x, $y) = explode("\n", $tput);

return [
'x' => intval($x),
'y' => intval($y)
];
}


 Console::getOutput()->writeAll("\033[18t");

$input = Console::getInput();


 $input->read(4); 

$x = null;
$y = null;
$handle = &$y;

do {
$char = $input->readCharacter();

switch ($char) {
case ';':
$handle = &$x;

break;

case 't':
break 2;

default:
if (false === ctype_digit($char)) {
break 2;
}

$handle .= $char;
}
} while (true);

if (null === $x || null === $y) {
return [
'x' => 0,
'y' => 0
];
}

return [
'x' => (int) $x,
'y' => (int) $y
];
}








public static function moveTo($x, $y)
{
if (OS_WIN) {
return;
}


 Console::getOutput()->writeAll("\033[3;" . $x . ";" . $y . "t");

return;
}






public static function getPosition()
{
if (OS_WIN) {
return;
}


 Console::getOutput()->writeAll("\033[13t");

$input = Console::getInput();


 $input->read(4); 

$x = null;
$y = null;
$handle = &$x;

do {
$char = $input->readCharacter();

switch ($char) {
case ';':
$handle = &$y;

break;

case 't':
break 2;

default:
$handle .= $char;
}
} while (true);

return [
'x' => (int) $x,
'y' => (int) $y
];
}












public static function scroll($directions, $repeat = 1)
{
if (OS_WIN) {
return;
}

if (1 > $repeat) {
return;
} elseif (1 === $repeat) {
$handle = explode(' ', $directions);
} else {
$handle = explode(' ', $directions, 1);
}

$tput = Console::getTput();
$count = ['up' => 0, 'down' => 0];

foreach ($handle as $direction) {
switch ($direction) {
case 'u':
case 'up':
case '↑':
++$count['up'];

break;

case 'd':
case 'down':
case '↓':
++$count['down'];

break;
}
}

$output = Console::getOutput();

if (0 < $count['up']) {
$output->writeAll(
str_replace(
'%p1%d',
$count['up'] * $repeat,
$tput->get('parm_index')
)
);
}

if (0 < $count['down']) {
$output->writeAll(
str_replace(
'%p1%d',
$count['down'] * $repeat,
$tput->get('parm_rindex')
)
);
}

return;
}






public static function minimize()
{
if (OS_WIN) {
return;
}


 Console::getOutput()->writeAll("\033[2t");

return;
}






public static function restore()
{
if (OS_WIN) {
return;
}

Console::getOutput()->writeAll("\033[1t");

return;
}






public static function raise()
{
if (OS_WIN) {
return;
}

Console::getOutput()->writeAll("\033[5t");

return;
}






public static function lower()
{
if (OS_WIN) {
return;
}

Console::getOutput()->writeAll("\033[6t");

return;
}







public static function setTitle($title)
{
if (OS_WIN) {
return;
}


 Console::getOutput()->writeAll("\033]0;" . $title . "\033\\");

return;
}






public static function getTitle()
{
if (OS_WIN) {
return;
}


 Console::getOutput()->writeAll("\033[21t");

$input = Console::getInput();
$read = [$input->getStream()->getStream()];
$write = [];
$except = [];
$out = null;

if (0 === stream_select($read, $write, $except, 0, 50000)) {
return $out;
}


 $input->read(3); 

do {
$char = $input->readCharacter();

if ("\033" === $char) {
$chaar = $input->readCharacter();

if ('\\' === $chaar) {
break;
}

$char .= $chaar;
}

$out .= $char;
} while (true);

return $out;
}






public static function getLabel()
{
if (OS_WIN) {
return;
}


 Console::getOutput()->writeAll("\033[20t");

$input = Console::getInput();
$read = [$input->getStream()->getStream()];
$write = [];
$except = [];
$out = null;

if (0 === stream_select($read, $write, $except, 0, 50000)) {
return $out;
}


 $input->read(3); 

do {
$char = $input->readCharacter();

if ("\033" === $char) {
$chaar = $input->readCharacter();

if ('\\' === $chaar) {
break;
}

$char .= $chaar;
}

$out .= $char;
} while (true);

return $out;
}






public static function refresh()
{
if (OS_WIN) {
return;
}


 Console::getOutput()->writeAll("\033[7t");

return;
}







public static function copy($data)
{
if (OS_WIN) {
return;
}

$out = "\033]52;;" . base64_encode($data) . "\033\\";
$output = Console::getOutput();
$considerMultiplexer = $output->considerMultiplexer(true);

$output->writeAll($out);
$output->considerMultiplexer($considerMultiplexer);

return;
}
}




Console::advancedInteraction();




if (function_exists('pcntl_signal')) {
Window::getInstance();
pcntl_signal(
SIGWINCH,
function () {
static $_window = null;

if (null === $_window) {
$_window = Window::getInstance();
}

Event::notify(
'hoa://Event/Console/Window:resize',
$_window,
new Event\Bucket([
'size' => Window::getSize()
])
);
}
);
}
<?php



































namespace Hoa\Console\Dispatcher;

use Hoa\Console;
use Hoa\Dispatcher;
use Hoa\Router;
use Hoa\View;









class Kit extends Dispatcher\Kit
{





public $parser = null;






protected $options = null;






protected $_options = null;










public function __construct(
Router $router,
Dispatcher $dispatcher,
View\Viewable $view = null
) {
parent::__construct($router, $dispatcher, $view);

$this->parser = new Console\Parser();

return;
}








public function getOption(&$optionValue, $short = null)
{
if (null === $this->_options && !empty($this->options)) {
$this->setOptions($this->options);
}

if (null === $this->_options) {
return false;
}

return $this->_options->getOption($optionValue, $short);
}








public function setOptions(array $options)
{
$old = $this->options;
$this->options = $options;
$rule = $this->router->getTheRule();
$variables = $rule[Router::RULE_VARIABLES];

if (isset($variables['_tail'])) {
$this->parser->parse($variables['_tail']);
$this->_options = new Console\GetOption(
$this->options,
$this->parser
);
}

return $old;
}








public function makeUsageOptionsList(array $definitions = [])
{
$out = [];

foreach ($this->options as $i => $options) {
$out[] = [
'  -' . $options[Console\GetOption::OPTION_VAL] . ', --' .
$options[Console\GetOption::OPTION_NAME] .
($options[Console\GetOption::OPTION_HAS_ARG] ===
Console\GetOption::REQUIRED_ARGUMENT
? '='
: ($options[Console\GetOption::OPTION_HAS_ARG] ===
Console\GetOption::OPTIONAL_ARGUMENT
? '[=]'
: '')),
(isset($definitions[$options[Console\GetOption::OPTION_VAL]])
? $definitions[$options[Console\GetOption::OPTION_VAL]]
: (isset($definitions[$options[0]])
? $definitions[$options[Console\GetOption::OPTION_NAME]]
: null
)
)
];
}

return Console\Chrome\Text::columnize(
$out,
Console\Chrome\Text::ALIGN_LEFT,
.5,
0,
'|: '
);
}








public function resolveOptionAmbiguity(array $solutions)
{
echo
'You have made a typo in the option ',
$solutions['option'], '; it can match the following options: ', "\n",
'    • ', implode(";\n    • ", $solutions['solutions']), '.', "\n",
'Please, type the right option (empty to choose the first one):', "\n";
$new = $this->readLine('> ');

if (empty($new)) {
$new = $solutions['solutions'][0];
}

$solutions['solutions'] = [$new];

$this->_options->resolveOptionAmbiguity($solutions);

return;
}








public function status($text, $status)
{
$window = Console\Window::getSize();
$out =
' ' . Console\Chrome\Text::colorize('*', 'foreground(yellow)') . ' ' .
$text . str_pad(
' ',
$window['x']
- strlen(preg_replace('#' . "\033" . '\[[0-9]+m#', '', $text))
- 8
) .
($status === true
? '[' . Console\Chrome\Text::colorize('ok', 'foreground(green)') . ']'
: '[' . Console\Chrome\Text::colorize('!!', 'foreground(white) background(red)') . ']');

Console::getOutput()->writeAll($out . "\n");

return;
}







public function readLine($prefix = null)
{
static $_rl = null;

if (null === $_rl) {
$_rl = new Console\Readline();
}

return $_rl->readLine($prefix);
}







public function readPassword($prefix = null)
{
static $_rl = null;

if (null === $_rl) {
$_rl = new Console\Readline\Password();
}

return $_rl->readLine($prefix);
}
}
<?php



































namespace Hoa\Console;

use Hoa\Event;
use Hoa\Stream;









class Processus
extends Stream
implements Stream\IStream\In,
Stream\IStream\Out,
Stream\IStream\Pathable
{





const SIGHUP = 1;






const SIGINT = 2;






const SIGQUIT = 3;






const SIGILL = 4;






const SIGTRAP = 5;






const SIGABRT = 6;






const SIGEMT = 7;






const SIGFPE = 8;






const SIGKILL = 9;






const SIGBUS = 10;






const SIGSEGV = 11;






const SIGSYS = 12;






const SIGPIPE = 13;






const SIGALRM = 14;






const SIGTERM = 15;






const SIGURG = 16;






const SIGSTOP = 17;






const SIGTSTP = 18;






const SIGCONT = 19;






const SIGCHLD = 20;






const SIGTTIN = 21;






const SIGTTOU = 22;






const SIGIO = 23;






const SIGXCPU = 24;






const SIGXFSZ = 25;






const SIGVTALRM = 26;






const SIGPROF = 27;






const SIGWINCH = 28;






const SIGINFO = 29;






const SIGUSR1 = 30;






const SIGUSR2 = 31;






protected $_command = null;






protected $_options = [];






protected $_cwd = null;






protected $_environment = null;






protected $_timeout = 30;






protected $_descriptors = [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w']
];






protected $_pipes = null;






protected $_seekable = [];















public function __construct(
$command,
array $options = null,
array $descriptors = null,
$cwd = null,
array $environment = null,
$timeout = 30
) {
$this->setCommand($command);

if (null !== $options) {
$this->setOptions($options);
}

if (null !== $descriptors) {
$this->_descriptors = [];

foreach ($descriptors as $descriptor => $nature) {
if (isset($this->_descriptors[$descriptor])) {
throw new Exception(
'Pipe descriptor %d already exists, cannot ' .
'redefine it.',
0,
$descriptor
);
}

$this->_descriptors[$descriptor] = $nature;
}
}

$this->setCwd($cwd ?: getcwd());

if (null !== $environment) {
$this->setEnvironment($environment);
}

$this->setTimeout($timeout);
parent::__construct($this->getCommandLine(), null, true);
$this->getListener()->addIds(['input', 'output', 'timeout', 'start', 'stop']);

return;
}









protected function &_open($streamName, Stream\Context $context = null)
{
$out = @proc_open(
$streamName,
$this->_descriptors,
$this->_pipes,
$this->getCwd(),
$this->getEnvironment()
);

if (false === $out) {
throw new Exception(
'Something wrong happen when running %s.',
1,
$streamName
);
}

return $out;
}






protected function _close()
{
foreach ($this->_pipes as $pipe) {
@fclose($pipe);
}

return @proc_close($this->getStream());
}









public function run()
{
if (false === $this->isOpened()) {
$this->open();
} else {
$this->_close();
$this->_setStream($this->_open(
$this->getStreamName(),
$this->getStreamContext()
));
}

$this->getListener()->fire('start', new Event\Bucket());

$_read = [];
$_write = [];
$_except = [];

foreach ($this->_pipes as $p => $pipe) {
switch ($this->_descriptors[$p][1]) {
case 'r':
stream_set_blocking($pipe, false);
$_write[] = $pipe;

break;

case 'w':
case 'a':
stream_set_blocking($pipe, true);
$_read[] = $pipe;

break;
}
}

while (true) {
foreach ($_read as $i => $r) {
if (false === is_resource($r)) {
unset($_read[$i]);
}
}

foreach ($_write as $i => $w) {
if (false === is_resource($w)) {
unset($_write[$i]);
}
}

foreach ($_except as $i => $e) {
if (false === is_resource($e)) {
unset($_except[$i]);
}
}

if (empty($_read) && empty($_write) && empty($_except)) {
break;
}

$read = $_read;
$write = $_write;
$except = $_except;
$select = stream_select($read, $write, $except, $this->getTimeout());

if (0 === $select) {
$this->getListener()->fire('timeout', new Event\Bucket());

break;
}

foreach ($read as $i => $_r) {
$pipe = array_search($_r, $this->_pipes);
$line = $this->readLine($pipe);

if (false === $line) {
$result = [false];
} else {
$result = $this->getListener()->fire(
'output',
new Event\Bucket([
'pipe' => $pipe,
'line' => $line
])
);
}

if (true === feof($_r) || in_array(false, $result, true)) {
fclose($_r);
unset($_read[$i]);

break;
}
}

foreach ($write as $j => $_w) {
$result = $this->getListener()->fire(
'input',
new Event\Bucket([
'pipe' => array_search($_w, $this->_pipes)
])
);

if (true === feof($_w) || in_array(false, $result, true)) {
fclose($_w);
unset($_write[$j]);
}
}

if (empty($_read)) {
break;
}
}

$this->getListener()->fire('stop', new Event\Bucket());

return;
}








protected function getPipe($pipe)
{
if (!isset($this->_pipes[$pipe])) {
throw new Exception(
'Pipe descriptor %d does not exist, cannot read from it.',
2,
$pipe
);
}

return $this->_pipes[$pipe];
}







protected function isPipeSeekable($pipe)
{
if (!isset($this->_seekable[$pipe])) {
$_pipe = $this->getPipe($pipe);
$data = stream_get_meta_data($_pipe);
$this->_seekable[$pipe] = $data['seekable'];
}

return $this->_seekable[$pipe];
}







public function eof($pipe = 1)
{
return feof($this->getPipe($pipe));
}









public function read($length, $pipe = 1)
{
if (0 > $length) {
throw new Exception(
'Length must be greater than 0, given %d.',
3,
$length
);
}

return fread($this->getPipe($pipe), $length);
}








public function readString($length, $pipe = 1)
{
return $this->read($length, $pipe);
}







public function readCharacter($pipe = 1)
{
return fgetc($this->getPipe($pipe));
}







public function readBoolean($pipe = 1)
{
return (bool) $this->read(1, $pipe);
}








public function readInteger($length = 1, $pipe = 1)
{
return (int) $this->read($length, $pipe);
}








public function readFloat($length = 1, $pipe = 1)
{
return (float) $this->read($length, $pipe);
}









public function readArray($format = null, $pipe = 1)
{
return $this->scanf($format, $pipe);
}







public function readLine($pipe = 1)
{
return stream_get_line($this->getPipe($pipe), 1 << 15, "\n");
}








public function readAll($offset = -1, $pipe = 1)
{
$_pipe = $this->getPipe($pipe);

if (true === $this->isPipeSeekable($pipe)) {
$offset += ftell($_pipe);
} else {
$offset = -1;
}

return stream_get_contents($_pipe, -1, $offset);
}








public function scanf($format, $pipe = 1)
{
return fscanf($this->getPipe($pipe), $format);
}










public function write($string, $length, $pipe = 0)
{
if (0 > $length) {
throw new Exception(
'Length must be greater than 0, given %d.',
4,
$length
);
}

return fwrite($this->getPipe($pipe), $string, $length);
}








public function writeString($string, $pipe = 0)
{
$string = (string) $string;

return $this->write($string, strlen($string), $pipe);
}








public function writeCharacter($char, $pipe = 0)
{
return $this->write((string) $char[0], 1, $pipe);
}








public function writeBoolean($boolean, $pipe = 0)
{
return $this->write((string) (bool) $boolean, 1, $pipe);
}








public function writeInteger($integer, $pipe = 0)
{
$integer = (string) (int) $integer;

return $this->write($integer, strlen($integer), $pipe);
}








public function writeFloat($float, $pipe = 0)
{
$float = (string) (float) $float;

return $this->write($float, strlen($float), $pipe);
}








public function writeArray(array $array, $pipe = 0)
{
$array = var_export($array, true);

return $this->write($array, strlen($array), $pipe);
}








public function writeLine($line, $pipe = 0)
{
if (false === $n = strpos($line, "\n")) {
return $this->write($line . "\n", strlen($line) + 1, $pipe);
}

++$n;

return $this->write(substr($line, 0, $n), $n, $pipe);
}








public function writeAll($string, $pipe = 0)
{
return $this->write($string, strlen($string), $pipe);
}








public function truncate($size, $pipe = 0)
{
return ftruncate($this->getPipe($pipe), $size);
}






public function getBasename()
{
return basename($this->getCommand());
}






public function getDirname()
{
return dirname($this->getCommand());
}






public function getStatus()
{
return proc_get_status($this->getStream());
}






public function getExitCode()
{
$handle = $this->getStatus();

return $handle['exitcode'];
}






public function isSuccessful()
{
return 0 === $this->getExitCode();
}









public function terminate($signal = self::SIGTERM)
{
return proc_terminate($this->getStream(), $signal);
}







protected function setCommand($command)
{
$old = $this->_command;
$this->_command = escapeshellcmd($command);

return $old;
}






public function getCommand()
{
return $this->_command;
}







protected function setOptions(array $options)
{
foreach ($options as &$option) {
$option = escapeshellarg($option);
}

$old = $this->_options;
$this->_options = $options;

return $old;
}






public function getOptions()
{
return $this->_options;
}






public function getCommandLine()
{
$out = $this->getCommand();

foreach ($this->getOptions() as $key => $value) {
if (!is_int($key)) {
$out .= ' ' . $key . '=' . $value;
} else {
$out .= ' ' . $value;
}
}

return $out;
}







protected function setCwd($cwd)
{
$old = $this->_cwd;
$this->_cwd = $cwd;

return $old;
}






public function getCwd()
{
return $this->_cwd;
}







protected function setEnvironment(array $environment)
{
$old = $this->_environment;
$this->_environment = $environment;

return $old;
}






public function getEnvironment()
{
return $this->_environment;
}







public function setTimeout($timeout)
{
$old = $this->_timeout;
$this->_timeout = $timeout;

return $old;
}






public function getTimeout()
{
return $this->_timeout;
}







public static function setTitle($title)
{
if (PHP_VERSION_ID < 50500) {
return;
}

cli_set_process_title($title);

return;
}






public static function getTitle()
{
if (PHP_VERSION_ID < 50500) {
return null;
}

return cli_get_process_title();
}







public static function locate($binary)
{
if (isset($_ENV['PATH'])) {
$separator = ':';
$path = &$_ENV['PATH'];
} elseif (isset($_SERVER['PATH'])) {
$separator = ':';
$path = &$_SERVER['PATH'];
} elseif (isset($_SERVER['Path'])) {
$separator = ';';
$path = &$_SERVER['Path'];
} else {
return null;
}

foreach (explode($separator, $path) as $directory) {
if (true === file_exists($out = $directory . DS . $binary)) {
return $out;
}
}

return null;
}









public static function execute($commandLine, $escape = true)
{
if (true === $escape) {
$commandLine = escapeshellcmd($commandLine);
}

return rtrim(shell_exec($commandLine));
}
}
<?php



































namespace Hoa\Console;

use Hoa\Ustring;













class GetOption
{





const NO_ARGUMENT = 0;






const REQUIRED_ARGUMENT = 1;






const OPTIONAL_ARGUMENT = 2;






const OPTION_NAME = 0;






const OPTION_HAS_ARG = 1;






const OPTION_VAL = 2;














protected $_options = [];






protected $_parser = null;






protected $_pipette = [];










public function __construct(array $options, Parser $parser)
{
$this->_options = $options;
$this->_parser = $parser;

if (empty($options)) {
$this->_pipette[null] = null;

return;
}

$names = [];

foreach ($options as $i => $option) {
if (isset($option[self::OPTION_NAME])) {
$names[$option[self::OPTION_NAME]] = $i;
}

if (isset($option[self::OPTION_VAL])) {
$names[$option[self::OPTION_VAL]] = $i;
}
}

$_names = array_keys($names);
$switches = $parser->getSwitches();

foreach ($switches as $name => $value) {
if (false === in_array($name, $_names)) {
if (1 === strlen($name)) {
$this->_pipette[] = ['__ambiguous', [
'solutions' => [],
'value' => $value,
'option' => $name
]];

continue;
}

$haystack = implode(';', $_names);
$differences = (int) ceil(strlen($name) / 3);
$searched = Ustring\Search::approximated(
$haystack,
$name,
$differences
);
$solutions = [];

foreach ($searched as $s) {
$h = substr($haystack, $s['i'], $s['l']);

if (false !== strpos($h, ';') ||
false !== in_array($h, array_keys($switches)) ||
false === in_array($h, $_names)) {
continue;
}

$solutions[] = $h;
}

if (empty($solutions)) {
continue;
}

$this->_pipette[] = ['__ambiguous', [
'solutions' => $solutions,
'value' => $value,
'option' => $name
]];

continue;
}

$option = $options[$names[$name]];
$argument = $option[self::OPTION_HAS_ARG];

if (self::NO_ARGUMENT === $argument) {
if (!is_bool($value)) {
$parser->transferSwitchToInput($name, $value);
}
} elseif (self::REQUIRED_ARGUMENT === $argument && !is_string($value)) {
throw new Exception(
'The argument %s requires a value (it is not a switch).',
0,
$name
);
}

$this->_pipette[] = [$option[self::OPTION_VAL], $value];
}

$this->_pipette[null] = null;
reset($this->_pipette);

return;
}











public function getOption(&$optionValue, $short = null)
{
static $first = true;

$optionValue = null;

if (true === $this->isPipetteEmpty() && true === $first) {
$first = false;

return false;
}

$k = key($this->_pipette);
$c = current($this->_pipette);
$key = $c[0];
$value = $c[1];

if (null == $k && null === $c) {
reset($this->_pipette);
$first = true;

return false;
}

$allow = [];

if (null === $short) {
foreach ($this->_options as $option) {
$allow[] = $option[self::OPTION_VAL];
}
} else {
$allow = str_split($short);
}

if (!in_array($key, $allow) && '__ambiguous' != $key) {
return false;
}

$optionValue = $value;
$return = $key;
next($this->_pipette);

return $return;
}






public function isPipetteEmpty()
{
return count($this->_pipette) == 1;
}











public function resolveOptionAmbiguity(array $solutions)
{
if (!isset($solutions['solutions']) ||
!isset($solutions['value']) ||
!isset($solutions['option'])) {
throw new Exception(
'Cannot resolve option ambiguity because the given solution ' .
'seems to be corruped.',
1
);
}

$choices = $solutions['solutions'];

if (1 > count($choices)) {
throw new Exception(
'Cannot resolve ambiguity, fix your typo in the option %s :-).',
2,
$solutions['option']
);
}

$theSolution = $choices[0];

foreach ($this->_options as $option) {
if ($theSolution == $option[self::OPTION_NAME] ||
$theSolution == $option[self::OPTION_VAL]) {
$argument = $option[self::OPTION_HAS_ARG];
$value = $solutions['value'];

if (self::NO_ARGUMENT === $argument) {
if (!is_bool($value)) {
$this->_parser->transferSwitchToInput($theSolution, $value);
}
} elseif (self::REQUIRED_ARGUMENT === $argument &&
!is_string($value)) {
throw new Exception(
'The argument %s requires a value (it is not a switch).',
3,
$theSolution
);
}

unset($this->_pipette[null]);
$this->_pipette[] = [$option[self::OPTION_VAL], $value];
$this->_pipette[null] = null;

return;
}
}

return;
}
}
<?php



































namespace Hoa\Console;











class Parser
{






protected $_longonly = false;






protected $_parsed = null;






























































































public function parse($command)
{
unset($this->_parsed);
$this->_parsed = [
'input' => [],
'switch' => []
];








































$regex = '#(?:(?<b>--?[^=\s]+)(?:(?:(=)|(\s))(?<!\\\)(?:("|\')|)(?<s>(?(3)[^-]|).*?)(?(4)(?<!\\\)\4|(?(2)(?<!\\\)\s|(?:(?:(?<!\\\)\s)|$))))?)|(?:(?<!\\\)(?:("|\')|)(?<i>.*?)(?(6)(?<!\\\)\6|(?:(?:(?<!\\\)\s)|$)))#Ssm';

preg_match_all($regex, $command, $matches, PREG_SET_ORDER);

for ($i = 0, $max = count($matches); $i < $max; ++$i) {
$match = $matches[$i];

if (isset($match['i']) &&
('0' === $match['i'] || !empty($match['i']))) {
$this->addInput($match);
} elseif (!isset($match['i']) && !isset($match['s'])) {
if (isset($matches[$i + 1])) {
$nextMatch = $matches[$i + 1];

if (!empty($nextMatch['i']) &&
'=' === $nextMatch['i'][0]) {
++$i;
$match[2] = '=';
$match[3] =
$match[4] = null;
$match['s'] =
$match[5] = substr($nextMatch[7], 1);

$this->addValuedSwitch($match);

continue;
}
}

$this->addBoolSwitch($match);
} elseif (!isset($match['i']) && isset($match['s'])) {
$this->addValuedSwitch($match);
}
}

return;
}







protected function addInput(array $input)
{
$handle = $input['i'];

if (!empty($input[6])) {
$handle = str_replace('\\' . $input[6], $input[6], $handle);
} else {
$handle = str_replace('\\ ', ' ', $handle);
}

$this->_parsed['input'][] = $handle;

return;
}







protected function addBoolSwitch(array $switch)
{
$this->addSwitch($switch['b'], true);

return;
}







protected function addValuedSwitch(array $switch)
{
$this->addSwitch($switch['b'], $switch['s'], $switch[4]);

return;
}









protected function addSwitch($name, $value, $escape = null)
{
if (substr($name, 0, 2) == '--') {
return $this->addSwitch(substr($name, 2), $value, $escape);
}

if (substr($name, 0, 1) == '-') {
if (true === $this->getLongOnly()) {
return $this->addSwitch('-' . $name, $value, $escape);
}

foreach (str_split(substr($name, 1)) as $foo => $switch) {
$this->addSwitch($switch, $value, $escape);
}

return;
}

if (null !== $escape) {
$escape = '' == $escape ? ' ' : $escape;

if (is_string($value)) {
$value = str_replace('\\' . $escape, $escape, $value);
}
} elseif (is_string($value)) {
$value = str_replace('\\ ', ' ', $value);
}

if (isset($this->_parsed['switch'][$name])) {
if (is_bool($this->_parsed['switch'][$name])) {
$value = !$this->_parsed['switch'][$name];
} else {
$value = [$this->_parsed['switch'][$name], $value];
}
}

if (empty($name)) {
return $this->addInput([6 => null, 'i' => $value]);
}

$this->_parsed['switch'][$name] = $value;

return;
}








public function transferSwitchToInput($name, &$value)
{
if (!isset($this->_parsed['switch'][$name])) {
return;
}

$this->_parsed['input'][] = $this->_parsed['switch'][$name];
$value = true;
unset($this->_parsed['switch'][$name]);

return;
}






public function getInputs()
{
return $this->_parsed['input'];
}












public function listInputs(
&$a,
&$b = null,
&$c = null,
&$d = null,
&$e = null,
&$f = null,
&$g = null,
&$h = null,
&$i = null,
&$j = null,
&$k = null,
&$l = null,
&$m = null,
&$n = null,
&$o = null,
&$p = null,
&$q = null,
&$r = null,
&$s = null,
&$t = null,
&$u = null,
&$v = null,
&$w = null,
&$x = null,
&$y = null,
&$z = null
) {
$inputs = $this->getInputs();
$i = 'a';
$ii = -1;

while (isset($inputs[++$ii]) && $i <= 'z') {
${$i++} = $inputs[$ii];
}

return;
}






public function getSwitches()
{
return $this->_parsed['switch'];
}











public function parseSpecialValue($value, array $keywords = [])
{
$out = [];

foreach (explode(',', $value) as $key => $subvalue) {
$subvalue = str_replace(
array_keys($keywords),
array_values($keywords),
$subvalue
);

if (0 !== preg_match('#^(-?[0-9]+):(-?[0-9]+)$#', $subvalue, $matches)) {
if (0 > $matches[1] && 0 > $matches[2]) {
throw new Exception(
'Cannot give two negative numbers, given %s.',
0,
$subvalue
);
}

array_shift($matches);
$max = max($matches);
$min = min($matches);

if (0 > $max || 0 > $min) {
if (0 > $max - $min) {
throw new Exception(
'The difference between operands must be ' .
'positive.',
1
);
}

$min = $max + $min;
}

$out = array_merge(range($min, $max), $out);
} else {
$out[] = $subvalue;
}
}

return $out;
}







public function setLongOnly($longonly = false)
{
$old = $this->_longonly;
$this->_longonly = $longonly;

return $old;
}






public function getLongOnly()
{
return $this->_longonly;
}
}
<?php



































namespace Hoa\Console\Readline;









class Password extends Readline
{





const STATE_CONTINUE = 5; 
}
<?php



































namespace Hoa\Console\Readline;

use Hoa\Consistency;
use Hoa\Console;
use Hoa\Ustring;









class Readline
{





const STATE_CONTINUE = 1;






const STATE_BREAK = 2;






const STATE_NO_ECHO = 4;






protected $_line = null;






protected $_lineCurrent = 0;






protected $_lineLength = 0;






protected $_buffer = null;






protected $_mapping = [];






protected $_history = [];






protected $_historyCurrent = 0;






protected $_historySize = 0;






protected $_prefix = null;






protected $_autocompleter = null;







public function __construct()
{
if (OS_WIN) {
return;
}

$this->_mapping["\033[A"] = xcallable($this, '_bindArrowUp');
$this->_mapping["\033[B"] = xcallable($this, '_bindArrowDown');
$this->_mapping["\033[C"] = xcallable($this, '_bindArrowRight');
$this->_mapping["\033[D"] = xcallable($this, '_bindArrowLeft');
$this->_mapping["\001"] = xcallable($this, '_bindControlA');
$this->_mapping["\002"] = xcallable($this, '_bindControlB');
$this->_mapping["\005"] = xcallable($this, '_bindControlE');
$this->_mapping["\006"] = xcallable($this, '_bindControlF');
$this->_mapping["\010"] =
$this->_mapping["\177"] = xcallable($this, '_bindBackspace');
$this->_mapping["\027"] = xcallable($this, '_bindControlW');
$this->_mapping["\n"] = xcallable($this, '_bindNewline');
$this->_mapping["\t"] = xcallable($this, '_bindTab');

return;
}







public function readLine($prefix = null)
{
$input = Console::getInput();

if (true === $input->eof()) {
return false;
}

$direct = Console::isDirect($input->getStream()->getStream());
$output = Console::getOutput();

if (false === $direct || OS_WIN) {
$out = $input->readLine();

if (false === $out) {
return false;
}

$out = substr($out, 0, -1);

if (true === $direct) {
$output->writeAll($prefix);
} else {
$output->writeAll($prefix . $out . "\n");
}

return $out;
}

$this->resetLine();
$this->setPrefix($prefix);
$read = [$input->getStream()->getStream()];
$output->writeAll($prefix);

while (true) {
@stream_select($read, $write, $except, 30, 0);

if (empty($read)) {
$read = [$input->getStream()->getStream()];

continue;
}

$char = $this->_read();
$this->_buffer = $char;
$return = $this->_readLine($char);

if (0 === ($return & self::STATE_NO_ECHO)) {
$output->writeAll($this->_buffer);
}

if (0 !== ($return & self::STATE_BREAK)) {
break;
}
}

return $this->getLine();
}







public function _readLine($char)
{
if (isset($this->_mapping[$char]) &&
is_callable($this->_mapping[$char])) {
$mapping = $this->_mapping[$char];

return $mapping($this);
}

if (isset($this->_mapping[$char])) {
$this->_buffer = $this->_mapping[$char];
} elseif (false === Ustring::isCharPrintable($char)) {
Console\Cursor::bip();

return static::STATE_CONTINUE | static::STATE_NO_ECHO;
}

if ($this->getLineLength() == $this->getLineCurrent()) {
$this->appendLine($this->_buffer);

return static::STATE_CONTINUE;
}

$this->insertLine($this->_buffer);
$tail = mb_substr(
$this->getLine(),
$this->getLineCurrent() - 1
);
$this->_buffer = "\033[K" . $tail . str_repeat(
"\033[D",
mb_strlen($tail) - 1
);

return static::STATE_CONTINUE;
}







public function addMappings(array $mappings)
{
foreach ($mappings as $key => $mapping) {
$this->addMapping($key, $mapping);
}

return;
}














public function addMapping($key, $mapping)
{
if ('\e[' === substr($key, 0, 3)) {
$this->_mapping["\033[" . substr($key, 3)] = $mapping;
} elseif ('\C-' === substr($key, 0, 3)) {
$_key = ord(strtolower(substr($key, 3))) - 96;
$this->_mapping[chr($_key)] = $mapping;
} else {
$this->_mapping[$key] = $mapping;
}

return;
}







public function addHistory($line = null)
{
if (empty($line)) {
return;
}

$this->_history[] = $line;
$this->_historyCurrent = $this->_historySize++;

return;
}






public function clearHistory()
{
unset($this->_history);
$this->_history = [];
$this->_historyCurrent = 0;
$this->_historySize = 1;

return;
}







public function getHistory($i = null)
{
if (null === $i) {
$i = $this->_historyCurrent;
}

if (!isset($this->_history[$i])) {
return null;
}

return $this->_history[$i];
}






public function previousHistory()
{
if (0 >= $this->_historyCurrent) {
return $this->getHistory(0);
}

return $this->getHistory($this->_historyCurrent--);
}






public function nextHistory()
{
if ($this->_historyCurrent + 1 >= $this->_historySize) {
return $this->getLine();
}

return $this->getHistory(++$this->_historyCurrent);
}






public function getLine()
{
return $this->_line;
}







public function appendLine($append)
{
$this->_line .= $append;
$this->_lineLength = mb_strlen($this->_line);
$this->_lineCurrent = $this->_lineLength;

return;
}







public function insertLine($insert)
{
if ($this->_lineLength == $this->_lineCurrent) {
return $this->appendLine($insert);
}

$this->_line = mb_substr($this->_line, 0, $this->_lineCurrent) .
$insert .
mb_substr($this->_line, $this->_lineCurrent);
$this->_lineLength = mb_strlen($this->_line);
$this->_lineCurrent += mb_strlen($insert);

return;
}






protected function resetLine()
{
$this->_line = null;
$this->_lineCurrent = 0;
$this->_lineLength = 0;

return;
}






public function getLineCurrent()
{
return $this->_lineCurrent;
}






public function getLineLength()
{
return $this->_lineLength;
}







public function setPrefix($prefix)
{
$this->_prefix = $prefix;

return;
}






public function getPrefix()
{
return $this->_prefix;
}






public function getBuffer()
{
return $this->_buffer;
}







public function setAutocompleter(Autocompleter $autocompleter)
{
$old = $this->_autocompleter;
$this->_autocompleter = $autocompleter;

return $old;
}






public function getAutocompleter()
{
return $this->_autocompleter;
}







public function _read($length = 512)
{
return Console::getInput()->read($length);
}







public function setLine($line)
{
$this->_line = $line;
$this->_lineLength = mb_strlen($this->_line);
$this->_lineCurrent = $this->_lineLength;

return;
}







public function setLineCurrent($current)
{
$this->_lineCurrent = $current;

return;
}







public function setLineLength($length)
{
$this->_lineLength = $length;

return;
}







public function setBuffer($buffer)
{
$this->_buffer = $buffer;

return;
}








public function _bindArrowUp(Readline $self)
{
if (0 === (static::STATE_CONTINUE & static::STATE_NO_ECHO)) {
Console\Cursor::clear('↔');
Console::getOutput()->writeAll($self->getPrefix());
}
$self->setBuffer($buffer = $self->previousHistory());
$self->setLine($buffer);

return static::STATE_CONTINUE;
}








public function _bindArrowDown(Readline $self)
{
if (0 === (static::STATE_CONTINUE & static::STATE_NO_ECHO)) {
Console\Cursor::clear('↔');
Console::getOutput()->writeAll($self->getPrefix());
}

$self->setBuffer($buffer = $self->nextHistory());
$self->setLine($buffer);

return static::STATE_CONTINUE;
}








public function _bindArrowRight(Readline $self)
{
if ($self->getLineLength() > $self->getLineCurrent()) {
if (0 === (static::STATE_CONTINUE & static::STATE_NO_ECHO)) {
Console\Cursor::move('→');
}

$self->setLineCurrent($self->getLineCurrent() + 1);
}

$self->setBuffer(null);

return static::STATE_CONTINUE;
}








public function _bindArrowLeft(Readline $self)
{
if (0 < $self->getLineCurrent()) {
if (0 === (static::STATE_CONTINUE & static::STATE_NO_ECHO)) {
Console\Cursor::move('←');
}

$self->setLineCurrent($self->getLineCurrent() - 1);
}

$self->setBuffer(null);

return static::STATE_CONTINUE;
}








public function _bindBackspace(Readline $self)
{
$buffer = null;

if (0 < $self->getLineCurrent()) {
if (0 === (static::STATE_CONTINUE & static::STATE_NO_ECHO)) {
Console\Cursor::move('←');
Console\Cursor::clear('→');
}

if ($self->getLineLength() == $current = $self->getLineCurrent()) {
$self->setLine(mb_substr($self->getLine(), 0, -1));
} else {
$line = $self->getLine();
$current = $self->getLineCurrent();
$tail = mb_substr($line, $current);
$buffer = $tail . str_repeat("\033[D", mb_strlen($tail));
$self->setLine(mb_substr($line, 0, $current - 1) . $tail);
$self->setLineCurrent($current - 1);
}
}

$self->setBuffer($buffer);

return static::STATE_CONTINUE;
}








public function _bindControlA(Readline $self)
{
for ($i = $self->getLineCurrent() - 1; 0 <= $i; --$i) {
$self->_bindArrowLeft($self);
}

return static::STATE_CONTINUE;
}








public function _bindControlB(Readline $self)
{
$current = $self->getLineCurrent();

if (0 === $current) {
return static::STATE_CONTINUE;
}

$words = preg_split(
'#\b#u',
$self->getLine(),
-1,
PREG_SPLIT_OFFSET_CAPTURE | PREG_SPLIT_NO_EMPTY
);

for (
$i = 0, $max = count($words) - 1;
$i < $max && $words[$i + 1][1] < $current;
++$i
);

for ($j = $words[$i][1] + 1; $current >= $j; ++$j) {
$self->_bindArrowLeft($self);
}

return static::STATE_CONTINUE;
}








public function _bindControlE(Readline $self)
{
for (
$i = $self->getLineCurrent(), $max = $self->getLineLength();
$i < $max;
++$i
) {
$self->_bindArrowRight($self);
}

return static::STATE_CONTINUE;
}








public function _bindControlF(Readline $self)
{
$current = $self->getLineCurrent();

if ($self->getLineLength() === $current) {
return static::STATE_CONTINUE;
}

$words = preg_split(
'#\b#u',
$self->getLine(),
-1,
PREG_SPLIT_OFFSET_CAPTURE | PREG_SPLIT_NO_EMPTY
);

for (
$i = 0, $max = count($words) - 1;
$i < $max && $words[$i][1] < $current;
++$i
);

if (!isset($words[$i + 1])) {
$words[$i + 1] = [1 => $self->getLineLength()];
}

for ($j = $words[$i + 1][1]; $j > $current; --$j) {
$self->_bindArrowRight($self);
}

return static::STATE_CONTINUE;
}








public function _bindControlW(Readline $self)
{
$current = $self->getLineCurrent();

if (0 === $current) {
return static::STATE_CONTINUE;
}

$words = preg_split(
'#\b#u',
$self->getLine(),
-1,
PREG_SPLIT_OFFSET_CAPTURE | PREG_SPLIT_NO_EMPTY
);

for (
$i = 0, $max = count($words) - 1;
$i < $max && $words[$i + 1][1] < $current;
++$i
);

for ($j = $words[$i][1] + 1; $current >= $j; ++$j) {
$self->_bindBackspace($self);
}

return static::STATE_CONTINUE;
}







public function _bindNewline(Readline $self)
{
$self->addHistory($self->getLine());

return static::STATE_BREAK;
}







public function _bindTab(Readline $self)
{
$output = Console::getOutput();
$autocompleter = $self->getAutocompleter();
$state = static::STATE_CONTINUE | static::STATE_NO_ECHO;

if (null === $autocompleter) {
return $state;
}

$current = $self->getLineCurrent();
$line = $self->getLine();

if (0 === $current) {
return $state;
}

$matches = preg_match_all(
'#' . $autocompleter->getWordDefinition() . '$#u',
mb_substr($line, 0, $current),
$words
);

if (0 === $matches) {
return $state;
}

$word = $words[0][0];

if ('' === trim($word)) {
return $state;
}

$solution = $autocompleter->complete($word);
$length = mb_strlen($word);

if (null === $solution) {
return $state;
}

if (is_array($solution)) {
$_solution = $solution;
$count = count($_solution) - 1;
$cWidth = 0;
$window = Console\Window::getSize();
$wWidth = $window['x'];
$cursor = Console\Cursor::getPosition();

array_walk($_solution, function (&$value) use (&$cWidth) {
$handle = mb_strlen($value);

if ($handle > $cWidth) {
$cWidth = $handle;
}

return;
});
array_walk($_solution, function (&$value) use (&$cWidth) {
$handle = mb_strlen($value);

if ($handle >= $cWidth) {
return;
}

$value .= str_repeat(' ', $cWidth - $handle);

return;
});

$mColumns = (int) floor($wWidth / ($cWidth + 2));
$mLines = (int) ceil(($count + 1) / $mColumns);
--$mColumns;
$i = 0;

if (0 > $window['y'] - $cursor['y'] - $mLines) {
Console\Window::scroll('↑', $mLines);
Console\Cursor::move('↑', $mLines);
}

Console\Cursor::save();
Console\Cursor::hide();
Console\Cursor::move('↓ LEFT');
Console\Cursor::clear('↓');

foreach ($_solution as $j => $s) {
$output->writeAll("\033[0m" . $s . "\033[0m");

if ($i++ < $mColumns) {
$output->writeAll('  ');
} else {
$i = 0;

if (isset($_solution[$j + 1])) {
$output->writeAll("\n");
}
}
}

Console\Cursor::restore();
Console\Cursor::show();

++$mColumns;
$input = Console::getInput();
$read = [$input->getStream()->getStream()];
$mColumn = -1;
$mLine = -1;
$coord = -1;
$unselect = function () use (
&$mColumn,
&$mLine,
&$coord,
&$_solution,
&$cWidth,
$output
) {
Console\Cursor::save();
Console\Cursor::hide();
Console\Cursor::move('↓ LEFT');
Console\Cursor::move('→', $mColumn * ($cWidth + 2));
Console\Cursor::move('↓', $mLine);
$output->writeAll("\033[0m" . $_solution[$coord] . "\033[0m");
Console\Cursor::restore();
Console\Cursor::show();

return;
};
$select = function () use (
&$mColumn,
&$mLine,
&$coord,
&$_solution,
&$cWidth,
$output
) {
Console\Cursor::save();
Console\Cursor::hide();
Console\Cursor::move('↓ LEFT');
Console\Cursor::move('→', $mColumn * ($cWidth + 2));
Console\Cursor::move('↓', $mLine);
$output->writeAll("\033[7m" . $_solution[$coord] . "\033[0m");
Console\Cursor::restore();
Console\Cursor::show();

return;
};
$init = function () use (
&$mColumn,
&$mLine,
&$coord,
&$select
) {
$mColumn = 0;
$mLine = 0;
$coord = 0;
$select();

return;
};

while (true) {
@stream_select($read, $write, $except, 30, 0);

if (empty($read)) {
$read = [$input->getStream()->getStream()];

continue;
}

switch ($char = $self->_read()) {
case "\033[A":
if (-1 === $mColumn && -1 === $mLine) {
$init();

break;
}

$unselect();
$coord = max(0, $coord - $mColumns);
$mLine = (int) floor($coord / $mColumns);
$mColumn = $coord % $mColumns;
$select();

break;

case "\033[B":
if (-1 === $mColumn && -1 === $mLine) {
$init();

break;
}

$unselect();
$coord = min($count, $coord + $mColumns);
$mLine = (int) floor($coord / $mColumns);
$mColumn = $coord % $mColumns;
$select();

break;

case "\t":
case "\033[C":
if (-1 === $mColumn && -1 === $mLine) {
$init();

break;
}

$unselect();
$coord = min($count, $coord + 1);
$mLine = (int) floor($coord / $mColumns);
$mColumn = $coord % $mColumns;
$select();

break;

case "\033[D":
if (-1 === $mColumn && -1 === $mLine) {
$init();

break;
}

$unselect();
$coord = max(0, $coord - 1);
$mLine = (int) floor($coord / $mColumns);
$mColumn = $coord % $mColumns;
$select();

break;

case "\n":
if (-1 !== $mColumn && -1 !== $mLine) {
$tail = mb_substr($line, $current);
$current -= $length;
$self->setLine(
mb_substr($line, 0, $current) .
$solution[$coord] .
$tail
);
$self->setLineCurrent(
$current + mb_strlen($solution[$coord])
);

Console\Cursor::move('←', $length);
$output->writeAll($solution[$coord]);
Console\Cursor::clear('→');
$output->writeAll($tail);
Console\Cursor::move('←', mb_strlen($tail));
}

default:
$mColumn = -1;
$mLine = -1;
$coord = -1;
Console\Cursor::save();
Console\Cursor::move('↓ LEFT');
Console\Cursor::clear('↓');
Console\Cursor::restore();

if ("\033" !== $char && "\n" !== $char) {
$self->setBuffer($char);

return $self->_readLine($char);
}

break 2;
}
}

return $state;
}

$tail = mb_substr($line, $current);
$current -= $length;
$self->setLine(
mb_substr($line, 0, $current) .
$solution .
$tail
);
$self->setLineCurrent(
$current + mb_strlen($solution)
);

Console\Cursor::move('←', $length);
$output->writeAll($solution);
Console\Cursor::clear('→');
$output->writeAll($tail);
Console\Cursor::move('←', mb_strlen($tail));

return $state;
}
}




Console::advancedInteraction();




Consistency::flexEntity('Hoa\Console\Readline\Readline');
<?php



































namespace Hoa\Console\Readline\Autocompleter;

use Hoa\Consistency;









interface Autocompleter
{







public function complete(&$prefix);







public function getWordDefinition();
}




Consistency::flexEntity('Hoa\Console\Readline\Autocompleter\Autocompleter');
<?php



































namespace Hoa\Console\Readline\Autocompleter;









class Aggregate implements Autocompleter
{





protected $_autocompleters = null;








public function __construct(array $autocompleters)
{
$this->setAutocompleters($autocompleters);

return;
}








public function complete(&$prefix)
{
foreach ($this->getAutocompleters() as $autocompleter) {
$preg = preg_match(
'#(' . $autocompleter->getWordDefinition() . ')$#u',
$prefix,
$match
);

if (0 === $preg) {
continue;
}

$_prefix = $match[0];

if (null === $out = $autocompleter->complete($_prefix)) {
continue;
}

$prefix = $_prefix;

return $out;
}

return null;
}







protected function setAutocompleters(array $autocompleters)
{
$old = $this->_autocompleters;
$this->_autocompleters = new \ArrayObject($autocompleters);

return $old;
}






public function getAutocompleters()
{
return $this->_autocompleters;
}






public function getWordDefinition()
{
return '.*';
}
}
<?php



































namespace Hoa\Console\Readline\Autocompleter;









class Word implements Autocompleter
{





protected $_words = null;








public function __construct(array $words)
{
$this->setWords($words);

return;
}








public function complete(&$prefix)
{
$out = [];
$length = mb_strlen($prefix);

foreach ($this->getWords() as $word) {
if (mb_substr($word, 0, $length) === $prefix) {
$out[] = $word;
}
}

if (empty($out)) {
return null;
}

if (1 === count($out)) {
return $out[0];
}

return $out;
}






public function getWordDefinition()
{
return '\b\w+';
}







public function setWords(array $words)
{
$old = $this->_words;
$this->_words = $words;

return $old;
}






public function getWords()
{
return $this->_words;
}
}
<?php



































namespace Hoa\Console\Readline\Autocompleter;









class Path implements Autocompleter
{





const PWD = null;






protected $_root = null;






protected $_iteratorFactory = null;











public function __construct(
$root = null,
\Closure $iteratorFactory = null
) {
if (null === $root) {
$root = static::PWD;
}

$this->setRoot($root);

if (null !== $iteratorFactory) {
$this->setIteratorFactory($iteratorFactory);
}

return;
}








public function complete(&$prefix)
{
$root = $this->getRoot();

if (static::PWD === $root) {
$root = getcwd();
}

$path = $root . DS . $prefix;

if (!is_dir($path)) {
$path = dirname($path) . DS;
$prefix = basename($prefix);
} else {
$prefix = null;
}

$iteratorFactory = $this->getIteratorFactory() ?:
static::getDefaultIteratorFactory();

try {
$iterator = $iteratorFactory($path);
$out = [];
$length = mb_strlen($prefix);

foreach ($iterator as $fileinfo) {
$filename = $fileinfo->getFilename();

if (null === $prefix ||
(mb_substr($filename, 0, $length) === $prefix)) {
if ($fileinfo->isDir()) {
$out[] = $filename . '/';
} else {
$out[] = $filename;
}
}
}
} catch (\Exception $e) {
return null;
}

$count = count($out);

if (1 === $count) {
return $out[0];
}

if (0 === $count) {
return null;
}

return $out;
}






public function getWordDefinition()
{
return '/?[\w\d\\_\-\.]+(/[\w\d\\_\-\.]*)*';
}







public function setRoot($root)
{
$old = $this->_root;
$this->_root = $root;

return $old;
}






public function getRoot()
{
return $this->_root;
}








public function setIteratorFactory(\Closure $iteratorFactory)
{
$old = $this->_iteratorFactory;
$this->_iteratorFactory = $iteratorFactory;

return $old;
}






public function getIteratorFactory()
{
return $this->_iteratorFactory;
}






public static function getDefaultIteratorFactory()
{
return function ($path) {
return new \DirectoryIterator($path);
};
}
}
<?php



































namespace Hoa\Console;









class Cursor
{

















public static function move($steps, $repeat = 1)
{
if (1 > $repeat) {
return;
} elseif (1 === $repeat) {
$handle = explode(' ', $steps);
} else {
$handle = explode(' ', $steps, 1);
}

$tput = Console::getTput();
$output = Console::getOutput();

foreach ($handle as $step) {
switch ($step) {
case 'u':
case 'up':
case '↑':
$output->writeAll(
str_replace(
'%p1%d',
$repeat,
$tput->get('parm_up_cursor')
)
);

break;

case 'U':
case 'UP':
static::moveTo(null, 1);

break;

case 'r':
case 'right':
case '→':
$output->writeAll(
str_replace(
'%p1%d',
$repeat,
$tput->get('parm_right_cursor')
)
);

break;

case 'R':
case 'RIGHT':
static::moveTo(9999);

break;

case 'd':
case 'down':
case '↓':
$output->writeAll(
str_replace(
'%p1%d',
$repeat,
$tput->get('parm_down_cursor')
)
);

break;

case 'D':
case 'DOWN':
static::moveTo(null, 9999);

break;

case 'l':
case 'left':
case '←':
$output->writeAll(
str_replace(
'%p1%d',
$repeat,
$tput->get('parm_left_cursor')
)
);

break;

case 'L':
case 'LEFT':
static::moveTo(1);

break;
}
}

return;
}









public static function moveTo($x = null, $y = null)
{
if (null === $x || null === $y) {
$position = static::getPosition();

if (null === $x) {
$x = $position['x'];
}

if (null === $y) {
$y = $position['y'];
}
}

Console::getOutput()->writeAll(
str_replace(
['%i%p1%d', '%p2%d'],
[$y, $x],
Console::getTput()->get('cursor_address')
)
);

return;
}






public static function getPosition()
{
$tput = Console::getTput();
$user7 = $tput->get('user7');

if (null === $user7) {
return [
'x' => 0,
'y' => 0
];
}

Console::getOutput()->writeAll($user7);

$input = Console::getInput();


 $input->read(2); 

$x = null;
$y = null;
$handle = &$y;

do {
$char = $input->readCharacter();

switch ($char) {
case ';':
$handle = &$x;

break;

case 'R':
break 2;

default:
$handle .= $char;
}
} while (true);

return [
'x' => (int) $x,
'y' => (int) $y
];
}






public static function save()
{
Console::getOutput()->writeAll(
Console::getTput()->get('save_cursor')
);

return;
}






public static function restore()
{
Console::getOutput()->writeAll(
Console::getTput()->get('restore_cursor')
);

return;
}















public static function clear($parts = 'all')
{
$tput = Console::getTput();
$output = Console::getOutput();

foreach (explode(' ', $parts) as $part) {
switch ($part) {
case 'a':
case 'all':
case '↕':
$output->writeAll($tput->get('clear_screen'));
static::moveTo(1, 1);

break;

case 'u':
case 'up':
case '↑':
$output->writeAll("\033[1J");

break;

case 'r':
case 'right':
case '→':
$output->writeAll($tput->get('clr_eol'));

break;

case 'd':
case 'down':
case '↓':
$output->writeAll($tput->get('clr_eos'));

break;

case 'l':
case 'left':
case '←':
$output->writeAll($tput->get('clr_bol'));

break;

case 'line':
case '↔':
$output->writeAll("\r" . $tput->get('clr_eol'));

break;
}
}

return;
}






public static function hide()
{
Console::getOutput()->writeAll(
Console::getTput()->get('cursor_invisible')
);

return;
}






public static function show()
{
Console::getOutput()->writeAll(
Console::getTput()->get('cursor_visible')
);

return;
}
































public static function colorize($attributes)
{
static $_rgbTo256 = null;

if (null === $_rgbTo256) {
$_rgbTo256 = [
'000000', '800000', '008000', '808000', '000080', '800080',
'008080', 'c0c0c0', '808080', 'ff0000', '00ff00', 'ffff00',
'0000ff', 'ff00ff', '00ffff', 'ffffff', '000000', '00005f',
'000087', '0000af', '0000d7', '0000ff', '005f00', '005f5f',
'005f87', '005faf', '005fd7', '005fff', '008700', '00875f',
'008787', '0087af', '0087d7', '0087ff', '00af00', '00af5f',
'00af87', '00afaf', '00afd7', '00afff', '00d700', '00d75f',
'00d787', '00d7af', '00d7d7', '00d7ff', '00ff00', '00ff5f',
'00ff87', '00ffaf', '00ffd7', '00ffff', '5f0000', '5f005f',
'5f0087', '5f00af', '5f00d7', '5f00ff', '5f5f00', '5f5f5f',
'5f5f87', '5f5faf', '5f5fd7', '5f5fff', '5f8700', '5f875f',
'5f8787', '5f87af', '5f87d7', '5f87ff', '5faf00', '5faf5f',
'5faf87', '5fafaf', '5fafd7', '5fafff', '5fd700', '5fd75f',
'5fd787', '5fd7af', '5fd7d7', '5fd7ff', '5fff00', '5fff5f',
'5fff87', '5fffaf', '5fffd7', '5fffff', '870000', '87005f',
'870087', '8700af', '8700d7', '8700ff', '875f00', '875f5f',
'875f87', '875faf', '875fd7', '875fff', '878700', '87875f',
'878787', '8787af', '8787d7', '8787ff', '87af00', '87af5f',
'87af87', '87afaf', '87afd7', '87afff', '87d700', '87d75f',
'87d787', '87d7af', '87d7d7', '87d7ff', '87ff00', '87ff5f',
'87ff87', '87ffaf', '87ffd7', '87ffff', 'af0000', 'af005f',
'af0087', 'af00af', 'af00d7', 'af00ff', 'af5f00', 'af5f5f',
'af5f87', 'af5faf', 'af5fd7', 'af5fff', 'af8700', 'af875f',
'af8787', 'af87af', 'af87d7', 'af87ff', 'afaf00', 'afaf5f',
'afaf87', 'afafaf', 'afafd7', 'afafff', 'afd700', 'afd75f',
'afd787', 'afd7af', 'afd7d7', 'afd7ff', 'afff00', 'afff5f',
'afff87', 'afffaf', 'afffd7', 'afffff', 'd70000', 'd7005f',
'd70087', 'd700af', 'd700d7', 'd700ff', 'd75f00', 'd75f5f',
'd75f87', 'd75faf', 'd75fd7', 'd75fff', 'd78700', 'd7875f',
'd78787', 'd787af', 'd787d7', 'd787ff', 'd7af00', 'd7af5f',
'd7af87', 'd7afaf', 'd7afd7', 'd7afff', 'd7d700', 'd7d75f',
'd7d787', 'd7d7af', 'd7d7d7', 'd7d7ff', 'd7ff00', 'd7ff5f',
'd7ff87', 'd7ffaf', 'd7ffd7', 'd7ffff', 'ff0000', 'ff005f',
'ff0087', 'ff00af', 'ff00d7', 'ff00ff', 'ff5f00', 'ff5f5f',
'ff5f87', 'ff5faf', 'ff5fd7', 'ff5fff', 'ff8700', 'ff875f',
'ff8787', 'ff87af', 'ff87d7', 'ff87ff', 'ffaf00', 'ffaf5f',
'ffaf87', 'ffafaf', 'ffafd7', 'ffafff', 'ffd700', 'ffd75f',
'ffd787', 'ffd7af', 'ffd7d7', 'ffd7ff', 'ffff00', 'ffff5f',
'ffff87', 'ffffaf', 'ffffd7', 'ffffff', '080808', '121212',
'1c1c1c', '262626', '303030', '3a3a3a', '444444', '4e4e4e',
'585858', '606060', '666666', '767676', '808080', '8a8a8a',
'949494', '9e9e9e', 'a8a8a8', 'b2b2b2', 'bcbcbc', 'c6c6c6',
'd0d0d0', 'dadada', 'e4e4e4', 'eeeeee'
];
}

$tput = Console::getTput();

if (1 >= $tput->count('max_colors')) {
return;
}

$handle = [];

foreach (explode(' ', $attributes) as $attribute) {
switch ($attribute) {
case 'n':
case 'normal':
$handle[] = 0;

break;

case 'b':
case 'bold':
$handle[] = 1;

break;

case 'u':
case 'underlined':
$handle[] = 4;

break;

case 'bl':
case 'blink':
$handle[] = 5;

break;

case 'i':
case 'inverse':
$handle[] = 7;

break;

case '!b':
case '!bold':
$handle[] = 22;

break;

case '!u':
case '!underlined':
$handle[] = 24;

break;

case '!bl':
case '!blink':
$handle[] = 25;

break;

case '!i':
case '!inverse':
$handle[] = 27;

break;

default:
if (0 === preg_match('#^([^\(]+)\(([^\)]+)\)$#', $attribute, $m)) {
break;
}

$shift = 0;

switch ($m[1]) {
case 'fg':
case 'foreground':
$shift = 0;

break;

case 'bg':
case 'background':
$shift = 10;

break;

default:
break 2;
}

$_handle = 0;
$_keyword = true;

switch ($m[2]) {
case 'black':
$_handle = 30;

break;

case 'red':
$_handle = 31;

break;

case 'green':
$_handle = 32;

break;

case 'yellow':
$_handle = 33;

break;

case 'blue':
$_handle = 34;

break;

case 'magenta':
$_handle = 35;

break;

case 'cyan':
$_handle = 36;

break;

case 'white':
$_handle = 37;

break;

case 'default':
$_handle = 39;

break;

default:
$_keyword = false;

if (256 <= $tput->count('max_colors') &&
'#' === $m[2][0]) {
$rgb = hexdec(substr($m[2], 1));
$r = ($rgb >> 16) & 255;
$g = ($rgb >> 8) & 255;
$b = $rgb & 255;
$distance = null;

foreach ($_rgbTo256 as $i => $_rgb) {
$_rgb = hexdec($_rgb);
$_r = ($_rgb >> 16) & 255;
$_g = ($_rgb >> 8) & 255;
$_b = $_rgb & 255;

$d = sqrt(
pow($_r - $r, 2)
+ pow($_g - $g, 2)
+ pow($_b - $b, 2)
);

if (null === $distance ||
$d <= $distance) {
$distance = $d;
$_handle = $i;
}
}
} else {
$_handle = intval($m[2]);
}
}

if (true === $_keyword) {
$handle[] = $_handle + $shift;
} else {
$handle[] = (38 + $shift) . ';5;' . $_handle;
}
}
}

Console::getOutput()->writeAll("\033[" . implode(';', $handle) . "m");

return;
}








public static function changeColor($fromCode, $toColor)
{
$tput = Console::getTput();

if (true !== $tput->has('can_change')) {
return;
}

$r = ($toColor >> 16) & 255;
$g = ($toColor >> 8) & 255;
$b = $toColor & 255;

Console::getOutput()->writeAll(
str_replace(
[
'%p1%d',
'rgb:',
'%p2%{255}%*%{1000}%/%2.2X/',
'%p3%{255}%*%{1000}%/%2.2X/',
'%p4%{255}%*%{1000}%/%2.2X'
],
[
$fromCode,
'',
sprintf('%02x', $r),
sprintf('%02x', $g),
sprintf('%02x', $b)
],
$tput->get('initialize_color')
)
);

return;
}












public static function setStyle($style, $blink = true)
{
if (OS_WIN) {
return;
}

switch ($style) {
case 'b':
case 'block':
case '▋':
$_style = 1;

break;

case 'u':
case 'underline':
case '_':
$_style = 2;

break;

case 'v':
case 'vertical':
case '|':
$_style = 5;

break;
}

if (false === $blink) {
++$_style;
}


 Console::getOutput()->writeAll("\033[" . $_style . " q");

return;
}






public static function bip()
{
Console::getOutput()->writeAll(
Console::getTput()->get('bell')
);

return;
}
}




Console::advancedInteraction();
<?php



































namespace Hoa\Iterator;









class Multiple extends \MultipleIterator
{





protected $_infos = [];













public function attachIterator(
\Iterator $iterator,
$infos = null,
$default = null
) {
$out = parent::attachIterator($iterator, $infos);

if (null === $infos) {
$this->_infos[] = $default;
} else {
$this->_infos[$infos] = $default;
}

return $out;
}






public function current()
{
$out = parent::current();

foreach ($out as $key => &$value) {
if (null === $value) {
$value = $this->_infos[$key];
}
}

return $out;
}
}
<?php



































namespace Hoa\Iterator;









class CallbackGenerator implements Iterator
{





protected $_callback = null;






protected $_key = 0;






protected $_current = null;








public function __construct(callable $callback)
{
$this->_callback = $callback;

return;
}






public function current()
{
$handle = $this->_callback;

return $this->_current = $handle($this->_key);
}






public function key()
{
return $this->_key;
}






public function next()
{
++$this->_key;

return;
}






public function rewind()
{
$this->_key = 0;
$this->_current = null;

return;
}






public function valid()
{
return true;
}
}
<?php



































namespace Hoa\Iterator;









class Directory extends \DirectoryIterator
{





protected $_splFileInfoClass = null;






protected $_relativePath = null;











public function __construct($path, $splFileInfoClass = null)
{
$this->_splFileInfoClass = $splFileInfoClass;
parent::__construct($path);
$this->setRelativePath($path);

return;
}







public function current()
{
$out = parent::current();

if (null !== $this->_splFileInfoClass &&
$out instanceof \SplFileInfo) {
$out->setInfoClass($this->_splFileInfoClass);
$out = $out->getFileInfo();

if ($out instanceof \Hoa\Iterator\SplFileInfo) {
$out->setRelativePath($this->getRelativePath());
}
}

return $out;
}







protected function setRelativePath($path)
{
$old = $this->_relativePath;
$this->_relativePath = $path;

return $old;
}






public function getRelativePath()
{
return $this->_relativePath;
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class Multiple extends Test\Unit\Suite
{
public function case_classic()
{
$this
->given(
$foo = new LUT\Map(['f', 'o', 'o']),
$bar = new LUT\Map(['b', 'a', 'r']),
$multiple = new LUT\Multiple(
LUT\Multiple::MIT_NEED_ANY
| LUT\Multiple::MIT_KEYS_ASSOC
),
$multiple->attachIterator($foo, 'one'),
$multiple->attachIterator($bar, 'two')
)
->when($result = iterator_to_array($multiple, false))
->then
->array($result)
->isEqualTo([
['one' => 'f', 'two' => 'b'],
['one' => 'o', 'two' => 'a'],
['one' => 'o', 'two' => 'r']
]);
}

public function case_default_value()
{
$this
->given(
$foobar = new LUT\Map(['f', 'o', 'o', 'b', 'a', 'r']),
$baz = new LUT\Map(['b', 'a', 'z']),
$multiple = new LUT\Multiple(
LUT\Multiple::MIT_NEED_ANY
| LUT\Multiple::MIT_KEYS_ASSOC
),
$multiple->attachIterator($foobar, 'one', '!'),
$multiple->attachIterator($baz, 'two', '?')
)
->when($result = iterator_to_array($multiple, false))
->then
->array($result)
->isEqualTo([
['one' => 'f', 'two' => 'b'],
['one' => 'o', 'two' => 'a'],
['one' => 'o', 'two' => 'z'],
['one' => 'b', 'two' => '?'],
['one' => 'a', 'two' => '?'],
['one' => 'r', 'two' => '?'],
]);
}

public function case_empty()
{
$this
->given($multiple = new LUT\Multiple())
->when($result = iterator_to_array($multiple))
->then
->array($result)
->isEmpty();
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class CallbackGenerator extends Test\Unit\Suite
{
public function case_classic()
{
$this
->given(
$iterator = new LUT\CallbackGenerator(function ($key) {
return $key * 2;
}),
$limit = new LUT\Limit($iterator, 0, 5)
)
->when($result = iterator_to_array($limit))
->then
->array($result)
->isEqualTo([
0,
2,
4,
6,
8
]);
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class Directory extends Test\Unit\Suite
{
public function case_classic()
{
$this
->given(
$root = resolve('hoa://Test/Vfs/Root?type=directory'),
resolve('hoa://Test/Vfs/Root/A?type=file'),
resolve('hoa://Test/Vfs/Root/Aa?type=file'),
resolve('hoa://Test/Vfs/Root/Aaa?type=file'),
$iterator = new LUT\Directory($root),
$result = []
)
->when(function () use ($iterator, &$result) {
foreach ($iterator as $key => $file) {
$result[$key] = $file->getFilename();

$this
->object($file)
->isInstanceOf(LUT\Directory::class);
}
})
->then
->array($result)
->isEqualTo([
0 => 'A',
1 => 'Aa',
2 => 'Aaa'
]);
}

public function case_seek_and_dots()
{
$this
->given(
$root = resolve('hoa://Test/Vfs/Root?type=directory'),
resolve('hoa://Test/Vfs/Root/.?type=directory'),
resolve('hoa://Test/Vfs/Root/..?type=directory'),
resolve('hoa://Test/Vfs/Root/Skip?type=file'),
resolve('hoa://Test/Vfs/Root/Gotcha?type=file'),
$iterator = new LUT\Directory($root)
)
->when($result = $iterator->current())
->then
->boolean($result->isDot())
->isTrue()

->when(
$iterator->next(),
$result = $iterator->current()
)
->then
->boolean($result->isDot())
->isTrue()

->when(
$iterator->seek(3),
$result = $iterator->current()
)
->then
->string($result->getFilename())
->isEqualTo('Gotcha')

->when(
$iterator->seek(2),
$result = $iterator->current()
)
->then
->string($result->getFilename())
->isEqualTo('Skip');
}

public function case_recursive()
{
$this
->given(
$root = resolve('hoa://Test/Vfs/Root?type=directory'),
resolve('hoa://Test/Vfs/Root/A?type=file'),
resolve('hoa://Test/Vfs/Root/Aa?type=file'),
resolve('hoa://Test/Vfs/Root/Aaa?type=file'),
resolve('hoa://Test/Vfs/Root/Foo?type=directory'),
resolve('hoa://Test/Vfs/Root/Foo/Bar?type=directory'),
resolve('hoa://Test/Vfs/Root/Foo/Bar/B?type=file'),
resolve('hoa://Test/Vfs/Root/Foo/Bar/Bb?type=file'),
resolve('hoa://Test/Vfs/Root/Foo/Bar/Bbb?type=file'),
resolve('hoa://Test/Vfs/Root/Foo/C?type=file'),
resolve('hoa://Test/Vfs/Root/Foo/Cc?type=file'),
resolve('hoa://Test/Vfs/Root/Foo/Ccc?type=file'),
$directory = new LUT\Recursive\Directory($root),
$iterator = new LUT\Recursive\Iterator($directory),
$result = []
)
->when(function () use ($iterator, &$result) {
foreach ($iterator as $file) {
$result[] = $file->getFilename();
}
})
->then
->array($result)
->isEqualTo([
'A',
'Aa',
'Aaa',
'B',
'Bb',
'Bbb',
'C',
'Cc',
'Ccc'
]);
}

public function case_splFileClassInfo()
{
$this
->given(
$splFileInfo = 'Hoa\Iterator\SplFileInfo',
$root = resolve('hoa://Test/Vfs/Root?type=directory'),
resolve('hoa://Test/Vfs/Root/a?type=file'),
resolve('hoa://Test/Vfs/Root/b?type=file'),
resolve('hoa://Test/Vfs/Root/c?type=file'),
resolve('hoa://Test/Vfs/Root/d?type=file'),
resolve('hoa://Test/Vfs/Root/e?type=file'),
resolve('hoa://Test/Vfs/Root/f?type=file'),
$iterator = new LUT\Directory(
$root,
$splFileInfo
),
$result = []
)
->when(function () use ($iterator, $splFileInfo, &$result) {
foreach ($iterator as $file) {
$this
->object($file)
->isInstanceOf($splFileInfo);

$result[] = $file->getFilename();
}
})
->then
->array($result)
->isEqualTo([
'a',
'b',
'c',
'd',
'e',
'f'
]);
}

public function case_recursive_splFileClassInfo()
{
$this
->given(
$splFileInfo = 'Hoa\Iterator\SplFileInfo',
$root = resolve('hoa://Test/Vfs/Root?type=directory'),
resolve('hoa://Test/Vfs/Root/A?type=directory'),
resolve('hoa://Test/Vfs/Root/A/a?type=file'),
resolve('hoa://Test/Vfs/Root/A/b?type=file'),
resolve('hoa://Test/Vfs/Root/A/c?type=file'),
resolve('hoa://Test/Vfs/Root/B?type=directory'),
resolve('hoa://Test/Vfs/Root/B/d?type=file'),
resolve('hoa://Test/Vfs/Root/B/e?type=file'),
resolve('hoa://Test/Vfs/Root/B/c?type=directory'),
resolve('hoa://Test/Vfs/Root/B/c/f?type=file'),
$directory = new LUT\Recursive\Directory(
$root,
LUT\FileSystem::CURRENT_AS_FILEINFO,
$splFileInfo
),
$iterator = new LUT\Recursive\Iterator($directory),
$result = []
)
->when(function () use ($iterator, $splFileInfo, &$result) {
foreach ($iterator as $file) {
$this
->object($file)
->isInstanceOf($splFileInfo);

$result[] = $file->getFilename();
}
})
->then
->array($result)
->isEqualTo([
'a',
'b',
'c',
'd',
'e',
'f'
]);
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class SplFileInfo extends Test\Unit\Suite
{
public function case_file()
{
$this
->given($pathname = 'hoa://Test/Vfs/Foo.bar?type=file')
->when($result = new LUT\SplFileInfo($pathname))
->then
->boolean($result->isFile())
->isTrue()
->string($result->getType())
->isEqualTo('file');
}

public function case_directory()
{
$this
->given($pathname = 'hoa://Test/Vfs/Foo?type=directory')
->when($result = new LUT\SplFileInfo($pathname))
->then
->boolean($result->isDir())
->isTrue()
->string($result->getType())
->isEqualTo('dir');
}

public function case_path_informations()
{
$this
->given(
$relativePath = 'hoa://Test/Vfs/A/B/',
$relativePathname = 'C/Foo.bar',
$pathname = $relativePath . $relativePathname
)
->when($result = new LUT\SplFileInfo($pathname . '?type=file', $relativePath))
->then
->boolean($result->isFile())
->isTrue()
->string($result->getBasename())
->isEqualTo('Foo.bar?type=file')
->string($result->getExtension())
->isEqualTo('bar?type=file')
->string($result->getRelativePath())
->isEqualTo($relativePath)
->string($result->getRelativePathname())
->isEqualTo($relativePathname . '?type=file')
->string($result->getPath())
->isEqualTo('hoa://Test/Vfs/A/B/C')
->string($result->getPathname())
->isEqualTo($pathname . '?type=file');
}

public function case_times()
{
$this
->given(
$timestamp = $this->realdom->boundinteger(
$this->realdom->timestamp('yesterday'),
$this->realdom->timestamp('tomorrow')
),
$atime = $this->sample($timestamp),
$ctime = $this->sample($timestamp),
$mtime = $this->sample($timestamp),
$pathname =
'hoa://Test/Vfs/Foo.bar?' .
http_build_query([
'type' => 'file',
'atime' => $atime,
'ctime' => $ctime,
'mtime' => $mtime
])
)
->when($result = new LUT\SplFileInfo($pathname))
->then
->integer($result->getATime())
->isEqualTo($atime)
->integer($result->getCTime())
->isEqualTo($ctime)
->integer($result->getMTime())
->isEqualTo($mtime);
}

public function case_permissions()
{
$this
->given($pathname = 'hoa://Test/Vfs/Fo.bar?type=file&permissions=0744')
->when($result = new LUT\SplFileInfo($pathname))
->then
->boolean($result->isReadable())
->isTrue()
->boolean($result->isWritable())
->isTrue()
->boolean($result->isExecutable())
->isTrue()

->given($pathname = 'hoa://Test/Vfs/Foo.bar?type=file&permissions=0644')
->when($result = new LUT\SplFileInfo($pathname))
->then
->boolean($result->isReadable())
->isTrue()
->boolean($result->isWritable())
->isTrue()
->boolean($result->isExecutable())
->isFalse()

->given($pathname = 'hoa://Test/Vfs/Fooo.bar?type=file&permissions=0444')
->when($result = new LUT\SplFileInfo($pathname))
->then
->boolean($result->isReadable())
->isTrue()
->boolean($result->isWritable())
->isFalse()
->boolean($result->isExecutable())
->isFalse()

->given($pathname = 'hoa://Test/Vfs/Foooo.bar?type=file&permissions=0044')
->when($result = new LUT\SplFileInfo($pathname))
->then
->boolean($result->isReadable())
->isFalse()
->boolean($result->isWritable())
->isFalse()
->boolean($result->isExecutable())
->isFalse();
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class FileSystem extends Test\Unit\Suite
{
public function case_classic()
{
$this
->given(
$root = resolve('hoa://Test/Vfs/Root?type=directory'),
resolve('hoa://Test/Vfs/Root/.?type=directory'),
resolve('hoa://Test/Vfs/Root/..?type=directory'),
resolve('hoa://Test/Vfs/Root/A?type=file'),
resolve('hoa://Test/Vfs/Root/B?type=file'),
$iterator = new LUT\FileSystem($root),
$result = []
)
->when(function () use ($iterator, &$result) {
foreach ($iterator as $pathname => $file) {
$this
->object($file)
->isInstanceOf('SplFileInfo');

$result[basename($pathname)] = $file->getFilename();
}
})
->array($result)
->isEqualTo([
'A' => 'A',
'B' => 'B'
]);
}

public function case_splFileClassInfo()
{
$this
->given(
$splFileInfo = 'Hoa\Iterator\SplFileInfo',
$root = resolve('hoa://Test/Vfs/Root?type=directory'),
resolve('hoa://Test/Vfs/Root/a?type=file'),
resolve('hoa://Test/Vfs/Root/b?type=file'),
resolve('hoa://Test/Vfs/Root/c?type=file'),
resolve('hoa://Test/Vfs/Root/d?type=file'),
resolve('hoa://Test/Vfs/Root/e?type=file'),
resolve('hoa://Test/Vfs/Root/f?type=file'),
$iterator = new LUT\FileSystem(
$root,
LUT\FileSystem::CURRENT_AS_FILEINFO,
$splFileInfo
),
$result = []
)
->when(function () use ($iterator, $splFileInfo, &$result) {
foreach ($iterator as $file) {
$this
->object($file)
->isInstanceOf($splFileInfo);

$result[] = $file->getFilename();
}
})
->then
->array($result)
->isEqualTo([
'a',
'b',
'c',
'd',
'e',
'f'
]);
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class CallbackFilter extends Test\Unit\Suite
{
public function case_classic()
{
$this
->given(
$foobar = $this->getDummyIterator(),
$filter = new LUT\CallbackFilter(
$foobar,
function ($value) {
return false === in_array($value, ['a', 'e', 'i', 'o', 'u']);
}
)
)
->when($result = iterator_to_array($filter))
->then
->array($result)
->isEqualTo([
0 => 'f',
3 => 'b',
5 => 'r'
]);
}

public function case_all_callback_parameters()
{
$self = $this;

$this
->given(
$foobar = $this->getDummyIterator(),
$keys = [],
$values = [],
$filter = new LUT\CallbackFilter(
$foobar,
function ($value, $key, $iterator) use (
$self,
$foobar,
&$keys,
&$values
) {
$self
->object($iterator)
->isIdenticalTo($foobar);

$keys[] = $key;
$values[] = $value;

return false === in_array($value, ['a', 'e', 'i', 'o', 'u']);
}
)
)
->when($result = iterator_to_array($filter))
->then
->array($result)
->isEqualTo([
0 => 'f',
3 => 'b',
5 => 'r'
])
->array(array_combine($keys, $values))
->isEqualTo(iterator_to_array($foobar));
}

public function case_remove_all()
{
$this
->given(
$foobar = $this->getDummyIterator(),
$filter = new LUT\CallbackFilter(
$foobar,
function () {
return false;
}
)
)
->when($result = iterator_to_array($filter))
->then
->array($result)
->isEmpty();
}

public function case_remove_none()
{
$this
->given(
$foobar = $this->getDummyIterator(),
$filter = new LUT\CallbackFilter(
$foobar,
function () {
return true;
}
)
)
->when(
$foobarResult = iterator_to_array($foobar),
$filterResult = iterator_to_array($filter)
)
->then
->array($foobarResult)
->isEqualTo($filterResult);
}

public function case_recursive()
{
$this
->given(
$foobar = $this->getDummyRecursiveIterator(),
$filter = new LUT\Recursive\CallbackFilter(
$foobar,
function ($value) {
return false === in_array($value, ['a', 'e', 'i', 'o', 'u']);
}
),
$iterator = new LUT\Recursive\Iterator($filter)
)
->when($result = iterator_to_array($iterator, false))
->then
->array($result)
->isEqualTo([
0 => 'f',
1 => 'b',
2 => 'r'
]);
}

public function case_recursive_remove_all()
{
$this
->given(
$foobar = $this->getDummyRecursiveIterator(),
$filter = new LUT\Recursive\CallbackFilter(
$foobar,
function () {
return false;
}
),
$iterator = new LUT\Recursive\Iterator($filter)
)
->when($result = iterator_to_array($iterator))
->then
->array($result)
->isEmpty();
}

public function case_recursive_remove_none()
{
$this
->given(
$foobar = $this->getDummyRecursiveIterator(),
$filter = new LUT\Recursive\CallbackFilter(
$foobar,
function () {
return true;
}
),
$foobarIterator = new LUT\Recursive\Iterator($foobar),
$filterIterator = new LUT\Recursive\Iterator($filter)
)
->when(
$foobarResult = iterator_to_array($foobarIterator),
$filterResult = iterator_to_array($filterIterator)
)
->then
->array($foobarResult)
->isEqualTo($filterResult);
}

protected function getDummyIterator()
{
return new LUT\Map(['f', 'o', 'o', 'b', 'a', 'r']);
}

protected function getDummyRecursiveIterator()
{
return new LUT\Recursive\Map([['f', 'o', 'o'], ['b', 'a', 'r']]);
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class Append extends Test\Unit\Suite
{
public function case_classic()
{
$this
->given(
$counter1 = new LUT\Counter(0, 12, 3),
$counter2 = new LUT\Counter(13, 23, 2),
$append = new LUT\Append(),
$append->append($counter1),
$append->append($counter2)
)
->when($result = iterator_to_array($append, false))
->then
->array($result)
->isEqualTo([
0,
3,
6,
9,
13,
15,
17,
19,
21
]);
}

public function case_singleton()
{
$this
->given(
$counter1 = new LUT\Counter(0, 12, 3),
$append = new LUT\Append(),
$append->append($counter1)
)
->when($result = iterator_to_array($append))
->then
->array($result)
->isEqualTo([
0,
3,
6,
9
]);
}

public function case_empty()
{
$this
->given($append = new LUT\Append())
->when($result = iterator_to_array($append))
->then
->array($result)
->isEmpty();
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class Demultiplexer extends Test\Unit\Suite
{
public function case_classic()
{
$this
->given(
$counter = new LUT\Counter(0, 10, 1),
$multiple = new LUT\Multiple(),
$multiple->attachIterator($counter),
$multiple->attachIterator(clone $counter),
$demultiplexer = new LUT\Demultiplexer(
$multiple,
function ($current) {
return $current[0] * $current[1];
}
)
)
->when($result = iterator_to_array($demultiplexer, false))
->then
->array($result)
->isEqualTo([
0,
1,
4,
9,
16,
25,
36,
49,
64,
81
]);
}

public function case_associative_keys()
{
$this
->given(
$counter = new LUT\Counter(0, 10, 1),
$multiple = new LUT\Multiple(
LUT\Multiple::MIT_NEED_ANY
| LUT\Multiple::MIT_KEYS_ASSOC
),
$multiple->attachIterator($counter, 'one'),
$multiple->attachIterator(clone $counter, 'two'),
$demultiplexer = new LUT\Demultiplexer(
$multiple,
function ($current) {
return $current['one'] * $current['two'];
}
)
)
->when($result = iterator_to_array($demultiplexer, false))
->then
->array($result)
->isEqualTo([
0,
1,
4,
9,
16,
25,
36,
49,
64,
81
]);
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class Mock extends Test\Unit\Suite
{
public function case_classic()
{
$this
->given($iterator = new LUT\Mock())
->when($result = iterator_to_array($iterator))
->then
->array($result)
->isEmpty();
}

public function case_recursive_mock_mock()
{
$this
->when($iterator = new LUT\Recursive\Mock(new LUT\Mock()))
->then
->variable($iterator->getChildren())
->isNull()
->boolean($iterator->hasChildren())
->isFalse();
}

public function case_recursive()
{
$this
->given(
$map = new LUT\Map(['a', 'b', 'c']),
$mock = new LUT\Recursive\Mock($map),
$iteratoriterator = new LUT\Recursive\Iterator($mock)
)
->when($result = iterator_to_array($map, false))
->then
->array($result)
->isEqualTo(['a', 'b', 'c']);
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class Map extends Test\Unit\Suite
{
private static $_dummyArray = ['f', 'o', 'o', 'b', 'a', 'r'];



public function case_classic()
{
$this
->given($iterator = new LUT\Map(self::$_dummyArray))
->when($result = iterator_to_array($iterator))
->then
->array($result)
->isEqualTo(self::$_dummyArray);
}

public function case_empty()
{
$this
->given($iterator = new LUT\Map())
->when($result = iterator_to_array($iterator))
->then
->array($result)
->isEmpty();
}

public function case_recursive()
{
$this
->given(
$array = [
'a' => ['b', 'c', 'd'],
'e' => ['f', 'g', 'i'],
'k'
],
$iterator = new LUT\Recursive\Map($array)
)
->when(function () use ($iterator) {
foreach ($iterator as $key => $value) {
if ('a' === $key) {
$this
->boolean($iterator->hasChildren())
->isTrue()
->object($children = $iterator->getChildren())
->isInstanceOf(LUT\Recursive\Map::class)
->array(iterator_to_array($children))
->isEqualTo(['b', 'c', 'd']);
} elseif ('e' === $key) {
$this
->boolean($iterator->hasChildren())
->isTrue()
->object($children = $iterator->getChildren())
->isInstanceOf(LUT\Recursive\Map::class)
->array(iterator_to_array($children))
->isEqualTo(['f', 'g', 'i']);
} elseif ('k' === $value) {
$this
->boolean($iterator->hasChildren())
->isFalse();
}
}
});
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class Limit extends Test\Unit\Suite
{
private static $_dummyArray = ['f', 'o', 'o', 'b', 'a', 'r'];



public function case_classic()
{
$this
->given(
$iterator = new LUT\Map(self::$_dummyArray),
$limit = new LUT\Limit($iterator, 2, 3)
)
->when($result = iterator_to_array($limit))
->then
->array($result)
->isEqualTo([
2 => 'o',
3 => 'b',
4 => 'a'
]);
}

public function case_negative_offset()
{
$this
->given($iterator = new LUT\Map(self::$_dummyArray))
->exception(function () use ($iterator) {
new LUT\Limit($iterator, -2, 3);
})
->isInstanceOf(\OutOfRangeException::class);
}

public function case_empty()
{
$this
->given(
$iterator = new LUT\Map(self::$_dummyArray),
$limit = new LUT\Limit($iterator, 0, 0)
)
->exception(function () use ($limit) {
iterator_to_array($limit);
})
->isInstanceOf(\OutOfBoundsException::class);
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class Counter extends Test\Unit\Suite
{
public function case_classic()
{
$this
->given($iterator = new LUT\Counter(0, 12, 3))
->when($result = iterator_to_array($iterator))
->then
->array($result)
->isEqualTo([0, 3, 6, 9]);
}

public function case_offset()
{
$this
->given($iterator = new LUT\Counter(6, 12, 3))
->when($result = iterator_to_array($iterator))
->then
->array($result)
->isEqualTo([6, 9]);
}

public function case_too_small()
{
$this
->exception(function () {
new LUT\Counter(0, 0, 0);
})
->isInstanceOf(LUT\Exception::class);
}

public function case_too_big()
{
$this
->given($iterator = new LUT\Counter(0, 12, 13))
->when($result = iterator_to_array($iterator))
->then
->array($result)
->isEqualTo([0]);
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class IteratorIterator extends Test\Unit\Suite
{
public function case_inner_iterator()
{
$this
->given(
$iterator = new LUT\Map([]),
$iteratoriterator = new LUT\IteratorIterator($iterator)
)
->when($result = $iteratoriterator->getInnerIterator())
->then
->object($result)
->isIdenticalTo($iterator);
}

public function case_traverse()
{
$this
->given(
$iterator = new LUT\Map(['a', 'b', 'c']),
$iteratoriterator = new LUT\IteratorIterator($iterator)
)
->when($result = iterator_to_array($iteratoriterator))
->then
->array($result)
->isEqualTo(['a', 'b', 'c']);
}

public function case_recursive_leaves_only()
{
$this
->given(
$array = [
'a' => ['b', 'c', 'd'],
'e' => ['f', 'g', 'i']
],
$iterator = new LUT\Recursive\Map($array),
$iteratoriterator = new LUT\Recursive\Iterator(
$iterator,
LUT\Recursive\Iterator::LEAVES_ONLY
)
)
->when($result = iterator_to_array($iteratoriterator, false))
->then
->array($result)
->isEqualTo(['b', 'c', 'd', 'f', 'g', 'i']);
}

public function case_recursive_self_first()
{
$this
->given(
$array = [
'a' => ['b', 'c', 'd'],
'e' => ['f', 'g', 'i']
],
$iterator = new LUT\Recursive\Map($array),
$iteratoriterator = new LUT\Recursive\Iterator(
$iterator,
LUT\Recursive\Iterator::SELF_FIRST
)
)
->when($result = iterator_to_array($iteratoriterator, false))
->then
->array($result)
->isEqualTo([
['b', 'c', 'd'],
'b',
'c',
'd',
['f', 'g', 'i'],
'f',
'g',
'i'
]);
}

public function case_recursive_child_first()
{
$this
->given(
$array = [
'a' => ['b', 'c', 'd'],
'e' => ['f', 'g', 'i']
],
$iterator = new LUT\Recursive\Map($array),
$iteratoriterator = new LUT\Recursive\Iterator(
$iterator,
LUT\Recursive\Iterator::CHILD_FIRST
)
)
->when($result = iterator_to_array($iteratoriterator, false))
->then
->array($result)
->isEqualTo([
'b',
'c',
'd',
['b', 'c', 'd'],
'f',
'g',
'i',
['f', 'g', 'i']
]);
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class MyFilter extends LUT\Filter
{
public function accept()
{
return true;
}
}









class Filter extends Test\Unit\Suite
{
public function case_classic()
{
$this
->given(
$foobar = $this->getDummyIterator(),
$filter = new \Mock\Hoa\Iterator\Test\Unit\MyFilter($foobar),
$this->calling($filter)->accept = function () {
$value = $this->current();

return false === in_array($value, ['a', 'e', 'i', 'o', 'u']);
}
)
->when($result = iterator_to_array($filter))
->then
->array($result)
->isEqualTo([
0 => 'f',
3 => 'b',
5 => 'r'
]);
}

public function case_remove_all()
{
$this
->given(
$foobar = $this->getDummyIterator(),
$filter = new \Mock\Hoa\Iterator\Test\Unit\MyFilter($foobar),
$this->calling($filter)->accept = false
)
->when($result = iterator_to_array($filter))
->then
->array($result)
->isEmpty();
}

public function case_remove_none()
{
$this
->given(
$foobar = $this->getDummyIterator(),
$filter = new MyFilter($foobar)
)
->when(
$foobarResult = iterator_to_array($foobar),
$filterResult = iterator_to_array($filter)
)
->then
->array($foobarResult)
->isEqualTo($filterResult);
}

protected function getDummyIterator()
{
return new LUT\Map(['f', 'o', 'o', 'b', 'a', 'r']);
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class Repeater extends Test\Unit\Suite
{
private static $_dummyArray = ['f', 'o', 'o', 'b', 'a', 'r'];



public function case_classic()
{
$this
->given(
$iterator = new LUT\Map(self::$_dummyArray),
$repeater = new LUT\Repeater($iterator, 3)
)
->when($result = iterator_to_array($repeater))
->then
->array($result)
->isEqualTo(
self::$_dummyArray +
self::$_dummyArray +
self::$_dummyArray
);
}

public function case_with_body()
{
$self = $this;

$this
->given(
$iterator = new LUT\Map(self::$_dummyArray),
$count = 0,
$repeater = new LUT\Repeater(
$iterator,
3,
function ($repetition) use ($self, &$count) {
$this
->integer($repetition)
->isEqualTo($count + 1);

++$count;
})
)
->when($result = iterator_to_array($repeater))
->then
->array($result)
->isEqualTo(
self::$_dummyArray +
self::$_dummyArray +
self::$_dummyArray
)
->integer($count)
->isEqualTo(3);
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class RegularExpression extends Test\Unit\Suite
{
public function case_classic()
{
$this
->given(
$map = new LUT\Map([
'abc',
'dea',
'fgh',
'iaj',
'klm'
]),
$iterator = new LUT\RegularExpression($map, '/a/')
)
->when($result = iterator_to_array($iterator))
->then
->array($result)
->isEqualTo([
0 => 'abc',
1 => 'dea',
3 => 'iaj'
]);
}

public function case_recursive()
{
$this
->given(
$map = new LUT\Recursive\Map([
['abc', 'dea', 'fgh'],
['iaj', 'klm']
]),
$regex = new LUT\Recursive\RegularExpression($map, '/a/'),
$iterator = new LUT\Recursive\Iterator($regex)
)
->when($result = iterator_to_array($iterator, false))
->then
->array($result)
->isEqualTo([
0 => 'abc',
1 => 'dea',
2 => 'iaj'
]);
}

public function case_recursive_children_flags()
{
$this
->given(
$map = new LUT\Recursive\Map([
['abc', 'dea', 'fgh'],
['iaj', 'klm']
]),
$mode = LUT\Recursive\RegularExpression::ALL_MATCHES,
$flag = LUT\Recursive\RegularExpression::USE_KEY,
$pregFlag = LUT\Recursive\RegularExpression::ALL_MATCHES,
$iterator = new LUT\Recursive\RegularExpression(
$map,
'/a/',
$mode,
$flag,
$pregFlag
)
)
->when($result = $iterator->getChildren())
->then
->object($result)
->isInstanceOf(LUT\Recursive\RegularExpression::class)
->integer($result->getMode())
->isEqualTo($mode)
->integer($result->getFlags())
->isEqualTo($flag)
->integer($result->getPregFlags())
->isEqualTo($pregFlag);
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class Infinite extends Test\Unit\Suite
{
public function case_classic()
{
$this
->given(
$iterator = new LUT\Map(['a']),
$infinite = new LUT\Infinite($iterator),
$limit = new LUT\Limit($infinite, 0, 100)
)
->when($result = iterator_to_array($limit, false))
->then
->array($result)
->isEqualTo(array_fill(0, 100, 'a'))
->size
->isEqualTo(100);
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class NoRewind extends Test\Unit\Suite
{
public function case_classic()
{
$this
->given(
$dummyArray = ['f', 'o', 'o', 'b', 'a', 'r'],
$iterator = new LUT\Map($dummyArray),
$norewind = new LUT\NoRewind($iterator)
)
->when($result = iterator_to_array($norewind))
->then
->array($result)
->isEqualTo($dummyArray)

->when($norewind->rewind())
->boolean($norewind->valid())
->isFalse()

->when($result = iterator_to_array($norewind))
->then
->array($result)
->isEmpty();
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class Lookahead extends Test\Unit\Suite
{
public function case_traverse()
{
$this
->given(
$iterator = new LUT\Map(['a', 'b', 'c']),
$lookahead = new LUT\Lookahead($iterator)
)
->when($result = iterator_to_array($iterator))
->then
->array($result)
->isEqualTo(['a', 'b', 'c']);
}

public function case_check_ahead()
{
$this
->given(
$iterator = new LUT\Map(['a', 'b', 'c']),
$lookahead = new LUT\Lookahead($iterator)
)
->when(
$lookahead->rewind(),
$key = $lookahead->key(),
$current = $lookahead->current(),
$hasNext = $lookahead->hasNext(),
$next = $lookahead->getNext()
)
->then
->integer($key)
->isEqualTo(0)
->string($current)
->isEqualTo('a')
->boolean($hasNext)
->isTrue()
->string($next)
->isEqualTo('b')

->when(
$lookahead->next(),
$key = $lookahead->key(),
$current = $lookahead->current(),
$hasNext = $lookahead->hasNext(),
$next = $lookahead->getNext()
)
->then
->integer($key)
->isEqualTo(1)
->string($current)
->isEqualTo('b')
->boolean($hasNext)
->isTrue()
->string($next)
->isEqualTo('c')

->when(
$lookahead->next(),
$key = $lookahead->key(),
$current = $lookahead->current(),
$hasNext = $lookahead->hasNext(),
$next = $lookahead->getNext()
)
->then
->integer($key)
->isEqualTo(2)
->string($current)
->isEqualTo('c')
->boolean($hasNext)
->isFalse()
->variable($next)
->isNull();
}

public function case_double_rewind()
{
$this
->given(
$iterator = new LUT\Map(['a', 'b', 'c']),
$lookahead = new LUT\Lookahead($iterator)
)
->when(
$lookahead->rewind(),
$key = $lookahead->key(),
$current = $lookahead->current(),
$hasNext = $lookahead->hasNext(),
$next = $lookahead->getNext()
)
->then
->integer($key)
->isEqualTo(0)
->string($current)
->isEqualTo('a')
->boolean($hasNext)
->isTrue()
->string($next)
->isEqualTo('b')

->when(
$lookahead->rewind(),
$key = $lookahead->key(),
$current = $lookahead->current(),
$hasNext = $lookahead->hasNext(),
$next = $lookahead->getNext()
)
->then
->integer($key)
->isEqualTo(0)
->string($current)
->isEqualTo('a')
->boolean($hasNext)
->isTrue()
->string($next)
->isEqualTo('b');
}

public function case_empty()
{
$this
->given(
$iterator = new LUT\Mock(),
$lookahead = new LUT\Lookahead($iterator)
)
->when(
$lookahead->rewind(),
$valid = $lookahead->valid()
)
->then
->boolean($valid)
->isFalse();
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Test;









class Lookbehind extends Test\Unit\Suite
{
public function case_traverse()
{
$this
->given(
$iterator = new LUT\Map(['a', 'b', 'c']),
$lookbehind = new LUT\Lookbehind($iterator)
)
->when($result = iterator_to_array($iterator))
->then
->array($result)
->isEqualTo(['a', 'b', 'c']);
}

public function case_check_behind()
{
$this
->given(
$iterator = new LUT\Map(['a', 'b', 'c']),
$lookbehind = new LUT\Lookbehind($iterator)
)
->when(
$lookbehind->rewind(),
$key = $lookbehind->key(),
$current = $lookbehind->current(),
$hasPrevious = $lookbehind->hasPrevious(),
$previous = $lookbehind->getPrevious()
)
->then
->integer($key)
->isEqualTo(0)
->string($current)
->isEqualTo('a')
->boolean($hasPrevious)
->isFalse()
->variable($previous)
->isNull()

->when(
$lookbehind->next(),
$key = $lookbehind->key(),
$current = $lookbehind->current(),
$hasPrevious = $lookbehind->hasPrevious(),
$previous = $lookbehind->getPrevious()
)
->then
->integer($key)
->isEqualTo(1)
->string($current)
->isEqualTo('b')
->boolean($hasPrevious)
->isTrue()
->string($previous)
->isEqualTo('a')

->when(
$lookbehind->next(),
$key = $lookbehind->key(),
$current = $lookbehind->current(),
$hasPrevious = $lookbehind->hasPrevious(),
$previous = $lookbehind->getPrevious()
)
->then
->integer($key)
->isEqualTo(2)
->string($current)
->isEqualTo('c')
->boolean($hasPrevious)
->isTrue()
->string($previous)
->isEqualTo('b');
}

public function case_double_rewind()
{
$this
->given(
$iterator = new LUT\Map(['a', 'b', 'c']),
$lookbehind = new LUT\Lookbehind($iterator)
)
->when(
$lookbehind->rewind(),
$key = $lookbehind->key(),
$current = $lookbehind->current(),
$hasPrevious = $lookbehind->hasPrevious()
)
->then
->integer($key)
->isEqualTo(0)
->string($current)
->isEqualTo('a')
->boolean($hasPrevious)
->isFalse()

->when(
$lookbehind->rewind(),
$key = $lookbehind->key(),
$current = $lookbehind->current(),
$hasPrevious = $lookbehind->hasPrevious()
)
->then
->integer($key)
->isEqualTo(0)
->string($current)
->isEqualTo('a')
->boolean($hasPrevious)
->isFalse();
}

public function case_empty()
{
$this
->given(
$iterator = new LUT\Mock(),
$lookbehind = new LUT\Lookbehind($iterator)
)
->when(
$lookbehind->rewind(),
$valid = $lookbehind->valid()
)
->then
->boolean($valid)
->isFalse();
}
}
<?php



































namespace Hoa\Iterator\Test\Unit;

use Hoa\Iterator as LUT;
use Hoa\Iterator\Buffer as SUT;
use Hoa\Test;









class Buffer extends Test\Unit\Suite
{
public function case_constructor()
{
$this
->given(
$innerIterator = $this->getInnerIterator(),
$bufferSize = 3
)
->when($result = new SUT($innerIterator, $bufferSize))
->then
->object($result->getInnerIterator())
->isIdenticalTo($innerIterator)
->integer($result->getBufferSize())
->isEqualTo($bufferSize)
->let($buffer = $this->invoke($result)->getBuffer())
->object($buffer)
->isInstanceOf(\SplDoublyLinkedList::class)
->boolean($buffer->isEmpty())
->isTrue();
}

public function case_negative_buffer_size()
{
$this
->given(
$innerIterator = $this->getInnerIterator(),
$bufferSize = -42
)
->when($result = new SUT($innerIterator, $bufferSize))
->then
->integer($result->getBufferSize())
->isEqualTo(1);
}

public function case_null_buffer_size()
{
$this
->given(
$innerIterator = $this->getInnerIterator(),
$bufferSize = 0
)
->when($result = new SUT($innerIterator, $bufferSize))
->then
->integer($result->getBufferSize())
->isEqualTo(1);
}

public function case_fast_forward()
{
$this
->given($iterator = new SUT($this->getInnerIterator(), 3))
->when($result = iterator_to_array($iterator))
->then
->array($result)
->isEqualTo(['a', 'b', 'c', 'd', 'e'])
->array(iterator_to_array($this->invoke($iterator)->getBuffer()))
->isEqualTo([
0 => [
$iterator::BUFFER_KEY => 3,
$iterator::BUFFER_VALUE => 'd'
],
1 => [
$iterator::BUFFER_KEY => 4,
$iterator::BUFFER_VALUE => 'e'
],
2 => [
$iterator::BUFFER_KEY => null,
$iterator::BUFFER_VALUE => null
]
]);
}

public function case_fast_forward_with_too_big_buffer()
{
$this
->given($iterator = new SUT($this->getInnerIterator(), 10))
->when($result = iterator_to_array($iterator))
->then
->array($result)
->isEqualTo(['a', 'b', 'c', 'd', 'e'])
->array(iterator_to_array($this->invoke($iterator)->getBuffer()))
->isEqualTo([
0 => [
$iterator::BUFFER_KEY => 0,
$iterator::BUFFER_VALUE => 'a'
],
1 => [
$iterator::BUFFER_KEY => 1,
$iterator::BUFFER_VALUE => 'b'
],
2 => [
$iterator::BUFFER_KEY => 2,
$iterator::BUFFER_VALUE => 'c'
],
3 => [
$iterator::BUFFER_KEY => 3,
$iterator::BUFFER_VALUE => 'd'
],
4 => [
$iterator::BUFFER_KEY => 4,
$iterator::BUFFER_VALUE => 'e'
],
5 => [
$iterator::BUFFER_KEY => null,
$iterator::BUFFER_VALUE => null
]
]);
}

public function case_fast_forward_with_smallest_buffer()
{
$this
->given($iterator = new SUT($this->getInnerIterator(), 1))
->when($result = iterator_to_array($iterator))
->then
->array($result)
->isEqualTo(['a', 'b', 'c', 'd', 'e'])
->array(iterator_to_array($this->invoke($iterator)->getBuffer()))
->isEqualTo([
0 => [
$iterator::BUFFER_KEY => null,
$iterator::BUFFER_VALUE => null
]
]);
}

public function case_forward_forward_forward()
{
$this
->when($result = new SUT(new LUT\Map(['a', 'b', 'c']), 2))
->then
->variable($result->rewind())
->isNull()
->boolean($result->valid())
->isTrue()
->integer($result->key())
->isEqualTo(0)
->string($result->current())
->isEqualTo('a')
->variable($result->next())
->isNull()

->boolean($result->valid())
->isTrue()
->integer($result->key())
->isEqualTo(1)
->string($result->current())
->isEqualTo('b')
->variable($result->next())
->isNull()

->boolean($result->valid())
->isTrue()
->integer($result->key())
->isEqualTo(2)
->string($result->current())
->isEqualTo('c')
->variable($result->next())
->isNull()

->boolean($result->valid())
->isFalse()
->variable($result->key())
->isNull()
->variable($result->current())
->isNull();
}

public function case_forward_forward_backward_backward_forward_forward_forward_step_by_step()
{
$this
->when($result = new SUT(new LUT\Map(['a', 'b', 'c']), 3))
->then
->variable($result->rewind())
->isNull()
->array(iterator_to_array($this->invoke($result)->getBuffer()))
->isEqualTo([
0 => [
$result::BUFFER_KEY => 0,
$result::BUFFER_VALUE => 'a'
]
])

->boolean($result->valid())
->isTrue()
->integer($result->key())
->isEqualTo(0)
->string($result->current())
->isEqualTo('a')
->variable($result->next())
->isNull()
->array(iterator_to_array($this->invoke($result)->getBuffer()))
->isEqualTo([
0 => [
$result::BUFFER_KEY => 0,
$result::BUFFER_VALUE => 'a'
],
1 => [
$result::BUFFER_KEY => 1,
$result::BUFFER_VALUE => 'b'
]
])

->boolean($result->valid())
->isTrue()
->integer($result->key())
->isEqualTo(1)
->string($result->current())
->isEqualTo('b')
->variable($result->next())
->isNull()
->array(iterator_to_array($this->invoke($result)->getBuffer()))
->isEqualTo([
0 => [
$result::BUFFER_KEY => 0,
$result::BUFFER_VALUE => 'a'
],
1 => [
$result::BUFFER_KEY => 1,
$result::BUFFER_VALUE => 'b'
],
2 => [
$result::BUFFER_KEY => 2,
$result::BUFFER_VALUE => 'c'
]
])

->boolean($result->valid())
->isTrue()
->integer($result->key())
->isEqualTo(2)
->string($result->current())
->isEqualTo('c')
->variable($result->previous())
->isNull()
->array(iterator_to_array($this->invoke($result)->getBuffer()))
->isEqualTo([
0 => [
$result::BUFFER_KEY => 0,
$result::BUFFER_VALUE => 'a'
],
1 => [
$result::BUFFER_KEY => 1,
$result::BUFFER_VALUE => 'b'
],
2 => [
$result::BUFFER_KEY => 2,
$result::BUFFER_VALUE => 'c'
]
])

->boolean($result->valid())
->isTrue()
->integer($result->key())
->isEqualTo(1)
->string($result->current())
->isEqualTo('b')
->variable($result->previous())
->isNull()
->array(iterator_to_array($this->invoke($result)->getBuffer()))
->isEqualTo([
0 => [
$result::BUFFER_KEY => 0,
$result::BUFFER_VALUE => 'a'
],
1 => [
$result::BUFFER_KEY => 1,
$result::BUFFER_VALUE => 'b'
],
2 => [
$result::BUFFER_KEY => 2,
$result::BUFFER_VALUE => 'c'
]
])

->boolean($result->valid())
->isTrue()
->integer($result->key())
->isEqualTo(0)
->string($result->current())
->isEqualTo('a')
->variable($result->next())
->isNull()
->array(iterator_to_array($this->invoke($result)->getBuffer()))
->isEqualTo([
0 => [
$result::BUFFER_KEY => 0,
$result::BUFFER_VALUE => 'a'
],
1 => [
$result::BUFFER_KEY => 1,
$result::BUFFER_VALUE => 'b'
],
2 => [
$result::BUFFER_KEY => 2,
$result::BUFFER_VALUE => 'c'
]
])

->boolean($result->valid())
->isTrue()
->integer($result->key())
->isEqualTo(1)
->string($result->current())
->isEqualTo('b')
->variable($result->next())
->isNull()
->array(iterator_to_array($this->invoke($result)->getBuffer()))
->isEqualTo([
0 => [
$result::BUFFER_KEY => 0,
$result::BUFFER_VALUE => 'a'
],
1 => [
$result::BUFFER_KEY => 1,
$result::BUFFER_VALUE => 'b'
],
2 => [
$result::BUFFER_KEY => 2,
$result::BUFFER_VALUE => 'c'
]
])

->boolean($result->valid())
->isTrue()
->integer($result->key())
->isEqualTo(2)
->string($result->current())
->isEqualTo('c')
->variable($result->next())
->isNull()
->array(iterator_to_array($this->invoke($result)->getBuffer()))
->isEqualTo([
0 => [
$result::BUFFER_KEY => 1,
$result::BUFFER_VALUE => 'b'
],
1 => [
$result::BUFFER_KEY => 2,
$result::BUFFER_VALUE => 'c'
],
2 => [
$result::BUFFER_KEY => null,
$result::BUFFER_VALUE => null
]
])

->boolean($result->valid())
->isFalse()
->variable($result->key())
->isNull()
->variable($result->current())
->isNull();
}

public function case_backward_out_of_buffer()
{
$this
->when($result = new SUT(new LUT\Map(['a', 'b', 'c']), 1))
->then
->variable($result->rewind())
->isNull()
->boolean($result->valid())
->isTrue()
->integer($result->key())
->isEqualTo(0)
->string($result->current())
->isEqualTo('a')
->variable($result->next())
->isNull()

->boolean($result->valid())
->isTrue()
->integer($result->key())
->isEqualTo(1)
->string($result->current())
->isEqualTo('b')
->variable($result->previous())
->isNull()

->boolean($result->valid())
->isFalse();
}

public function case_rewind_rewind()
{
$this
->when($result = new SUT(new LUT\Map(['a', 'b']), 3))
->then
->variable($result->rewind())
->isNull()
->boolean($result->valid())
->isTrue()
->integer($result->key())
->isEqualTo(0)
->string($result->current())
->isEqualTo('a')
->variable($result->next())
->isNull()

->variable($result->rewind())
->isNull()
->boolean($result->valid())
->isTrue()
->integer($result->key())
->isEqualTo(0)
->string($result->current())
->isEqualTo('a')
->variable($result->next())
->isNull()

->array(iterator_to_array($this->invoke($result)->getBuffer()))
->isEqualTo([
0 => [
$result::BUFFER_KEY => 0,
$result::BUFFER_VALUE => 'a'
],
1 => [
$result::BUFFER_KEY => 1,
$result::BUFFER_VALUE => 'b'
]
]);
}

protected function getInnerIterator()
{
return new LUT\Map(['a', 'b', 'c', 'd', 'e']);
}
}
<?php



































namespace Hoa\Iterator;









class SplFileInfo extends \SplFileInfo
{





protected $_hash = null;






protected $_relativePath = null;









public function __construct($filename, $relativePath = null)
{
parent::__construct($filename);

if (-1 !== $mtime = $this->getMTime()) {
$this->_hash = md5($this->getPathname() . $mtime);
}

$this->_relativePath = $relativePath;

return;
}






public function getHash()
{
return $this->_hash;
}






public function getMTime()
{
try {
return parent::getMTime();
} catch (\RuntimeException $e) {
return -1;
}
}







public function setRelativePath($relativePath)
{
$old = $this->_relativePath;
$this->_relativePath = $relativePath;

return $old;
}






public function getRelativePath()
{
return $this->_relativePath;
}






public function getRelativePathname()
{
if (null === $relative = $this->getRelativePath()) {
return $this->getPathname();
}

return substr($this->getPathname(), strlen($relative));
}
}
<?php



































namespace Hoa\Iterator;









interface Aggregate extends \IteratorAggregate
{
}
<?php



































namespace Hoa\Iterator;

use Hoa\Consistency;









interface Iterator extends \Iterator
{
}




Consistency::flexEntity('Hoa\Iterator\Iterator');
<?php



































namespace Hoa\Iterator;









class FileSystem extends \FilesystemIterator
{





protected $_splFileInfoClass = null;












public function __construct($path, $flags = null, $splFileInfoClass = null)
{
$this->_splFileInfoClass = $splFileInfoClass;

if (null === $flags) {
parent::__construct($path);
} else {
parent::__construct($path, $flags);
}

return;
}







public function current()
{
$out = parent::current();

if (null !== $this->_splFileInfoClass &&
$out instanceof \SplFileInfo) {
$out->setInfoClass($this->_splFileInfoClass);
$out = $out->getFileInfo();
}

return $out;
}
}
<?php



































namespace Hoa\Iterator;









class CallbackFilter extends \CallbackFilterIterator
{
}
<?php



































namespace Hoa\Iterator;

use Hoa\Exception as HoaException;









class Exception extends HoaException
{
}
<?php



































namespace Hoa\Iterator;









class Append extends \AppendIterator
{
}
<?php



































namespace Hoa\Iterator;










class Demultiplexer implements Iterator
{





protected $_iterator = null;






protected $_current = null;






protected $_demuxer = null;










public function __construct(\Traversable $iterator, $demuxer)
{
if ($iterator instanceof \IteratorAggregate) {
$iterator = $iterator->getIterator();
}

$this->_iterator = $iterator;
$this->_demuxer = $demuxer;

return;
}






public function current()
{
if (null !== $this->_current) {
return $this->_current;
}

$demuxer = $this->_demuxer;

return $this->_current = $demuxer($this->_iterator->current());
}






public function key()
{
return $this->_iterator->key();
}






public function next()
{
$this->_current = null;

return $this->_iterator->next();
}






public function rewind()
{
return $this->_iterator->rewind();
}






public function valid()
{
return $this->_iterator->valid();
}
}
<?php



































namespace Hoa\Iterator;









class Glob extends \GlobIterator
{
}
<?php



































namespace Hoa\Iterator;









class Mock extends \EmptyIterator
{
}
<?php



































namespace Hoa\Iterator;









class Map extends \ArrayIterator
{
}
<?php



































namespace Hoa\Iterator;









interface Outer extends \OuterIterator
{
}
<?php



































namespace Hoa\Iterator;









class Limit extends \LimitIterator
{
}
<?php



































namespace Hoa\Iterator;









class Counter implements Iterator
{





protected $_from = 0;






protected $_key = 0;






protected $_i = 0;






protected $_to = 0;






protected $_step = 0;













public function __construct($from, $to, $step)
{
if ($step <= 0) {
throw new Exception(
'The step must be non-negative; given %d.',
0,
$step
);
}

$this->_from = $from;
$this->_to = $to;
$this->_step = $step;

return;
}






public function current()
{
return $this->_i;
}






public function key()
{
return $this->_key;
}






public function next()
{
++$this->_key;
$this->_i += $this->_step;

return;
}






public function rewind()
{
$this->_key = 0;
$this->_i = $this->_from;

return;
}






public function valid()
{
return $this->_i < $this->_to;
}
}
<?php



































namespace Hoa\Iterator;









class IteratorIterator extends \IteratorIterator
{
}
<?php



































namespace Hoa\Iterator;









abstract class Filter extends \FilterIterator
{
}
<?php



































namespace Hoa\Iterator\Recursive;









class Directory extends \RecursiveDirectoryIterator
{





protected $_splFileInfoClass = null;






protected $_relativePath = 0;






private static $_handlePath = null;












public function __construct($path, $flags = null, $splFileInfoClass = null)
{
if (null === $flags) {
parent::__construct($path);
} else {
parent::__construct($path, $flags);
}

if (null !== self::$_handlePath) {
$this->_relativePath = self::$_handlePath;
self::$_handlePath = null;
} else {
$this->_relativePath = $path;
}

$this->setSplFileInfoClass($splFileInfoClass);

return;
}







public function current()
{
$out = parent::current();

if (null !== $this->_splFileInfoClass &&
$out instanceof \SplFileInfo) {
$out->setInfoClass($this->_splFileInfoClass);
$out = $out->getFileInfo();

if ($out instanceof \Hoa\Iterator\SplFileInfo) {
$out->setRelativePath($this->getRelativePath());
}
}

return $out;
}







public function getChildren()
{
self::$_handlePath = $this->getRelativePath();
$out = parent::getChildren();

if ($out instanceof \RecursiveDirectoryIterator) {
$out->setSplFileInfoClass($this->_splFileInfoClass);
}

return $out;
}







public function setSplFileInfoClass($splFileInfoClass)
{
$this->_splFileInfoClass = $splFileInfoClass;

return;
}






public function getRelativePath()
{
return $this->_relativePath;
}
}
<?php



































namespace Hoa\Iterator\Recursive;

use Hoa\Consistency;









interface Recursive extends \RecursiveIterator
{
}




Consistency::flexEntity('Hoa\Iterator\Recursive\Recursive');
<?php



































namespace Hoa\Iterator\Recursive;









class Iterator extends \RecursiveIteratorIterator
{
}
<?php



































namespace Hoa\Iterator\Recursive;









class CallbackFilter extends \RecursiveCallbackFilterIterator
{
}
<?php



































namespace Hoa\Iterator\Recursive;










class Mock implements Recursive
{





protected $_iterator = null;








public function __construct(\Traversable $iterator)
{
if ($iterator instanceof \IteratorAggregate) {
$iterator = $iterator->getIterator();
}

$this->_iterator = $iterator;

return;
}






public function current()
{
return $this->_iterator->current();
}






public function key()
{
return $this->_iterator->key();
}






public function next()
{
return $this->_iterator->next();
}






public function rewind()
{
return $this->_iterator->rewind();
}






public function valid()
{
return $this->_iterator->valid();
}







public function getChildren()
{
return null;
}







public function hasChildren()
{
return false;
}
}
<?php



































namespace Hoa\Iterator\Recursive;









class Map extends \RecursiveArrayIterator
{
}
<?php



































namespace Hoa\Iterator\Recursive;









abstract class Filter extends \RecursiveFilterIterator
{
}
<?php



































namespace Hoa\Iterator\Recursive;

use Hoa\Iterator;













class RegularExpression extends Iterator\RegularExpression implements Recursive
{















public function __construct(
\RecursiveIterator $iterator,
$regex,
$mode = self::MATCH,
$flags = 0,
$pregFlags = 0
) {
parent::__construct($iterator, $regex, $mode, $flags, $pregFlags);

return;
}






public function accept()
{
return
true === $this->hasChildren() ||
true === parent::accept();
}






public function getChildren()
{
return new static(
true === $this->hasChildren()
? $this->getInnerIterator()->getChildren()
: null,
$this->getRegex(),
$this->getMode(),
$this->getFlags(),
$this->getPregFlags()
);
}






public function hasChildren()
{
return $this->getInnerIterator()->hasChildren();
}
}
<?php



































namespace Hoa\Iterator;









class Repeater implements Iterator
{





protected $_iterator = null;






protected $_n = 1;






protected $_i = 1;






protected $_body = null;











public function __construct(\Traversable $iterator, $n, $body = null)
{
if (0 >= $n) {
throw new Exception(
'n must be greater than 0, given %d.',
0,
$n
);
}

if ($iterator instanceof \IteratorAggregate) {
$iterator = $iterator->getIterator();
}

$this->_iterator = $iterator;
$this->_n = $n;
$this->_body = $body;

return;
}






public function current()
{
return $this->_iterator->current();
}






public function key()
{
return $this->_iterator->key();
}






public function next()
{
return $this->_iterator->next();
}






public function rewind()
{
return $this->_iterator->rewind();
}






public function valid()
{
$valid = $this->_iterator->valid();

if (true === $valid) {
return true;
}

if (null !== $this->_body) {
$handle = &$this->_body;
$handle($this->_i);
}

$this->rewind();

if ($this->_n <= $this->_i++) {
$this->_i = 1;

return false;
}

return true;
}
}
<?php



































namespace Hoa\Iterator;









interface Seekable extends \SeekableIterator
{
}
<?php



































namespace Hoa\Iterator;













class RegularExpression extends Filter
{





const USE_KEY = 1;






const INVERT_MATCH = 2;






const MATCH = 0;






const GET_MATCH = 1;






const ALL_MATCHES = 2;






const SPLIT = 3;






const REPLACE = 4;






protected $_regex = null;







protected $_mode = 0;







protected $_flags = 0;






protected $_pregFlags = 0;






protected $_key = 0;






protected $_current = null;






public $replacement = null;


















public function __construct(
\Iterator $iterator,
$regex,
$mode = self::MATCH,
$flags = 0,
$pregFlags = 0
) {
parent::__construct($iterator);

$this->_regex = $regex;
$this->setMode($mode);
$this->setFlags($flags);
$this->setPregFlags($pregFlags);
$this->replacement = null;

return;
}






public function accept()
{
if (is_array(parent::current())) {
return false;
}

$this->_key = parent::key();
$this->_current = parent::current();

$matches = [];
$useKey = $this->_flags & self::USE_KEY;
$subject = $useKey ? $this->_key : $this->_current;
$out = false;

switch ($this->_mode) {

case self::MATCH:
$out = 0 !== preg_match(
$this->_regex,
$subject,
$matches,
$this->_pregFlags
);

break;

case self::GET_MATCH:
$this->_current = [];
$out = 0 !== preg_match(
$this->_regex,
$subject,
$this->_current,
$this->_pregFlags
);

break;

case self::ALL_MATCHES:
$this->_current = [];
$out = 0 < preg_match_all(
$this->_regex,
$subject,
$this->_current,
$this->_pregFlags
);

break;

case self::SPLIT:
$this->_current = preg_split(
$this->_regex,
$subject,
null,
$this->_pregFlags
);

$out =
is_array($this->_current) &&
1 < count($this->_current);

break;

case self::REPLACE:
$numberOfReplacement = 0;
$result = preg_replace(
$this->_regex,
$this->replacement,
$subject,
-1,
$numberOfReplacement
);

if (null === $result || 0 === $numberOfReplacement) {
$out = false;

break;
}

if (0 !== $useKey) {
$this->_key = $result;
$out = true;

break;
}

$this->_current = $result;
$out = true;

break;

default:
$out = false;

break;
}

if (0 !== ($this->_flags & self::INVERT_MATCH)) {
return false === $out;
}

return $out;
}






public function key()
{
return $this->_key;
}






public function current()
{
return $this->_current;
}







public function setMode($mode)
{
if ($mode < self::MATCH || $mode > self::REPLACE) {
throw new \InvalidArgumentException(
'Illegal mode ' . $mode . '.'
);
}

$this->_mode = $mode;

return;
}







public function setFlags($flags)
{
$this->_flags = $flags;

return;
}







public function setPregFlags($pregFlags)
{
$this->_pregFlags = $pregFlags;

return;
}






public function getRegex()
{
return $this->_regex;
}






public function getMode()
{
return $this->_mode;
}






public function getFlags()
{
return $this->_flags;
}






public function getPregFlags()
{
return $this->_pregFlags;
}
}
<?php



































namespace Hoa\Iterator;









class Infinite extends \InfiniteIterator
{
}
<?php



































namespace Hoa\Iterator;









class NoRewind extends \NoRewindIterator
{
}
<?php



































namespace Hoa\Iterator;









class Lookahead extends IteratorIterator implements Outer
{





protected $_iterator = null;






protected $_key = 0;






protected $_current = null;






protected $_valid = false;








public function __construct(\Iterator $iterator)
{
$this->_iterator = $iterator;

return;
}






public function getInnerIterator()
{
return $this->_iterator;
}






public function current()
{
return $this->_current;
}






public function key()
{
return $this->_key;
}






public function next()
{
$innerIterator = $this->getInnerIterator();
$this->_valid = $innerIterator->valid();

if (false === $this->_valid) {
return;
}

$this->_key = $innerIterator->key();
$this->_current = $innerIterator->current();

return $innerIterator->next();
}






public function rewind()
{
$out = $this->getInnerIterator()->rewind();
$this->next();

return $out;
}






public function valid()
{
return $this->_valid;
}






public function hasNext()
{
return $this->getInnerIterator()->valid();
}






public function getNext()
{
return $this->getInnerIterator()->current();
}






public function getNextKey()
{
return $this->getInnerIterator()->key();
}
}
<?php



































namespace Hoa\Iterator;









class Lookbehind extends IteratorIterator implements Outer
{





protected $_iterator = null;






protected $_previousKey = -1;






protected $_previousCurrent = null;








public function __construct(\Iterator $iterator)
{
$this->_iterator = $iterator;

return;
}






public function getInnerIterator()
{
return $this->_iterator;
}






public function current()
{
return $this->getInnerIterator()->current();
}






public function key()
{
return $this->getInnerIterator()->key();
}






public function next()
{
$this->_previousKey = $this->key();
$this->_previousCurrent = $this->current();

return $this->getInnerIterator()->next();
}






public function rewind()
{
$this->_previousKey = -1;
$this->_previousCurrent = null;

return $this->getInnerIterator()->rewind();
}






public function valid()
{
return $this->getInnerIterator()->valid();
}






public function hasPrevious()
{
return -1 !== $this->_previousKey;
}






public function getPrevious()
{
return $this->_previousCurrent;
}






public function getPreviousKey()
{
return $this->_previousKey;
}
}
<?php



































namespace Hoa\Iterator;









class Buffer extends IteratorIterator implements Outer
{





const BUFFER_KEY = 0;






const BUFFER_VALUE = 1;






protected $_iterator = null;






protected $_buffer = null;






protected $_bufferSize = 1;









public function __construct(\Iterator $iterator, $bufferSize)
{
$this->_iterator = $iterator;
$this->_bufferSize = max($bufferSize, 1);
$this->_buffer = new \SplDoublyLinkedList();

return;
}






public function getInnerIterator()
{
return $this->_iterator;
}






protected function getBuffer()
{
return $this->_buffer;
}






public function getBufferSize()
{
return $this->_bufferSize;
}






public function current()
{
return $this->getBuffer()->current()[self::BUFFER_VALUE];
}






public function key()
{
return $this->getBuffer()->current()[self::BUFFER_KEY];
}






public function next()
{
$innerIterator = $this->getInnerIterator();
$buffer = $this->getBuffer();

$buffer->next();


 if (false === $buffer->valid()) {
for (
$bufferSize = count($buffer),
$maximumBufferSize = $this->getBufferSize();
$bufferSize >= $maximumBufferSize;
--$bufferSize
) {
$buffer->shift();
}

$innerIterator->next();

$buffer->push([
self::BUFFER_KEY => $innerIterator->key(),
self::BUFFER_VALUE => $innerIterator->current()
]);


 $buffer->setIteratorMode($buffer::IT_MODE_LIFO | $buffer::IT_MODE_KEEP);
$buffer->rewind();
$buffer->setIteratorMode($buffer::IT_MODE_FIFO | $buffer::IT_MODE_KEEP);
}

return;
}






public function previous()
{
$this->getBuffer()->prev();

return;
}






public function rewind()
{
$innerIterator = $this->getInnerIterator();
$buffer = $this->getBuffer();

$innerIterator->rewind();

if (true === $buffer->isEmpty()) {
$buffer->push([
self::BUFFER_KEY => $innerIterator->key(),
self::BUFFER_VALUE => $innerIterator->current()
]);
}

$buffer->rewind();

return;
}






public function valid()
{
return
$this->getBuffer()->valid() &&
$this->getInnerIterator()->valid();
}
}
<?php



































namespace Hoa\Consistency\Test\Unit;

use Hoa\Consistency\Consistency as SUT;
use Hoa\Test;









class Consistency extends Test\Unit\Suite
{
protected function _entity_exists_with_xxx($class, $interface, $trait)
{
$this
->given(
$this->function->class_exists = $class,
$this->function->interface_exists = $interface,
$this->function->trait_exists = $trait
)
->when($result = SUT::entityExists('foo'))
->then
->boolean($result)
->isTrue();
}

public function case_entity_exists_with_class()
{
return $this->_entity_exists_with_xxx(true, false, false);
}

public function case_entity_exists_with_interface()
{
return $this->_entity_exists_with_xxx(false, true, false);
}

public function case_entity_exists_with_trait()
{
return $this->_entity_exists_with_xxx(false, false, true);
}

public function case_entity_does_not_exists()
{
$this
->given(
$this->function->class_exists = false,
$this->function->interface_exists = false,
$this->function->trait_exists = false
)
->when($result = SUT::entityExists('foo'))
->then
->boolean($result)
->isFalse();
}

public function case_get_entity_shortest_name()
{
$this
->when($result = SUT::getEntityShortestName('Foo\Bar\Bar'))
->then
->string($result)
->isEqualTo('Foo\Bar');
}

public function case_get_entity_shortest_name_with_already_the_shortest()
{
$this
->when($result = SUT::getEntityShortestName('Foo\Bar'))
->then
->string($result)
->isEqualTo('Foo\Bar');
}

public function case_get_entity_shortest_name_with_no_namespace()
{
$this
->when($result = SUT::getEntityShortestName('Foo'))
->then
->string($result)
->isEqualTo('Foo');
}

public function case_is_keyword()
{
$this
->given(
$keywords = [
'__HALT_COMPILER',
'abstract',
'and',
'array',
'as',
'bool',
'break',
'callable',
'case',
'catch',
'class',
'clone',
'const',
'continue',
'declare',
'default',
'die',
'do',
'echo',
'else',
'elseif',
'empty',
'enddeclare',
'endfor',
'endforeach',
'endif',
'endswitch',
'endwhile',
'eval',
'exit',
'extends',
'false',
'final',
'float',
'for',
'foreach',
'function',
'global',
'goto',
'if',
'implements',
'include',
'include_once',
'instanceof',
'insteadof',
'int',
'interface',
'isset',
'list',
'mixed',
'namespace',
'new',
'null',
'numeric',
'object',
'or',
'print',
'private',
'protected',
'public',
'require',
'require_once',
'resource',
'return',
'static',
'string',
'switch',
'throw',
'trait',
'true',
'try',
'unset',
'use',
'var',
'void',
'while',
'xor',
'yield',
'__CLASS__',
'__DIR__',
'__FILE__',
'__FUNCTION__',
'__LINE__',
'__METHOD__',
'__NAMESPACE__',
'__TRAIT__'
]
)
->when(function () use ($keywords) {
foreach ($keywords as $keyword) {
$this
->boolean(SUT::isKeyword($keyword))
->isTrue();
}
});
}

public function case_is_identifier()
{
$this
->given($_identifier = $this->realdom->regex('#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x80-\xff]*$#'))
->when(function () use ($_identifier) {
foreach ($this->sampleMany($_identifier, 1000) as $identifier) {
$this
->boolean(SUT::isIdentifier($identifier))
->isTrue();
}
});
}

public function case_register_shutdown_function()
{
$self = $this;

$this
->given(
$callable = function () {
},
$this->function->register_shutdown_function = function ($_callable) use (&$called, $self, &$callable) {
$called = true;

$self
->variable($_callable)
->isEqualTo($callable);

return true;
}
)
->when($result = SUT::registerShutdownFunction($callable))
->then
->boolean($result)
->isTrue();
}

public function case_get_php_binary_with_constant()
{
$this
->given($this->constant->PHP_BINARY = '/foo/php')
->when($result = SUT::getPHPBinary())
->then
->string($result)
->isEqualTo('/foo/php');
}

public function case_get_php_binary_with_server()
{
$this
->given(
$this->function->defined = false,
$_SERVER['_'] = '/bar/php'
)
->when($result = SUT::getPHPBinary())
->then
->string($result)
->isEqualTo('/bar/php');
}

public function case_get_php_binary_with_bin_directory()
{
unset($_SERVER['_']);

$this
->given(
$this->function->defined = false,
$this->function->file_exists = true,
$this->function->realpath = '/baz/php'
)
->when($result = SUT::getPHPBinary())
->then
->string($result)
->isEqualTo('/baz/php');
}

public function case_uuid()
{
$this
->given($this->function->mt_rand = 42)
->when($result = SUT::uuid())
->then
->string($result)
->isEqualTo('002a002a-002a-402a-802a-002a002a002a');
}

public function case_uuid_all_differents()
{
$this
->when(function () {
$uuids = [];

for ($i = 0; $i < 10000; ++$i) {
$uuids[] = SUT::uuid();
}

$this
->integer(count($uuids))
->isEqualTo(count(array_unique($uuids)));
});
}
}
<?php



































namespace Hoa\Consistency\Test\Unit;

use Hoa\Consistency\Xcallable as SUT;
use Hoa\Test;









class Xcallable extends Test\Unit\Suite
{
public function case_form_function()
{
$this
->when($result = new SUT('strtoupper'))
->then
->string($result('foo'))
->isEqualTo('FOO')
->string($result->getValidCallback())
->isEqualTo('strtoupper')
->string($result->getHash())
->isEqualTo('function#strtoupper')
->isEqualTo($result . '')
->object($reflection = $result->getReflection())
->isInstanceOf('ReflectionFunction')
->string($reflection->getName())
->isEqualTo('strtoupper');
}

public function case_form_class___method()
{
$this
->when($result = new SUT(__CLASS__ . '::strtoupper'))
->then
->string($result('foo'))
->isEqualTo('FOO')
->array($result->getValidCallback())
->isEqualTo([__CLASS__, 'strtoupper'])
->string($result->getHash())
->isEqualTo('class#' . __CLASS__ . '::strtoupper')
->isEqualTo($result . '')
->object($reflection = $result->getReflection())
->isInstanceOf('ReflectionMethod')
->string($reflection->getName())
->isEqualTo('strtoupper');
}

public function case_form_class_method()
{
$this
->when($result = new SUT(__CLASS__, 'strtoupper'))
->then
->string($result('foo'))
->isEqualTo('FOO')
->array($result->getValidCallback())
->isEqualTo([__CLASS__, 'strtoupper'])
->string($result->getHash())
->isEqualTo('class#' . __CLASS__ . '::strtoupper')
->isEqualTo($result . '')
->object($reflection = $result->getReflection())
->isInstanceOf('ReflectionMethod')
->string($reflection->getName())
->isEqualTo('strtoupper');
}

public function case_form_object_method()
{
$this
->when($result = new SUT($this, 'strtolower'))
->then
->string($result('FOO'))
->isEqualTo('foo')
->array($result->getValidCallback())
->isEqualTo([$this, 'strtolower'])
->string($result->getHash())
->matches(
'/^object\([^:]+\)#' .
preg_quote(__CLASS__) .
'::strtolower$/'
)
->isEqualTo($result . '')
->object($reflection = $result->getReflection())
->isInstanceOf('ReflectionMethod')
->string($reflection->getName())
->isEqualTo('strtolower');
}

public function case_form_object_invoke()
{
$this
->when($result = new SUT($this))
->then
->string($result('foo'))
->isEqualTo('FOO')
->array($result->getValidCallback())
->isEqualTo([$this, '__invoke'])
->string($result->getHash())
->matches(
'/^object\([^:]+\)#' .
preg_quote(__CLASS__) .
'::__invoke$/'
)
->isEqualTo($result . '')
->object($reflection = $result->getReflection())
->isInstanceOf('ReflectionMethod')
->string($reflection->getName())
->isEqualTo('__invoke');
}

public function case_form_closure()
{
$this
->given(
$closure = function ($string) {
return strtoupper($string);
}
)
->when($result = new SUT($closure))
->then
->string($result('foo'))
->isEqualTo('FOO')
->object($result->getValidCallback())
->isIdenticalTo($closure)
->string($result->getHash())
->matches('/^closure\([^:]+\)$/')
->isEqualTo($result . '')
->object($reflection = $result->getReflection())
->isInstanceOf('ReflectionFunction')
->string($reflection->getName())
->isEqualTo('Hoa\Consistency\Test\Unit\{closure}');
}

public function case_form_array_of_class_method()
{
$this
->when($result = new SUT([__CLASS__, 'strtoupper']))
->then
->string($result('foo'))
->isEqualTo('FOO')
->array($result->getValidCallback())
->isEqualTo([__CLASS__, 'strtoupper'])
->string($result->getHash())
->isEqualTo('class#' . __CLASS__ . '::strtoupper')
->isEqualTo($result . '')
->object($reflection = $result->getReflection())
->isInstanceOf('ReflectionMethod')
->string($reflection->getName())
->isEqualTo('strtoupper');
}

public function case_form_array_of_object_method()
{
$this
->when($result = new SUT([$this, 'strtolower']))
->then
->string($result('FOO'))
->isEqualTo('foo')
->array($result->getValidCallback())
->isEqualTo([$this, 'strtolower'])
->string($result->getHash())
->matches(
'/^object\([^:]+\)#' .
preg_quote(__CLASS__) .
'::strtolower$/'
)
->isEqualTo($result . '')
->object($reflection = $result->getReflection())
->isInstanceOf('ReflectionMethod')
->string($reflection->getName())
->isEqualTo('strtolower');
}

public function case_form_able_not_a_string()
{
$this
->exception(function () {
new SUT(__CLASS__, 123);
})
->isInstanceOf('Hoa\Consistency\Exception');
}

public function case_form_function_not_defined()
{
$this
->exception(function () {
new SUT('__hoa_test_undefined_function__');
})
->isInstanceOf('Hoa\Consistency\Exception');
}

public function case_form_able_cannot_be_deduced()
{
$this
->given($this->function->method_exists = false)
->exception(function () {
new SUT($this);
})
->isInstanceOf('Hoa\Consistency\Exception');
}

public function case_invoke()
{
$this
->given(
$callable = new SUT(
function ($x, $y, $z) {
return [$x, $y, $z];
}
)
)
->when($result = $callable(7, [4.2], 'foo'))
->then
->array($result)
->isEqualTo([7, [4.2], 'foo']);
}

public function case_distribute_arguments()
{
$this
->given(
$callable = new SUT(
function ($x, $y, $z) {
return [$x, $y, $z];
}
)
)
->when($result = $callable->distributeArguments([7, [4.2], 'foo']))
->then
->array($result)
->isEqualTo([7, [4.2], 'foo']);
}

protected function _get_valid_callback_stream_xxx($argument, $method)
{
$this
->given(
$stream = new \Mock\Hoa\Stream\IStream\Out(),
$arguments = [$argument],
$xcallable = new SUT($stream)
)
->when($result = $xcallable->getValidCallback($arguments))
->then
->array($result)
->isEqualTo([$stream, $method]);
}

public function case_get_valid_callback_stream_character()
{
return $this->_get_valid_callback_stream_xxx('f', 'writeCharacter');
}

public function case_get_valid_callback_stream_string()
{
return $this->_get_valid_callback_stream_xxx('foo', 'writeString');
}

public function case_get_valid_callback_stream_boolean()
{
return $this->_get_valid_callback_stream_xxx(true, 'writeBoolean');
}

public function case_get_valid_callback_stream_integer()
{
return $this->_get_valid_callback_stream_xxx(7, 'writeInteger');
}

public function case_get_valid_callback_stream_array()
{
return $this->_get_valid_callback_stream_xxx([4, 2], 'writeArray');
}

public function case_get_valid_callback_stream_float()
{
return $this->_get_valid_callback_stream_xxx(4.2, 'writeFloat');
}

public function case_get_valid_callback_stream_other()
{
return $this->_get_valid_callback_stream_xxx($this, 'writeAll');
}

public static function strtoupper($string)
{
return strtoupper($string);
}

public function strtolower($string)
{
return strtolower($string);
}

public function __invoke($string)
{
return strtoupper($string);
}

public function __toString()
{
return 'hello';
}
}
<?php



































namespace Hoa\Consistency\Test\Unit;

use Hoa\Consistency\Exception as SUT;
use Hoa\Test;









class Exception extends Test\Unit\Suite
{
public function case_hoa_exception()
{
$this
->when($result = new SUT('foo', 0))
->then
->object($result)
->isInstanceOf('Hoa\Exception\Exception');
}
}
<?php



































namespace Hoa\Consistency\Test\Unit;

use Hoa\Consistency\Autoloader as SUT;
use Hoa\Test;









class Autoloader extends Test\Unit\Suite
{
public function case_add_namespace_prepend()
{
$this
->given(
$autoloader = new SUT(),
$prefix = 'Foo\Bar\\',
$baseDirectoryA = 'Source/Foo/Bar/',
$baseDirectoryB = 'Source/Foo/Bar/'
)
->when(
$autoloader->addNamespace($prefix, $baseDirectoryA),
$result = $autoloader->addNamespace($prefix, $baseDirectoryB)
)
->then
->boolean($autoloader->hasBaseDirectory($prefix))
->isTrue()
->array($autoloader->getBaseDirectories($prefix))
->isEqualTo([
$baseDirectoryB,
$baseDirectoryA
]);
}

public function case_add_namespace_append()
{
$this
->given(
$autoloader = new SUT(),
$prefix = 'Foo\Bar\\',
$baseDirectoryA = 'Source/Foo/Bar/',
$baseDirectoryB = 'Source/Foo/Bar/'
)
->when(
$autoloader->addNamespace($prefix, $baseDirectoryA),
$result = $autoloader->addNamespace($prefix, $baseDirectoryB)
)
->then
->boolean($autoloader->hasBaseDirectory($prefix))
->isTrue()
->array($autoloader->getBaseDirectories($prefix))
->isEqualTo([
$baseDirectoryA,
$baseDirectoryB
]);
}

public function case_add_namespace_with_invalid_prefix()
{
$this
->given(
$autoloader = new SUT(),
$prefix = '\\\\Foo\Bar',
$baseDirectory = 'Source/Foo/Bar/'
)
->when($result = $autoloader->addNamespace($prefix, $baseDirectory))
->then
->boolean($autoloader->hasBaseDirectory('Foo\Bar\\'))
->isTrue()
->array($autoloader->getBaseDirectories('Foo\Bar\\'))
->isEqualTo([$baseDirectory]);
}

public function case_add_namespace_with_invalid_base_directory()
{
$this
->given(
$autoloader = new SUT(),
$prefix = 'Foo\Bar\\',
$baseDirectory = 'Source/Foo/Bar'
)
->when($result = $autoloader->addNamespace($prefix, $baseDirectory))
->then
->boolean($autoloader->hasBaseDirectory('Foo\Bar\\'))
->isTrue()
->array($autoloader->getBaseDirectories('Foo\Bar\\'))
->isEqualTo(['Source/Foo/Bar/']);
}

public function case_add_namespace_with_crazy_invalid_base_directory()
{
$this
->given(
$autoloader = new SUT(),
$prefix = 'Foo\Bar\\',
$baseDirectory = 'Source/Foo/Bar/////'
)
->when($result = $autoloader->addNamespace($prefix, $baseDirectory))
->then
->boolean($autoloader->hasBaseDirectory('Foo\Bar\\'))
->isTrue()
->array($autoloader->getBaseDirectories('Foo\Bar\\'))
->isEqualTo(['Source/Foo/Bar/']);
}

public function case_load()
{
$this
->given(
$autoloader = new \Mock\Hoa\Consistency\Autoloader(),
$autoloader->addNamespace('Foo\Bar\\', 'Source/Foo/Bar/'),
$this->calling($autoloader)->requireFile = function ($file) {
return $file;
}
)
->when($result = $autoloader->load('Foo\Bar\Baz\Qux'))
->then
->string($result)
->isEqualTo('Source/Foo/Bar/Baz/Qux.php');
}

public function case_load_invalid_entity()
{
$this
->given($autoloader = new SUT())
->when($result = $autoloader->load('Foo'))
->then
->variable($result)
->isNull();
}

public function case_load_flex_entity()
{
$self = $this;

$this
->given(
$autoloader = new \Mock\Hoa\Consistency\Autoloader(),
$autoloader->addNamespace('Foo\Bar\\', 'Source/Foo/'),
$this->calling($autoloader)->runAutoloaderStack = function ($entity) use ($self, &$called) {
$called = true;
$self
->string($entity)
->isEqualTo('Foo\Bar\Baz\Baz');

return;
},
$autoloader->register()
)
->when($result = $autoloader->load('Foo\Bar\Baz'))
->then
->variable($result)
->isNull()
->boolean($called)
->isTrue();
}

public function case_load_unmapped_flex_entity()
{
$self = $this;

$this
->given(
$autoloader = new \Mock\Hoa\Consistency\Autoloader(),
$this->calling($autoloader)->runAutoloaderStack = function ($entity) use ($self, &$called) {
$called = true;

return;
},
$autoloader->register()
)
->when($result = $autoloader->load('Foo\Bar\Baz'))
->then
->variable($result)
->isNull()
->variable($called)
->isNull();
}

public function case_require_existing_file()
{
$this
->given(
$autoloader = new SUT(),

$this->function->file_exists = true,

$constantName = 'HOA_TEST_' . uniqid(),
$filename = 'hoa://Test/Vfs/Foo?type=file',

file_put_contents($filename, '<?php define("' . $constantName . '", "BAR");')
)
->when($result = $autoloader->requireFile($filename))
->then
->boolean($result)
->isTrue()
->string(constant($constantName))
->isEqualTo('BAR');
}

public function case_require_not_existing_file()
{
$this
->given(
$autoloader = new SUT(),
$this->function->file_exists = false
)
->when($result = $autoloader->requireFile('/hoa/flatland'))
->then
->boolean($result)
->isFalse();
}

public function case_has_not_base_directory()
{
$this
->given($autoloader = new SUT())
->when($result = $autoloader->hasBaseDirectory('foo'))
->then
->boolean($result)
->isFalse();
}

public function case_get_base_undeclared_namespace_prefix()
{
$this
->given($autoloader = new SUT())
->when($result = $autoloader->getBaseDirectories('foo'))
->then
->array($result)
->isEmpty();
}

public function case_dnew()
{
$this
->given($classname = 'Hoa\Consistency\Autoloader')
->when($result = SUT::dnew($classname))
->then
->object($result)
->isInstanceOf($classname);
}

public function case_dnew_unknown_class()
{
$this
->given($this->function->spl_autoload_call = null)
->exception(function () {
SUT::dnew('Foo');
})
->isInstanceOf('ReflectionException');
}

public function case_get_loaded_classes()
{
$this
->given(
$declaredClasses = get_declared_classes(),
$this->function->get_declared_classes = $declaredClasses
)
->when($result = SUT::getLoadedClasses())
->then
->array($result)
->isEqualTo($declaredClasses);
}

public function case_register()
{
$self = $this;

$this
->given($autoloader = new SUT())
->when($result = $autoloader->register())
->then
->boolean($result)
->isTrue()
->array($autoloader->getRegisteredAutoloaders())
->isEqualTo(spl_autoload_functions());
}

public function case_unregister()
{
$this
->given(
$autoloader = new SUT(),
$oldRegisteredAutoloaders = $autoloader->getRegisteredAutoloaders()
)
->when($result = $autoloader->register())
->then
->boolean($result)
->isTrue()
->integer(count($autoloader->getRegisteredAutoloaders()))
->isEqualTo(count($oldRegisteredAutoloaders) + 1)

->when($result = $autoloader->unregister())
->then
->boolean($result)
->isTrue()
->array($autoloader->getRegisteredAutoloaders())
->isEqualTo($oldRegisteredAutoloaders);
}
}
<?php



































namespace Hoa\Consistency
{










class Consistency
{







public static function entityExists($entityName, $autoloader = false)
{
return
class_exists($entityName, $autoloader) ||
interface_exists($entityName, false) ||
trait_exists($entityName, false);
}







public static function getEntityShortestName($entityName)
{
$parts = explode('\\', $entityName);
$count = count($parts);

if (1 >= $count) {
return $entityName;
}

if ($parts[$count - 2] === $parts[$count - 1]) {
return implode('\\', array_slice($parts, 0, -1));
}

return $entityName;
}







public static function flexEntity($entityName)
{
return class_alias(
$entityName,
static::getEntityShortestName($entityName),
false
);
}







public static function isKeyword($word)
{
static $_list = [

 '__halt_compiler',
'abstract',
'and',
'array',
'as',
'bool',
'break',
'callable',
'case',
'catch',
'class',
'clone',
'const',
'continue',
'declare',
'default',
'die',
'do',
'echo',
'else',
'elseif',
'empty',
'enddeclare',
'endfor',
'endforeach',
'endif',
'endswitch',
'endwhile',
'eval',
'exit',
'extends',
'false',
'final',
'float',
'for',
'foreach',
'function',
'global',
'goto',
'if',
'implements',
'include',
'include_once',
'instanceof',
'insteadof',
'int',
'interface',
'isset',
'list',
'mixed',
'namespace',
'new',
'null',
'numeric',
'object',
'or',
'print',
'private',
'protected',
'public',
'require',
'require_once',
'resource',
'return',
'static',
'string',
'switch',
'throw',
'trait',
'true',
'try',
'unset',
'use',
'var',
'void',
'while',
'xor',
'yield',


 '__class__',
'__dir__',
'__file__',
'__function__',
'__line__',
'__method__',
'__namespace__',
'__trait__'
];

return in_array(strtolower($word), $_list);
}







public static function isIdentifier($id)
{
return 0 !== preg_match(
'#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x80-\xff]*$#',
$id
);
}








public static function registerShutdownFunction($callable)
{
return register_shutdown_function($callable);
}






public static function getPHPBinary()
{
if (defined('PHP_BINARY')) {
return PHP_BINARY;
}

if (isset($_SERVER['_'])) {
return $_SERVER['_'];
}

foreach (['', '.exe'] as $extension) {
if (file_exists($_ = PHP_BINDIR . DS . 'php' . $extension)) {
return realpath($_);
}
}

return null;
}






public static function uuid()
{
return sprintf(
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0xffff)
);
}
}

}

namespace
{

if (70000 > PHP_VERSION_ID && false === interface_exists('Throwable', false)) {



interface Throwable
{
public function getMessage();
public function getCode();
public function getFile();
public function getLine();
public function getTrace();
public function getPrevious();
public function getTraceAsString();
public function __toString();
}
}




if (50600 > PHP_VERSION_ID) {
$define = function ($constantName, $constantValue, $case = false) {
if (!defined($constantName)) {
return define($constantName, $constantValue, $case);
}

return false;
};

$define('STREAM_CRYPTO_METHOD_TLSv1_0_SERVER', 8);
$define('STREAM_CRYPTO_METHOD_TLSv1_1_SERVER', 16);
$define('STREAM_CRYPTO_METHOD_TLSv1_2_SERVER', 32);
$define('STREAM_CRYPTO_METHOD_ANY_SERVER', 62);

$define('STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT', 9);
$define('STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT', 17);
$define('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT', 33);
$define('STREAM_CRYPTO_METHOD_ANY_CLIENT', 63);
}

if (!function_exists('curry')) {




















function curry($callable)
{
$arguments = func_get_args();
array_shift($arguments);
$ii = array_keys($arguments, …, true);

return function () use ($callable, $arguments, $ii) {
return call_user_func_array(
$callable,
array_replace($arguments, array_combine($ii, func_get_args()))
);
};
}
}




Hoa\Consistency\Consistency::flexEntity('Hoa\Consistency\Consistency');

}
<?php



































namespace Hoa\Consistency;

use Hoa\Event;
use Hoa\Stream;











class Xcallable
{





protected $_callback = null;






protected $_hash = null;


















public function __construct($call, $able = '')
{
if ($call instanceof \Closure) {
$this->_callback = $call;

return;
}

if (!is_string($able)) {
throw new Exception(
'Bad callback form; the able part must be a string.',
0
);
}

if ('' === $able) {
if (is_string($call)) {
if (false === strpos($call, '::')) {
if (!function_exists($call)) {
throw new Exception(
'Bad callback form; function %s does not exist.',
1,
$call
);
}

$this->_callback = $call;

return;
}

list($call, $able) = explode('::', $call);
} elseif (is_object($call)) {
if ($call instanceof Stream\IStream\Out) {
$able = null;
} elseif (method_exists($call, '__invoke')) {
$able = '__invoke';
} else {
throw new Exception(
'Bad callback form; an object but without a known ' .
'method.',
2
);
}
} elseif (is_array($call) && isset($call[0])) {
if (!isset($call[1])) {
return $this->__construct($call[0]);
}

return $this->__construct($call[0], $call[1]);
} else {
throw new Exception(
'Bad callback form.',
3
);
}
}

$this->_callback = [$call, $able];

return;
}







public function __invoke()
{
$arguments = func_get_args();
$valid = $this->getValidCallback($arguments);

return call_user_func_array($valid, $arguments);
}







public function distributeArguments(array $arguments)
{
return call_user_func_array([$this, '__invoke'], $arguments);
}








public function getValidCallback(array &$arguments = [])
{
$callback = $this->_callback;
$head = null;

if (isset($arguments[0])) {
$head = &$arguments[0];
}


 
 if (null !== $head &&
is_array($callback) &&
null === $callback[1]) {
if ($head instanceof Event\Bucket) {
$head = $head->getData();
}

switch ($type = gettype($head)) {
case 'string':
if (1 === strlen($head)) {
$method = 'writeCharacter';
} else {
$method = 'writeString';
}

break;

case 'boolean':
case 'integer':
case 'array':
$method = 'write' . ucfirst($type);

break;

case 'double':
$method = 'writeFloat';

break;

default:
$method = 'writeAll';
$head = $head . "\n";
}

$callback[1] = $method;
}

return $callback;
}











public function getHash()
{
if (null !== $this->_hash) {
return $this->_hash;
}

$_ = &$this->_callback;

if (is_string($_)) {
return $this->_hash = 'function#' . $_;
}

if (is_array($_)) {
return
$this->_hash =
(is_object($_[0])
? 'object(' . spl_object_hash($_[0]) . ')' .
'#' . get_class($_[0])
: 'class#' . $_[0]) .
'::' .
(null !== $_[1]
? $_[1]
: '???');
}

return $this->_hash = 'closure(' . spl_object_hash($_) . ')';
}







public function getReflection()
{
$arguments = func_get_args();
$valid = $this->getValidCallback($arguments);

if (is_string($valid)) {
return new \ReflectionFunction($valid);
}

if ($valid instanceof \Closure) {
return new \ReflectionFunction($valid);
}

if (is_array($valid)) {
if (is_string($valid[0])) {
if (false === method_exists($valid[0], $valid[1])) {
return new \ReflectionClass($valid[0]);
}

return new \ReflectionMethod($valid[0], $valid[1]);
}

$object = new \ReflectionObject($valid[0]);

if (null === $valid[1]) {
return $object;
}

return $object->getMethod($valid[1]);
}
}






public function __toString()
{
return $this->getHash();
}
}
<?php



































namespace Hoa\Consistency;

use Hoa\Exception as HoaException;









class Exception extends HoaException
{
}
<?php



































if (false === defined('HOA')) {
define('HOA', true);
}

if (false === defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50400) {
throw new Exception(
'Hoa needs at least PHP5.4 to work; you have ' . phpversion() . '.'
);
}

require_once __DIR__ . DIRECTORY_SEPARATOR . 'Autoloader.php';
require_once __DIR__ . DIRECTORY_SEPARATOR . 'Consistency.php';

$define = function ($constantName, $constantValue, $case = false) {
if (!defined($constantName)) {
return define($constantName, $constantValue, $case);
}

return false;
};

$define('SUCCEED', true);
$define('FAILED', false);
$define('…', '__hoa_core_fill');
$define('DS', DIRECTORY_SEPARATOR);
$define('PS', PATH_SEPARATOR);
$define('ROOT_SEPARATOR', ';');
$define('RS', ROOT_SEPARATOR);
$define('CRLF', "\r\n");
$define('OS_WIN', defined('PHP_WINDOWS_VERSION_PLATFORM'));
$define('S_64_BITS', PHP_INT_SIZE == 8);
$define('S_32_BITS', !S_64_BITS);
$define('PHP_INT_MIN', ~PHP_INT_MAX);
$define('PHP_FLOAT_MIN', (float) PHP_INT_MIN);
$define('PHP_FLOAT_MAX', (float) PHP_INT_MAX);
$define('π', M_PI);
$define('nil', null);
$define('_public', 1);
$define('_protected', 2);
$define('_private', 4);
$define('_static', 8);
$define('_abstract', 16);
$define('_pure', 32);
$define('_final', 64);
$define('_dynamic', ~_static);
$define('_concrete', ~_abstract);
$define('_overridable', ~_final);
$define('WITH_COMPOSER', class_exists('Composer\Autoload\ClassLoader', false) ||
('cli' === PHP_SAPI &&
file_exists(__DIR__ . DS . '..' . DS . '..' . DS . 'autoload.php')));








if (!function_exists('xcallable')) {
function xcallable($call, $able = '')
{
if ($call instanceof Hoa\Consistency\Xcallable) {
return $call;
}

return new Hoa\Consistency\Xcallable($call, $able);
}
}
<?php



































namespace Hoa\Consistency;









class Autoloader
{





protected $_namespacePrefixesToBaseDirectories = [];












public function addNamespace($prefix, $baseDirectory, $prepend = false)
{
$prefix = trim($prefix, '\\') . '\\';
$baseDirectory = rtrim($baseDirectory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;

if (false === isset($this->_namespacePrefixesToBaseDirectories[$prefix])) {
$this->_namespacePrefixesToBaseDirectories[$prefix] = [];
}

if (true === $prepend) {
array_unshift(
$this->_namespacePrefixesToBaseDirectories[$prefix],
$baseDirectory
);
} else {
array_push(
$this->_namespacePrefixesToBaseDirectories[$prefix],
$baseDirectory
);
}

return;
}







public function load($entity)
{
$entityPrefix = $entity;
$hasBaseDirectory = false;

while (false !== $pos = strrpos($entityPrefix, '\\')) {
$currentEntityPrefix = substr($entity, 0, $pos + 1);
$entityPrefix = rtrim($currentEntityPrefix, '\\');
$entitySuffix = substr($entity, $pos + 1);
$entitySuffixAsPath = str_replace('\\', '/', $entitySuffix);

if (false === $this->hasBaseDirectory($currentEntityPrefix)) {
continue;
}

$hasBaseDirectory = true;

foreach ($this->getBaseDirectories($currentEntityPrefix) as $baseDirectory) {
$file = $baseDirectory . $entitySuffixAsPath . '.php';

if (false !== $this->requireFile($file)) {
return $file;
}
}
}

if (true === $hasBaseDirectory &&
$entity === Consistency::getEntityShortestName($entity) &&
false !== $pos = strrpos($entity, '\\')) {
return $this->runAutoloaderStack(
$entity . '\\' . substr($entity, $pos + 1)
);
}

return null;
}







public function requireFile($filename)
{
if (false === file_exists($filename)) {
return false;
}

require $filename;

return true;
}







public function hasBaseDirectory($namespacePrefix)
{
return isset($this->_namespacePrefixesToBaseDirectories[$namespacePrefix]);
}







public function getBaseDirectories($namespacePrefix)
{
if (false === $this->hasBaseDirectory($namespacePrefix)) {
return [];
}

return $this->_namespacePrefixesToBaseDirectories[$namespacePrefix];
}






public static function getLoadedClasses()
{
return get_declared_classes();
}







public function runAutoloaderStack($entity)
{
return spl_autoload_call($entity);
}







public function register($prepend = false)
{
return spl_autoload_register([$this, 'load'], true, $prepend);
}






public function unregister()
{
return spl_autoload_unregister([$this, 'load']);
}






public function getRegisteredAutoloaders()
{
return spl_autoload_functions();
}









public static function dnew($classname, array $arguments = [])
{
$classname = ltrim($classname, '\\');

if (false === Consistency::entityExists($classname, false)) {
spl_autoload_call($classname);
}

$class = new \ReflectionClass($classname);

if (empty($arguments) || false === $class->hasMethod('__construct')) {
return $class->newInstance();
}

return $class->newInstanceArgs($arguments);
}
}




$autoloader = new Autoloader();
$autoloader->addNamespace('Hoa', dirname(__DIR__));
$autoloader->register();
<?php

if (!function_exists('getallheaders')) {






function getallheaders()
{
$headers = array();

$copy_server = array(
'CONTENT_TYPE' => 'Content-Type',
'CONTENT_LENGTH' => 'Content-Length',
'CONTENT_MD5' => 'Content-Md5',
);

foreach ($_SERVER as $key => $value) {
if (substr($key, 0, 5) === 'HTTP_') {
$key = substr($key, 5);
if (!isset($copy_server[$key]) || !isset($_SERVER[$key])) {
$key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key))));
$headers[$key] = $value;
}
} elseif (isset($copy_server[$key])) {
$headers[$copy_server[$key]] = $value;
}
}

if (!isset($headers['Authorization'])) {
if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
$headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
} elseif (isset($_SERVER['PHP_AUTH_USER'])) {
$basic_pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
$headers['Authorization'] = 'Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $basic_pass);
} elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) {
$headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST'];
}
}

return $headers;
}

}
<?php
use Codeception\Module\Sequence;

if (!function_exists('sq')) {
    function sq($id = null)
    {
        if ($id and isset(Sequence::$hash[$id])) {
            return Sequence::$hash[$id];
        }
        $prefix = str_replace('{id}', $id, Sequence::$prefix);
        $sequence = $prefix . uniqid($id);
        if ($id) {
            Sequence::$hash[$id] = $sequence;
        }
        return $sequence;
    }
}

if (!function_exists('sqs')) {
    function sqs($id = null)
    {
        if ($id and isset(Sequence::$suiteHash[$id])) {
            return Sequence::$suiteHash[$id];
        }
        $prefix = str_replace('{id}', $id, Sequence::$prefix);
        $sequence = $prefix . uniqid($id);
        if ($id) {
            Sequence::$suiteHash[$id] = $sequence;
        }
        return $sequence;
    }
}
<?php
namespace Codeception\Module;

use Codeception\Module as CodeceptionModule;
use Codeception\Exception\ModuleException;
use Codeception\TestInterface;

/**
 * Sequence solves data cleanup issue in alternative way.
 * Instead cleaning up the database between tests,
 * you can use generated unique names, that should not conflict.
 * When you create article on a site, for instance, you can assign it a unique name and then check it.
 *
 * This module has no actions, but introduces a function `sq` for generating unique sequences within test and
 * `sqs` for generating unique sequences across suite.
 *
 * ### Usage
 *
 * Function `sq` generates sequence, the only parameter it takes, is id.
 * You can get back to previously generated sequence using that id:
 *
 * ``` php
 * <?php
 * sq('post1'); // post1_521fbc63021eb
 * sq('post2'); // post2_521fbc6302266
 * sq('post1'); // post1_521fbc63021eb
 * ```
 *
 * Example:
 *
 * ``` php
 * <?php
 * $I->wantTo('create article');
 * $I->click('New Article');
 * $I->fillField('Title', sq('Article'));
 * $I->fillField('Body', 'Demo article with Lorem Ipsum');
 * $I->click('save');
 * $I->see(sq('Article') ,'#articles')
 * ```
 *
 * Populating Database:
 *
 * ``` php
 * <?php
 *
 * for ($i = 0; $i<10; $i++) {
 *      $I->haveInDatabase('users', array('login' => sq("user$i"), 'email' => sq("user$i").'@email.com');
 * }
 * ?>
 * ```
 *
 * Cest Suite tests:
 *
 * ``` php
 * <?php
 * class UserTest
 * {
 *     public function createUser(AcceptanceTester $I)
 *     {
 *         $I->createUser(sqs('user') . '@mailserver.com', sqs('login'), sqs('pwd'));
 *     }
 *
 *     public function checkEmail(AcceptanceTester $I)
 *     {
 *         $I->seeInEmailTo(sqs('user') . '@mailserver.com', sqs('login'));
 *     }
 *
 *     public function removeUser(AcceptanceTester $I)
 *     {
 *         $I->removeUser(sqs('user') . '@mailserver.com');
 *     }
 * }
 * ?>
 * ```
 *
 * ### Config
 *
 * By default produces unique string with param as a prefix:
 *
 * ```
 * sq('user') => 'user_876asd8as87a'
 * ```
 *
 * This behavior can be configured using `prefix` config param.
 *
 * Old style sequences:
 *
 * ```yaml
 * Sequence:
 *     prefix: '_'
 * ```
 *
 * Using id param inside prefix:
 *
 * ```yaml
 * Sequence:
 *     prefix: '{id}.'
 * ```
 */
class Sequence extends CodeceptionModule
{
    public static $hash = [];
    public static $suiteHash = [];
    public static $prefix = '';

    protected $config = ['prefix' => '{id}_'];

    public function _initialize()
    {
        static::$prefix = $this->config['prefix'];
    }

    public function _after(TestInterface $t)
    {
        self::$hash = [];
    }

    public function _afterSuite()
    {
        self::$suiteHash = [];
    }
}

if (!function_exists('sq') && !function_exists('sqs')) {
    require_once __DIR__ . '/../Util/sq.php';
} else {
    throw new ModuleException('Codeception\Module\Sequence', "function 'sq' and 'sqs' already defined");
}
<?php

namespace Codeception\Lib\Driver;

use Codeception\Exception\ModuleConfigException;
use Codeception\Exception\ModuleException;
use MongoDB\Database;

class MongoDb
{
    const DEFAULT_PORT = 27017;

    private $legacy;
    private $dbh;
    private $dsn;
    private $dbName;
    private $host;
    private $user;
    private $password;
    private $client;
    private $quiet = '';

    public static function connect($dsn, $user, $password)
    {
        throw new \Exception(__CLASS__ . '::connect() - hm, it looked like this method had become obsolete...');
    }

    /**
     * Connect to the Mongo server using the MongoDB extension.
     */
    protected function setupMongoDB($dsn, $options)
    {
        try {
            $this->client = new \MongoDB\Client($dsn, $options);
            $this->dbh    = $this->client->selectDatabase($this->dbName);
        } catch (\MongoDB\Driver\Exception $e) {
            throw new ModuleException($this, sprintf('Failed to open Mongo connection: %s', $e->getMessage()));
        }
    }

    /**
     * Connect to the Mongo server using the legacy mongo extension.
     */
    protected function setupMongo($dsn, $options)
    {
        try {
            $this->client = new \MongoClient($dsn, $options);
            $this->dbh    = $this->client->selectDB($this->dbName);
        } catch (\MongoConnectionException $e) {
            throw new ModuleException($this, sprintf('Failed to open Mongo connection: %s', $e->getMessage()));
        }
    }

    /**
     * Clean up the Mongo database using the MongoDB extension.
     */
    protected function cleanupMongoDB()
    {
        try {
            $this->dbh->drop();
        } catch (\MongoDB\Driver\Exception $e) {
            throw new \Exception(sprintf('Failed to drop the DB: %s', $e->getMessage()));
        }
    }

    /**
     * Clean up the Mongo database using the legacy Mongo extension.
     */
    protected function cleanupMongo()
    {
        try {
            $list = $this->dbh->listCollections();
        } catch (\MongoException $e) {
            throw new \Exception(sprintf('Failed to list collections of the DB: %s', $e->getMessage()));
        }
        foreach ($list as $collection) {
            try {
                $collection->drop();
            } catch (\MongoException $e) {
                throw new \Exception(sprintf('Failed to drop collection: %s', $e->getMessage()));
            }
        }
    }

    /**
     * $dsn has to contain db_name after the host. E.g. "mongodb://localhost:27017/mongo_test_db"
     *
     * @static
     *
     * @param $dsn
     * @param $user
     * @param $password
     *
     * @throws ModuleConfigException
     * @throws \Exception
     */
    public function __construct($dsn, $user, $password)
    {
        $this->legacy = extension_loaded('mongodb') === false &&
            class_exists('\\MongoClient') &&
            strpos(\MongoClient::VERSION, 'mongofill') === false;

        /* defining DB name */
        $this->dbName = preg_replace('/\?.*/', '', substr($dsn, strrpos($dsn, '/') + 1));

        if (strlen($this->dbName) == 0) {
            throw new ModuleConfigException($this, 'Please specify valid $dsn with DB name after the host:port');
        }

        /* defining host */
        if (strpos($dsn, 'mongodb://') !== false) {
            $this->host = str_replace('mongodb://', '', preg_replace('/\?.*/', '', $dsn));
        } else {
            $this->host = $dsn;
        }
        $this->host = rtrim(str_replace($this->dbName, '', $this->host), '/');

        $options = [
            'connect' => true
        ];

        if ($user && $password) {
            $options += [
                'username' => $user,
                'password' => $password
            ];
        }

        $this->{$this->legacy ? 'setupMongo' : 'setupMongoDB'}($dsn, $options);

        $this->dsn = $dsn;
        $this->user = $user;
        $this->password = $password;
    }

    /**
     * @static
     *
     * @param $dsn
     * @param $user
     * @param $password
     *
     * @return MongoDb
     */
    public static function create($dsn, $user, $password)
    {
        return new MongoDb($dsn, $user, $password);
    }

    public function cleanup()
    {
        $this->{$this->legacy ? 'cleanupMongo' : 'cleanupMongoDB'}();
    }

    /**
     * dump file has to be a javascript document where one can use all the mongo shell's commands
     * just FYI: this file can be easily created be RockMongo's export button
     *
     * @param $dumpFile
     */
    public function load($dumpFile)
    {
        $cmd = sprintf(
            'mongo %s %s%s',
            $this->host . '/' . $this->dbName,
            $this->createUserPasswordCmdString(),
            escapeshellarg($dumpFile)
        );
        shell_exec($cmd);
    }

    public function loadFromMongoDump($dumpFile)
    {
        list($host, $port) = $this->getHostPort();
        $cmd = sprintf(
            "mongorestore %s --host %s --port %s -d %s %s %s",
            $this->quiet,
            $host,
            $port,
            $this->dbName,
            $this->createUserPasswordCmdString(),
            escapeshellarg($dumpFile)
        );
        shell_exec($cmd);
    }

    public function loadFromTarGzMongoDump($dumpFile)
    {
        list($host, $port) = $this->getHostPort();
        $getDirCmd = sprintf(
            "tar -tf %s | awk 'BEGIN { FS = \"/\" } ; { print $1 }' | uniq",
            escapeshellarg($dumpFile)
        );
        $dirCountCmd = $getDirCmd . ' | wc -l';
        if (trim(shell_exec($dirCountCmd)) !== '1') {
            throw new ModuleException(
                $this,
                'Archive MUST contain single directory with db dump'
            );
        }
        $dirName = trim(shell_exec($getDirCmd));
        $cmd = sprintf(
            'tar -xzf %s && mongorestore %s --host %s --port %s -d %s %s %s && rm -r %s',
            escapeshellarg($dumpFile),
            $this->quiet,
            $host,
            $port,
            $this->dbName,
            $this->createUserPasswordCmdString(),
            $dirName,
            $dirName
        );
        shell_exec($cmd);
    }

    private function createUserPasswordCmdString()
    {
        if ($this->user && $this->password) {
            return sprintf(
                '--username %s --password %s ',
                $this->user,
                $this->password
            );
        }
        return '';
    }

    public function getDbh()
    {
        return $this->dbh;
    }

    public function setDatabase($dbName)
    {
        $this->dbh = $this->client->{$this->legacy ? 'selectDB' : 'selectDatabase'}($dbName);
    }

    public function getDbHash()
    {
        $result = $this->dbh->command(['dbHash' => 1]);

        if (!is_array($result)) {
            $result = iterator_to_array($result);
        }

        return isset($result[0]->md5) ? $result[0]->md5 : null;
    }

    /**
     * Determine if this driver is using the legacy extension or not.
     *
     * @return bool
     */
    public function isLegacy()
    {
        return $this->legacy;
    }

    private function getHostPort()
    {
        $hostPort = explode(':', $this->host);
        if (count($hostPort) === 2) {
            return $hostPort;
        }
        if (count($hostPort) === 1) {
            return [$hostPort[0], self::DEFAULT_PORT];
        }
        throw new ModuleException($this, '$dsn MUST be like (mongodb://)<host>:<port>/<db name>');
    }

    public function setQuiet($quiet)
    {
        $this->quiet = $quiet ? '--quiet' : '';
    }
}
<?php
namespace Codeception\Module;

use Codeception\Lib\Interfaces\RequiresPackage;
use Codeception\Module as CodeceptionModule;
use Codeception\Configuration;
use Codeception\Exception\ModuleConfigException;
use Codeception\Exception\ModuleException;
use Codeception\Lib\Driver\MongoDb as MongoDbDriver;
use Codeception\TestInterface;

/**
 * Works with MongoDb database.
 *
 * The most important function of this module is cleaning database before each test.
 * To have your database properly cleaned you should configure it to access the database.
 *
 * In order to have your database populated with data you need a valid js file with data (of the same style which can be fed up to mongo binary)
 * File can be generated by RockMongo export command
 * You can also use directory, generated by ```mongodump``` tool or it's ```.tar.gz``` archive (not available for Windows systems), generated by ```tar -czf <archive_file_name>.tar.gz <path_to dump directory>```.
 * Just put it in ``` tests/_data ``` dir (by default) and specify path to it in config.
 * Next time after database is cleared all your data will be restored from dump.
 * The DB preparation should as following:
 * - clean database
 * - system collection system.users should contain the user which will be authenticated while script performs DB operations
 *
 * Connection is done by MongoDb driver, which is stored in Codeception\Lib\Driver namespace.
 * Check out the driver if you get problems loading dumps and cleaning databases.
 *
 * HINT: This module can be used with [Mongofill](https://github.com/mongofill/mongofill) library which is Mongo client written in PHP without extension.
 *
 * ## Status
 *
 * * Maintainer: **judgedim**, **davert**
 * * Stability: **beta**
 * * Contact: davert@codeception.com
 *
 * *Please review the code of non-stable modules and provide patches if you have issues.*
 *
 * ## Config
 *
 * * dsn *required* - MongoDb DSN with the db name specified at the end of the host after slash
 * * user *required* - user to access database
 * * password *required* - password
 * * dump_type *required* - type of dump.
 *   One of 'js' (MongoDb::DUMP_TYPE_JS), 'mongodump' (MongoDb::DUMP_TYPE_MONGODUMP) or 'mongodump-tar-gz' (MongoDb::DUMP_TYPE_MONGODUMP_TAR_GZ).
 *   default: MongoDb::DUMP_TYPE_JS).
 * * dump - path to database dump
 * * populate: true - should the dump be loaded before test suite is started.
 * * cleanup: true - should the dump be reloaded after each test.
 *   Boolean or 'dirty'. If cleanup is set to 'dirty', the dump is only reloaded if any data has been written to the db during a test. This is
 *   checked using the [dbHash](https://docs.mongodb.com/manual/reference/command/dbHash/) command.
 *
 */
class MongoDb extends CodeceptionModule implements RequiresPackage
{
    const DUMP_TYPE_JS = 'js';
    const DUMP_TYPE_MONGODUMP = 'mongodump';
    const DUMP_TYPE_MONGODUMP_TAR_GZ = 'mongodump-tar-gz';

    /**
     * @api
     * @var
     */
    public $dbh;

    /**
     * @var
     */

    protected $dumpFile;
    protected $isDumpFileEmpty = true;

    protected $dbHash;

    protected $config = [
        'populate'  => true,
        'cleanup'   => true,
        'dump'      => null,
        'dump_type' => self::DUMP_TYPE_JS,
        'user'      => null,
        'password'  => null,
        'quiet'     => false,
    ];

    protected $populated = false;

    /**
     * @var \Codeception\Lib\Driver\MongoDb
     */
    public $driver;

    protected $requiredFields = ['dsn'];

    public function _initialize()
    {

        try {
            $this->driver = MongoDbDriver::create(
                $this->config['dsn'],
                $this->config['user'],
                $this->config['password']
            );
        } catch (\MongoConnectionException $e) {
            throw new ModuleException(__CLASS__, $e->getMessage() . ' while creating Mongo connection');
        }

        // starting with loading dump
        if ($this->config['populate']) {
            $this->cleanup();
            $this->loadDump();
            $this->populated = true;
        }
    }

    private function validateDump()
    {
        if ($this->config['dump'] && ($this->config['cleanup'] or ($this->config['populate']))) {
            if (!file_exists(Configuration::projectDir() . $this->config['dump'])) {
                throw new ModuleConfigException(
                    __CLASS__,
                    "File with dump doesn't exist.\n
                    Please, check path for dump file: " . $this->config['dump']
                );
            }
            $this->dumpFile = Configuration::projectDir() . $this->config['dump'];
            $this->isDumpFileEmpty = false;

            if ($this->config['dump_type'] === self::DUMP_TYPE_JS) {
                $content = file_get_contents($this->dumpFile);
                $content = trim(preg_replace('%/\*(?:(?!\*/).)*\*/%s', "", $content));
                if (!sizeof(explode("\n", $content))) {
                    $this->isDumpFileEmpty = true;
                }
                return;
            }

            if ($this->config['dump_type'] === self::DUMP_TYPE_MONGODUMP) {
                if (!is_dir($this->dumpFile)) {
                    throw new ModuleConfigException(
                        __CLASS__,
                        "Dump must be a directory.\n
                        Please, check dump: " . $this->config['dump']
                    );
                }
                $this->isDumpFileEmpty = true;
                $dumpDir = dir($this->dumpFile);
                while (false !== ($entry = $dumpDir->read())) {
                    if ($entry !== '..' && $entry !== '.') {
                        $this->isDumpFileEmpty = false;
                        break;
                    }
                }
                $dumpDir->close();
                return;
            }

            if ($this->config['dump_type'] === self::DUMP_TYPE_MONGODUMP_TAR_GZ) {
                if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
                    throw new ModuleConfigException(
                        __CLASS__,
                        "Tar gunzip archives are not supported for Windows systems"
                    );
                }
                if (!preg_match('/(\.tar\.gz|\.tgz)$/', $this->dumpFile)) {
                    throw new ModuleConfigException(
                        __CLASS__,
                        "Dump file must be a valid tar gunzip archive.\n
                        Please, check dump file: " . $this->config['dump']
                    );
                }
                return;
            }

            throw new ModuleConfigException(
                __CLASS__,
                '\"dump_type\" must be one of ["'
                . self::DUMP_TYPE_JS . '", "'
                . self::DUMP_TYPE_MONGODUMP . '", "'
                . self::DUMP_TYPE_MONGODUMP_TAR_GZ . '"].'
            );
        }
    }

    public function _before(TestInterface $test)
    {
        if ($this->shouldCleanup()) {
            $this->cleanup();
            $this->loadDump();
        }
    }

    public function _after(TestInterface $test)
    {
        $this->populated = false;
    }

    protected function shouldCleanup()
    {
        if ($this->populated) {
            return false;
        }

        return $this->config['cleanup'] === 'dirty'
            ? ($this->dbHash === null || $this->driver->getDbHash() !== $this->dbHash)
            : (bool)$this->config['cleanup'];
    }

    protected function cleanup()
    {
        $dbh = $this->driver->getDbh();
        if (!$dbh) {
            throw new ModuleConfigException(
                __CLASS__,
                "No connection to database. Remove this module from config if you don't need database repopulation"
            );
        }
        try {
            $this->driver->cleanup();
        } catch (\Exception $e) {
            throw new ModuleException(__CLASS__, $e->getMessage());
        }
    }

    protected function loadDump()
    {
        $this->validateDump();

        if ($this->isDumpFileEmpty) {
            return;
        }

        try {
            if ($this->config['dump_type'] === self::DUMP_TYPE_JS) {
                $this->driver->load($this->dumpFile);
            }
            if ($this->config['dump_type'] === self::DUMP_TYPE_MONGODUMP) {
                $this->driver->setQuiet($this->config['quiet']);
                $this->driver->loadFromMongoDump($this->dumpFile);
            }
            if ($this->config['dump_type'] === self::DUMP_TYPE_MONGODUMP_TAR_GZ) {
                $this->driver->setQuiet($this->config['quiet']);
                $this->driver->loadFromTarGzMongoDump($this->dumpFile);
            }
        } catch (\Exception $e) {
            throw new ModuleException(__CLASS__, $e->getMessage());
        }

        if ($this->config['cleanup'] === 'dirty') {
            $this->dbHash = $this->driver->getDbHash();
        }
    }

    /**
     * Specify the database to use
     *
     * ``` php
     * <?php
     * $I->useDatabase('db_1');
     * ```
     *
     * @param $dbName
     */
    public function useDatabase($dbName)
    {
        $this->driver->setDatabase($dbName);
    }

    /**
     * Inserts data into collection
     *
     * ``` php
     * <?php
     * $I->haveInCollection('users', array('name' => 'John', 'email' => 'john@coltrane.com'));
     * $user_id = $I->haveInCollection('users', array('email' => 'john@coltrane.com'));
     * ```
     *
     * @param $collection
     * @param array $data
     */
    public function haveInCollection($collection, array $data)
    {
        $collection = $this->driver->getDbh()->selectCollection($collection);
        if ($this->driver->isLegacy()) {
            $collection->insert($data);
            return $data['_id'];
        }

        $response = $collection->insertOne($data);
        return (string) $response->getInsertedId();
    }

    /**
     * Checks if collection contains an item.
     *
     * ``` php
     * <?php
     * $I->seeInCollection('users', array('name' => 'miles'));
     * ```
     *
     * @param $collection
     * @param array $criteria
     */
    public function seeInCollection($collection, $criteria = [])
    {
        $collection = $this->driver->getDbh()->selectCollection($collection);
        $res = $collection->count($criteria);
        \PHPUnit\Framework\Assert::assertGreaterThan(0, $res);
    }

    /**
     * Checks if collection doesn't contain an item.
     *
     * ``` php
     * <?php
     * $I->dontSeeInCollection('users', array('name' => 'miles'));
     * ```
     *
     * @param $collection
     * @param array $criteria
     */
    public function dontSeeInCollection($collection, $criteria = [])
    {
        $collection = $this->driver->getDbh()->selectCollection($collection);
        $res = $collection->count($criteria);
        \PHPUnit\Framework\Assert::assertLessThan(1, $res);
    }

    /**
     * Grabs a data from collection
     *
     * ``` php
     * <?php
     * $user = $I->grabFromCollection('users', array('name' => 'miles'));
     * ```
     *
     * @param $collection
     * @param array $criteria
     * @return array
     */
    public function grabFromCollection($collection, $criteria = [])
    {
        $collection = $this->driver->getDbh()->selectCollection($collection);
        return $collection->findOne($criteria);
    }

    /**
     * Grabs the documents count from a collection
     *
     * ``` php
     * <?php
     * $count = $I->grabCollectionCount('users');
     * // or
     * $count = $I->grabCollectionCount('users', array('isAdmin' => true));
     * ```
     *
     * @param $collection
     * @param array $criteria
     * @return integer
     */
    public function grabCollectionCount($collection, $criteria = [])
    {
        $collection = $this->driver->getDbh()->selectCollection($collection);
        return $collection->count($criteria);
    }

    /**
     * Asserts that an element in a collection exists and is an Array
     *
     * ``` php
     * <?php
     * $I->seeElementIsArray('users', array('name' => 'John Doe') , 'data.skills');
     * ```
     *
     * @param String $collection
     * @param Array $criteria
     * @param String $elementToCheck
     */
    public function seeElementIsArray($collection, $criteria = [], $elementToCheck = null)
    {
        $collection = $this->driver->getDbh()->selectCollection($collection);

        $res = $collection->count(
            array_merge(
                $criteria,
                [
                    $elementToCheck => ['$exists' => true],
                    '$where' => "Array.isArray(this.{$elementToCheck})"
                ]
            )
        );
        if ($res > 1) {
            throw new \PHPUnit\Framework\ExpectationFailedException(
                'Error: you should test against a single element criteria when asserting that elementIsArray'
            );
        }
        \PHPUnit\Framework\Assert::assertEquals(1, $res, 'Specified element is not a Mongo Object');
    }

    /**
     * Asserts that an element in a collection exists and is an Object
     *
     * ``` php
     * <?php
     * $I->seeElementIsObject('users', array('name' => 'John Doe') , 'data');
     * ```
     *
     * @param String $collection
     * @param Array $criteria
     * @param String $elementToCheck
     */
    public function seeElementIsObject($collection, $criteria = [], $elementToCheck = null)
    {
        $collection = $this->driver->getDbh()->selectCollection($collection);

        $res = $collection->count(
            array_merge(
                $criteria,
                [
                    $elementToCheck => ['$exists' => true],
                    '$where' => "! Array.isArray(this.{$elementToCheck}) && isObject(this.{$elementToCheck})"
                ]
            )
        );
        if ($res > 1) {
            throw new \PHPUnit\Framework\ExpectationFailedException(
                'Error: you should test against a single element criteria when asserting that elementIsObject'
            );
        }
        \PHPUnit\Framework\Assert::assertEquals(1, $res, 'Specified element is not a Mongo Object');
    }

    /**
     * Count number of records in a collection
     *
     * ``` php
     * <?php
     * $I->seeNumElementsInCollection('users', 2);
     * $I->seeNumElementsInCollection('users', 1, array('name' => 'miles'));
     * ```
     *
     * @param $collection
     * @param integer $expected
     * @param array $criteria
     */
    public function seeNumElementsInCollection($collection, $expected, $criteria = [])
    {
        $collection = $this->driver->getDbh()->selectCollection($collection);
        $res = $collection->count($criteria);
        \PHPUnit\Framework\Assert::assertSame($expected, $res);
    }

    /**
     * Returns list of classes and corresponding packages required for this module
     */
    public function _requires()
    {
        return ['MongoDB\Client' => '"mongodb/mongodb": "^1.0"'];
    }
}
<?php

namespace Codeception\Module;

use Codeception\Lib\Notification;

/**
 * Special module for using asserts in your tests.
 */
class Asserts extends AbstractAsserts
{
    /**
     * Handles and checks exception called inside callback function.
     * Either exception class name or exception instance should be provided.
     *
     * ```php
     * <?php
     * $I->expectException(MyException::class, function() {
     *     $this->doSomethingBad();
     * });
     *
     * $I->expectException(new MyException(), function() {
     *     $this->doSomethingBad();
     * });
     * ```
     * If you want to check message or exception code, you can pass them with exception instance:
     * ```php
     * <?php
     * // will check that exception MyException is thrown with "Don't do bad things" message
     * $I->expectException(new MyException("Don't do bad things"), function() {
     *     $this->doSomethingBad();
     * });
     * ```
     *
     * @deprecated Use expectThrowable() instead
     * @param \Exception|string $exception
     * @param callable $callback
     */
    public function expectException($exception, $callback)
    {
        Notification::deprecate('Use expectThrowable() instead');
        $this->expectThrowable($exception, $callback);
    }

    /**
     * Handles and checks throwables (Exceptions/Errors) called inside the callback function.
     * Either throwable class name or throwable instance should be provided.
     *
     * ```php
     * <?php
     * $I->expectThrowable(MyThrowable::class, function() {
     *     $this->doSomethingBad();
     * });
     *
     * $I->expectThrowable(new MyException(), function() {
     *     $this->doSomethingBad();
     * });
     * ```
     * If you want to check message or throwable code, you can pass them with throwable instance:
     * ```php
     * <?php
     * // will check that throwable MyError is thrown with "Don't do bad things" message
     * $I->expectThrowable(new MyError("Don't do bad things"), function() {
     *     $this->doSomethingBad();
     * });
     * ```
     *
     * @param \Throwable|string $throwable
     * @param callable $callback
     */
    public function expectThrowable($throwable, $callback)
    {
        if (is_object($throwable)) {
            $class = get_class($throwable);
            $msg = $throwable->getMessage();
            $code = $throwable->getCode();
        } else {
            $class = $throwable;
            $msg = null;
            $code = null;
        }

        try {
            $callback();
        } catch (\Exception $t) {
            $this->checkThrowable($t, $class, $msg, $code);
            return;
        } catch (\Throwable $t) {
            $this->checkThrowable($t, $class, $msg, $code);
            return;
        }

        $this->fail("Expected throwable of class '$class' to be thrown, but nothing was caught");
    }

    /**
     * Check if the given throwable matches the expected data,
     * fail (throws an exception) if it does not.
     *
     * @param \Throwable $throwable
     * @param string $expectedClass
     * @param string $expectedMsg
     * @param int $expectedCode
     */
    protected function checkThrowable($throwable, $expectedClass, $expectedMsg, $expectedCode)
    {
        if (!($throwable instanceof $expectedClass)) {
            $this->fail(sprintf(
                "Exception of class '$expectedClass' expected to be thrown, but class '%s' was caught",
                get_class($throwable)
            ));
        }

        if (null !== $expectedMsg && $throwable->getMessage() !== $expectedMsg) {
            $this->fail(sprintf(
                "Exception of class '$expectedClass' expected to have message '$expectedMsg', but actual message was '%s'",
                $throwable->getMessage()
            ));
        }

        if (null !== $expectedCode && $throwable->getCode() !== $expectedCode) {
            $this->fail(sprintf(
                "Exception of class '$expectedClass' expected to have code '$expectedCode', but actual code was '%s'",
                $throwable->getCode()
            ));
        }

        $this->assertTrue(true); // increment assertion counter
    }
}
<?php

namespace Codeception\Module;

use Codeception\Module as CodeceptionModule;
use Codeception\Util\Shared\Asserts as SharedAsserts;

abstract class AbstractAsserts extends CodeceptionModule
{
    use SharedAsserts {
        assertArrayHasKey as public;
        assertArrayNotHasKey as public;
        assertClassHasAttribute as public;
        assertClassHasStaticAttribute as public;
        assertClassNotHasAttribute as public;
        assertClassNotHasStaticAttribute as public;
        assertContains as public;
        assertContainsEquals as public;
        assertContainsOnly as public;
        assertContainsOnlyInstancesOf as public;
        assertCount as public;
        assertDirectoryDoesNotExist as public;
        assertDirectoryExists as public;
        assertDirectoryIsNotReadable as public;
        assertDirectoryIsNotWritable as public;
        assertDirectoryIsReadable as public;
        assertDirectoryIsWritable as public;
        assertDoesNotMatchRegularExpression as public;
        assertEmpty as public;
        assertEquals as public;
        assertEqualsCanonicalizing as public;
        assertEqualsIgnoringCase as public;
        assertEqualsWithDelta as public;
        assertFalse as public;
        assertFileDoesNotExist as public;
        assertFileEquals as public;
        assertFileEqualsCanonicalizing as public;
        assertFileEqualsIgnoringCase as public;
        assertFileExists as public;
        assertFileIsNotReadable as public;
        assertFileIsNotWritable as public;
        assertFileIsReadable as public;
        assertFileIsWritable as public;
        assertFileNotEquals as public;
        assertFileNotEqualsCanonicalizing as public;
        assertFileNotEqualsIgnoringCase as public;
        assertFileNotExists as public;
        assertFinite as public;
        assertGreaterOrEquals as public;
        assertGreaterThan as public;
        assertGreaterThanOrEqual as public;
        assertInfinite as public;
        assertInstanceOf as public;
        assertIsArray as public;
        assertIsBool as public;
        assertIsCallable as public;
        assertIsClosedResource as public;
        assertIsEmpty as public;
        assertIsFloat as public;
        assertIsInt as public;
        assertIsIterable as public;
        assertIsNotArray as public;
        assertIsNotBool as public;
        assertIsNotCallable as public;
        assertIsNotClosedResource as public;
        assertIsNotFloat as public;
        assertIsNotInt as public;
        assertIsNotIterable as public;
        assertIsNotNumeric as public;
        assertIsNotObject as public;
        assertIsNotReadable as public;
        assertIsNotResource as public;
        assertIsNotScalar as public;
        assertIsNotString as public;
        assertIsNotWritable as public;
        assertIsNumeric as public;
        assertIsObject as public;
        assertIsReadable as public;
        assertIsResource as public;
        assertIsScalar as public;
        assertIsString as public;
        assertIsWritable as public;
        assertJson as public;
        assertJsonFileEqualsJsonFile as public;
        assertJsonFileNotEqualsJsonFile as public;
        assertJsonStringEqualsJsonFile as public;
        assertJsonStringEqualsJsonString as public;
        assertJsonStringNotEqualsJsonFile as public;
        assertJsonStringNotEqualsJsonString as public;
        assertLessOrEquals as public;
        assertLessThan as public;
        assertLessThanOrEqual as public;
        assertMatchesRegularExpression as public;
        assertNan as public;
        assertNotContains as public;
        assertNotContainsEquals as public;
        assertNotContainsOnly as public;
        assertNotCount as public;
        assertNotEmpty as public;
        assertNotEquals as public;
        assertNotEqualsCanonicalizing as public;
        assertNotEqualsIgnoringCase as public;
        assertNotEqualsWithDelta as public;
        assertNotFalse as public;
        assertNotInstanceOf as public;
        assertNotNull as public;
        assertNotRegExp as public;
        assertNotSame as public;
        assertNotSameSize as public;
        assertNotTrue as public;
        assertNull as public;
        assertObjectHasAttribute as public;
        assertObjectNotHasAttribute as public;
        assertRegExp as public;
        assertSame as public;
        assertSameSize as public;
        assertStringContainsString as public;
        assertStringContainsStringIgnoringCase as public;
        assertStringEndsNotWith as public;
        assertStringEndsWith as public;
        assertStringEqualsFile as public;
        assertStringEqualsFileCanonicalizing as public;
        assertStringEqualsFileIgnoringCase as public;
        assertStringMatchesFormat as public;
        assertStringMatchesFormatFile as public;
        assertStringNotContainsString as public;
        assertStringNotContainsStringIgnoringCase as public;
        assertStringNotEqualsFile as public;
        assertStringNotEqualsFileCanonicalizing as public;
        assertStringNotEqualsFileIgnoringCase as public;
        assertStringNotMatchesFormat as public;
        assertStringNotMatchesFormatFile as public;
        assertStringStartsNotWith as public;
        assertStringStartsWith as public;
        assertThat as public;
        assertThatItsNot as public;
        assertTrue as public;
        assertXmlFileEqualsXmlFile as public;
        assertXmlFileNotEqualsXmlFile as public;
        assertXmlStringEqualsXmlFile as public;
        assertXmlStringEqualsXmlString as public;
        assertXmlStringNotEqualsXmlFile as public;
        assertXmlStringNotEqualsXmlString as public;
        fail as public;
        markTestIncomplete as public;
        markTestSkipped as public;
    }
}<?php
namespace Codeception\PHPUnit\ResultPrinter;

use Codeception\Lib\Console\Output;
use Codeception\PHPUnit\ConsolePrinter;
use Codeception\PHPUnit\ResultPrinter;
use Codeception\Test\Descriptor;

class Report extends ResultPrinter implements ConsolePrinter
{
    /**
     * @param \PHPUnit\Framework\Test $test
     * @param float $time
     */
    public function endTest(\PHPUnit\Framework\Test $test, float $time) : void
    {
        $name = Descriptor::getTestAsString($test);
        $success = ($this->testStatus == \PHPUnit\Runner\BaseTestRunner::STATUS_PASSED);
        if ($success) {
            $this->successful++;
        }

        if ($this->testStatus == \PHPUnit\Runner\BaseTestRunner::STATUS_FAILURE) {
            $status = "\033[41;37mFAIL\033[0m";
        } elseif ($this->testStatus == \PHPUnit\Runner\BaseTestRunner::STATUS_SKIPPED) {
            $status = 'Skipped';
        } elseif ($this->testStatus == \PHPUnit\Runner\BaseTestRunner::STATUS_INCOMPLETE) {
            $status = 'Incomplete';
        } elseif ($this->testStatus == \PHPUnit\Runner\BaseTestRunner::STATUS_ERROR) {
            $status = 'ERROR';
        } else {
            $status = 'Ok';
        }

        if (strlen($name) > 75) {
            $name = substr($name, 0, 70);
        }
        $line = $name . str_repeat('.', 75 - strlen($name));
        $line .= $status;

        $this->write($line . "\n");
    }

    protected function endRun() : void
    {
        $this->write("\nCodeception Results\n");
        $this->write(sprintf(
            "Successful: %s. Failed: %s. Incomplete: %s. Skipped: %s",
            $this->successful,
            $this->failed,
            $this->skipped,
            $this->incomplete
        ) . "\n");
    }

    public function printResult(\PHPUnit\Framework\TestResult $result)
    {
    }

    public function write(string $buffer) : void
    {
        parent::write($buffer);
    }
}
   <tr class="scenarioRow {scenarioStatus}">
    <td>
     <p class="{scenarioStatus}" onclick="showHide('{id}', this)">{toggle}
          {name} <span style="color: #34495e; font-size: 70%;">{time}s</span></p>
    </td>
   </tr>
   <tr class="scenarioRow {scenarioStatus}">
    <td>
     <table border="0" width="100%" class="{scenarioStatus} scenarioStepsTable" id="stepContainer{id}">


{steps}
         {failure}
         {png}
         {html}
     </table>


    </td>
   </tr>


<html>
 <head>
	<title>Test results</title>
	<meta charset='utf-8'>
	<link href='https://fonts.googleapis.com/css?family=Varela+Round&v2' rel='stylesheet' type='text/css'>
     <meta name="viewport" content="width=device-width, initial-scale=1">
	 <style>
		 .layout {
		 margin: 0 auto;
		 max-width: 1000px;

		 }
		 body { font-family: arial, serif; margin: 0; padding: 0; background: #ecf0f1; font-size: 20px; }
		 h1,h2,h3 { font-family: arial, serif; color: #7f8c8d; }
		 h1 { font-size: 2.5em; }
		 h2 { font-size: 1.3em; }
         h3 { font-size: 1em; color: #84BBDD; margin: 0.5em 0; }

		 table { border: none; margin: 0; padding: 0; font-size: 0.9em;}
		 .scenarioStepsTable .stepName { padding: 5px; }

		 .scenarioStepsTable td {
            background: #fff;
		 }

         .quiet {
             color: #333;
             font-size: 0.8em;
         }

         .screenshot {
             max-height: 400px;
             overflow-y: scroll;
             display: block;
         }
         .screenshot img {
             zoom: 0.5;
         }

         @media (max-width: 1200px) {
           #toolbar-filter {
             display: none !important;
           }
         }

         .scenarioStepsTable .nostyle {
             background: none;
             border: none;
         }

		 p {
		    cursor: pointer;
		 }

         .scenarioRow>td>p {
             padding: 5px;
         }

         .scenarioStepsTable .failedStep {
             padding: 10px;
             background: #ecf0f1;
             border: 2px solid #e74c3c;
             border-radius: 0px;
             color:  #e74c3c;
         }

         .scenarioStepsTable .error {
             background:  #999;
             padding: 10px;
             color: #fff;
             border-radius: 0px;
         }

         .scenarioStepsTable .error a {
             color: #eef;
         }

         .scenarioStepsTable.substeps td {
             background: #bdc3c7;
         }

		 .header { font-size: large; font-weight: bold; }
		 p.scenarioSuccess {
    		 background: rgb(157,213,58); /* Old browsers */
		 }


		 .scenario { color: black; }
		 p.scenarioFailed, p.scenarioError { color: black;
		   background: #e74c3c
		 }

		 table.scenarioFailed tr:last-child { font-weight: bold; }

		 td.scenarioSuccess { color: green }
		 td.scenarioFailed { color: red }
		 .scenarioSkipped { color: teal; }
		 .scenarioIncomplete { color: gray; }
		 .scenarioStepsTable { margin-left: 10px; display: none; color: #333; }

		 #stepContainerSummary {
		 background: white;
		 -webkit-border-radius: 5px;
		 -moz-border-radius: 5px;
		 border-radius: 5px;
		 padding: 20px;
		 }

         .toggle {
             background: rgba(255,255,255,0.5);
             border-radius: 10px;
             display: inline-block;
             width: 20px;
             height: 20px;
             text-align: center;
             margin: auto;
             color: #666
         }

		 ul#toolbar-filter {
            display: block;
            position: fixed;
            top: 20px;
            left: 0px;
            padding: 0px;
		 }
		 ul#toolbar-filter li {
		    list-style: none;
		    text-align: center;
			padding: 20px;
			background-color: #3498db;
		 }
		 ul#toolbar-filter li a, ul#toolbar-filter li a:hover, ul#toolbar-filter li a:visited {
		    color: #34495e;
		    text-decoration: none;
		 }
		 ul#toolbar-filter li.disabled {
			background-color: #bdc3c7;
		 }
	 </style>

  <script type="text/javascript">
  var showAll = true;
  function showHide(nodeId, linkObj)
  {
    var subObj = document.getElementById('stepContainer' + nodeId);
    var toggle = linkObj.childNodes[0];
    if (toggle.innerHTML != '-') {
      toggle.innerHTML = '-';
      subObj.style.display='block';
      subObj.style.width = '100%';
    } else {
      toggle.innerHTML = '+';
      subObj.style.display='none';
    }
  }

  function showAllScenarios() {
    var toolbar = document.getElementById('toolbar-filter');
    for (var i = 0; i < toolbar.children.length; i++) {
      toolbar.children[i].className = '';
    }

    var trs = document.getElementsByTagName('tr');
    for(var z = 0; z < trs.length; z++) {
      trs[z].style.display = '';
    }
    showAll = true;
  }

  function toggleScenarios(name, linkObj) {
    var links = document.getElementById('toolbar-filter').children;
    var rows = document.getElementsByClassName('scenarioRow');
    if (showAll) {
        for (var i = 0; i < links.length; i++) {
            links[i].className = 'disabled';
        }

        for (var i = 0; i < rows.length; i++) {
            rows[i].style.display = 'none';
        }

    }
    showAll = false;

    if (linkObj.className == '') {
        linkObj.className = 'disabled';
        for (var i = 0; i < rows.length; i++) {
          if (rows[i].classList.contains(name)) {
                rows[i].style.display = 'none';
          }
        }
        return;
    }
    if (linkObj.className == 'disabled') {
        linkObj.className = '';
        for (var i = 0; i < rows.length; i++) {
          if (rows[i].classList.contains(name)) {
                rows[i].style.display = 'table-row';
          }
        }
        return;
    }

  }
  </script>
 </head>

 <body>
   <ul id="toolbar-filter">
     <li> <a href="#" title="Show all" onClick="showAllScenarios()">◯</a></li>
     <li> <a href="#" title="Successful" onClick="toggleScenarios('scenarioSuccess', this.parentElement)"><strong>✔</strong> {successfulScenarios}</a></li>
     <li> <a href="#" title="Failed" onClick="toggleScenarios('scenarioFailed', this.parentElement)"><strong>✗</strong> {failedScenarios}</a></li>
     <li> <a href="#" title="Skipped" onClick="toggleScenarios('scenarioSkipped', this.parentElement)"><strong>S</strong> {skippedScenarios}</a></li>
     <li> <a href="#" title="Incomplete" onClick="toggleScenarios('scenarioIncomplete', this.parentElement)"><strong>I</strong> {incompleteScenarios}</a></li>
   </ul>
 <div class="layout">
 {header}

	 <table border="0" style="width: 100%;">
		{scenarios}
   <tr>
    <td>
	    <h2>Summary</h2>
     <div id="stepContainerSummary">
      <table border="0">
       <tr>
        <td width="250" class="scenarioSuccess">Successful scenarios:</td>
        <td class="scenarioSuccessValue"><strong>{successfulScenarios}</strong></td>
       </tr>
       <tr>
        <td class="scenarioFailed">Failed scenarios:</td>
        <td class="scenarioFailedValue"><strong>{failedScenarios}</strong></td>
       </tr>
       <tr>
        <td class="scenarioSkipped">Skipped scenarios:</td>
        <td class="scenarioSkippedValue"><strong>{skippedScenarios}</strong></td>
       </tr>
       <tr>
        <td class="scenarioIncomplete">Incomplete scenarios:</td>
        <td class="scenarioIncompleteValue"><strong>{incompleteScenarios}</strong></td>
       </tr>
      </table>
     </div>
    </td>
   </tr>
  </table>
 </div>
 </body>
</html>
<tr>
 <td>
     <h3>{suite} Tests</h3>
 </td>
</tr><tr>
 <td class="stepName {error}" ><p onclick="showHide('{id}', this)"><span class="toggle">+</span> {metaStep}</p>

     </td>
</tr>
<tr>
 <td class="nostyle">
  <table border="0" width="100%" class="substeps scenarioStepsTable" id="stepContainer{id}">
    {steps}
  </table>
 </td>
</tr>
<h1>{name} <small>{status} ({time}s)</small></h1>

      <tr>
       <td class="stepName {error}">&nbsp;&nbsp;&nbsp;&nbsp;{action}</td>
      </tr>

<tr >
    <td class="error">
        {fail}
    </td>
</tr><?php
namespace Codeception\PHPUnit\ResultPrinter;

use Codeception\PHPUnit\ResultPrinter as CodeceptionResultPrinter;
use Codeception\Step;
use Codeception\Step\Meta;
use Codeception\Test\Descriptor;
use Codeception\Test\Interfaces\ScenarioDriven;
use Codeception\TestInterface;
use Codeception\Util\PathResolver;

class HTML extends CodeceptionResultPrinter
{
    /**
     * @var boolean
     */
    protected $printsHTML = true;

    /**
     * @var integer
     */
    protected $id = 0;

    /**
     * @var string
     */
    protected $scenarios = '';

    /**
     * @var string
     */
    protected $templatePath;

    /**
     * @var int
     */
    protected $timeTaken = 0;

    protected $failures = [];

    /**
     * Constructor.
     *
     * @param  mixed $out
     * @throws InvalidArgumentException
     */
    public function __construct($out = null)
    {
        parent::__construct($out);

        $this->templatePath = sprintf(
            '%s%stemplate%s',
            __DIR__,
            DIRECTORY_SEPARATOR,
            DIRECTORY_SEPARATOR
        );
    }

    /**
     * Handler for 'start class' event.
     *
     * @param  string $name
     */
    protected function startClass(string $name):void
    {
    }

    public function endTest(\PHPUnit\Framework\Test $test, float $time) : void
    {
        $steps = [];
        $success = ($this->testStatus == \PHPUnit\Runner\BaseTestRunner::STATUS_PASSED);
        if ($success) {
            $this->successful++;
        }

        if ($test instanceof ScenarioDriven) {
            $steps = $test->getScenario()->getSteps();
        }
        $this->timeTaken += $time;

        switch ($this->testStatus) {
            case \PHPUnit\Runner\BaseTestRunner::STATUS_FAILURE:
                $scenarioStatus = 'scenarioFailed';
                break;
            case \PHPUnit\Runner\BaseTestRunner::STATUS_SKIPPED:
                $scenarioStatus = 'scenarioSkipped';
                break;
            case \PHPUnit\Runner\BaseTestRunner::STATUS_INCOMPLETE:
                $scenarioStatus = 'scenarioIncomplete';
                break;
            case \PHPUnit\Runner\BaseTestRunner::STATUS_ERROR:
                $scenarioStatus = 'scenarioFailed';
                break;
            default:
                $scenarioStatus = 'scenarioSuccess';
        }

        $stepsBuffer = '';
        $subStepsRendered = [];

        foreach ($steps as $step) {
            if ($step->getMetaStep()) {
                $key = $step->getMetaStep()->getLine() . $step->getMetaStep()->getAction();
                $subStepsRendered[$key][] = $this->renderStep($step);
            }
        }

        foreach ($steps as $step) {
            if ($step->getMetaStep()) {
                $key = $step->getMetaStep()->getLine() . $step->getMetaStep()->getAction();
                if (! empty($subStepsRendered[$key])) {
                    $subStepsBuffer = implode('', $subStepsRendered[$key]);
                    unset($subStepsRendered[$key]);
                    $stepsBuffer .= $this->renderSubsteps($step->getMetaStep(), $subStepsBuffer);
                }
            } else {
                $stepsBuffer .= $this->renderStep($step);
            }
        }

        $scenarioTemplate = new \Text_Template(
            $this->templatePath . 'scenario.html'
        );

        $failures = '';
        $name = Descriptor::getTestSignatureUnique($test);
        if (isset($this->failures[$name])) {
            $failTemplate = new \Text_Template(
                $this->templatePath . 'fail.html'
            );
            foreach ($this->failures[$name] as $failure) {
                $failTemplate->setVar(['fail' => nl2br($failure)]);
                $failures .= $failTemplate->render() . PHP_EOL;
            }
            $this->failures[$name] = [];
        }

        $png = '';
        $html = '';
        if ($test instanceof TestInterface) {
            $reports = $test->getMetadata()->getReports();
            if (isset($reports['png'])) {
                $localPath = PathResolver::getRelativeDir($reports['png'], codecept_output_dir());
                $png = "<tr><td class='error'><div class='screenshot'><img src='$localPath' alt='failure screenshot'></div></td></tr>";
            }
            if (isset($reports['html'])) {
                $localPath = PathResolver::getRelativeDir($reports['html'], codecept_output_dir());
                $html = "<tr><td class='error'>See <a href='$localPath' target='_blank'>HTML snapshot</a> of a failed page</td></tr>";
            }
        }

        $toggle = $stepsBuffer ? '<span class="toggle">+</span>' : '';

        $testString = htmlspecialchars(ucfirst(Descriptor::getTestAsString($test)));
        $testString = preg_replace('~^([\s\w\\\]+):\s~', '<span class="quiet">$1 &raquo;</span> ', $testString);

        $scenarioTemplate->setVar(
            [
                'id'             => ++$this->id,
                'name'           => $testString,
                'scenarioStatus' => $scenarioStatus,
                'steps'          => $stepsBuffer,
                'toggle'         => $toggle,
                'failure'        => $failures,
                'png'            => $png,
                'html'            => $html,
                'time'           => round($time, 2)
            ]
        );

        $this->scenarios .= $scenarioTemplate->render();
    }

    public function startTestSuite(\PHPUnit\Framework\TestSuite $suite) : void
    {
        $suiteTemplate = new \Text_Template(
            $this->templatePath . 'suite.html'
        );
        if (!$suite->getName()) {
            return;
        }

        $suiteTemplate->setVar(['suite' => ucfirst($suite->getName())]);

        $this->scenarios .= $suiteTemplate->render();
    }

    /**
     * Handler for 'end run' event.
     */
    protected function endRun():void
    {
        $scenarioHeaderTemplate = new \Text_Template(
            $this->templatePath . 'scenario_header.html'
        );

        $status = !$this->failed
            ? '<span style="color: green">OK</span>'
            : '<span style="color: #e74c3c">FAILED</span>';


        $scenarioHeaderTemplate->setVar(
            [
                'name'   => 'Codeception Results',
                'status' => $status,
                'time'   => round($this->timeTaken, 1)
            ]
        );

        $header = $scenarioHeaderTemplate->render();

        $scenariosTemplate = new \Text_Template(
            $this->templatePath . 'scenarios.html'
        );

        $scenariosTemplate->setVar(
            [
                'header'              => $header,
                'scenarios'           => $this->scenarios,
                'successfulScenarios' => $this->successful,
                'failedScenarios'     => $this->failed,
                'skippedScenarios'    => $this->skipped,
                'incompleteScenarios' => $this->incomplete
            ]
        );

        $this->write($scenariosTemplate->render());
    }

    /**
     * An error occurred.
     *
     * @param \PHPUnit\Framework\Test $test
     * @param \Exception $e
     * @param float $time
     */
    public function addError(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
    {
        $this->failures[Descriptor::getTestSignatureUnique($test)][] = $this->cleanMessage($e);
        parent::addError($test, $e, $time);
    }

    /**
     * A failure occurred.
     *
     * @param \PHPUnit\Framework\Test                 $test
     * @param \PHPUnit\Framework\AssertionFailedError $e
     * @param float                                  $time
     */
    public function addFailure(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\AssertionFailedError $e, float $time) : void
    {
        $this->failures[Descriptor::getTestSignatureUnique($test)][] = $this->cleanMessage($e);
        parent::addFailure($test, $e, $time);
    }

    /**
     * Starts test
     *
     * @param \PHPUnit\Framework\Test $test
     */
    public function startTest(\PHPUnit\Framework\Test $test):void
    {
        $name = Descriptor::getTestSignatureUnique($test);
        if (isset($this->failures[$name])) {
            // test failed in before hook
            return;
        }

        // start test and mark initialize as passed
        parent::startTest($test);
    }


    /**
     * @param $step
     * @return string
     */
    protected function renderStep(Step $step)
    {
        $stepTemplate = new \Text_Template($this->templatePath . 'step.html');
        $stepTemplate->setVar(['action' => $step->getHtml(), 'error' => $step->hasFailed() ? 'failedStep' : '']);
        return $stepTemplate->render();
    }

    /**
     * @param $metaStep
     * @param $substepsBuffer
     * @return string
     */
    protected function renderSubsteps(Meta $metaStep, $substepsBuffer)
    {
        $metaTemplate = new \Text_Template($this->templatePath . 'substeps.html');
        $metaTemplate->setVar(['metaStep' => $metaStep->getHtml(), 'error' => $metaStep->hasFailed() ? 'failedStep' : '', 'steps' => $substepsBuffer, 'id' => uniqid()]);
        return $metaTemplate->render();
    }

    private function cleanMessage($exception)
    {
        $msg = $exception->getMessage();
        if ($exception instanceof \PHPUnit\Framework\ExpectationFailedException && $exception->getComparisonFailure()) {
            $msg .= $exception->getComparisonFailure()->getDiff();
        }
        $msg = str_replace(['<info>','</info>','<bold>','</bold>'], ['','','',''], $msg);
        return htmlentities($msg);
    }
}
<?php
namespace Codeception\PHPUnit\ResultPrinter;

use Codeception\Event\FailEvent;
use Codeception\Events;
use Codeception\PHPUnit\DispatcherWrapper;
use Codeception\Test\Unit;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\EventDispatcher\EventDispatcher;

class UI extends \PHPUnit\TextUI\ResultPrinter
{
    use DispatcherWrapper;

    /**
     * @var EventDispatcher
     */
    protected $dispatcher;

    public function __construct(EventDispatcher $dispatcher, $options, $out = null)
    {
        parent::__construct($out, $options['verbosity'] > OutputInterface::VERBOSITY_NORMAL, $options['colors'] ? 'always' : 'never');
        $this->dispatcher = $dispatcher;
    }

    protected function printDefect(\PHPUnit\Framework\TestFailure $defect, int $count): void
    {
        $this->write("\n---------\n");
        $this->dispatch(
            $this->dispatcher,
            Events::TEST_FAIL_PRINT,
            new FailEvent($defect->failedTest(), null, $defect->thrownException(), $count)
        );
    }

    /**
     * @param \PHPUnit\Framework\TestFailure $defect
     */
    protected function printDefectTrace(\PHPUnit\Framework\TestFailure $defect): void
    {
        $this->write($defect->getExceptionAsString());
        $this->writeNewLine();

        $stackTrace = \PHPUnit\Util\Filter::getFilteredStacktrace($defect->thrownException());

        foreach ($stackTrace as $i => $frame) {
            if (!isset($frame['file'])) {
                continue;
            }

            $this->write(
                sprintf(
                    "#%d %s(%s)",
                    $i + 1,
                    $frame['file'],
                    isset($frame['line']) ? $frame['line'] : '?'
                )
            );

            $this->writeNewLine();
        }
    }

    public function startTest(\PHPUnit\Framework\Test $test) : void
    {
        if ($test instanceof Unit) {
            parent::startTest($test);
        }
    }

    public function endTest(\PHPUnit\Framework\Test $test, float $time) : void
    {
        if ($test instanceof \PHPUnit\Framework\TestCase or $test instanceof \Codeception\Test\Test) {
            $this->numAssertions += $test->getNumAssertions();
        }

        $this->lastTestFailed = false;
    }

    public function addError(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
    {
        $this->lastTestFailed = true;
    }

    public function addFailure(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\AssertionFailedError $e, float $time) : void
    {
        $this->lastTestFailed = true;
    }

    public function addWarning(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\Warning $e, float $time) : void
    {
        $this->lastTestFailed = true;
    }

    public function addIncompleteTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
    {
        $this->lastTestFailed = true;
    }

    public function addRiskyTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
    {
        $this->lastTestFailed = true;
    }

    public function addSkippedTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
    {
        $this->lastTestFailed = true;
    }
}
<?php
namespace Codeception\PHPUnit;

use Codeception\PHPUnit\DispatcherWrapper;
use Codeception\Event\FailEvent;
use Codeception\Event\SuiteEvent;
use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\TestInterface;
use Symfony\Component\EventDispatcher\EventDispatcher;

class Listener implements \PHPUnit\Framework\TestListener
{
    use DispatcherWrapper;

    /**
     * @var \Symfony\Component\EventDispatcher\EventDispatcher
     */
    protected $dispatcher;

    protected $unsuccessfulTests = [];
    protected $skippedTests = [];
    protected $startedTests = [];

    public function __construct(EventDispatcher $dispatcher)
    {
        $this->dispatcher = $dispatcher;
    }

    /**
     * Risky test.
     *
     * @param PHPUnit\Framework\Test $test
     * @param \Throwable $e
     * @param float $time
     * @since  Method available since Release 4.0.0
     */
    public function addRiskyTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
    {
    }

    public function addFailure(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\AssertionFailedError $e, float $time) : void
    {
        $this->unsuccessfulTests[] = spl_object_hash($test);
        $this->fire(Events::TEST_FAIL, new FailEvent($test, $time, $e));
    }

    public function addError(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
    {
        $this->unsuccessfulTests[] = spl_object_hash($test);
        $this->fire(Events::TEST_ERROR, new FailEvent($test, $time, $e));
    }

    // This method was added in PHPUnit 6
    public function addWarning(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\Warning $e, float $time) : void
    {
        $this->unsuccessfulTests[] = spl_object_hash($test);
        $this->fire(Events::TEST_WARNING, new FailEvent($test, $time, $e));
    }

    public function addIncompleteTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
    {
        if (in_array(spl_object_hash($test), $this->skippedTests)) {
            return;
        }
        $this->unsuccessfulTests[] = spl_object_hash($test);
        $this->fire(Events::TEST_INCOMPLETE, new FailEvent($test, $time, $e));
        $this->skippedTests[] = spl_object_hash($test);
    }

    public function addSkippedTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
    {
        if (in_array(spl_object_hash($test), $this->skippedTests)) {
            return;
        }
        $this->unsuccessfulTests[] = spl_object_hash($test);
        $this->fire(Events::TEST_SKIPPED, new FailEvent($test, $time, $e));
        $this->skippedTests[] = spl_object_hash($test);
    }

    public function startTestSuite(\PHPUnit\Framework\TestSuite $suite) : void
    {
        $this->dispatch($this->dispatcher, 'suite.start', new SuiteEvent($suite));
    }

    public function endTestSuite(\PHPUnit\Framework\TestSuite $suite) : void
    {
        $this->dispatch($this->dispatcher, 'suite.end', new SuiteEvent($suite));
    }

    public function startTest(\PHPUnit\Framework\Test $test) : void
    {
        $this->dispatch($this->dispatcher, Events::TEST_START, new TestEvent($test));
        if (!$test instanceof TestInterface) {
            return;
        }
        if ($test->getMetadata()->isBlocked()) {
            return;
        }

        try {
            $this->startedTests[] = spl_object_hash($test);
            $this->fire(Events::TEST_BEFORE, new TestEvent($test));
        } catch (\PHPUnit\Framework\IncompleteTestError $e) {
            $test->getTestResultObject()->addFailure($test, $e, 0);
        } catch (\PHPUnit\Framework\SkippedTestError $e) {
            $test->getTestResultObject()->addFailure($test, $e, 0);
        } catch (\Throwable $e) {
            $test->getTestResultObject()->addError($test, $e, 0);
        }
    }

    public function endTest(\PHPUnit\Framework\Test $test, float $time) : void
    {
        $hash = spl_object_hash($test);
        if (!in_array($hash, $this->unsuccessfulTests)) {
            $this->fire(Events::TEST_SUCCESS, new TestEvent($test, $time));
        }
        if (in_array($hash, $this->startedTests)) {
            $this->fire(Events::TEST_AFTER, new TestEvent($test, $time));
        }

        $this->dispatch($this->dispatcher, Events::TEST_END, new TestEvent($test, $time));
    }

    protected function fire($event, TestEvent $eventType)
    {
        $test = $eventType->getTest();
        if ($test instanceof TestInterface) {
            foreach ($test->getMetadata()->getGroups() as $group) {
                $this->dispatch($this->dispatcher, $event . '.' . $group, $eventType);
            }
        }
        $this->dispatch($this->dispatcher, $event, $eventType);
    }
}
<?php

namespace Codeception\PHPUnit;

use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface;

trait DispatcherWrapper
{
    /**
     * Compatibility wrapper for dispatcher change between Symfony 4 and 5
     * @param EventDispatcher $dispatcher
     * @param string $eventType
     * @param Event $eventObject
     */
    protected function dispatch(EventDispatcher $dispatcher, $eventType, Event $eventObject)
    {
        // The `EventDispatcherInterface` of `Symfony\Contracts` is only implemented in Symfony 4.3 or higher
        if ($dispatcher instanceof ContractsEventDispatcherInterface) {
            //Symfony 4.3 or higher
            $dispatcher->dispatch($eventObject, $eventType);
        } else {
            //Symfony 4.2 or lower
            $dispatcher->dispatch($eventType, $eventObject);
        }

    }
}
<?php
namespace Codeception\PHPUnit\Constraint;

use SebastianBergmann\Comparator\ComparisonFailure;
use Codeception\Util\Locator;

class WebDriverNot extends WebDriver
{
    protected function matches($nodes) : bool
    {
        return !parent::matches($nodes);
    }

    protected function fail($nodes, $selector, ComparisonFailure $comparisonFailure = null) : void
    {
        if (!is_string($selector) || strpos($selector, "'") === false) {
            $selector = Locator::humanReadableString($selector);
        }
        if (!$this->string) {
            throw new \PHPUnit\Framework\ExpectationFailedException(
                "Element $selector was found",
                $comparisonFailure
            );
        }

        $output = "There was $selector element";
        $output .= $this->uriMessage("on page");
        $output .= $this->nodesList($nodes, $this->string);
        $output .= "\ncontaining '{$this->string}'";

        throw new \PHPUnit\Framework\ExpectationFailedException(
            $output,
            $comparisonFailure
        );
    }

    public function toString() : string
    {
        if ($this->string) {
            return 'that contains text "' . $this->string . '"';
        }
    }
}
<?php

namespace Codeception\PHPUnit\Constraint;

use SebastianBergmann\Comparator\ComparisonFailure;
use SebastianBergmann\Comparator\ArrayComparator;
use SebastianBergmann\Comparator\Factory;
use Codeception\Util\JsonArray;

class JsonContains extends \PHPUnit\Framework\Constraint\Constraint
{
    /**
     * @var
     */
    protected $expected;

    public function __construct(array $expected)
    {
        $this->expected = $expected;
    }

    /**
     * Evaluates the constraint for parameter $other. Returns true if the
     * constraint is met, false otherwise.
     *
     * @param mixed $other Value or object to evaluate.
     *
     * @return bool
     */
    protected function matches($other) : bool
    {
        $jsonResponseArray = new JsonArray($other);
        if (!is_array($jsonResponseArray->toArray())) {
            throw new \PHPUnit\Framework\AssertionFailedError('JSON response is not an array: ' . $other);
        }

        if ($jsonResponseArray->containsArray($this->expected)) {
            return true;
        }

        $comparator = new ArrayComparator();
        $comparator->setFactory(new Factory);
        try {
            $comparator->assertEquals($this->expected, $jsonResponseArray->toArray());
        } catch (ComparisonFailure $failure) {
            throw new \PHPUnit\Framework\ExpectationFailedException(
                "Response JSON does not contain the provided JSON\n",
                $failure
            );
        }

        return false;
    }

    /**
     * Returns a string representation of the constraint.
     *
     * @return string
     */
    public function toString() : string
    {
        //unused
        return '';
    }

    protected function failureDescription($other) : string
    {
        //unused
        return '';
    }
}
<?php
namespace Codeception\PHPUnit\Constraint;

use Codeception\Lib\Console\Message;

class Page extends \PHPUnit\Framework\Constraint\Constraint
{
    protected $uri;
    protected $string;

    public function __construct($string, $uri = '')
    {
        $this->string = $this->normalizeText((string)$string);
        $this->uri = $uri;
    }

    /**
     * Evaluates the constraint for parameter $other. Returns true if the
     * constraint is met, false otherwise.
     *
     * @param mixed $other Value or object to evaluate.
     *
     * @return bool
     */
    protected function matches($other) : bool
    {
        $other = $this->normalizeText($other);
        return mb_stripos($other, $this->string, null, 'UTF-8') !== false;
    }

    /**
     * @param $text
     * @return string
     */
    private function normalizeText($text)
    {
        $text = strtr($text, "\r\n", "  ");
        return trim(preg_replace('/\\s{2,}/', ' ', $text));
    }

    /**
     * Returns a string representation of the constraint.
     *
     * @return string
     */
    public function toString() : string
    {
        return sprintf(
            'contains "%s"',
            $this->string
        );
    }

    protected function failureDescription($pageContent) : string
    {
        $message = $this->uriMessage('on page');
        $message->append("\n--> ");
        $message->append(mb_substr($pageContent, 0, 300, 'utf-8'));
        if (mb_strlen($pageContent, 'utf-8') > 300) {
            $debugMessage = new Message(
                "[Content too long to display. See complete response in '" . codecept_output_dir() . "' directory]"
            );
            $message->append("\n")->append($debugMessage);
        }
        $message->append("\n--> ");
        return $message->getMessage() . $this->toString();
    }

    protected function uriMessage($onPage = "")
    {
        if (!$this->uri) {
            return new Message('');
        }
        $message = new Message($this->uri);
        $message->prepend(" $onPage ");
        return $message;
    }
}
<?php
namespace Codeception\PHPUnit\Constraint;

use SebastianBergmann\Comparator\ComparisonFailure;

class CrawlerNot extends Crawler
{
    protected function matches($nodes) : bool
    {
        return !parent::matches($nodes);
    }

    protected function fail($nodes, $selector, ComparisonFailure $comparisonFailure = null) : void
    {
        if (!$this->string) {
            throw new \PHPUnit\Framework\ExpectationFailedException(
                "Element '$selector' was found",
                $comparisonFailure
            );
        }
        /** @var $nodes DomCrawler  * */

        $output = "There was '$selector' element";
        $output .= $this->uriMessage('on page');
        $output .= $this->nodesList($nodes, $this->string);
        $output .= "\ncontaining '{$this->string}'";

        throw new \PHPUnit\Framework\ExpectationFailedException(
            $output,
            $comparisonFailure
        );
    }

    public function toString() : string
    {
        if ($this->string) {
            return 'that contains text "' . $this->string . '"';
        }
    }
}
<?php

namespace Codeception\PHPUnit\Constraint;

use Codeception\Util\JsonType as JsonTypeUtil;
use Codeception\Util\JsonArray;

class JsonType extends \PHPUnit\Framework\Constraint\Constraint
{
    protected $jsonType;
    private $match;

    public function __construct(array $jsonType, $match = true)
    {
        $this->jsonType = $jsonType;
        $this->match = $match;
    }

    /**
     * Evaluates the constraint for parameter $other. Returns true if the
     * constraint is met, false otherwise.
     *
     * @param mixed $jsonArray Value or object to evaluate.
     *
     * @return bool
     */
    protected function matches($jsonArray) : bool
    {
        if ($jsonArray instanceof JsonArray) {
            $jsonArray = $jsonArray->toArray();
        }

        $matched = (new JsonTypeUtil($jsonArray))->matches($this->jsonType);

        if ($this->match) {
            if ($matched !== true) {
                throw new \PHPUnit\Framework\ExpectationFailedException($matched);
            }
        } else {
            if ($matched === true) {
                throw new \PHPUnit\Framework\ExpectationFailedException('Unexpectedly response matched: ' . json_encode($jsonArray));
            }
        }
        return true;
    }

    /**
     * Returns a string representation of the constraint.
     *
     * @return string
     */
    public function toString() : string
    {
        //unused
        return '';
    }

    protected function failureDescription($other) : string
    {
        //unused
        return '';
    }
}
<?php
namespace Codeception\PHPUnit\Constraint;

use Codeception\Exception\ElementNotFound;
use Codeception\Lib\Console\Message;
use Symfony\Component\DomCrawler\Crawler as DomCrawler;
use SebastianBergmann\Comparator\ComparisonFailure;

class Crawler extends Page
{
    protected function matches($nodes) : bool
    {
        /** @var $nodes DomCrawler  * */
        if (!$nodes->count()) {
            return false;
        }
        if ($this->string === '') {
            return true;
        }

        foreach ($nodes as $node) {
            if (parent::matches($node->nodeValue)) {
                return true;
            }
        }
        return false;
    }

    protected function fail($nodes, $selector, ComparisonFailure $comparisonFailure = null):void
    {
        /** @var $nodes DomCrawler  * */
        if (!$nodes->count()) {
            throw new ElementNotFound($selector, 'Element located either by name, CSS or XPath');
        }

        $output = "Failed asserting that any element by '$selector'";
        $output .= $this->uriMessage('on page');
        $output .= " ";

        if ($nodes->count() < 10) {
            $output .= $this->nodesList($nodes);
        } else {
            $message = new Message("[total %s elements]");
            $output .= $message->with($nodes->count())->getMessage();
        }
        $output .= "\ncontains text '{$this->string}'";

        throw new \PHPUnit\Framework\ExpectationFailedException(
            $output,
            $comparisonFailure
        );
    }

    protected function failureDescription($other) : string
    {
        $desc = '';
        foreach ($other as $o) {
            $desc .= parent::failureDescription($o->textContent);
        }
        return $desc;
    }

    protected function nodesList(DomCrawler $nodes, $contains = null)
    {
        $output = "";
        foreach ($nodes as $node) {
            if ($contains && strpos($node->nodeValue, $contains) === false) {
                continue;
            }
            $output .= "\n+ " . $node->C14N();
        }
        return $output;
    }
}
<?php
namespace Codeception\PHPUnit\Constraint;

use Codeception\Exception\ElementNotFound;
use Codeception\Lib\Console\Message;
use Codeception\Util\Locator;
use SebastianBergmann\Comparator\ComparisonFailure;

class WebDriver extends Page
{

    protected function matches($nodes) : bool
    {
        if (!count($nodes)) {
            return false;
        }
        if ($this->string === '') {
            return true;
        }

        foreach ($nodes as $node) {
            /** @var $node \WebDriverElement  * */
            if (!$node->isDisplayed()) {
                continue;
            }
            if (parent::matches(htmlspecialchars_decode($node->getText()))) {
                return true;
            }
        }
        return false;
    }

    protected function fail($nodes, $selector, ComparisonFailure $comparisonFailure = null) : void
    {
        if (!count($nodes)) {
            throw new ElementNotFound($selector, 'Element located either by name, CSS or XPath');
        }

        $output = "Failed asserting that any element by " . Locator::humanReadableString($selector);
        $output .= $this->uriMessage('on page');

        if (count($nodes) < 5) {
            $output .= "\nElements: ";
            $output .= $this->nodesList($nodes);
        } else {
            $message = new Message("[total %s elements]");
            $output .= $message->with(count($nodes));
        }
        $output .= "\ncontains text '" . $this->string . "'";

        throw new \PHPUnit\Framework\ExpectationFailedException(
            $output,
            $comparisonFailure
        );
    }

    protected function failureDescription($nodes) : string
    {
        $desc = '';
        foreach ($nodes as $node) {
            $desc .= parent::failureDescription($node->getText());
        }
        return $desc;
    }

    protected function nodesList($nodes, $contains = null)
    {
        $output = "";
        foreach ($nodes as $node) {
            if ($contains && strpos($node->getText(), $contains) === false) {
                continue;
            }
            /** @var $node \WebDriverElement  * */
            $message = new Message("\n+ <%s> %s");
            $output .= $message->with($node->getTagName(), $node->getText());
        }
        return $output;
    }
}
<?php declare(strict_types=1);
/*
 * This file is part of PHPUnit.
 *
 * (c) Sebastian Bergmann <sebastian@phpunit.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace Codeception\PHPUnit\NonFinal;

use PHPUnit\Framework\Error\Deprecated;
use PHPUnit\Framework\Error\Notice;
use PHPUnit\Framework\Error\Warning;
use PHPUnit\Framework\Exception;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestResult;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Runner\AfterLastTestHook;
use PHPUnit\Runner\BaseTestRunner;
use PHPUnit\Runner\BeforeFirstTestHook;
use PHPUnit\Runner\Filter\ExcludeGroupFilterIterator;
use PHPUnit\Runner\Filter\Factory;
use PHPUnit\Runner\Filter\IncludeGroupFilterIterator;
use PHPUnit\Runner\Filter\NameFilterIterator;
use PHPUnit\Runner\Hook;
use PHPUnit\Runner\NullTestResultCache;
use PHPUnit\Runner\ResultCacheExtension;
use PHPUnit\Runner\StandardTestSuiteLoader;
use PHPUnit\Runner\TestHook;
use PHPUnit\Runner\TestListenerAdapter;
use PHPUnit\Runner\TestResultCache;
use PHPUnit\Runner\TestSuiteLoader;
use PHPUnit\Runner\TestSuiteSorter;
use PHPUnit\Runner\Version;
use PHPUnit\TextUI\ResultPrinter;
use PHPUnit\Util\Configuration;
use PHPUnit\Util\Filesystem;
use PHPUnit\Util\Log\JUnit;
use PHPUnit\Util\Log\TeamCity;
use PHPUnit\Util\Printer;
use PHPUnit\Util\TestDox\CliTestDoxPrinter;
use PHPUnit\Util\TestDox\HtmlResultPrinter;
use PHPUnit\Util\TestDox\TextResultPrinter;
use PHPUnit\Util\TestDox\XmlResultPrinter;
use PHPUnit\Util\XdebugFilterScriptGenerator;
use ReflectionClass;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Exception as CodeCoverageException;
use SebastianBergmann\CodeCoverage\Filter as CodeCoverageFilter;
use SebastianBergmann\CodeCoverage\Report\Clover as CloverReport;
use SebastianBergmann\CodeCoverage\Report\Crap4j as Crap4jReport;
use SebastianBergmann\CodeCoverage\Report\Html\Facade as HtmlReport;
use SebastianBergmann\CodeCoverage\Report\PHP as PhpReport;
use SebastianBergmann\CodeCoverage\Report\Text as TextReport;
use SebastianBergmann\CodeCoverage\Report\Xml\Facade as XmlReport;
use SebastianBergmann\Comparator\Comparator;
use SebastianBergmann\Environment\Runtime;
use SebastianBergmann\Invoker\Invoker;

/**
 * @internal This class is not covered by the backward compatibility promise for PHPUnit
 */
class TestRunner extends BaseTestRunner
{
    public const SUCCESS_EXIT   = 0;

    public const FAILURE_EXIT   = 1;

    public const EXCEPTION_EXIT = 2;

    /**
     * @var bool
     */
    protected static $versionStringPrinted = false;

    /**
     * @var CodeCoverageFilter
     */
    protected $codeCoverageFilter;

    /**
     * @var TestSuiteLoader
     */
    protected $loader;

    /**
     * @var ResultPrinter
     */
    protected $printer;

    /**
     * @var Runtime
     */
    private $runtime;

    /**
     * @var bool
     */
    private $messagePrinted = false;

    /**
     * @var Hook[]
     */
    private $extensions = [];

    /**
     * @param ReflectionClass|Test $test
     * @param bool                 $exit
     *
     * @throws \RuntimeException
     * @throws \InvalidArgumentException
     * @throws Exception
     * @throws \ReflectionException
     */
    public static function run($test, array $arguments = [], $exit = true): TestResult
    {
        if ($test instanceof ReflectionClass) {
            $test = new TestSuite($test);
        }

        if ($test instanceof Test) {
            $aTestRunner = new self;

            return $aTestRunner->doRun(
                $test,
                $arguments,
                $exit
            );
        }

        throw new Exception('No test case or test suite found.');
    }

    public function __construct(TestSuiteLoader $loader = null, CodeCoverageFilter $filter = null)
    {
        if ($filter === null) {
            $filter = new CodeCoverageFilter;
        }

        $this->codeCoverageFilter = $filter;
        $this->loader             = $loader;
        $this->runtime            = new Runtime;
    }

    /**
     * @throws \PHPUnit\Runner\Exception
     * @throws Exception
     * @throws \InvalidArgumentException
     * @throws \RuntimeException
     * @throws \ReflectionException
     */
    public function doRun(Test $suite, array $arguments = [], bool $exit = true): TestResult
    {
        if (isset($arguments['configuration'])) {
            $GLOBALS['__PHPUNIT_CONFIGURATION_FILE'] = $arguments['configuration'];
        }

        $this->handleConfiguration($arguments);

        if (\is_int($arguments['columns']) && $arguments['columns'] < 16) {
            $arguments['columns']   = 16;
            $tooFewColumnsRequested = true;
        }

        if (isset($arguments['bootstrap'])) {
            $GLOBALS['__PHPUNIT_BOOTSTRAP'] = $arguments['bootstrap'];
        }

        if ($suite instanceof TestCase || $suite instanceof TestSuite) {
            if ($arguments['backupGlobals'] === true) {
                $suite->setBackupGlobals(true);
            }

            if ($arguments['backupStaticAttributes'] === true) {
                $suite->setBackupStaticAttributes(true);
            }

            if ($arguments['beStrictAboutChangesToGlobalState'] === true) {
                $suite->setBeStrictAboutChangesToGlobalState(true);
            }
        }

        if ($arguments['executionOrder'] === TestSuiteSorter::ORDER_RANDOMIZED) {
            \mt_srand($arguments['randomOrderSeed']);
        }

        if ($arguments['cacheResult']) {
            if (isset($arguments['cacheResultFile'])) {
                $cache = new TestResultCache($arguments['cacheResultFile']);
            } else {
                $cache = new TestResultCache;
            }

            $this->addExtension(new ResultCacheExtension($cache));
        }

        if ($arguments['executionOrder'] !== TestSuiteSorter::ORDER_DEFAULT || $arguments['executionOrderDefects'] !== TestSuiteSorter::ORDER_DEFAULT || $arguments['resolveDependencies']) {
            $cache = $cache ?? new NullTestResultCache;

            $cache->load();

            $sorter = new TestSuiteSorter($cache);

            $sorter->reorderTestsInSuite($suite, $arguments['executionOrder'], $arguments['resolveDependencies'], $arguments['executionOrderDefects']);
            $originalExecutionOrder = $sorter->getOriginalExecutionOrder();

            unset($sorter);
        }

        if (\is_int($arguments['repeat']) && $arguments['repeat'] > 0) {
            $_suite = new TestSuite;

            /* @noinspection PhpUnusedLocalVariableInspection */
            foreach (\range(1, $arguments['repeat']) as $step) {
                $_suite->addTest($suite);
            }

            $suite = $_suite;

            unset($_suite);
        }

        $result = $this->createTestResult();

        $listener       = new TestListenerAdapter;
        $listenerNeeded = false;

        foreach ($this->extensions as $extension) {
            if ($extension instanceof TestHook) {
                $listener->add($extension);

                $listenerNeeded = true;
            }
        }

        if ($listenerNeeded) {
            $result->addListener($listener);
        }

        unset($listener, $listenerNeeded);

        if (!$arguments['convertErrorsToExceptions']) {
            $result->convertErrorsToExceptions(false);
        }

        if (!$arguments['convertDeprecationsToExceptions']) {
            Deprecated::$enabled = false;
        }

        if (!$arguments['convertNoticesToExceptions']) {
            Notice::$enabled = false;
        }

        if (!$arguments['convertWarningsToExceptions']) {
            Warning::$enabled = false;
        }

        if ($arguments['stopOnError']) {
            $result->stopOnError(true);
        }

        if ($arguments['stopOnFailure']) {
            $result->stopOnFailure(true);
        }

        if ($arguments['stopOnWarning']) {
            $result->stopOnWarning(true);
        }

        if ($arguments['stopOnIncomplete']) {
            $result->stopOnIncomplete(true);
        }

        if ($arguments['stopOnRisky']) {
            $result->stopOnRisky(true);
        }

        if ($arguments['stopOnSkipped']) {
            $result->stopOnSkipped(true);
        }

        if ($arguments['stopOnDefect']) {
            $result->stopOnDefect(true);
        }

        if ($arguments['registerMockObjectsFromTestArgumentsRecursively']) {
            $result->setRegisterMockObjectsFromTestArgumentsRecursively(true);
        }

        if ($this->printer === null) {
            if (isset($arguments['printer']) &&
                $arguments['printer'] instanceof Printer) {
                $this->printer = $arguments['printer'];
            } else {
                $printerClass = ResultPrinter::class;

                if (isset($arguments['printer']) && \is_string($arguments['printer']) && \class_exists($arguments['printer'], false)) {
                    $class = new ReflectionClass($arguments['printer']);

                    if ($class->isSubclassOf(ResultPrinter::class)) {
                        $printerClass = $arguments['printer'];
                    }
                }

                $this->printer = new $printerClass(
                    (isset($arguments['stderr']) && $arguments['stderr'] === true) ? 'php://stderr' : null,
                    $arguments['verbose'],
                    $arguments['colors'],
                    $arguments['debug'],
                    $arguments['columns'],
                    $arguments['reverseList']
                );

                if (isset($originalExecutionOrder) && ($this->printer instanceof CliTestDoxPrinter)) {
                    /* @var CliTestDoxPrinter */
                    $this->printer->setOriginalExecutionOrder($originalExecutionOrder);
                }
            }
        }

        $this->printer->write(
            Version::getVersionString() . "\n"
        );

        self::$versionStringPrinted = true;

        if ($arguments['verbose']) {
            $this->writeMessage('Runtime', $this->runtime->getNameWithVersionAndCodeCoverageDriver());

            if ($arguments['executionOrder'] === TestSuiteSorter::ORDER_RANDOMIZED) {
                $this->writeMessage(
                    'Random seed',
                    (string) $arguments['randomOrderSeed']
                );
            }

            if (isset($arguments['configuration'])) {
                $this->writeMessage(
                    'Configuration',
                    $arguments['configuration']->getFilename()
                );
            }

            foreach ($arguments['loadedExtensions'] as $extension) {
                $this->writeMessage(
                    'Extension',
                    $extension
                );
            }

            foreach ($arguments['notLoadedExtensions'] as $extension) {
                $this->writeMessage(
                    'Extension',
                    $extension
                );
            }
        }

        if (isset($tooFewColumnsRequested)) {
            $this->writeMessage('Error', 'Less than 16 columns requested, number of columns set to 16');
        }

        if ($this->runtime->discardsComments()) {
            $this->writeMessage('Warning', 'opcache.save_comments=0 set; annotations will not work');
        }

        if (isset($arguments['configuration']) && $arguments['configuration']->hasValidationErrors()) {
            $this->write(
                "\n  Warning - The configuration file did not pass validation!\n  The following problems have been detected:\n"
            );

            foreach ($arguments['configuration']->getValidationErrors() as $line => $errors) {
                $this->write(\sprintf("\n  Line %d:\n", $line));

                foreach ($errors as $msg) {
                    $this->write(\sprintf("  - %s\n", $msg));
                }
            }
            $this->write("\n  Test results may not be as expected.\n\n");
        }

        foreach ($arguments['listeners'] as $listener) {
            $result->addListener($listener);
        }

        $result->addListener($this->printer);

        $codeCoverageReports = 0;

        if (!isset($arguments['noLogging'])) {
            if (isset($arguments['testdoxHTMLFile'])) {
                $result->addListener(
                    new HtmlResultPrinter(
                        $arguments['testdoxHTMLFile'],
                        $arguments['testdoxGroups'],
                        $arguments['testdoxExcludeGroups']
                    )
                );
            }

            if (isset($arguments['testdoxTextFile'])) {
                $result->addListener(
                    new TextResultPrinter(
                        $arguments['testdoxTextFile'],
                        $arguments['testdoxGroups'],
                        $arguments['testdoxExcludeGroups']
                    )
                );
            }

            if (isset($arguments['testdoxXMLFile'])) {
                $result->addListener(
                    new XmlResultPrinter(
                        $arguments['testdoxXMLFile']
                    )
                );
            }

            if (isset($arguments['teamcityLogfile'])) {
                $result->addListener(
                    new TeamCity($arguments['teamcityLogfile'])
                );
            }

            if (isset($arguments['junitLogfile'])) {
                $result->addListener(
                    new JUnit(
                        $arguments['junitLogfile'],
                        $arguments['reportUselessTests']
                    )
                );
            }

            if (isset($arguments['coverageClover'])) {
                $codeCoverageReports++;
            }

            if (isset($arguments['coverageCrap4J'])) {
                $codeCoverageReports++;
            }

            if (isset($arguments['coverageHtml'])) {
                $codeCoverageReports++;
            }

            if (isset($arguments['coveragePHP'])) {
                $codeCoverageReports++;
            }

            if (isset($arguments['coverageText'])) {
                $codeCoverageReports++;
            }

            if (isset($arguments['coverageXml'])) {
                $codeCoverageReports++;
            }
        }

        if (isset($arguments['noCoverage'])) {
            $codeCoverageReports = 0;
        }

        if ($codeCoverageReports > 0 && !$this->runtime->canCollectCodeCoverage()) {
            $this->writeMessage('Error', 'No code coverage driver is available');

            $codeCoverageReports = 0;
        }

        if ($codeCoverageReports > 0 || isset($arguments['xdebugFilterFile'])) {
            $whitelistFromConfigurationFile = false;
            $whitelistFromOption            = false;

            if (isset($arguments['whitelist'])) {
                $this->codeCoverageFilter->addDirectoryToWhitelist($arguments['whitelist']);

                $whitelistFromOption = true;
            }

            if (isset($arguments['configuration'])) {
                $filterConfiguration = $arguments['configuration']->getFilterConfiguration();

                if (!empty($filterConfiguration['whitelist'])) {
                    $whitelistFromConfigurationFile = true;
                }

                if (!empty($filterConfiguration['whitelist'])) {
                    foreach ($filterConfiguration['whitelist']['include']['directory'] as $dir) {
                        $this->codeCoverageFilter->addDirectoryToWhitelist(
                            $dir['path'],
                            $dir['suffix'],
                            $dir['prefix']
                        );
                    }

                    foreach ($filterConfiguration['whitelist']['include']['file'] as $file) {
                        $this->codeCoverageFilter->addFileToWhitelist($file);
                    }

                    foreach ($filterConfiguration['whitelist']['exclude']['directory'] as $dir) {
                        $this->codeCoverageFilter->removeDirectoryFromWhitelist(
                            $dir['path'],
                            $dir['suffix'],
                            $dir['prefix']
                        );
                    }

                    foreach ($filterConfiguration['whitelist']['exclude']['file'] as $file) {
                        $this->codeCoverageFilter->removeFileFromWhitelist($file);
                    }
                }
            }
        }

        if ($codeCoverageReports > 0) {
            $codeCoverage = new CodeCoverage(
                null,
                $this->codeCoverageFilter
            );

            $codeCoverage->setUnintentionallyCoveredSubclassesWhitelist(
                [Comparator::class]
            );

            $codeCoverage->setCheckForUnintentionallyCoveredCode(
                $arguments['strictCoverage']
            );

            $codeCoverage->setCheckForMissingCoversAnnotation(
                $arguments['strictCoverage']
            );

            if (isset($arguments['forceCoversAnnotation'])) {
                $codeCoverage->setForceCoversAnnotation(
                    $arguments['forceCoversAnnotation']
                );
            }

            if (isset($arguments['ignoreDeprecatedCodeUnitsFromCodeCoverage'])) {
                $codeCoverage->setIgnoreDeprecatedCode(
                    $arguments['ignoreDeprecatedCodeUnitsFromCodeCoverage']
                );
            }

            if (isset($arguments['disableCodeCoverageIgnore'])) {
                $codeCoverage->setDisableIgnoredLines(true);
            }

            if (!empty($filterConfiguration['whitelist'])) {
                $codeCoverage->setAddUncoveredFilesFromWhitelist(
                    $filterConfiguration['whitelist']['addUncoveredFilesFromWhitelist']
                );

                $codeCoverage->setProcessUncoveredFilesFromWhitelist(
                    $filterConfiguration['whitelist']['processUncoveredFilesFromWhitelist']
                );
            }

            if (!$this->codeCoverageFilter->hasWhitelist()) {
                if (!$whitelistFromConfigurationFile && !$whitelistFromOption) {
                    $this->writeMessage('Error', 'No whitelist is configured, no code coverage will be generated.');
                } else {
                    $this->writeMessage('Error', 'Incorrect whitelist config, no code coverage will be generated.');
                }

                $codeCoverageReports = 0;

                unset($codeCoverage);
            }
        }

        if (isset($arguments['xdebugFilterFile'], $filterConfiguration)) {
            $this->write("\n");

            $script = (new XdebugFilterScriptGenerator)->generate($filterConfiguration['whitelist']);

            if ($arguments['xdebugFilterFile'] !== 'php://stdout' && $arguments['xdebugFilterFile'] !== 'php://stderr' && !Filesystem::createDirectory(\dirname($arguments['xdebugFilterFile']))) {
                $this->write(\sprintf('Cannot write Xdebug filter script to %s ' . \PHP_EOL, $arguments['xdebugFilterFile']));

                exit(self::EXCEPTION_EXIT);
            }

            \file_put_contents($arguments['xdebugFilterFile'], $script);

            $this->write(\sprintf('Wrote Xdebug filter script to %s ' . \PHP_EOL, $arguments['xdebugFilterFile']));

            exit(self::SUCCESS_EXIT);
        }

        $this->printer->write("\n");

        if (isset($codeCoverage)) {
            $result->setCodeCoverage($codeCoverage);

            if ($codeCoverageReports > 1 && isset($arguments['cacheTokens'])) {
                $codeCoverage->setCacheTokens($arguments['cacheTokens']);
            }
        }

        $result->beStrictAboutTestsThatDoNotTestAnything($arguments['reportUselessTests']);
        $result->beStrictAboutOutputDuringTests($arguments['disallowTestOutput']);
        $result->beStrictAboutTodoAnnotatedTests($arguments['disallowTodoAnnotatedTests']);
        $result->beStrictAboutResourceUsageDuringSmallTests($arguments['beStrictAboutResourceUsageDuringSmallTests']);

        if ($arguments['enforceTimeLimit'] === true) {
            if (!\class_exists(Invoker::class)) {
                $this->writeMessage('Error', 'Package phpunit/php-invoker is required for enforcing time limits');
            }

            if (!\extension_loaded('pcntl') || \strpos(\ini_get('disable_functions'), 'pcntl') !== false) {
                $this->writeMessage('Error', 'PHP extension pcntl is required for enforcing time limits');
            }
        }
        $result->enforceTimeLimit($arguments['enforceTimeLimit']);
        $result->setDefaultTimeLimit($arguments['defaultTimeLimit']);
        $result->setTimeoutForSmallTests($arguments['timeoutForSmallTests']);
        $result->setTimeoutForMediumTests($arguments['timeoutForMediumTests']);
        $result->setTimeoutForLargeTests($arguments['timeoutForLargeTests']);

        if ($suite instanceof TestSuite) {
            $this->processSuiteFilters($suite, $arguments);
            $suite->setRunTestInSeparateProcess($arguments['processIsolation']);
        }

        foreach ($this->extensions as $extension) {
            if ($extension instanceof BeforeFirstTestHook) {
                $extension->executeBeforeFirstTest();
            }
        }

        $suite->run($result);

        foreach ($this->extensions as $extension) {
            if ($extension instanceof AfterLastTestHook) {
                $extension->executeAfterLastTest();
            }
        }

        $result->flushListeners();

        if ($this->printer instanceof ResultPrinter) {
            $this->printer->printResult($result);
        }

        if (isset($codeCoverage)) {
            if (isset($arguments['coverageClover'])) {
                $this->printer->write(
                    "\nGenerating code coverage report in Clover XML format ..."
                );

                try {
                    $writer = new CloverReport;
                    $writer->process($codeCoverage, $arguments['coverageClover']);

                    $this->printer->write(" done\n");
                    unset($writer);
                } catch (CodeCoverageException $e) {
                    $this->printer->write(
                        " failed\n" . $e->getMessage() . "\n"
                    );
                }
            }

            if (isset($arguments['coverageCrap4J'])) {
                $this->printer->write(
                    "\nGenerating Crap4J report XML file ..."
                );

                try {
                    $writer = new Crap4jReport($arguments['crap4jThreshold']);
                    $writer->process($codeCoverage, $arguments['coverageCrap4J']);

                    $this->printer->write(" done\n");
                    unset($writer);
                } catch (CodeCoverageException $e) {
                    $this->printer->write(
                        " failed\n" . $e->getMessage() . "\n"
                    );
                }
            }

            if (isset($arguments['coverageHtml'])) {
                $this->printer->write(
                    "\nGenerating code coverage report in HTML format ..."
                );

                try {
                    $writer = new HtmlReport(
                        $arguments['reportLowUpperBound'],
                        $arguments['reportHighLowerBound'],
                        \sprintf(
                            ' and <a href="https://phpunit.de/">PHPUnit %s</a>',
                            Version::id()
                        )
                    );

                    $writer->process($codeCoverage, $arguments['coverageHtml']);

                    $this->printer->write(" done\n");
                    unset($writer);
                } catch (CodeCoverageException $e) {
                    $this->printer->write(
                        " failed\n" . $e->getMessage() . "\n"
                    );
                }
            }

            if (isset($arguments['coveragePHP'])) {
                $this->printer->write(
                    "\nGenerating code coverage report in PHP format ..."
                );

                try {
                    $writer = new PhpReport;
                    $writer->process($codeCoverage, $arguments['coveragePHP']);

                    $this->printer->write(" done\n");
                    unset($writer);
                } catch (CodeCoverageException $e) {
                    $this->printer->write(
                        " failed\n" . $e->getMessage() . "\n"
                    );
                }
            }

            if (isset($arguments['coverageText'])) {
                if ($arguments['coverageText'] == 'php://stdout') {
                    $outputStream = $this->printer;
                    $colors       = $arguments['colors'] && $arguments['colors'] != ResultPrinter::COLOR_NEVER;
                } else {
                    $outputStream = new Printer($arguments['coverageText']);
                    $colors       = false;
                }

                $processor = new TextReport(
                    $arguments['reportLowUpperBound'],
                    $arguments['reportHighLowerBound'],
                    $arguments['coverageTextShowUncoveredFiles'],
                    $arguments['coverageTextShowOnlySummary']
                );

                $outputStream->write(
                    $processor->process($codeCoverage, $colors)
                );
            }

            if (isset($arguments['coverageXml'])) {
                $this->printer->write(
                    "\nGenerating code coverage report in PHPUnit XML format ..."
                );

                try {
                    $writer = new XmlReport(Version::id());
                    $writer->process($codeCoverage, $arguments['coverageXml']);

                    $this->printer->write(" done\n");
                    unset($writer);
                } catch (CodeCoverageException $e) {
                    $this->printer->write(
                        " failed\n" . $e->getMessage() . "\n"
                    );
                }
            }
        }

        if ($exit) {
            if ($result->wasSuccessful()) {
                if ($arguments['failOnRisky'] && !$result->allHarmless()) {
                    exit(self::FAILURE_EXIT);
                }

                if ($arguments['failOnWarning'] && $result->warningCount() > 0) {
                    exit(self::FAILURE_EXIT);
                }

                exit(self::SUCCESS_EXIT);
            }

            if ($result->errorCount() > 0) {
                exit(self::EXCEPTION_EXIT);
            }

            if ($result->failureCount() > 0) {
                exit(self::FAILURE_EXIT);
            }
        }

        return $result;
    }

    public function setPrinter(ResultPrinter $resultPrinter): void
    {
        $this->printer = $resultPrinter;
    }

    /**
     * Returns the loader to be used.
     */
    public function getLoader(): TestSuiteLoader
    {
        if ($this->loader === null) {
            $this->loader = new StandardTestSuiteLoader;
        }

        return $this->loader;
    }

    public function addExtension(TestHook $extension): void
    {
        $this->extensions[] = $extension;
    }

    protected function createTestResult(): TestResult
    {
        return new TestResult;
    }

    /**
     * Override to define how to handle a failed loading of
     * a test suite.
     */
    protected function runFailed(string $message): void
    {
        $this->write($message . \PHP_EOL);

        exit(self::FAILURE_EXIT);
    }

    protected function write(string $buffer): void
    {
        if (\PHP_SAPI != 'cli' && \PHP_SAPI != 'phpdbg') {
            $buffer = \htmlspecialchars($buffer);
        }

        if ($this->printer !== null) {
            $this->printer->write($buffer);
        } else {
            print $buffer;
        }
    }

    /**
     * @throws Exception
     */
    protected function handleConfiguration(array &$arguments): void
    {
        if (isset($arguments['configuration']) &&
            !$arguments['configuration'] instanceof Configuration) {
            $arguments['configuration'] = Configuration::getInstance(
                $arguments['configuration']
            );
        }

        $arguments['debug']     = $arguments['debug'] ?? false;
        $arguments['filter']    = $arguments['filter'] ?? false;
        $arguments['listeners'] = $arguments['listeners'] ?? [];

        if (isset($arguments['configuration'])) {
            $arguments['configuration']->handlePHPConfiguration();

            $phpunitConfiguration = $arguments['configuration']->getPHPUnitConfiguration();

            if (isset($phpunitConfiguration['backupGlobals']) && !isset($arguments['backupGlobals'])) {
                $arguments['backupGlobals'] = $phpunitConfiguration['backupGlobals'];
            }

            if (isset($phpunitConfiguration['backupStaticAttributes']) && !isset($arguments['backupStaticAttributes'])) {
                $arguments['backupStaticAttributes'] = $phpunitConfiguration['backupStaticAttributes'];
            }

            if (isset($phpunitConfiguration['beStrictAboutChangesToGlobalState']) && !isset($arguments['beStrictAboutChangesToGlobalState'])) {
                $arguments['beStrictAboutChangesToGlobalState'] = $phpunitConfiguration['beStrictAboutChangesToGlobalState'];
            }

            if (isset($phpunitConfiguration['bootstrap']) && !isset($arguments['bootstrap'])) {
                $arguments['bootstrap'] = $phpunitConfiguration['bootstrap'];
            }

            if (isset($phpunitConfiguration['cacheResult']) && !isset($arguments['cacheResult'])) {
                $arguments['cacheResult'] = $phpunitConfiguration['cacheResult'];
            }

            if (isset($phpunitConfiguration['cacheResultFile']) && !isset($arguments['cacheResultFile'])) {
                $arguments['cacheResultFile'] = $phpunitConfiguration['cacheResultFile'];
            }

            if (isset($phpunitConfiguration['cacheTokens']) && !isset($arguments['cacheTokens'])) {
                $arguments['cacheTokens'] = $phpunitConfiguration['cacheTokens'];
            }

            if (isset($phpunitConfiguration['cacheTokens']) && !isset($arguments['cacheTokens'])) {
                $arguments['cacheTokens'] = $phpunitConfiguration['cacheTokens'];
            }

            if (isset($phpunitConfiguration['colors']) && !isset($arguments['colors'])) {
                $arguments['colors'] = $phpunitConfiguration['colors'];
            }

            if (isset($phpunitConfiguration['convertDeprecationsToExceptions']) && !isset($arguments['convertDeprecationsToExceptions'])) {
                $arguments['convertDeprecationsToExceptions'] = $phpunitConfiguration['convertDeprecationsToExceptions'];
            }

            if (isset($phpunitConfiguration['convertErrorsToExceptions']) && !isset($arguments['convertErrorsToExceptions'])) {
                $arguments['convertErrorsToExceptions'] = $phpunitConfiguration['convertErrorsToExceptions'];
            }

            if (isset($phpunitConfiguration['convertNoticesToExceptions']) && !isset($arguments['convertNoticesToExceptions'])) {
                $arguments['convertNoticesToExceptions'] = $phpunitConfiguration['convertNoticesToExceptions'];
            }

            if (isset($phpunitConfiguration['convertWarningsToExceptions']) && !isset($arguments['convertWarningsToExceptions'])) {
                $arguments['convertWarningsToExceptions'] = $phpunitConfiguration['convertWarningsToExceptions'];
            }

            if (isset($phpunitConfiguration['processIsolation']) && !isset($arguments['processIsolation'])) {
                $arguments['processIsolation'] = $phpunitConfiguration['processIsolation'];
            }

            if (isset($phpunitConfiguration['stopOnDefect']) && !isset($arguments['stopOnDefect'])) {
                $arguments['stopOnDefect'] = $phpunitConfiguration['stopOnDefect'];
            }

            if (isset($phpunitConfiguration['stopOnError']) && !isset($arguments['stopOnError'])) {
                $arguments['stopOnError'] = $phpunitConfiguration['stopOnError'];
            }

            if (isset($phpunitConfiguration['stopOnFailure']) && !isset($arguments['stopOnFailure'])) {
                $arguments['stopOnFailure'] = $phpunitConfiguration['stopOnFailure'];
            }

            if (isset($phpunitConfiguration['stopOnWarning']) && !isset($arguments['stopOnWarning'])) {
                $arguments['stopOnWarning'] = $phpunitConfiguration['stopOnWarning'];
            }

            if (isset($phpunitConfiguration['stopOnIncomplete']) && !isset($arguments['stopOnIncomplete'])) {
                $arguments['stopOnIncomplete'] = $phpunitConfiguration['stopOnIncomplete'];
            }

            if (isset($phpunitConfiguration['stopOnRisky']) && !isset($arguments['stopOnRisky'])) {
                $arguments['stopOnRisky'] = $phpunitConfiguration['stopOnRisky'];
            }

            if (isset($phpunitConfiguration['stopOnSkipped']) && !isset($arguments['stopOnSkipped'])) {
                $arguments['stopOnSkipped'] = $phpunitConfiguration['stopOnSkipped'];
            }

            if (isset($phpunitConfiguration['failOnWarning']) && !isset($arguments['failOnWarning'])) {
                $arguments['failOnWarning'] = $phpunitConfiguration['failOnWarning'];
            }

            if (isset($phpunitConfiguration['failOnRisky']) && !isset($arguments['failOnRisky'])) {
                $arguments['failOnRisky'] = $phpunitConfiguration['failOnRisky'];
            }

            if (isset($phpunitConfiguration['timeoutForSmallTests']) && !isset($arguments['timeoutForSmallTests'])) {
                $arguments['timeoutForSmallTests'] = $phpunitConfiguration['timeoutForSmallTests'];
            }

            if (isset($phpunitConfiguration['timeoutForMediumTests']) && !isset($arguments['timeoutForMediumTests'])) {
                $arguments['timeoutForMediumTests'] = $phpunitConfiguration['timeoutForMediumTests'];
            }

            if (isset($phpunitConfiguration['timeoutForLargeTests']) && !isset($arguments['timeoutForLargeTests'])) {
                $arguments['timeoutForLargeTests'] = $phpunitConfiguration['timeoutForLargeTests'];
            }

            if (isset($phpunitConfiguration['reportUselessTests']) && !isset($arguments['reportUselessTests'])) {
                $arguments['reportUselessTests'] = $phpunitConfiguration['reportUselessTests'];
            }

            if (isset($phpunitConfiguration['strictCoverage']) && !isset($arguments['strictCoverage'])) {
                $arguments['strictCoverage'] = $phpunitConfiguration['strictCoverage'];
            }

            if (isset($phpunitConfiguration['ignoreDeprecatedCodeUnitsFromCodeCoverage']) && !isset($arguments['ignoreDeprecatedCodeUnitsFromCodeCoverage'])) {
                $arguments['ignoreDeprecatedCodeUnitsFromCodeCoverage'] = $phpunitConfiguration['ignoreDeprecatedCodeUnitsFromCodeCoverage'];
            }

            if (isset($phpunitConfiguration['disallowTestOutput']) && !isset($arguments['disallowTestOutput'])) {
                $arguments['disallowTestOutput'] = $phpunitConfiguration['disallowTestOutput'];
            }

            if (isset($phpunitConfiguration['defaultTimeLimit']) && !isset($arguments['defaultTimeLimit'])) {
                $arguments['defaultTimeLimit'] = $phpunitConfiguration['defaultTimeLimit'];
            }

            if (isset($phpunitConfiguration['enforceTimeLimit']) && !isset($arguments['enforceTimeLimit'])) {
                $arguments['enforceTimeLimit'] = $phpunitConfiguration['enforceTimeLimit'];
            }

            if (isset($phpunitConfiguration['disallowTodoAnnotatedTests']) && !isset($arguments['disallowTodoAnnotatedTests'])) {
                $arguments['disallowTodoAnnotatedTests'] = $phpunitConfiguration['disallowTodoAnnotatedTests'];
            }

            if (isset($phpunitConfiguration['beStrictAboutResourceUsageDuringSmallTests']) && !isset($arguments['beStrictAboutResourceUsageDuringSmallTests'])) {
                $arguments['beStrictAboutResourceUsageDuringSmallTests'] = $phpunitConfiguration['beStrictAboutResourceUsageDuringSmallTests'];
            }

            if (isset($phpunitConfiguration['verbose']) && !isset($arguments['verbose'])) {
                $arguments['verbose'] = $phpunitConfiguration['verbose'];
            }

            if (isset($phpunitConfiguration['reverseDefectList']) && !isset($arguments['reverseList'])) {
                $arguments['reverseList'] = $phpunitConfiguration['reverseDefectList'];
            }

            if (isset($phpunitConfiguration['forceCoversAnnotation']) && !isset($arguments['forceCoversAnnotation'])) {
                $arguments['forceCoversAnnotation'] = $phpunitConfiguration['forceCoversAnnotation'];
            }

            if (isset($phpunitConfiguration['disableCodeCoverageIgnore']) && !isset($arguments['disableCodeCoverageIgnore'])) {
                $arguments['disableCodeCoverageIgnore'] = $phpunitConfiguration['disableCodeCoverageIgnore'];
            }

            if (isset($phpunitConfiguration['registerMockObjectsFromTestArgumentsRecursively']) && !isset($arguments['registerMockObjectsFromTestArgumentsRecursively'])) {
                $arguments['registerMockObjectsFromTestArgumentsRecursively'] = $phpunitConfiguration['registerMockObjectsFromTestArgumentsRecursively'];
            }

            if (isset($phpunitConfiguration['executionOrder']) && !isset($arguments['executionOrder'])) {
                $arguments['executionOrder'] = $phpunitConfiguration['executionOrder'];
            }

            if (isset($phpunitConfiguration['executionOrderDefects']) && !isset($arguments['executionOrderDefects'])) {
                $arguments['executionOrderDefects'] = $phpunitConfiguration['executionOrderDefects'];
            }

            if (isset($phpunitConfiguration['resolveDependencies']) && !isset($arguments['resolveDependencies'])) {
                $arguments['resolveDependencies'] = $phpunitConfiguration['resolveDependencies'];
            }

            $groupCliArgs = [];

            if (!empty($arguments['groups'])) {
                $groupCliArgs = $arguments['groups'];
            }

            $groupConfiguration = $arguments['configuration']->getGroupConfiguration();

            if (!empty($groupConfiguration['include']) && !isset($arguments['groups'])) {
                $arguments['groups'] = $groupConfiguration['include'];
            }

            if (!empty($groupConfiguration['exclude']) && !isset($arguments['excludeGroups'])) {
                $arguments['excludeGroups'] = \array_diff($groupConfiguration['exclude'], $groupCliArgs);
            }

            foreach ($arguments['configuration']->getExtensionConfiguration() as $extension) {
                if (!\class_exists($extension['class'], false) && $extension['file'] !== '') {
                    require_once $extension['file'];
                }

                if (!\class_exists($extension['class'])) {
                    throw new Exception(
                        \sprintf(
                            'Class "%s" does not exist',
                            $extension['class']
                        )
                    );
                }

                $extensionClass = new ReflectionClass($extension['class']);

                if (!$extensionClass->implementsInterface(Hook::class)) {
                    throw new Exception(
                        \sprintf(
                            'Class "%s" does not implement a PHPUnit\Runner\Hook interface',
                            $extension['class']
                        )
                    );
                }

                if (\count($extension['arguments']) == 0) {
                    $extensionObject = $extensionClass->newInstance();
                } else {
                    $extensionObject = $extensionClass->newInstanceArgs(
                        $extension['arguments']
                    );
                }

                \assert($extensionObject instanceof TestHook);

                $this->addExtension($extensionObject);
            }

            foreach ($arguments['configuration']->getListenerConfiguration() as $listener) {
                if (!\class_exists($listener['class'], false) &&
                    $listener['file'] !== '') {
                    require_once $listener['file'];
                }

                if (!\class_exists($listener['class'])) {
                    throw new Exception(
                        \sprintf(
                            'Class "%s" does not exist',
                            $listener['class']
                        )
                    );
                }

                $listenerClass = new ReflectionClass($listener['class']);

                if (!$listenerClass->implementsInterface(TestListener::class)) {
                    throw new Exception(
                        \sprintf(
                            'Class "%s" does not implement the PHPUnit\Framework\TestListener interface',
                            $listener['class']
                        )
                    );
                }

                if (\count($listener['arguments']) == 0) {
                    $listener = new $listener['class'];
                } else {
                    $listener = $listenerClass->newInstanceArgs(
                        $listener['arguments']
                    );
                }

                $arguments['listeners'][] = $listener;
            }

            $loggingConfiguration = $arguments['configuration']->getLoggingConfiguration();

            if (isset($loggingConfiguration['coverage-clover']) && !isset($arguments['coverageClover'])) {
                $arguments['coverageClover'] = $loggingConfiguration['coverage-clover'];
            }

            if (isset($loggingConfiguration['coverage-crap4j']) && !isset($arguments['coverageCrap4J'])) {
                $arguments['coverageCrap4J'] = $loggingConfiguration['coverage-crap4j'];

                if (isset($loggingConfiguration['crap4jThreshold']) && !isset($arguments['crap4jThreshold'])) {
                    $arguments['crap4jThreshold'] = $loggingConfiguration['crap4jThreshold'];
                }
            }

            if (isset($loggingConfiguration['coverage-html']) && !isset($arguments['coverageHtml'])) {
                if (isset($loggingConfiguration['lowUpperBound']) && !isset($arguments['reportLowUpperBound'])) {
                    $arguments['reportLowUpperBound'] = $loggingConfiguration['lowUpperBound'];
                }

                if (isset($loggingConfiguration['highLowerBound']) && !isset($arguments['reportHighLowerBound'])) {
                    $arguments['reportHighLowerBound'] = $loggingConfiguration['highLowerBound'];
                }

                $arguments['coverageHtml'] = $loggingConfiguration['coverage-html'];
            }

            if (isset($loggingConfiguration['coverage-php']) && !isset($arguments['coveragePHP'])) {
                $arguments['coveragePHP'] = $loggingConfiguration['coverage-php'];
            }

            if (isset($loggingConfiguration['coverage-text']) && !isset($arguments['coverageText'])) {
                $arguments['coverageText'] = $loggingConfiguration['coverage-text'];

                if (isset($loggingConfiguration['coverageTextShowUncoveredFiles'])) {
                    $arguments['coverageTextShowUncoveredFiles'] = $loggingConfiguration['coverageTextShowUncoveredFiles'];
                } else {
                    $arguments['coverageTextShowUncoveredFiles'] = false;
                }

                if (isset($loggingConfiguration['coverageTextShowOnlySummary'])) {
                    $arguments['coverageTextShowOnlySummary'] = $loggingConfiguration['coverageTextShowOnlySummary'];
                } else {
                    $arguments['coverageTextShowOnlySummary'] = false;
                }
            }

            if (isset($loggingConfiguration['coverage-xml']) && !isset($arguments['coverageXml'])) {
                $arguments['coverageXml'] = $loggingConfiguration['coverage-xml'];
            }

            if (isset($loggingConfiguration['plain'])) {
                $arguments['listeners'][] = new ResultPrinter(
                    $loggingConfiguration['plain'],
                    true
                );
            }

            if (isset($loggingConfiguration['teamcity']) && !isset($arguments['teamcityLogfile'])) {
                $arguments['teamcityLogfile'] = $loggingConfiguration['teamcity'];
            }

            if (isset($loggingConfiguration['junit']) && !isset($arguments['junitLogfile'])) {
                $arguments['junitLogfile'] = $loggingConfiguration['junit'];
            }

            if (isset($loggingConfiguration['testdox-html']) && !isset($arguments['testdoxHTMLFile'])) {
                $arguments['testdoxHTMLFile'] = $loggingConfiguration['testdox-html'];
            }

            if (isset($loggingConfiguration['testdox-text']) && !isset($arguments['testdoxTextFile'])) {
                $arguments['testdoxTextFile'] = $loggingConfiguration['testdox-text'];
            }

            if (isset($loggingConfiguration['testdox-xml']) && !isset($arguments['testdoxXMLFile'])) {
                $arguments['testdoxXMLFile'] = $loggingConfiguration['testdox-xml'];
            }

            $testdoxGroupConfiguration = $arguments['configuration']->getTestdoxGroupConfiguration();

            if (isset($testdoxGroupConfiguration['include']) &&
                !isset($arguments['testdoxGroups'])) {
                $arguments['testdoxGroups'] = $testdoxGroupConfiguration['include'];
            }

            if (isset($testdoxGroupConfiguration['exclude']) &&
                !isset($arguments['testdoxExcludeGroups'])) {
                $arguments['testdoxExcludeGroups'] = $testdoxGroupConfiguration['exclude'];
            }
        }

        $arguments['addUncoveredFilesFromWhitelist']                  = $arguments['addUncoveredFilesFromWhitelist'] ?? true;
        $arguments['backupGlobals']                                   = $arguments['backupGlobals'] ?? null;
        $arguments['backupStaticAttributes']                          = $arguments['backupStaticAttributes'] ?? null;
        $arguments['beStrictAboutChangesToGlobalState']               = $arguments['beStrictAboutChangesToGlobalState'] ?? null;
        $arguments['beStrictAboutResourceUsageDuringSmallTests']      = $arguments['beStrictAboutResourceUsageDuringSmallTests'] ?? false;
        $arguments['cacheResult']                                     = $arguments['cacheResult'] ?? true;
        $arguments['cacheTokens']                                     = $arguments['cacheTokens'] ?? false;
        $arguments['colors']                                          = $arguments['colors'] ?? ResultPrinter::COLOR_DEFAULT;
        $arguments['columns']                                         = $arguments['columns'] ?? 80;
        $arguments['convertDeprecationsToExceptions']                 = $arguments['convertDeprecationsToExceptions'] ?? true;
        $arguments['convertErrorsToExceptions']                       = $arguments['convertErrorsToExceptions'] ?? true;
        $arguments['convertNoticesToExceptions']                      = $arguments['convertNoticesToExceptions'] ?? true;
        $arguments['convertWarningsToExceptions']                     = $arguments['convertWarningsToExceptions'] ?? true;
        $arguments['crap4jThreshold']                                 = $arguments['crap4jThreshold'] ?? 30;
        $arguments['disallowTestOutput']                              = $arguments['disallowTestOutput'] ?? false;
        $arguments['disallowTodoAnnotatedTests']                      = $arguments['disallowTodoAnnotatedTests'] ?? false;
        $arguments['defaultTimeLimit']                                = $arguments['defaultTimeLimit'] ?? 0;
        $arguments['enforceTimeLimit']                                = $arguments['enforceTimeLimit'] ?? false;
        $arguments['excludeGroups']                                   = $arguments['excludeGroups'] ?? [];
        $arguments['failOnRisky']                                     = $arguments['failOnRisky'] ?? false;
        $arguments['failOnWarning']                                   = $arguments['failOnWarning'] ?? false;
        $arguments['executionOrderDefects']                           = $arguments['executionOrderDefects'] ?? TestSuiteSorter::ORDER_DEFAULT;
        $arguments['groups']                                          = $arguments['groups'] ?? [];
        $arguments['processIsolation']                                = $arguments['processIsolation'] ?? false;
        $arguments['processUncoveredFilesFromWhitelist']              = $arguments['processUncoveredFilesFromWhitelist'] ?? false;
        $arguments['randomOrderSeed']                                 = $arguments['randomOrderSeed'] ?? \time();
        $arguments['registerMockObjectsFromTestArgumentsRecursively'] = $arguments['registerMockObjectsFromTestArgumentsRecursively'] ?? false;
        $arguments['repeat']                                          = $arguments['repeat'] ?? false;
        $arguments['reportHighLowerBound']                            = $arguments['reportHighLowerBound'] ?? 90;
        $arguments['reportLowUpperBound']                             = $arguments['reportLowUpperBound'] ?? 50;
        $arguments['reportUselessTests']                              = $arguments['reportUselessTests'] ?? true;
        $arguments['reverseList']                                     = $arguments['reverseList'] ?? false;
        $arguments['executionOrder']                                  = $arguments['executionOrder'] ?? TestSuiteSorter::ORDER_DEFAULT;
        $arguments['resolveDependencies']                             = $arguments['resolveDependencies'] ?? true;
        $arguments['stopOnError']                                     = $arguments['stopOnError'] ?? false;
        $arguments['stopOnFailure']                                   = $arguments['stopOnFailure'] ?? false;
        $arguments['stopOnIncomplete']                                = $arguments['stopOnIncomplete'] ?? false;
        $arguments['stopOnRisky']                                     = $arguments['stopOnRisky'] ?? false;
        $arguments['stopOnSkipped']                                   = $arguments['stopOnSkipped'] ?? false;
        $arguments['stopOnWarning']                                   = $arguments['stopOnWarning'] ?? false;
        $arguments['stopOnDefect']                                    = $arguments['stopOnDefect'] ?? false;
        $arguments['strictCoverage']                                  = $arguments['strictCoverage'] ?? false;
        $arguments['testdoxExcludeGroups']                            = $arguments['testdoxExcludeGroups'] ?? [];
        $arguments['testdoxGroups']                                   = $arguments['testdoxGroups'] ?? [];
        $arguments['timeoutForLargeTests']                            = $arguments['timeoutForLargeTests'] ?? 60;
        $arguments['timeoutForMediumTests']                           = $arguments['timeoutForMediumTests'] ?? 10;
        $arguments['timeoutForSmallTests']                            = $arguments['timeoutForSmallTests'] ?? 1;
        $arguments['verbose']                                         = $arguments['verbose'] ?? false;
    }

    /**
     * @throws \ReflectionException
     * @throws \InvalidArgumentException
     */
    private function processSuiteFilters(TestSuite $suite, array $arguments): void
    {
        if (!$arguments['filter'] &&
            empty($arguments['groups']) &&
            empty($arguments['excludeGroups'])) {
            return;
        }

        $filterFactory = new Factory;

        if (!empty($arguments['excludeGroups'])) {
            $filterFactory->addFilter(
                new ReflectionClass(ExcludeGroupFilterIterator::class),
                $arguments['excludeGroups']
            );
        }

        if (!empty($arguments['groups'])) {
            $filterFactory->addFilter(
                new ReflectionClass(IncludeGroupFilterIterator::class),
                $arguments['groups']
            );
        }

        if ($arguments['filter']) {
            $filterFactory->addFilter(
                new ReflectionClass(NameFilterIterator::class),
                $arguments['filter']
            );
        }

        $suite->injectFilter($filterFactory);
    }

    private function writeMessage(string $type, string $message): void
    {
        if (!$this->messagePrinted) {
            $this->write("\n");
        }

        $this->write(
            \sprintf(
                "%-15s%s\n",
                $type . ':',
                $message
            )
        );

        $this->messagePrinted = true;
    }
}
<?php declare(strict_types=1);
/*
 * This file is part of PHPUnit.
 *
 * (c) Sebastian Bergmann <sebastian@phpunit.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace Codeception\PHPUnit\NonFinal;

use PHPUnit\Framework\TestSuite;
use PHPUnit\Framework\WarningTestCase;
use PHPUnit\Util\RegularExpression;
use RecursiveFilterIterator;
use RecursiveIterator;

/**
 * @internal This class is not covered by the backward compatibility promise for PHPUnit
 */
class NameFilterIterator extends RecursiveFilterIterator
{
    /**
     * @var string
     */
    protected $filter;

    /**
     * @var int
     */
    protected $filterMin;

    /**
     * @var int
     */
    protected $filterMax;

    /**
     * @throws \Exception
     */
    public function __construct(RecursiveIterator $iterator, string $filter)
    {
        parent::__construct($iterator);

        $this->setFilter($filter);
    }

    /**
     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
     */
    public function accept(): bool
    {
        $test = $this->getInnerIterator()->current();

        if ($test instanceof TestSuite) {
            return true;
        }

        $tmp = \PHPUnit\Util\Test::describe($test);

        if ($test instanceof WarningTestCase) {
            $name = $test->getMessage();
        } else {
            if ($tmp[0] !== '') {
                $name = \implode('::', $tmp);
            } else {
                $name = $tmp[1];
            }
        }

        $accepted = @\preg_match($this->filter, $name, $matches);

        if ($accepted && isset($this->filterMax)) {
            $set      = \end($matches);
            $accepted = $set >= $this->filterMin && $set <= $this->filterMax;
        }

        return (bool) $accepted;
    }

    /**
     * @throws \Exception
     */
    protected function setFilter(string $filter): void
    {
        if (RegularExpression::safeMatch($filter, '') === false) {
            // Handles:
            //  * testAssertEqualsSucceeds#4
            //  * testAssertEqualsSucceeds#4-8
            if (\preg_match('/^(.*?)#(\d+)(?:-(\d+))?$/', $filter, $matches)) {
                if (isset($matches[3]) && $matches[2] < $matches[3]) {
                    $filter = \sprintf(
                        '%s.*with data set #(\d+)$',
                        $matches[1]
                    );

                    $this->filterMin = $matches[2];
                    $this->filterMax = $matches[3];
                } else {
                    $filter = \sprintf(
                        '%s.*with data set #%s$',
                        $matches[1],
                        $matches[2]
                    );
                }
            } // Handles:
            //  * testDetermineJsonError@JSON_ERROR_NONE
            //  * testDetermineJsonError@JSON.*
            elseif (\preg_match('/^(.*?)@(.+)$/', $filter, $matches)) {
                $filter = \sprintf(
                    '%s.*with data set "%s"$',
                    $matches[1],
                    $matches[2]
                );
            }

            // Escape delimiters in regular expression. Do NOT use preg_quote,
            // to keep magic characters.
            $filter = \sprintf('/%s/i', \str_replace(
                '/',
                '\\/',
                $filter
            ));
        }

        $this->filter = $filter;
    }
}
<?php declare(strict_types=1);
/*
 * This file is part of PHPUnit.
 *
 * (c) Sebastian Bergmann <sebastian@phpunit.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace Codeception\PHPUnit\NonFinal;

use DOMDocument;
use DOMElement;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\ExceptionWrapper;
use PHPUnit\Framework\SelfDescribing;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestFailure;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Framework\Warning;
use PHPUnit\Util\Filter;
use PHPUnit\Util\Printer;
use PHPUnit\Util\Xml;
use ReflectionClass;
use ReflectionException;

/**
 * @internal This class is not covered by the backward compatibility promise for PHPUnit
 */
class JUnit extends Printer implements TestListener
{
    /**
     * @var DOMDocument
     */
    protected $document;

    /**
     * @var DOMElement
     */
    protected $root;

    /**
     * @var bool
     */
    protected $reportUselessTests = false;

    /**
     * @var bool
     */
    protected $writeDocument = true;

    /**
     * @var DOMElement[]
     */
    protected $testSuites = [];

    /**
     * @var int[]
     */
    protected $testSuiteTests = [0];

    /**
     * @var int[]
     */
    protected $testSuiteAssertions = [0];

    /**
     * @var int[]
     */
    protected $testSuiteErrors = [0];

    /**
     * @var int[]
     */
    protected $testSuiteFailures = [0];

    /**
     * @var int[]
     */
    protected $testSuiteSkipped = [0];

    /**
     * @var int[]
     */
    protected $testSuiteTimes = [0];

    /**
     * @var int
     */
    protected $testSuiteLevel = 0;

    /**
     * @var DOMElement
     */
    protected $currentTestCase;

    /**
     * Constructor.
     *
     * @param null|mixed $out
     *
     * @throws \PHPUnit\Framework\Exception
     */
    public function __construct($out = null, bool $reportUselessTests = false)
    {
        $this->document               = new DOMDocument('1.0', 'UTF-8');
        $this->document->formatOutput = true;

        $this->root = $this->document->createElement('testsuites');
        $this->document->appendChild($this->root);

        parent::__construct($out);

        $this->reportUselessTests = $reportUselessTests;
    }

    /**
     * Flush buffer and close output.
     */
    public function flush(): void
    {
        if ($this->writeDocument === true) {
            $this->write($this->getXML());
        }

        parent::flush();
    }

    /**
     * An error occurred.
     *
     * @throws \InvalidArgumentException
     * @throws ReflectionException
     */
    public function addError(Test $test, \Throwable $t, float $time): void
    {
        $this->doAddFault($test, $t, $time, 'error');
        $this->testSuiteErrors[$this->testSuiteLevel]++;
    }

    /**
     * A warning occurred.
     *
     * @throws \InvalidArgumentException
     * @throws ReflectionException
     */
    public function addWarning(Test $test, Warning $e, float $time): void
    {
        $this->doAddFault($test, $e, $time, 'warning');
        $this->testSuiteFailures[$this->testSuiteLevel]++;
    }

    /**
     * A failure occurred.
     *
     * @throws \InvalidArgumentException
     * @throws ReflectionException
     */
    public function addFailure(Test $test, AssertionFailedError $e, float $time): void
    {
        $this->doAddFault($test, $e, $time, 'failure');
        $this->testSuiteFailures[$this->testSuiteLevel]++;
    }

    /**
     * Incomplete test.
     */
    public function addIncompleteTest(Test $test, \Throwable $t, float $time): void
    {
        $this->doAddSkipped($test);
    }

    /**
     * Risky test.
     *
     * @throws ReflectionException
     */
    public function addRiskyTest(Test $test, \Throwable $t, float $time): void
    {
        if (!$this->reportUselessTests || $this->currentTestCase === null) {
            return;
        }

        $error = $this->document->createElement(
            'error',
            Xml::prepareString(
                "Risky Test\n" .
                Filter::getFilteredStacktrace($t)
            )
        );

        $error->setAttribute('type', \get_class($t));

        $this->currentTestCase->appendChild($error);

        $this->testSuiteErrors[$this->testSuiteLevel]++;
    }

    /**
     * Skipped test.
     */
    public function addSkippedTest(Test $test, \Throwable $t, float $time): void
    {
        $this->doAddSkipped($test);
    }

    /**
     * A testsuite started.
     */
    public function startTestSuite(TestSuite $suite): void
    {
        $testSuite = $this->document->createElement('testsuite');
        $testSuite->setAttribute('name', $suite->getName());

        if (\class_exists($suite->getName(), false)) {
            try {
                $class = new ReflectionClass($suite->getName());

                $testSuite->setAttribute('file', $class->getFileName());
            } catch (ReflectionException $e) {
            }
        }

        if ($this->testSuiteLevel > 0) {
            $this->testSuites[$this->testSuiteLevel]->appendChild($testSuite);
        } else {
            $this->root->appendChild($testSuite);
        }

        $this->testSuiteLevel++;
        $this->testSuites[$this->testSuiteLevel]          = $testSuite;
        $this->testSuiteTests[$this->testSuiteLevel]      = 0;
        $this->testSuiteAssertions[$this->testSuiteLevel] = 0;
        $this->testSuiteErrors[$this->testSuiteLevel]     = 0;
        $this->testSuiteFailures[$this->testSuiteLevel]   = 0;
        $this->testSuiteSkipped[$this->testSuiteLevel]    = 0;
        $this->testSuiteTimes[$this->testSuiteLevel]      = 0;
    }

    /**
     * A testsuite ended.
     */
    public function endTestSuite(TestSuite $suite): void
    {
        $this->testSuites[$this->testSuiteLevel]->setAttribute(
            'tests',
            (string) $this->testSuiteTests[$this->testSuiteLevel]
        );

        $this->testSuites[$this->testSuiteLevel]->setAttribute(
            'assertions',
            (string) $this->testSuiteAssertions[$this->testSuiteLevel]
        );

        $this->testSuites[$this->testSuiteLevel]->setAttribute(
            'errors',
            (string) $this->testSuiteErrors[$this->testSuiteLevel]
        );

        $this->testSuites[$this->testSuiteLevel]->setAttribute(
            'failures',
            (string) $this->testSuiteFailures[$this->testSuiteLevel]
        );

        $this->testSuites[$this->testSuiteLevel]->setAttribute(
            'skipped',
            (string) $this->testSuiteSkipped[$this->testSuiteLevel]
        );

        $this->testSuites[$this->testSuiteLevel]->setAttribute(
            'time',
            \sprintf('%F', $this->testSuiteTimes[$this->testSuiteLevel])
        );

        if ($this->testSuiteLevel > 1) {
            $this->testSuiteTests[$this->testSuiteLevel - 1] += $this->testSuiteTests[$this->testSuiteLevel];
            $this->testSuiteAssertions[$this->testSuiteLevel - 1] += $this->testSuiteAssertions[$this->testSuiteLevel];
            $this->testSuiteErrors[$this->testSuiteLevel - 1] += $this->testSuiteErrors[$this->testSuiteLevel];
            $this->testSuiteFailures[$this->testSuiteLevel - 1] += $this->testSuiteFailures[$this->testSuiteLevel];
            $this->testSuiteSkipped[$this->testSuiteLevel - 1] += $this->testSuiteSkipped[$this->testSuiteLevel];
            $this->testSuiteTimes[$this->testSuiteLevel - 1] += $this->testSuiteTimes[$this->testSuiteLevel];
        }

        $this->testSuiteLevel--;
    }

    /**
     * A test started.
     *
     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
     * @throws ReflectionException
     */
    public function startTest(Test $test): void
    {
        $usesDataprovider = false;

        if (\method_exists($test, 'usesDataProvider')) {
            $usesDataprovider = $test->usesDataProvider();
        }

        $testCase = $this->document->createElement('testcase');
        $testCase->setAttribute('name', $test->getName());

        $class      = new ReflectionClass($test);
        $methodName = $test->getName(!$usesDataprovider);

        if ($class->hasMethod($methodName)) {
            $method = $class->getMethod($methodName);

            $testCase->setAttribute('class', $class->getName());
            $testCase->setAttribute('classname', \str_replace('\\', '.', $class->getName()));
            $testCase->setAttribute('file', $class->getFileName());
            $testCase->setAttribute('line', (string) $method->getStartLine());
        }

        $this->currentTestCase = $testCase;
    }

    /**
     * A test ended.
     */
    public function endTest(Test $test, float $time): void
    {
        $numAssertions = 0;

        if (\method_exists($test, 'getNumAssertions')) {
            $numAssertions = $test->getNumAssertions();
        }

        $this->testSuiteAssertions[$this->testSuiteLevel] += $numAssertions;

        $this->currentTestCase->setAttribute(
            'assertions',
            (string) $numAssertions
        );

        $this->currentTestCase->setAttribute(
            'time',
            \sprintf('%F', $time)
        );

        $this->testSuites[$this->testSuiteLevel]->appendChild(
            $this->currentTestCase
        );

        $this->testSuiteTests[$this->testSuiteLevel]++;
        $this->testSuiteTimes[$this->testSuiteLevel] += $time;

        $testOutput = '';

        if (\method_exists($test, 'hasOutput') && \method_exists($test, 'getActualOutput')) {
            $testOutput = $test->hasOutput() ? $test->getActualOutput() : '';
        }

        if (!empty($testOutput)) {
            $systemOut = $this->document->createElement(
                'system-out',
                Xml::prepareString($testOutput)
            );

            $this->currentTestCase->appendChild($systemOut);
        }

        $this->currentTestCase = null;
    }

    /**
     * Returns the XML as a string.
     */
    public function getXML(): string
    {
        return $this->document->saveXML();
    }

    /**
     * Enables or disables the writing of the document
     * in flush().
     *
     * This is a "hack" needed for the integration of
     * PHPUnit with Phing.
     */
    public function setWriteDocument(/*bool*/ $flag): void
    {
        if (\is_bool($flag)) {
            $this->writeDocument = $flag;
        }
    }

    /**
     * Method which generalizes addError() and addFailure()
     *
     * @throws \InvalidArgumentException
     * @throws ReflectionException
     */
    private function doAddFault(Test $test, \Throwable $t, float $time, $type): void
    {
        if ($this->currentTestCase === null) {
            return;
        }

        if ($test instanceof SelfDescribing) {
            $buffer = $test->toString() . "\n";
        } else {
            $buffer = '';
        }

        $buffer .= TestFailure::exceptionToString($t) . "\n" .
            Filter::getFilteredStacktrace($t);

        $fault = $this->document->createElement(
            $type,
            Xml::prepareString($buffer)
        );

        if ($t instanceof ExceptionWrapper) {
            $fault->setAttribute('type', $t->getClassName());
        } else {
            $fault->setAttribute('type', \get_class($t));
        }

        $this->currentTestCase->appendChild($fault);
    }

    private function doAddSkipped(Test $test): void
    {
        if ($this->currentTestCase === null) {
            return;
        }

        $skipped = $this->document->createElement('skipped');
        $this->currentTestCase->appendChild($skipped);

        $this->testSuiteSkipped[$this->testSuiteLevel]++;
    }
}
<?php

namespace Codeception\PHPUnit;


abstract class TestCase extends \PHPUnit\Framework\TestCase
{

    protected function setUp(): void
    {
        if (method_exists($this, '_setUp')) {
            $this->_setUp();
        }
    }

    protected function tearDown(): void
    {
        if (method_exists($this, '_tearDown')) {
            $this->_tearDown();
        }
    }

    public static function setUpBeforeClass(): void
    {
        if (method_exists(get_called_class(), '_setUpBeforeClass')) {
            static::_setUpBeforeClass();
        }
    }

    public static function tearDownAfterClass(): void
    {
        if (method_exists(get_called_class(), '_tearDownAfterClass')) {
            static::_tearDownAfterClass();
        }
    }

    public function expectExceptionMessageRegExp(string $regularExpression): void
    {
        $this->expectExceptionMessageMatches($regularExpression);
    }
}
<?php
namespace Codeception\PHPUnit;

/**
 * Printer implementing this interface prints output to console, thus should be marked as printer and not just a logger
 *
 * Interface ConsolePrinter
 * @package Codeception\PHPUnit
 */
interface ConsolePrinter
{
    public function write(string $buffer);

    public function printResult(\PHPUnit\Framework\TestResult $result);
}
<?php
// @codingStandardsIgnoreStart
// PHPUnit 6 compatibility

namespace PHPUnit\Framework {
    if (!interface_exists(Test::class, false)) {
        interface Test extends \Countable {
            public function run(TestResult $result = null);
        }

    }
    if (!interface_exists(SelfDescribing::class, false)) {
        interface SelfDescribing
        {
            public function toString();
        }
    }

}
// @codingStandardsIgnoreEnd
<?php
namespace Codeception\PHPUnit\Log;

use Codeception\Configuration;
use Codeception\Test\Interfaces\Reported;
use Codeception\Test\Test;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestSuite;

class PhpUnit extends \Codeception\PHPUnit\NonFinal\JUnit
{
    const SUITE_LEVEL = 1;
    const FILE_LEVEL  = 2;

    protected $strictAttributes = ['file', 'name', 'class'];

    private $currentFile;
    private $currentFileSuite;

    public function startTest(\PHPUnit\Framework\Test $test):void
    {
        if (method_exists($test, 'getFileName') ) {
            $filename = $test->getFileName();
        } else {
            $reflector = new \ReflectionClass($test);
            $filename = $reflector->getFileName();
        }

        if ($filename !== $this->currentFile) {
            if ($this->currentFile !== null) {
                parent::endTestSuite(new TestSuite());
            }

            //initialize all values to avoid warnings
            $this->testSuiteAssertions[self::FILE_LEVEL] = 0;
            $this->testSuiteTests[self::FILE_LEVEL]      = 0;
            $this->testSuiteTimes[self::FILE_LEVEL]      = 0;
            $this->testSuiteErrors[self::FILE_LEVEL]     = 0;
            $this->testSuiteFailures[self::FILE_LEVEL]   = 0;
            $this->testSuiteSkipped[self::FILE_LEVEL]    = 0;

            $this->testSuiteLevel = self::FILE_LEVEL;

            $this->currentFile = $filename;
            $this->currentFileSuite = $this->document->createElement('testsuite');

            if ($test instanceof Reported) {
                $reportFields = $test->getReportFields();
                $class = isset($reportFields['class']) ? $reportFields['class'] : $reportFields['name'];
                $this->currentFileSuite->setAttribute('name', $class);
            } else {
                $this->currentFileSuite->setAttribute('name', get_class($test));
            }

            $this->currentFileSuite->setAttribute('file', $filename);

            $this->testSuites[self::SUITE_LEVEL]->appendChild($this->currentFileSuite);
            $this->testSuites[self::FILE_LEVEL] = $this->currentFileSuite;
        }

        if (!$test instanceof Reported) {
            parent::startTest($test);
            return;
        }

        $this->currentTestCase = $this->document->createElement('testcase');

        $isStrict = Configuration::config()['settings']['strict_xml'];

        foreach ($test->getReportFields() as $attr => $value) {
            if ($isStrict and !in_array($attr, $this->strictAttributes)) {
                continue;
            }
            $this->currentTestCase->setAttribute($attr, $value);
        }
    }

    public function endTest(\PHPUnit\Framework\Test $test, float $time):void
    {
        if ($this->currentTestCase !== null && $test instanceof Test) {
            $numAssertions = $test->getNumAssertions();
            $this->testSuiteAssertions[$this->testSuiteLevel] += $numAssertions;

            $this->currentTestCase->setAttribute(
                'assertions',
                $numAssertions
            );
        }

        if ($test instanceof TestCase) {
            parent::endTest($test, $time);
            return;
        }

        // In PhpUnit 7.4.*, parent::endTest ignores tests that aren't instances of TestCase
        // so I copied this code from PhpUnit 7.3.5

        $this->currentTestCase->setAttribute(
            'time',
            \sprintf('%F', $time)
        );
        $this->testSuites[$this->testSuiteLevel]->appendChild(
            $this->currentTestCase
        );
        $this->testSuiteTests[$this->testSuiteLevel]++;
        $this->testSuiteTimes[$this->testSuiteLevel] += $time;
        $this->currentTestCase = null;
    }

    /**
     * Cleans the mess caused by test suite manipulation in startTest
     */
    public function endTestSuite(TestSuite $suite): void
    {
        if ($suite->getName()) {
            if ($this->currentFile) {
                //close last file in the test suite
                parent::endTestSuite(new TestSuite());
                $this->currentFile = null;
            }
            $this->testSuiteLevel = self::SUITE_LEVEL;
        }
        parent::endTestSuite($suite);
    }
}
<?php
namespace Codeception\PHPUnit\Log;

use Codeception\Configuration;
use Codeception\Test\Interfaces\Reported;
use Codeception\Test\Test;
use PHPUnit\Framework\TestCase;

class JUnit extends \Codeception\PHPUnit\NonFinal\JUnit
{
    protected $strictAttributes = ['file', 'name', 'class'];

    public function startTest(\PHPUnit\Framework\Test $test):void
    {
        if (!$test instanceof Reported) {
            parent::startTest($test);
            return;
        }

        $this->currentTestCase = $this->document->createElement('testcase');

        $isStrict = Configuration::config()['settings']['strict_xml'];

        foreach ($test->getReportFields() as $attr => $value) {
            if ($isStrict and !in_array($attr, $this->strictAttributes)) {
                continue;
            }
            $this->currentTestCase->setAttribute($attr, $value);
        }
    }

    public function endTest(\PHPUnit\Framework\Test $test, float $time):void
    {
        if ($this->currentTestCase !== null and $test instanceof Test) {
            $numAssertions = $test->getNumAssertions();
            $this->testSuiteAssertions[$this->testSuiteLevel] += $numAssertions;

            $this->currentTestCase->setAttribute(
                'assertions',
                $numAssertions
            );
        }

        if ($test instanceof TestCase) {
            parent::endTest($test, $time);
            return;
        }

        // since PhpUnit 7.4.0, parent::endTest ignores tests that aren't instances of TestCase
        // so I copied this code from PhpUnit 7.3.5

        $this->currentTestCase->setAttribute(
            'time',
            \sprintf('%F', $time)
        );
        $this->testSuites[$this->testSuiteLevel]->appendChild(
            $this->currentTestCase
        );
        $this->testSuiteTests[$this->testSuiteLevel]++;
        $this->testSuiteTimes[$this->testSuiteLevel] += $time;
        $this->currentTestCase = null;
    }
}
<?php
namespace Codeception\PHPUnit;

use \PHPUnit\Framework\AssertionFailedError;
use \PHPUnit\Framework\Test;
use \PHPUnit\Runner\BaseTestRunner;

class ResultPrinter extends \PHPUnit\Util\TestDox\ResultPrinter
{
    /**
     * An error occurred.
     *
     * @param \PHPUnit\Framework\Test $test
     * @param \Throwable $e
     * @param float $time
     */
    public function addError(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
    {
        $this->testStatus = \PHPUnit\Runner\BaseTestRunner::STATUS_ERROR;
        $this->failed++;
    }

    /**
     * A failure occurred.
     *
     * @param \PHPUnit\Framework\Test $test
     * @param \PHPUnit\Framework\AssertionFailedError $e
     * @param float $time
     */
    public function addFailure(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\AssertionFailedError $e, float $time) : void
    {
        $this->testStatus = \PHPUnit\Runner\BaseTestRunner::STATUS_FAILURE;
        $this->failed++;
    }

    /**
     * A warning occurred.
     *
     * @param \PHPUnit\Framework\Test $test
     * @param \PHPUnit\Framework\Warning $e
     * @param float $time
     */
    public function addWarning(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\Warning $e, float $time): void
    {
        $this->testStatus = \PHPUnit\Runner\BaseTestRunner::STATUS_WARNING;
        $this->warned++;
    }

    /**
     * Incomplete test.
     *
     * @param \PHPUnit\Framework\Test $test
     * @param \Throwable $e
     * @param float $time
     */
    public function addIncompleteTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
    {
        $this->testStatus = \PHPUnit\Runner\BaseTestRunner::STATUS_INCOMPLETE;
        $this->incomplete++;
    }

    /**
     * Risky test.
     *
     * @param \PHPUnit\Framework\Test $test
     * @param \Throwable $e
     * @param float $time
     *
     * @since  Method available since Release 4.0.0
     */
    public function addRiskyTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
    {
        $this->testStatus = \PHPUnit\Runner\BaseTestRunner::STATUS_RISKY;
        $this->risky++;
    }

    /**
     * Skipped test.
     *
     * @param \PHPUnit\Framework\Test $test
     * @param \Throwable $e
     * @param float $time
     *
     * @since  Method available since Release 3.0.0
     */
    public function addSkippedTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time) : void
    {
        $this->testStatus = \PHPUnit\Runner\BaseTestRunner::STATUS_SKIPPED;
        $this->skipped++;
    }

    public function startTest(\PHPUnit\Framework\Test $test) : void
    {
        $this->testStatus = \PHPUnit\Runner\BaseTestRunner::STATUS_PASSED;
    }
}
<?php
// @codingStandardsIgnoreStart
/*
 * This file is part of PHPUnit.
 *
 * (c) Sebastian Bergmann <sebastian@phpunit.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace {

    if (!class_exists('PHPUnit_Util_String')) {

        /**
         * String helpers.
         */
        class PHPUnit_Util_String
        {
            /**
             * Converts a string to UTF-8 encoding.
             *
             * @param string $string
             *
             * @return string
             */
            public static function convertToUtf8($string)
            {
                return mb_convert_encoding($string, 'UTF-8');
            }

            /**
             * Checks a string for UTF-8 encoding.
             *
             * @param string $string
             *
             * @return bool
             */
            protected static function isUtf8($string)
            {
                $length = strlen($string);

                for ($i = 0; $i < $length; $i++) {
                    if (ord($string[$i]) < 0x80) {
                        $n = 0;
                    } elseif ((ord($string[$i]) & 0xE0) == 0xC0) {
                        $n = 1;
                    } elseif ((ord($string[$i]) & 0xF0) == 0xE0) {
                        $n = 2;
                    } elseif ((ord($string[$i]) & 0xF0) == 0xF0) {
                        $n = 3;
                    } else {
                        return false;
                    }

                    for ($j = 0; $j < $n; $j++) {
                        if ((++$i == $length) || ((ord($string[$i]) & 0xC0) != 0x80)) {
                            return false;
                        }
                    }
                }

                return true;
            }
        }
    }
}


namespace PHPUnit\Util\Log {

    /*
     * This file is part of PHPUnit.
     *
     * (c) Sebastian Bergmann <sebastian@phpunit.de>
     *
     * For the full copyright and license information, please view the LICENSE
     * file that was distributed with this source code.
     */

    use Codeception\Test\Descriptor;

    /**
     * A TestListener that generates JSON messages.
     */
    if (!class_exists('\PHPUnit\Util\Log\JSON')) {
        class JSON extends \PHPUnit\Util\Printer implements \PHPUnit\Framework\TestListener
        {
            /**
             * @var string
             */
            protected $currentTestSuiteName = '';

            /**
             * @var string
             */
            protected $currentTestName = '';

            /**
             * @var bool
             */
            protected $currentTestPass = true;

            /**
             * @var array
             */
            protected $logEvents = [];

            /**
             * An error occurred.
             *
             * @param \PHPUnit\Framework\Test $test
             * @param \Throwable $e
             * @param float $time
             */
            public function addError(\PHPUnit\Framework\Test $test, \Throwable $e, float $time): void
            {
                $this->writeCase(
                    'error',
                    $time,
                    \PHPUnit\Util\Filter::getFilteredStacktrace($e, false),
                    \PHPUnit\Framework\TestFailure::exceptionToString($e),
                    $test
                );

                $this->currentTestPass = false;
            }

            /**
             * A warning occurred.
             *
             * @param \PHPUnit\Framework\Test $test
             * @param \PHPUnit\Framework\Warning $e
             * @param float $time
             */
            public function addWarning(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\Warning $e, float $time): void
            {
                $this->writeCase(
                    'warning',
                    $time,
                    \PHPUnit\Util\Filter::getFilteredStacktrace($e, false),
                    \PHPUnit\Framework\TestFailure::exceptionToString($e),
                    $test
                );

                $this->currentTestPass = false;
            }

            /**
             * A failure occurred.
             *
             * @param \PHPUnit\Framework\Test $test
             * @param \PHPUnit\Framework\AssertionFailedError $e
             * @param float $time
             */
            public function addFailure(
                \PHPUnit\Framework\Test $test,
                \PHPUnit\Framework\AssertionFailedError $e,
                float $time
            ): void{
                $this->writeCase(
                    'fail',
                    $time,
                    \PHPUnit\Util\Filter::getFilteredStacktrace($e, false),
                    \PHPUnit\Framework\TestFailure::exceptionToString($e),
                    $test
                );

                $this->currentTestPass = false;
            }

            /**
             * Incomplete test.
             *
             * @param \PHPUnit\Framework\Test $test
             * @param Throwable $e
             * @param float $time
             */
            public function addIncompleteTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time): void
            {
                $this->writeCase(
                    'error',
                    $time,
                    \PHPUnit\Util\Filter::getFilteredStacktrace($e, false),
                    'Incomplete Test: ' . $e->getMessage(),
                    $test
                );

                $this->currentTestPass = false;
            }

            /**
             * Risky test.
             *
             * @param \PHPUnit\Framework\Test $test
             * @param Throwable $e
             * @param float $time
             */
            public function addRiskyTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time): void
            {
                $this->writeCase(
                    'error',
                    $time,
                    \PHPUnit\Util\Filter::getFilteredStacktrace($e, false),
                    'Risky Test: ' . $e->getMessage(),
                    $test
                );

                $this->currentTestPass = false;
            }

            /**
             * Skipped test.
             *
             * @param \PHPUnit\Framework\Test $test
             * @param Throwable $e
             * @param float $time
             */
            public function addSkippedTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time): void
            {
                $this->writeCase(
                    'error',
                    $time,
                    \PHPUnit\Util\Filter::getFilteredStacktrace($e, false),
                    'Skipped Test: ' . $e->getMessage(),
                    $test
                );

                $this->currentTestPass = false;
            }

            /**
             * A testsuite started.
             *
             * @param \PHPUnit\Framework\TestSuite $suite
             */
            public function startTestSuite(\PHPUnit\Framework\TestSuite $suite): void
            {
                $this->currentTestSuiteName = $suite->getName();
                $this->currentTestName = '';

                $this->addLogEvent(
                    [
                        'event' => 'suiteStart',
                        'suite' => $this->currentTestSuiteName,
                        'tests' => count($suite)
                    ]
                );
            }

            /**
             * A testsuite ended.
             *
             * @param \PHPUnit\Framework\TestSuite $suite
             */
            public function endTestSuite(\PHPUnit\Framework\TestSuite $suite): void
            {
                $this->currentTestSuiteName = '';
                $this->currentTestName = '';

                $this->writeArray($this->logEvents);
            }

            /**
             * A test started.
             *
             * @param \PHPUnit\Framework\Test $test
             */
            public function startTest(\PHPUnit\Framework\Test $test): void
            {
                $this->currentTestName = \PHPUnit\Util\Test::describe($test);
                $this->currentTestPass = true;

                $this->addLogEvent(
                    [
                        'event' => 'testStart',
                        'suite' => $this->currentTestSuiteName,
                        'test' => $this->currentTestName
                    ]
                );
            }

            /**
             * A test ended.
             *
             * @param \PHPUnit\Framework\Test $test
             * @param float $time
             */
            public function endTest(\PHPUnit\Framework\Test $test, float $time): void
            {
                if ($this->currentTestPass) {
                    $this->writeCase('pass', $time, [], '', $test);
                }
            }

            /**
             * @param string $status
             * @param float $time
             * @param array $trace
             * @param string $message
             * @param \PHPUnit\Framework\TestCase|null $test
             */
            protected function writeCase($status, float $time, array $trace = [], $message = '', $test = null): void
            {
                $output = '';
                // take care of TestSuite producing error (e.g. by running into exception) as TestSuite doesn't have hasOutput
                if ($test !== null && method_exists($test, 'hasOutput') && $test->hasOutput()) {
                    $output = $test->getActualOutput();
                }
                $this->addLogEvent(
                    [
                        'event' => 'test',
                        'suite' => $this->currentTestSuiteName,
                        'test' => $this->currentTestName,
                        'status' => $status,
                        'time' => $time,
                        'trace' => $trace,
                        'message' => \PHPUnit_Util_String::convertToUtf8($message),
                        'output' => $output,
                    ]
                );
            }

            /**
             * @param array $event_data
             */
            protected function addLogEvent($event_data = []): void
            {
                if (count($event_data)) {
                    array_push($this->logEvents, $event_data);
                }
            }

            /**
             * @param array $buffer
             */
            public function writeArray($buffer)
            {
                array_walk_recursive(
                    $buffer, function (&$input){
                    if (is_string($input)) {
                        $input = \PHPUnit_Util_String::convertToUtf8($input);
                    }
                }
                );

                $this->write(json_encode($buffer, JSON_PRETTY_PRINT));
            }
        }
    }

    /*
     * This file is part of PHPUnit.
     *
     * (c) Sebastian Bergmann <sebastian@phpunit.de>
     *
     * For the full copyright and license information, please view the LICENSE
     * file that was distributed with this source code.
     */

    if (!class_exists('\PHPUnit\Util\Log\TAP')) {

        /**
         * A TestListener that generates a logfile of the
         * test execution using the Test Anything Protocol (TAP).
         */
        class TAP extends \PHPUnit\Util\Printer implements \PHPUnit\Framework\TestListener
        {
            /**
             * @var int
             */
            protected $testNumber = 0;

            /**
             * @var int
             */
            protected $testSuiteLevel = 0;

            /**
             * @var bool
             */
            protected $testSuccessful = true;

            /**
             * Constructor.
             *
             * @param mixed $out
             *
             * @throws \PHPUnit\Framework\Throwable
             */
            public function __construct($out = null)
            {
                parent::__construct($out);
                $this->write("TAP version 13\n");
            }

            /**
             * An error occurred.
             *
             * @param \PHPUnit\Framework\Test $test
             * @param Throwable $e
             * @param float $time
             */
            public function addError(\PHPUnit\Framework\Test $test, \Throwable $e, float $time): void
            {
                $this->writeNotOk($test, 'Error');
            }

            /**
             * A warning occurred.
             *
             * @param \PHPUnit\Framework\Test $test
             * @param \PHPUnit\Framework\Warning $e
             * @param float $time
             */
            public function addWarning(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\Warning $e, float $time): void
            {
                $this->writeNotOk($test, 'Warning');
            }

            /**
             * A failure occurred.
             *
             * @param \PHPUnit\Framework\Test $test
             * @param \PHPUnit\Framework\AssertionFailedError $e
             * @param float $time
             */
            public function addFailure(
                \PHPUnit\Framework\Test $test,
                \PHPUnit\Framework\AssertionFailedError $e,
                float $time
            ): void{
                $this->writeNotOk($test, 'Failure');

                $message = explode(
                    "\n",
                    \PHPUnit\Framework\TestFailure::exceptionToString($e)
                );

                $diagnostic = [
                    'message' => $message[0],
                    'severity' => 'fail'
                ];

                if ($e instanceof \PHPUnit\Framework\ExpectationFailedThrowable) {
                    $cf = $e->getComparisonFailure();

                    if ($cf !== null) {
                        $diagnostic['data'] = [
                            'got' => $cf->getActual(),
                            'expected' => $cf->getExpected()
                        ];
                    }
                }

                $yaml = new \Symfony\Component\Yaml\Dumper;

                $this->write(
                    sprintf(
                        "  ---\n%s  ...\n",
                        $yaml->dump($diagnostic, 2, 2)
                    )
                );
            }

            /**
             * Incomplete test.
             *
             * @param \PHPUnit\Framework\Test $test
             * @param \Throwable $e
             * @param float $time
             */
            public function addIncompleteTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time): void
            {
                $this->writeNotOk($test, '', 'TODO Incomplete Test');
            }

            /**
             * Risky test.
             *
             * @param \PHPUnit\Framework\Test $test
             * @param Throwable $e
             * @param float $time
             */
            public function addRiskyTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time): void
            {
                $this->write(
                    sprintf(
                        "ok %d - # RISKY%s\n",
                        $this->testNumber,
                        $e->getMessage() != '' ? ' ' . $e->getMessage() : ''
                    )
                );

                $this->testSuccessful = false;
            }

            /**
             * Skipped test.
             *
             * @param \PHPUnit\Framework\Test $test
             * @param Throwable $e
             * @param float $time
             */
            public function addSkippedTest(\PHPUnit\Framework\Test $test, \Throwable $e, float $time): void
            {
                $this->write(
                    sprintf(
                        "ok %d - # SKIP%s\n",
                        $this->testNumber,
                        $e->getMessage() != '' ? ' ' . $e->getMessage() : ''
                    )
                );

                $this->testSuccessful = false;
            }

            /**
             * A testsuite started.
             *
             * @param \PHPUnit\Framework\TestSuite $suite
             */
            public function startTestSuite(\PHPUnit\Framework\TestSuite $suite): void
            {
                $this->testSuiteLevel++;
            }

            /**
             * A testsuite ended.
             *
             * @param \PHPUnit\Framework\TestSuite $suite
             */
            public function endTestSuite(\PHPUnit\Framework\TestSuite $suite): void
            {
                $this->testSuiteLevel--;

                if ($this->testSuiteLevel == 0) {
                    $this->write(sprintf("1..%d\n", $this->testNumber));
                }
            }

            /**
             * A test started.
             *
             * @param \PHPUnit\Framework\Test $test
             */
            public function startTest(\PHPUnit\Framework\Test $test): void
            {
                $this->testNumber++;
                $this->testSuccessful = true;
            }

            /**
             * A test ended.
             *
             * @param \PHPUnit\Framework\Test $test
             * @param float $time
             */
            public function endTest(\PHPUnit\Framework\Test $test, float $time): void
            {
                if ($this->testSuccessful === true) {
                    $this->write(
                        sprintf(
                            "ok %d - %s\n",
                            $this->testNumber,
                            Descriptor::getTestSignature($test)
                        )
                    );
                }

                $this->writeDiagnostics($test);
            }

            /**
             * @param \PHPUnit\Framework\Test $test
             * @param string $prefix
             * @param string $directive
             */
            protected function writeNotOk(\PHPUnit\Framework\Test $test, $prefix = '', $directive = '')
            {
                $this->write(
                    sprintf(
                        "not ok %d - %s%s%s\n",
                        $this->testNumber,
                        $prefix != '' ? $prefix . ': ' : '',
                        \PHPUnit\Util\Test::describeAsString($test),
                        $directive != '' ? ' # ' . $directive : ''
                    )
                );

                $this->testSuccessful = false;
            }

            /**
             * @param \PHPUnit\Framework\Test $test
             */
            private function writeDiagnostics(\PHPUnit\Framework\Test $test)
            {
                if (!$test instanceof \PHPUnit\Framework\TestCase) {
                    return;
                }

                if (!$test->hasOutput()) {
                    return;
                }

                foreach (explode("\n", trim($test->getActualOutput())) as $line) {
                    $this->write(
                        sprintf(
                            "# %s\n",
                            $line
                        )
                    );
                }
            }
        }
    }
}
// @codingStandardsIgnoreEnd
<?php
namespace Codeception\PHPUnit;

use Codeception\Configuration;
use Codeception\Exception\ConfigurationException;

class Runner extends NonFinal\TestRunner
{
    public static $persistentListeners = [];

    protected $defaultListeners = [
        'xml'         => false,
        'phpunit-xml' => false,
        'html'        => false,
        'tap'         => false,
        'json'        => false,
        'report'      => false
    ];

    protected $config = [];

    protected $logDir = null;

    public function __construct()
    {
        $this->config = Configuration::config();
        $this->logDir = Configuration::outputDir(); // prepare log dir
        $this->phpUnitOverriders();
        parent::__construct();
    }

    public function phpUnitOverriders()
    {
        require_once __DIR__ . DIRECTORY_SEPARATOR . 'Overrides/Filter.php';
    }

    /**
     * @return null|\PHPUnit\TextUI\ResultPrinter
     */
    public function getPrinter()
    {
        return $this->printer;
    }

    public function prepareSuite(\PHPUnit\Framework\Test $suite, array &$arguments)
    {
        $this->handleConfiguration($arguments);

        $filterAdded = false;

        $filterFactory = new \PHPUnit\Runner\Filter\Factory();
        if ($arguments['groups']) {
            $filterAdded = true;
            $filterFactory->addFilter(
                new \ReflectionClass('PHPUnit\Runner\Filter\IncludeGroupFilterIterator'),
                $arguments['groups']
            );
        }

        if ($arguments['excludeGroups']) {
            $filterAdded = true;
            $filterFactory->addFilter(
                new \ReflectionClass('PHPUnit\Runner\Filter\ExcludeGroupFilterIterator'),
                $arguments['excludeGroups']
            );
        }

        if ($arguments['filter']) {
            $filterAdded = true;
            $filterFactory->addFilter(
                new \ReflectionClass('Codeception\PHPUnit\FilterTest'),
                $arguments['filter']
            );
        }

        if ($filterAdded) {
            $suite->injectFilter($filterFactory);
        }
    }

    public function doEnhancedRun(
        \PHPUnit\Framework\Test $suite,
        \PHPUnit\Framework\TestResult $result,
        array $arguments = []
    ) {
        unset($GLOBALS['app']); // hook for not to serialize globals

        $result->convertErrorsToExceptions(false);

        if (isset($arguments['report_useless_tests'])) {
            $result->beStrictAboutTestsThatDoNotTestAnything((bool)$arguments['report_useless_tests']);
        }

        if (isset($arguments['disallow_test_output'])) {
            $result->beStrictAboutOutputDuringTests((bool)$arguments['disallow_test_output']);
        }

        if (empty(self::$persistentListeners)) {
            $this->applyReporters($result, $arguments);
        }

        if (class_exists('\Symfony\Bridge\PhpUnit\SymfonyTestsListener')) {
            $arguments['listeners'] = isset($arguments['listeners']) ? $arguments['listeners'] : [];

            $listener = new \Symfony\Bridge\PhpUnit\SymfonyTestsListener();
            $listener->globalListenerDisabled();
            $arguments['listeners'][] = $listener;
        }

        $arguments['listeners'][] = $this->printer;

        // clean up listeners between suites
        foreach ($arguments['listeners'] as $listener) {
            $result->addListener($listener);
        }

        $suite->run($result);
        unset($suite);

        foreach ($arguments['listeners'] as $listener) {
            $result->removeListener($listener);
        }

        return $result;
    }

    /**
     * @param \PHPUnit\Framework\TestResult $result
     * @param array $arguments
     *
     * @return array
     */
    protected function applyReporters(\PHPUnit\Framework\TestResult $result, array $arguments)
    {
        foreach ($this->defaultListeners as $listener => $value) {
            if (!isset($arguments[$listener])) {
                $arguments[$listener] = $value;
            }
        }

        if ($arguments['report']) {
            self::$persistentListeners[] = $this->instantiateReporter('report');
        }

        if ($arguments['html']) {
            codecept_debug('Printing HTML report into ' . $arguments['html']);
            self::$persistentListeners[] = $this->instantiateReporter(
                'html',
                [$this->absolutePath($arguments['html'])]
            );
        }
        if ($arguments['xml']) {
            codecept_debug('Printing JUNIT report into ' . $arguments['xml']);
            self::$persistentListeners[] = $this->instantiateReporter(
                'xml',
                [$this->absolutePath($arguments['xml']), (bool)$arguments['log_incomplete_skipped']]
            );
        }
        if ($arguments['phpunit-xml']) {
            codecept_debug('Printing PHPUNIT report into ' . $arguments['phpunit-xml']);
            self::$persistentListeners[] = $this->instantiateReporter(
                'phpunit-xml',
                [$this->absolutePath($arguments['phpunit-xml']), (bool)$arguments['log_incomplete_skipped']]
            );
        }
        if ($arguments['tap']) {
            codecept_debug('Printing TAP report into ' . $arguments['tap']);
            self::$persistentListeners[] = $this->instantiateReporter('tap', [$this->absolutePath($arguments['tap'])]);
        }
        if ($arguments['json']) {
            codecept_debug('Printing JSON report into ' . $arguments['json']);
            self::$persistentListeners[] = $this->instantiateReporter(
                'json',
                [$this->absolutePath($arguments['json'])]
            );
        }

        foreach (self::$persistentListeners as $listener) {
            if ($listener instanceof ConsolePrinter) {
                $this->printer = $listener;
                continue;
            }
            $result->addListener($listener);
        }
    }

    protected function instantiateReporter($name, $args = [])
    {
        if (!isset($this->config['reporters'][$name])) {
            throw new ConfigurationException("Reporter $name not defined");
        }
        return (new \ReflectionClass($this->config['reporters'][$name]))->newInstanceArgs($args);
    }

    private function absolutePath($path)
    {
        if ((strpos($path, '/') === 0) or (strpos($path, ':') === 1)) { // absolute path
            return $path;
        }
        return $this->logDir . $path;
    }
}
<?php
namespace Codeception\PHPUnit;

use Codeception\PHPUnit\NonFinal\NameFilterIterator;
use Codeception\Test\Descriptor;

/**
 * Extended Filter Test from PHPUnit to use Codeception's Descriptor to locate tests.
 *
 * Class FilterTest
 * @package Codeception\PHPUnit
 */
class FilterTest extends NameFilterIterator
{
    public function accept():bool
    {
        $test = $this->getInnerIterator()->current();

        if ($test instanceof \PHPUnit\Framework\TestSuite) {
            return true;
        }

        $name = Descriptor::getTestSignature($test);
        $index = Descriptor::getTestDataSetIndex($test);

        if (!is_null($index)) {
            $name .= " with data set #{$index}";
        }

        $accepted = preg_match($this->filter, $name, $matches);

        // This fix the issue when an invalid dataprovider method generate a warning
        // See issue https://github.com/Codeception/Codeception/issues/4888
        if($test instanceof \PHPUnit\Framework\WarningTestCase) {
            $message = $test->getMessage();
            $accepted = preg_match($this->filter, $message, $matches);
        }

        if ($accepted && isset($this->filterMax)) {
            $set = end($matches);
            $accepted = $set >= $this->filterMin && $set <= $this->filterMax;
        }
        return $accepted;
    }
}
<?php
// @codingStandardsIgnoreStart
// Add aliases for PHPUnit 6
namespace {    

    if (!class_exists('PHPUnit_Framework_Assert')) {
        class_alias('PHPUnit\Framework\Assert', 'PHPUnit_Framework_Assert');
    }
    
    if (!class_exists('PHPUnit_Framework_TestCase')) {
        class_alias('PHPUnit\Framework\TestCase', 'PHPUnit_Framework_TestCase');
    }

    if (!class_exists('PHPUnit\Util\Log\JSON') || !class_exists('PHPUnit\Util\Log\TAP')) {
        if (class_exists('PHPUnit\Util\Printer')) {
            require_once __DIR__ . '/phpunit5-loggers.php'; // TAP and JSON loggers were removed in PHPUnit 6
        }
    }
}

// @codingStandardsIgnoreEnd
<?php

namespace Codeception\PHPUnit;

class Init
{
    /**
     * @api
     */
    public static function init()
    {
        require_once __DIR__ . DIRECTORY_SEPARATOR . 'phpunit7-interfaces.php';
        require_once __DIR__ . DIRECTORY_SEPARATOR . 'shim.php';
    }
}<?php
namespace PHPUnit\Util;
// @codingStandardsIgnoreStart
class Filter
{
    // @codingStandardsIgnoreEnd
    protected static $filteredClassesPattern = [
        'Symfony\Component\Console',
        'Codeception\Command\\',
        'Codeception\TestCase\\',
    ];

    public static function getFilteredStackTrace($e, $asString = true, $filter = true)
    {
        $stackTrace = $asString ? '' : [];

        $trace = $e->getPrevious() ? $e->getPrevious()->getTrace() : $e->getTrace();
        if ($e instanceof \PHPUnit\Framework\ExceptionWrapper) {
            $trace = $e->getSerializableTrace();
        }

        $eFile = $e->getFile();
        $eLine = $e->getLine();

        if (!self::frameExists($trace, $eFile, $eLine)) {
            array_unshift(
                $trace,
                ['file' => $eFile, 'line' => $eLine]
            );
        }

        foreach ($trace as $step) {
            if (self::classIsFiltered($step) and $filter) {
                continue;
            }
            if (self::fileIsFiltered($step) and $filter) {
                continue;
            }

            if (!$asString) {
                $stackTrace[] = $step;
                continue;
            }
            if (!isset($step['file'])) {
                continue;
            }

            $stackTrace .= $step['file'] . ':' . $step['line'] . "\n";
        }

        return $stackTrace;
    }

    protected static function classIsFiltered($step)
    {
        if (!isset($step['class'])) {
            return false;
        }
        $className = $step['class'];

        foreach (self::$filteredClassesPattern as $filteredClassName) {
            if (strpos($className, $filteredClassName) === 0) {
                return true;
            }
        }
        return false;
    }

    protected static function fileIsFiltered($step)
    {
        if (!isset($step['file'])) {
            return false;
        }

        if (strpos($step['file'], 'codecept.phar/') !== false) {
            return true;
        }

        if (strpos($step['file'], 'vendor' . DIRECTORY_SEPARATOR . 'phpunit') !== false) {
            return true;
        }

        if (strpos($step['file'], 'vendor' . DIRECTORY_SEPARATOR . 'codeception') !== false) {
            return true;
        }

        $modulePath = 'src' . DIRECTORY_SEPARATOR . 'Codeception' . DIRECTORY_SEPARATOR . 'Module';
        if (strpos($step['file'], $modulePath) !== false) {
            return false; // don`t filter modules
        }

        if (strpos($step['file'], 'src' . DIRECTORY_SEPARATOR . 'Codeception' . DIRECTORY_SEPARATOR) !== false) {
            return true;
        }

        return false;
    }

    /**
     * @param array  $trace
     * @param string $file
     * @param int    $line
     *
     * @return bool
     */
    private static function frameExists(array $trace, $file, $line)
    {
        foreach ($trace as $frame) {
            if (isset($frame['file']) && $frame['file'] == $file &&
                isset($frame['line']) && $frame['line'] == $line) {
                return true;
            }
        }

        return false;
    }
}
<?php
/**
 * This is project's console commands configuration for Robo task runner.
 *
 * @see http://robo.li/
 */
class RoboFile extends \Robo\Tasks
{
    // define public methods as commands
    public function prepareDependencies()
    {
        $config = json_decode(file_get_contents(__DIR__ . '/composer.json'), true);

        $config['name'] = 'codeception/phpunit-wrapper-test';
        $config['require-dev']['codeception/codeception'] = getenv('CODECEPTION_VERSION');
        $config['require-dev']['codeception/module-asserts'] = 'dev-master';
        $config['require-dev']['codeception/module-cli'] = '*';
        $config['require-dev']['codeception/module-db'] = '*';
        $config['require-dev']['codeception/module-filesystem'] = '*';
        $config['require-dev']['codeception/module-phpbrowser'] = '*';
        $config['require-dev']['codeception/util-universalframework'] = '*';
        $config['replace'] = ['codeception/phpunit-wrapper' => '*'];

        file_put_contents(__DIR__ . '/composer.json', json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
    }

    public function prepareTests()
    {
        $this->_copyDir(__DIR__ . '/vendor/codeception/codeception/tests', __DIR__ . '/tests');
        $this->_copy(__DIR__ . '/vendor/codeception/codeception/codeception.yml', __DIR__ .'/codeception.yml');
        $this->_symlink(__DIR__ . '/vendor/bin/codecept', __DIR__ . '/codecept');
    }

    public function prepareTestAutoloading()
    {
        $config = json_decode(file_get_contents(__DIR__ . '/composer.json'), true);
        $config['autoload-dev'] = [
            'classmap' => [
                'tests/cli/_steps',
                'tests/data/DummyClass.php',
                'tests/data/claypit/tests/_data'
            ]
        ];
        file_put_contents(__DIR__ . '/composer.json', json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
    }
}
<?php
namespace Codeception\Lib\Interfaces;

interface SessionSnapshot
{
    /**
     * Saves current cookies into named snapshot in order to restore them in other tests
     * This is useful to save session state between tests.
     * For example, if user needs log in to site for each test this scenario can be executed once
     * while other tests can just restore saved cookies.
     *
     * ``` php
     * <?php
     * // inside AcceptanceTester class:
     *
     * public function login()
     * {
     *      // if snapshot exists - skipping login
     *      if ($I->loadSessionSnapshot('login')) return;
     *
     *      // logging in
     *      $I->amOnPage('/login');
     *      $I->fillField('name', 'jon');
     *      $I->fillField('password', '123345');
     *      $I->click('Login');
     *
     *      // saving snapshot
     *      $I->saveSessionSnapshot('login');
     * }
     * ?>
     * ```
     *
     * @param $name
     * @return mixed
     */
    public function saveSessionSnapshot($name);

    /**
     * Loads cookies from a saved snapshot.
     * Allows to reuse same session across tests without additional login.
     *
     * See [saveSessionSnapshot](#saveSessionSnapshot)
     *
     * @param $name
     * @return mixed
     */
    public function loadSessionSnapshot($name);

    /**
     * Deletes session snapshot.
     *
     * See [saveSessionSnapshot](#saveSessionSnapshot)
     *
     * @param $name
     * @return mixed
     */
    public function deleteSessionSnapshot($name);
}
<?php
namespace Codeception\Lib\Interfaces;

interface ScreenshotSaver
{
    /**
     * Saves screenshot of current page to a file
     *
     * ```php
     * $this->getModule('{{MODULE_NAME}}')->_saveScreenshot(codecept_output_dir().'screenshot_1.png');
     * ```
     * @api
     * @param $filename
     */
    public function _saveScreenshot($filename);
}
<?php

namespace Codeception\Module;

use Codeception\Coverage\Subscriber\LocalServer;
use Codeception\Exception\ConnectionException;
use Codeception\Exception\ElementNotFound;
use Codeception\Exception\MalformedLocatorException;
use Codeception\Exception\ModuleConfigException;
use Codeception\Exception\ModuleException;
use Codeception\Exception\TestRuntimeException;
use Codeception\Lib\Interfaces\ConflictsWithModule;
use Codeception\Lib\Interfaces\ElementLocator;
use Codeception\Lib\Interfaces\MultiSession as MultiSessionInterface;
use Codeception\Lib\Interfaces\PageSourceSaver;
use Codeception\Lib\Interfaces\Remote as RemoteInterface;
use Codeception\Lib\Interfaces\RequiresPackage;
use Codeception\Lib\Interfaces\ScreenshotSaver;
use Codeception\Lib\Interfaces\SessionSnapshot;
use Codeception\Lib\Interfaces\Web as WebInterface;
use Codeception\Module as CodeceptionModule;
use Codeception\PHPUnit\Constraint\Page as PageConstraint;
use Codeception\PHPUnit\Constraint\WebDriver as WebDriverConstraint;
use Codeception\PHPUnit\Constraint\WebDriverNot as WebDriverConstraintNot;
use Codeception\Test\Descriptor;
use Codeception\Test\Interfaces\ScenarioDriven;
use Codeception\TestInterface;
use Codeception\Util\ActionSequence;
use Codeception\Util\Locator;
use Codeception\Util\Uri;
use Facebook\WebDriver\Cookie;
use Facebook\WebDriver\Exception\InvalidElementStateException;
use Facebook\WebDriver\Exception\InvalidSelectorException;
use Facebook\WebDriver\Exception\NoSuchElementException;
use Facebook\WebDriver\Exception\UnknownErrorException;
use Facebook\WebDriver\Exception\UnknownServerException;
use Facebook\WebDriver\Exception\WebDriverCurlException;
use Facebook\WebDriver\Interactions\WebDriverActions;
use Facebook\WebDriver\Remote\LocalFileDetector;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\RemoteWebElement;
use Facebook\WebDriver\Remote\UselessFileDetector;
use Facebook\WebDriver\Remote\WebDriverCapabilityType;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\WebDriverDimension;
use Facebook\WebDriver\WebDriverElement;
use Facebook\WebDriver\WebDriverExpectedCondition;
use Facebook\WebDriver\WebDriverKeys;
use Facebook\WebDriver\WebDriverSelect;

/**
 * Run tests in real browsers using the W3C [WebDriver protocol](https://www.w3.org/TR/webdriver/).
 * There are multiple ways of running browser tests using WebDriver:
 *
 * ## Selenium (Recommended)
 *
 * * Java is required
 * * NodeJS is required
 * 
 * The fastest way to get started is to [Install and launch Selenium using selenium-standalone NodeJS package](https://www.npmjs.com/package/selenium-standalone).
 * 
 * Launch selenium standalone in separate console window:
 * 
 * ```
 * selenium-standalone start
 * ```
 *
 * Update configuration in `acceptance.suite.yml`:
 *
 * ```yaml
 * modules:
 *    enabled:
 *       - WebDriver:
 *          url: 'http://localhost/'
 *          browser: chrome # 'chrome' or 'firefox'
 * ```
 * 
 * ## Headless Chrome Browser
 * 
 * To enable headless mode (launch tests without showing a window) for Chrome browser using Selenium use this config in `acceptance.suite.yml`:
 * 
 * ```yaml
 * modules:
 *    enabled:
 *       - WebDriver:
 *          url: 'http://localhost/'
 *          browser: chrome
 *            capabilities:
 *              chromeOptions:
 *                args: ["--headless", "--disable-gpu"]
 * ```
 * 
 * ## Headless Selenium in Docker
 *
 * Docker can ship Selenium Server with all its dependencies and browsers inside a single container.
 * Running tests inside Docker is as easy as pulling [official selenium image](https://github.com/SeleniumHQ/docker-selenium) and starting a container with Chrome:
 *
 * ```
 * docker run --net=host selenium/standalone-chrome
 * ```
 *
 * By using `--net=host` allow Selenium to access local websites.
 *
 * ## Local Chrome and/or Firefox
 *
 * Tests can be executed directly throgh ChromeDriver or GeckoDriver (for Firefox). Consider using this option if you don't plan to use Selenium.
 * 
 * ### ChromeDriver
 * 
 * * Download and install [ChromeDriver](https://sites.google.com/chromium.org/driver/downloads?authuser=0)
 * * Launch ChromeDriver in a separate console window: `chromedriver --url-base=/wd/hub`.
 * 
 * Configuration in `acceptance.suite.yml`:
 *
 * ```yaml
 * modules:
 *    enabled:
 *       - WebDriver:
 *          url: 'http://localhost/'
 *          window_size: false # disabled in ChromeDriver
 *          port: 9515
 *          browser: chrome
 *          capabilities:
 *              chromeOptions:
 *                  args: ["--headless", "--disable-gpu"] # Run Chrome in headless mode
 *                  prefs:
 *                      download.default_directory: "..."
 * ```
 * See here for additional [Chrome options](https://sites.google.com/a/chromium.org/chromedriver/capabilities)
 *
 *
 * ### GeckoDriver
 * 
 * * [GeckoDriver])(https://github.com/mozilla/geckodriver/releases) must be installed 
 * * Start GeckoDriver in a separate console window: `geckodriver`.
 *  
 * Configuration in `acceptance.suite.yml`:
 *
 * ```yaml
 * modules:
 *    enabled:
 *       - WebDriver:
 *          url: 'http://localhost/'
 *          browser: firefox
 *          path: ''
 *          capabilities:
 *              acceptInsecureCerts: true # allow self-signed certificates
 *              moz:firefoxOptions:
 *                  args: ["-headless"] # Run Firefox in headless mode
 *                  prefs:
 *                      intl.accept_languages: "de-AT" # Set HTTP-Header `Accept-Language: de-AT` for requests
 * ```
 * See here for [Firefox capabilities](https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities#List_of_capabilities)
 * 
 * ## Cloud Testing
 *
 * Cloud Testing services can run your WebDriver tests in the cloud.
 * In case you want to test a local site or site behind a firewall
 * you should use a tunnel application provided by a service.
 *
 * ### SauceLabs
 *
 * 1. Create an account at [SauceLabs.com](http://SauceLabs.com) to get your username and access key
 * 2. In the module configuration use the format `username`:`access_key`@ondemand.saucelabs.com' for `host`
 * 3. Configure `platform` under `capabilities` to define the [Operating System](https://docs.saucelabs.com/reference/platforms-configurator/#/)
 * 4. run a tunnel app if your site can't be accessed from Internet
 *
 * ```yaml
 *     modules:
 *        enabled:
 *           - WebDriver:
 *              url: http://mysite.com
 *              host: '<username>:<access key>@ondemand.saucelabs.com'
 *              port: 80
 *              browser: chrome
 *              capabilities:
 *                  platform: 'Windows 10'
 * ```
 *
 * ### BrowserStack
 *
 * 1. Create an account at [BrowserStack](https://www.browserstack.com/) to get your username and access key
 * 2. In the module configuration use the format `username`:`access_key`@hub.browserstack.com' for `host`
 * 3. Configure `os` and `os_version` under `capabilities` to define the operating System
 * 4. If your site is available only locally or via VPN you should use a tunnel app. In this case add `browserstack.local` capability and set it to true.
 *
 * ```yaml
 *     modules:
 *        enabled:
 *           - WebDriver:
 *              url: http://mysite.com
 *              host: '<username>:<access key>@hub.browserstack.com'
 *              port: 80
 *              browser: chrome
 *              capabilities:
 *                  os: Windows
 *                  os_version: 10
 *                  browserstack.local: true # for local testing
 * ```
 *
 * ### LambdaTest
 *
 * 1. Create an account at [LambdaTest](https://www.lambdatest.com/) to get your username and access key
 * 2. In the module configuration use the format `username`:`access key`@hub.lambdatest.com' for `host`
 * 3. Configure `os` and `os_version` under `capabilities` to define the operating System
 * 4. If your site is available only locally or via VPN you should use a tunnel app. In this case add capabilities.setCapability("tunnel",true);.
 *
 * ```yaml
 *    modules:
 *  enabled:
 *    - WebDriver:
 *       url: http://mysite.com
 *       host: '<username>:<access key>@hub.lambdatest.com'
 *       build: <your build name>
 *       name: <your test name>
 *       port: 80
 *       browser: chrome
 *       capabilities:
 *           os: Windows
 *           os_version: 10
 *           browser_version: 86
 *           resolution: 1366x768
 *           tunnel: true # for local testing
 * ```
 *
 * ### TestingBot
 *
 * 1. Create an account at [TestingBot](https://testingbot.com/) to get your key and secret
 * 2. In the module configuration use the format `key`:`secret`@hub.testingbot.com' for `host`
 * 3. Configure `platform` under `capabilities` to define the [Operating System](https://testingbot.com/support/getting-started/browsers.html)
 * 4. Run [TestingBot Tunnel](https://testingbot.com/support/other/tunnel) if your site can't be accessed from Internet
 *
 * ```yaml
 *     modules:
 *        enabled:
 *           - WebDriver:
 *              url: http://mysite.com
 *              host: '<key>:<secret>@hub.testingbot.com'
 *              port: 80
 *              browser: chrome
 *              capabilities:
 *                  platform: Windows 10
 * ```
 *
 * ## Configuration
 *
 * * `url` *required* - Base URL for your app (amOnPage opens URLs relative to this setting).
 * * `browser` *required* - Browser to launch.
 * * `host` - Selenium server host (127.0.0.1 by default).
 * * `port` - Selenium server port (4444 by default).
 * * `restart` - Set to `false` (default) to use the same browser window for all tests, or set to `true` to create a new window for each test. In any case, when all tests are finished the browser window is closed.
 * * `start` - Autostart a browser for tests. Can be disabled if browser session is started with `_initializeSession` inside a Helper.
 * * `window_size` - Initial window size. Set to `maximize` or a dimension in the format `640x480`.
 * * `clear_cookies` - Set to false to keep cookies, or set to true (default) to delete all cookies between tests.
 * * `wait` (default: 0 seconds) - Whenever element is required and is not on page, wait for n seconds to find it before fail.
 * * `capabilities` - Sets Selenium [desired capabilities](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities). Should be a key-value array.
 * * `connection_timeout` - timeout for opening a connection to remote selenium server (30 seconds by default).
 * * `request_timeout` - timeout for a request to return something from remote selenium server (30 seconds by default).
 * * `pageload_timeout` - amount of time to wait for a page load to complete before throwing an error (default 0 seconds).
 * * `http_proxy` - sets http proxy server url for testing a remote server.
 * * `http_proxy_port` - sets http proxy server port
 * * `ssl_proxy` - sets ssl(https) proxy server url for testing a remote server.
 * * `ssl_proxy_port` - sets ssl(https) proxy server port
 * * `debug_log_entries` - how many selenium entries to print with `debugWebDriverLogs` or on fail (0 by default).
 * * `log_js_errors` - Set to true to include possible JavaScript to HTML report, or set to false (default) to deactivate.
 * * `webdriver_proxy` - sets http proxy to tunnel requests to the remote Selenium WebDriver through
 * * `webdriver_proxy_port` - sets http proxy server port to tunnel requests to the remote Selenium WebDriver through
 *
 * Example (`acceptance.suite.yml`)
 *
 * ```yaml
 *     modules:
 *        enabled:
 *           - WebDriver:
 *              url: 'http://localhost/'
 *              browser: firefox
 *              window_size: 1024x768
 *              capabilities:
 *                  unexpectedAlertBehaviour: 'accept'
 *                  firefox_profile: '~/firefox-profiles/codeception-profile.zip.b64'
 * ```
 *
 * ## Loading Parts from other Modules
 *
 * While all Codeception modules are designed to work stand-alone, it's still possible to load *several* modules at once. To use e.g. the [Asserts module](https://codeception.com/docs/modules/Asserts) in your acceptance tests, just load it like this in your `acceptance.suite.yml`:
 *
 * ```yaml
 * modules:
 *     enabled:
 *         - WebDriver
 *         - Asserts
 * ```
 *
 * However, when loading a framework module (e.g. [Symfony](https://codeception.com/docs/modules/Symfony)) like this, it would lead to a conflict: When you call `$I->amOnPage()`, Codeception wouldn't know if you want to access the page using WebDriver's `amOnPage()`, or Symfony's `amOnPage()`. That's why possibly conflicting modules are separated into "parts". Here's how to load just the "services" part from e.g. Symfony:
 * ```yaml
 * modules:
 *     enabled:
 *         - WebDriver
 *         - Symfony:
 *             part: services
 * ```
 * To find out which parts each module has, look at the "Parts" header on the module's page.
 *
 * ## Usage
 *
 * ### Locating Elements
 *
 * Most methods in this module that operate on a DOM element (e.g. `click`) accept a locator as the first argument,
 * which can be either a string or an array.
 *
 * If the locator is an array, it should have a single element,
 * with the key signifying the locator type (`id`, `name`, `css`, `xpath`, `link`, or `class`)
 * and the value being the locator itself.
 * This is called a "strict" locator.
 * Examples:
 *
 * * `['id' => 'foo']` matches `<div id="foo">`
 * * `['name' => 'foo']` matches `<div name="foo">`
 * * `['css' => 'input[type=input][value=foo]']` matches `<input type="input" value="foo">`
 * * `['xpath' => "//input[@type='submit'][contains(@value, 'foo')]"]` matches `<input type="submit" value="foobar">`
 * * `['link' => 'Click here']` matches `<a href="google.com">Click here</a>`
 * * `['class' => 'foo']` matches `<div class="foo">`
 *
 * Writing good locators can be tricky.
 * The Mozilla team has written an excellent guide titled [Writing reliable locators for Selenium and WebDriver tests](https://blog.mozilla.org/webqa/2013/09/26/writing-reliable-locators-for-selenium-and-webdriver-tests/).
 *
 * If you prefer, you may also pass a string for the locator. This is called a "fuzzy" locator.
 * In this case, Codeception uses a a variety of heuristics (depending on the exact method called) to determine what element you're referring to.
 * For example, here's the heuristic used for the `submitForm` method:
 *
 * 1. Does the locator look like an ID selector (e.g. "#foo")? If so, try to find a form matching that ID.
 * 2. If nothing found, check if locator looks like a CSS selector. If so, run it.
 * 3. If nothing found, check if locator looks like an XPath expression. If so, run it.
 * 4. Throw an `ElementNotFound` exception.
 *
 * Be warned that fuzzy locators can be significantly slower than strict locators.
 * Especially if you use Selenium WebDriver with `wait` (aka implicit wait) option.
 * In the example above if you set `wait` to 5 seconds and use XPath string as fuzzy locator,
 * `submitForm` method will wait for 5 seconds at each step.
 * That means 5 seconds finding the form by ID, another 5 seconds finding by CSS
 * until it finally tries to find the form by XPath).
 * If speed is a concern, it's recommended you stick with explicitly specifying the locator type via the array syntax.
 *
 * ### Get Scenario Metadata
 *
 * You can inject `\Codeception\Scenario` into your test to get information about the current configuration:
 * ```php
 * use Codeception\Scenario
 * public function myTest(AcceptanceTester $I, Scenario $scenario)
 * {
 *     if ('firefox' === $scenario->current('browser')) {
 *         // ...
 *     }
 * }
 * ```
 * See [Get Scenario Metadata](https://codeception.com/docs/07-AdvancedUsage#Get-Scenario-Metadata) for more information on `$scenario`.
 *
 * ## Public Properties
 *
 * * `webDriver` - instance of `\Facebook\WebDriver\Remote\RemoteWebDriver`. Can be accessed from Helper classes for complex WebDriver interactions.
 *
 * ```php
 * // inside Helper class
 * $this->getModule('WebDriver')->webDriver->getKeyboard()->sendKeys('hello, webdriver');
 * ```
 *
 */
class WebDriver extends CodeceptionModule implements
    WebInterface,
    RemoteInterface,
    MultiSessionInterface,
    SessionSnapshot,
    ScreenshotSaver,
    PageSourceSaver,
    ElementLocator,
    ConflictsWithModule,
    RequiresPackage
{
    protected $requiredFields = ['browser', 'url'];
    protected $config = [
        'protocol'             => 'http',
        'host'                 => '127.0.0.1',
        'port'                 => '4444',
        'path'                 => '/wd/hub',
        'start'                => true,
        'restart'              => false,
        'wait'                 => 0,
        'clear_cookies'        => true,
        'window_size'          => false,
        'capabilities'         => [],
        'connection_timeout'   => null,
        'request_timeout'      => null,
        'pageload_timeout'     => null,
        'http_proxy'           => null,
        'http_proxy_port'      => null,
        'ssl_proxy'            => null,
        'ssl_proxy_port'       => null,
        'debug_log_entries'    => 0,
        'log_js_errors'        => false,
        'webdriver_proxy'      => null,
        'webdriver_proxy_port' => null,
    ];

    protected $wdHost;
    protected $capabilities;
    protected $connectionTimeoutInMs;
    protected $requestTimeoutInMs;
    protected $test;
    protected $sessions = [];
    protected $sessionSnapshots = [];
    protected $webdriverProxy;
    protected $webdriverProxyPort;

    /**
     * @var RemoteWebDriver
     */
    public $webDriver;

    /**
     * @var RemoteWebElement
     */
    protected $baseElement;

    public function _requires()
    {
        return ['Facebook\WebDriver\Remote\RemoteWebDriver' => '"php-webdriver/webdriver": "^1.0.1"'];
    }

    /**
     * @return RemoteWebElement
     * @throws ModuleException
     */
    protected function getBaseElement()
    {
        if (!$this->baseElement) {
            throw new ModuleException($this, "Page not loaded. Use `\$I->amOnPage` (or hidden API methods `_request` and `_loadPage`) to open it");
        }
        return $this->baseElement;
    }

    public function _initialize()
    {
        $this->wdHost = sprintf('%s://%s:%s%s', $this->config['protocol'], $this->config['host'], $this->config['port'], $this->config['path']);
        $this->capabilities = $this->config['capabilities'];
        $this->capabilities[WebDriverCapabilityType::BROWSER_NAME] = $this->config['browser'];
        if ($proxy = $this->getProxy()) {
            $this->capabilities[WebDriverCapabilityType::PROXY] = $proxy;
        }
        $this->connectionTimeoutInMs = $this->config['connection_timeout'] * 1000;
        $this->requestTimeoutInMs = $this->config['request_timeout'] * 1000;
        $this->webdriverProxy = $this->config['webdriver_proxy'];
        $this->webdriverProxyPort = $this->config['webdriver_proxy_port'];
        $this->loadFirefoxProfile();
    }

    /**
     * Change capabilities of WebDriver. Should be executed before starting a new browser session.
     * This method expects a function to be passed which returns array or [WebDriver Desired Capabilities](https://github.com/php-webdriver/php-webdriver/blob/main/lib/Remote/DesiredCapabilities.php) object.
     * Additional [Chrome options](https://github.com/php-webdriver/php-webdriver/wiki/ChromeOptions) (like adding extensions) can be passed as well.
     *
     * ```php
     * <?php // in helper
     * public function _before(TestInterface $test)
     * {
     *     $this->getModule('WebDriver')->_capabilities(function($currentCapabilities) {
     *         // or new \Facebook\WebDriver\Remote\DesiredCapabilities();
     *         return \Facebook\WebDriver\Remote\DesiredCapabilities::firefox();
     *     });
     * }
     * ```
     *
     * to make this work load `\Helper\Acceptance` before `WebDriver` in `acceptance.suite.yml`:
     *
     * ```yaml
     * modules:
     *     enabled:
     *         - \Helper\Acceptance
     *         - WebDriver
     * ```
     *
     * For instance, [**BrowserStack** cloud service](https://www.browserstack.com/automate/capabilities) may require a test name to be set in capabilities.
     * This is how it can be done via `_capabilities` method from `Helper\Acceptance`:
     *
     * ```php
     * <?php // inside Helper\Acceptance
     * public function _before(TestInterface $test)
     * {
     *      $name = $test->getMetadata()->getName();
     *      $this->getModule('WebDriver')->_capabilities(function($currentCapabilities) use ($name) {
     *          $currentCapabilities['name'] = $name;
     *          return $currentCapabilities;
     *      });
     * }
     * ```
     * In this case, please ensure that `\Helper\Acceptance` is loaded before WebDriver so new capabilities could be applied.
     *
     * @api
     * @param \Closure $capabilityFunction
     */
    public function _capabilities(\Closure $capabilityFunction)
    {
        $this->capabilities = $capabilityFunction($this->capabilities);
    }

    public function _conflicts()
    {
        return 'Codeception\Lib\Interfaces\Web';
    }

    public function _before(TestInterface $test)
    {
        if (!isset($this->webDriver) && $this->config['start']) {
            $this->_initializeSession();
        }
        $this->setBaseElement();

        $test->getMetadata()->setCurrent(
            [
                'browser'      => $this->webDriver->getCapabilities()->getBrowserName(),
                'capabilities' => $this->webDriver->getCapabilities()->toArray(),
            ]
        );
    }

    /**
     * Restarts a web browser.
     * Can be used with `_reconfigure` to open browser with different configuration
     *
     * ```php
     * <?php
     * // inside a Helper
     * $this->getModule('WebDriver')->_restart(); // just restart
     * $this->getModule('WebDriver')->_restart(['browser' => $browser]); // reconfigure + restart
     * ```
     *
     * @param array $config
     * @api
     */
    public function _restart($config = [])
    {
        $this->webDriver->quit();
        if (!empty($config)) {
            $this->_reconfigure($config);
        }
        $this->_initializeSession();
    }

    protected function onReconfigure()
    {
        $this->_initialize();
    }

    protected function loadFirefoxProfile()
    {
        if (!array_key_exists('firefox_profile', $this->config['capabilities'])) {
            return;
        }

        $firefox_profile = $this->config['capabilities']['firefox_profile'];
        if (file_exists($firefox_profile) === false) {
            throw new ModuleConfigException(
                __CLASS__,
                "Firefox profile does not exist under given path " . $firefox_profile
            );
        }
        // Set firefox profile as capability
        $this->capabilities['firefox_profile'] = file_get_contents($firefox_profile);
    }

    protected function initialWindowSize()
    {
        if ($this->config['window_size'] == 'maximize') {
            $this->maximizeWindow();
            return;
        }
        $size = explode('x', $this->config['window_size']);
        if (count($size) == 2) {
            $this->resizeWindow(intval($size[0]), intval($size[1]));
        }
    }

    public function _after(TestInterface $test)
    {
        if ($this->config['restart']) {
            $this->stopAllSessions();
            return;
        }
        if ($this->config['clear_cookies'] && isset($this->webDriver)) {
            try {
                $this->webDriver->manage()->deleteAllCookies();
            } catch (\Exception $e) {
                // may cause fatal errors when not handled
                $this->debug("Error, can't clean cookies after a test: " . $e->getMessage());
            }
        }
    }

    public function _failed(TestInterface $test, $fail)
    {
        $this->debugWebDriverLogs($test);
        $filename = preg_replace('~[^a-zA-Z0-9\x80-\xff]~', '.', Descriptor::getTestSignatureUnique($test));
        $outputDir = codecept_output_dir();
        $this->_saveScreenshot($report = $outputDir . mb_strcut($filename, 0, 245, 'utf-8') . '.fail.png');
        $test->getMetadata()->addReport('png', $report);
        $this->_savePageSource($report = $outputDir . mb_strcut($filename, 0, 244, 'utf-8') . '.fail.html');
        $test->getMetadata()->addReport('html', $report);
        $this->debug("Screenshot and page source were saved into '$outputDir' dir");
    }

    /**
     * Print out latest Selenium Logs in debug mode
     *
     * @param \Codeception\TestInterface $test
     */
    public function debugWebDriverLogs(TestInterface $test = null)
    {
        if (!isset($this->webDriver)) {
            $this->debug('WebDriver::debugWebDriverLogs method has been called when webDriver is not set');
            return;
        }
        // don't show logs if log entries not set
        if (!$this->config['debug_log_entries']) {
            return;
        }

        try {
            // Dump out latest Selenium logs
            $logs = $this->webDriver->manage()->getAvailableLogTypes();
            foreach ($logs as $logType) {
                $logEntries = array_slice(
                    $this->webDriver->manage()->getLog($logType),
                    -$this->config['debug_log_entries']
                );

                if (empty($logEntries)) {
                    $this->debugSection("Selenium {$logType} Logs", " EMPTY ");
                    continue;
                }
                $this->debugSection("Selenium {$logType} Logs", "\n" . $this->formatLogEntries($logEntries));

                if ($logType === 'browser' && $this->config['log_js_errors']
                    && ($test instanceof ScenarioDriven)
                ) {
                    $this->logJSErrors($test, $logEntries);
                }
            }
        } catch (\Exception $e) {
            $this->debug('Unable to retrieve Selenium logs : ' . $e->getMessage());
        }
    }

    /**
     * Turns an array of log entries into a human-readable string.
     * Each log entry is an array with the keys "timestamp", "level", and "message".
     * See https://code.google.com/p/selenium/wiki/JsonWireProtocol#Log_Entry_JSON_Object
     *
     * @param array $logEntries
     * @return string
     */
    protected function formatLogEntries(array $logEntries)
    {
        $formattedLogs = '';

        foreach ($logEntries as $logEntry) {
            // Timestamp is in milliseconds, but date() requires seconds.
            $time = date('H:i:s', $logEntry['timestamp'] / 1000) .
                // Append the milliseconds to the end of the time string
                '.' . ($logEntry['timestamp'] % 1000);
            $formattedLogs .= "{$time} {$logEntry['level']} - {$logEntry['message']}\n";
        }
        return $formattedLogs;
    }

    /**
     * Logs JavaScript errors as comments.
     *
     * @param ScenarioDriven $test
     * @param array $browserLogEntries
     */
    protected function logJSErrors(ScenarioDriven $test, array $browserLogEntries)
    {
        foreach ($browserLogEntries as $logEntry) {
            if (true === isset($logEntry['level'])
                && true === isset($logEntry['message'])
                && $this->isJSError($logEntry['level'], $logEntry['message'])
            ) {
                // Timestamp is in milliseconds, but date() requires seconds.
                $time = date('H:i:s', $logEntry['timestamp'] / 1000) .
                    // Append the milliseconds to the end of the time string
                    '.' . ($logEntry['timestamp'] % 1000);
                $test->getScenario()->comment("{$time} {$logEntry['level']} - {$logEntry['message']}");
            }
        }
    }

    /**
     * Determines if the log entry is an error.
     * The decision is made depending on browser and log-level.
     *
     * @param string $logEntryLevel
     * @param string $message
     * @return bool
     */
    protected function isJSError($logEntryLevel, $message)
    {
        return
            (
                ($this->isPhantom() && $logEntryLevel != 'INFO')          // phantomjs logs errors as "WARNING"
                || $logEntryLevel === 'SEVERE'                            // other browsers log errors as "SEVERE"
            )
            && strpos($message, 'ERR_PROXY_CONNECTION_FAILED') === false;  // ignore blackhole proxy
    }

    public function _afterSuite()
    {
        // this is just to make sure webDriver is cleared after suite
        $this->stopAllSessions();
    }

    protected function stopAllSessions()
    {
        foreach ($this->sessions as $session) {
            $this->_closeSession($session);
        }
        $this->webDriver = null;
        $this->baseElement = null;
    }

    public function amOnSubdomain($subdomain)
    {
        $url = $this->config['url'];
        $url = preg_replace('~(https?:\/\/)(.*\.)(.*\.)~', "$1$3", $url); // removing current subdomain
        $url = preg_replace('~(https?:\/\/)(.*)~', "$1$subdomain.$2", $url); // inserting new
        $this->_reconfigure(['url' => $url]);
    }

    /**
     * Returns URL of a host.
     *
     * @api
     * @return mixed
     * @throws ModuleConfigException
     */
    public function _getUrl()
    {
        if (!isset($this->config['url'])) {
            throw new ModuleConfigException(
                __CLASS__,
                "Module connection failure. The URL for client can't bre retrieved"
            );
        }
        return $this->config['url'];
    }

    protected function getProxy()
    {
        $proxyConfig = [];
        if ($this->config['http_proxy']) {
            $proxyConfig['httpProxy'] = $this->config['http_proxy'];
            if ($this->config['http_proxy_port']) {
                $proxyConfig['httpProxy'] .= ':' . $this->config['http_proxy_port'];
            }
        }
        if ($this->config['ssl_proxy']) {
            $proxyConfig['sslProxy'] = $this->config['ssl_proxy'];
            if ($this->config['ssl_proxy_port']) {
                $proxyConfig['sslProxy'] .= ':' . $this->config['ssl_proxy_port'];
            }
        }
        if (!empty($proxyConfig)) {
            $proxyConfig['proxyType'] = 'manual';
            return $proxyConfig;
        }
        return null;
    }

    /**
     * Uri of currently opened page.
     * @return string
     * @api
     * @throws ModuleException
     */
    public function _getCurrentUri()
    {
        $url = $this->webDriver->getCurrentURL();
        if ($url == 'about:blank' || strpos($url, 'data:') === 0) {
            throw new ModuleException($this, 'Current url is blank, no page was opened');
        }
        return Uri::retrieveUri($url);
    }

    public function _saveScreenshot($filename)
    {
        if (!isset($this->webDriver)) {
            $this->debug('WebDriver::_saveScreenshot method has been called when webDriver is not set');
            return;
        }
        try {
            $this->webDriver->takeScreenshot($filename);
        } catch (\Exception $e) {
            $this->debug('Unable to retrieve screenshot from Selenium : ' . $e->getMessage());
            return;
        }
    }

    public function _saveElementScreenshot($selector, $filename)
    {
        if (!isset($this->webDriver)) {
            $this->debug('WebDriver::_saveElementScreenshot method has been called when webDriver is not set');
            return;
        }
        try {
            $this->matchFirstOrFail($this->webDriver, $selector)->takeElementScreenshot($filename);
        } catch (\Exception $e) {
            $this->debug('Unable to retrieve element screenshot from Selenium : ' . $e->getMessage());
            return;
        }
    }

    public function _findElements($locator)
    {
        return $this->match($this->webDriver, $locator);
    }

    /**
     * Saves HTML source of a page to a file
     * @param $filename
     */
    public function _savePageSource($filename)
    {
        if (!isset($this->webDriver)) {
            $this->debug('WebDriver::_savePageSource method has been called when webDriver is not set');
            return;
        }
        try {
            file_put_contents($filename, $this->webDriver->getPageSource());
        } catch (\Exception $e) {
            $this->debug('Unable to retrieve source page from Selenium : ' . $e->getMessage());
        }
    }

    /**
     * Takes a screenshot of the current window and saves it to `tests/_output/debug`.
     *
     * ``` php
     * <?php
     * $I->amOnPage('/user/edit');
     * $I->makeScreenshot('edit_page');
     * // saved to: tests/_output/debug/edit_page.png
     * $I->makeScreenshot();
     * // saved to: tests/_output/debug/2017-05-26_14-24-11_4b3403665fea6.png
     * ```
     *
     * @param $name
     */
    public function makeScreenshot($name = null)
    {
        if (empty($name)) {
            $name = uniqid(date("Y-m-d_H-i-s_"));
        }
        $debugDir = codecept_log_dir() . 'debug';
        if (!is_dir($debugDir)) {
            mkdir($debugDir, 0777);
        }
        $screenName = $debugDir . DIRECTORY_SEPARATOR . $name . '.png';
        $this->_saveScreenshot($screenName);
        $this->debugSection('Screenshot Saved', "file://$screenName");
    }

    /**
     * Takes a screenshot of an element of the current window and saves it to `tests/_output/debug`.
     *
     * ``` php
     * <?php
     * $I->amOnPage('/user/edit');
     * $I->makeElementScreenshot('#dialog', 'edit_page');
     * // saved to: tests/_output/debug/edit_page.png
     * $I->makeElementScreenshot('#dialog');
     * // saved to: tests/_output/debug/2017-05-26_14-24-11_4b3403665fea6.png
     * ```
     *
     * @param $name
     */
    public function makeElementScreenshot($selector, $name = null)
    {
        if (empty($name)) {
            $name = uniqid(date("Y-m-d_H-i-s_"));
        }
        $debugDir = codecept_log_dir() . 'debug';
        if (!is_dir($debugDir)) {
            mkdir($debugDir, 0777);
        }
        $screenName = $debugDir . DIRECTORY_SEPARATOR . $name . '.png';
        $this->_saveElementScreenshot($selector, $screenName);
        $this->debugSection('Screenshot Saved', "file://$screenName");
    }

    public function makeHtmlSnapshot($name = null)
    {
        if (empty($name)) {
            $name = uniqid(date("Y-m-d_H-i-s_"));
        }
        $debugDir = codecept_output_dir() . 'debug';
        if (!is_dir($debugDir)) {
            mkdir($debugDir, 0777);
        }
        $fileName = $debugDir . DIRECTORY_SEPARATOR . $name . '.html';

        $this->_savePageSource($fileName);
        $this->debugSection('Snapshot Saved', "file://$fileName");
    }



    /**
     * Resize the current window.
     *
     * ``` php
     * <?php
     * $I->resizeWindow(800, 600);
     *
     * ```
     *
     * @param int $width
     * @param int $height
     */
    public function resizeWindow($width, $height)
    {
        $this->webDriver->manage()->window()->setSize(new WebDriverDimension($width, $height));
    }

    private function debugCookies()
    {
        $result = [];
        $cookies = $this->webDriver->manage()->getCookies();
        foreach ($cookies as $cookie) {
            $result[] = is_array($cookie) ? $cookie : $cookie->toArray();
        }
        $this->debugSection('Cookies', json_encode($result));
    }

    public function seeCookie($cookie, array $params = [])
    {
        $cookies = $this->filterCookies($this->webDriver->manage()->getCookies(), $params);
        $cookies = array_map(
            function ($c) {
                return $c['name'];
            },
            $cookies
        );
        $this->debugCookies();
        $this->assertContains($cookie, $cookies);
    }

    public function dontSeeCookie($cookie, array $params = [])
    {
        $cookies = $this->filterCookies($this->webDriver->manage()->getCookies(), $params);
        $cookies = array_map(
            function ($c) {
                return $c['name'];
            },
            $cookies
        );
        $this->debugCookies();
        $this->assertNotContains($cookie, $cookies);
    }

    public function setCookie($cookie, $value, array $params = [], $showDebug = true)
    {
        $params['name'] = $cookie;
        $params['value'] = $value;
        if (isset($params['expires'])) { // PhpBrowser compatibility
            $params['expiry'] = $params['expires'];
        }

        // #5401 Supply defaults, otherwise chromedriver 2.46 complains.
        $defaults = [
            'path' => '/',
            'expiry' => time() + 86400,
            'secure' => false,
            'httpOnly' => false,
        ];
        foreach ($defaults as $key => $default) {
            if (empty($params[$key])) {
                $params[$key] = $default;
            }
        }
        $this->webDriver->manage()->addCookie($params);
        if ($showDebug) {
            $this->debugCookies();
        }
    }

    public function resetCookie($cookie, array $params = [])
    {
        $this->webDriver->manage()->deleteCookieNamed($cookie);
        $this->debugCookies();
    }

    public function grabCookie($cookie, array $params = [])
    {
        $params['name'] = $cookie;
        $cookies = $this->filterCookies($this->webDriver->manage()->getCookies(), $params);
        if (empty($cookies)) {
            return null;
        }
        $cookie = reset($cookies);
        return $cookie['value'];
    }

    /**
     * Grabs current page source code.
     *
     * @throws ModuleException if no page was opened.
     *
     * @return string Current page source code.
     */
    public function grabPageSource()
    {
        // Make sure that some page was opened.
        $this->_getCurrentUri();

        return $this->webDriver->getPageSource();
    }

    protected function filterCookies($cookies, $params = [])
    {
        foreach (['domain', 'path', 'name'] as $filter) {
            if (!isset($params[$filter])) {
                continue;
            }
            $cookies = array_filter(
                $cookies,
                function ($item) use ($filter, $params) {
                    return $item[$filter] == $params[$filter];
                }
            );
        }
        return $cookies;
    }

    public function amOnUrl($url)
    {
        $host = Uri::retrieveHost($url);
        $this->_reconfigure(['url' => $host]);
        $this->debugSection('Host', $host);
        $this->webDriver->get($url);
    }

    public function amOnPage($page)
    {
        $url = Uri::appendPath($this->config['url'], $page);
        $this->debugSection('GET', $url);
        $this->webDriver->get($url);
    }

    public function see($text, $selector = null)
    {
        if (!$selector) {
            return $this->assertPageContains($text);
        }
        $this->enableImplicitWait();
        $nodes = $this->matchVisible($selector);
        $this->disableImplicitWait();
        $this->assertNodesContain($text, $nodes, $selector);
    }

    public function dontSee($text, $selector = null)
    {
        if (!$selector) {
            return $this->assertPageNotContains($text);
        }
        $nodes = $this->matchVisible($selector);
        $this->assertNodesNotContain($text, $nodes, $selector);
    }

    public function seeInSource($raw)
    {
        $this->assertPageSourceContains($raw);
    }

    public function dontSeeInSource($raw)
    {
        $this->assertPageSourceNotContains($raw);
    }

    /**
     * Checks that the page source contains the given string.
     *
     * ```php
     * <?php
     * $I->seeInPageSource('<link rel="apple-touch-icon"');
     * ```
     *
     * @param $text
     */
    public function seeInPageSource($text)
    {
        $this->assertThat(
            $this->webDriver->getPageSource(),
            new PageConstraint($text, $this->_getCurrentUri()),
            ''
        );
    }

    /**
     * Checks that the page source doesn't contain the given string.
     *
     * @param $text
     */
    public function dontSeeInPageSource($text)
    {
        $this->assertThatItsNot(
            $this->webDriver->getPageSource(),
            new PageConstraint($text, $this->_getCurrentUri()),
            ''
        );
    }

    public function click($link, $context = null)
    {
        $page = $this->webDriver;
        if ($context) {
            $page = $this->matchFirstOrFail($this->webDriver, $context);
        }
        $el = $this->_findClickable($page, $link);
        if (!$el) { // check one more time if this was a CSS selector we didn't match
            try {
                $els = $this->match($page, $link);
            } catch (MalformedLocatorException $e) {
                throw new ElementNotFound("name=$link", "'$link' is invalid CSS and XPath selector and Link or Button");
            }
            $el = reset($els);
        }
        if (!$el) {
            throw new ElementNotFound($link, 'Link or Button or CSS or XPath');
        }
        $el->click();
    }

    /**
     * Locates a clickable element.
     *
     * Use it in Helpers or GroupObject or Extension classes:
     *
     * ```php
     * <?php
     * $module = $this->getModule('WebDriver');
     * $page = $module->webDriver;
     *
     * // search a link or button on a page
     * $el = $module->_findClickable($page, 'Click Me');
     *
     * // search a link or button within an element
     * $topBar = $module->_findElements('.top-bar')[0];
     * $el = $module->_findClickable($topBar, 'Click Me');
     *
     * ```
     * @api
     * @param RemoteWebDriver $page WebDriver instance or an element to search within
     * @param $link a link text or locator to click
     * @return WebDriverElement
     */
    public function _findClickable($page, $link)
    {
        if (is_array($link) or ($link instanceof WebDriverBy)) {
            return $this->matchFirstOrFail($page, $link);
        }

        // try to match by strict locators, CSS Ids or XPath
        if (Locator::isPrecise($link)) {
            return $this->matchFirstOrFail($page, $link);
        }

        $locator = static::xpathLiteral(trim($link));

        // narrow
        $xpath = Locator::combine(
            ".//a[normalize-space(.)=$locator]",
            ".//button[normalize-space(.)=$locator]",
            ".//a/img[normalize-space(@alt)=$locator]/ancestor::a",
            ".//input[./@type = 'submit' or ./@type = 'image' or ./@type = 'button'][normalize-space(@value)=$locator]"
        );

        $els = $page->findElements(WebDriverBy::xpath($xpath));
        if (count($els)) {
            return reset($els);
        }

        // wide
        $xpath = Locator::combine(
            ".//a[./@href][((contains(normalize-space(string(.)), $locator)) or contains(./@title, $locator) or .//img[contains(./@alt, $locator)])]",
            ".//input[./@type = 'submit' or ./@type = 'image' or ./@type = 'button'][contains(./@value, $locator)]",
            ".//input[./@type = 'image'][contains(./@alt, $locator)]",
            ".//button[contains(normalize-space(string(.)), $locator)]",
            ".//input[./@type = 'submit' or ./@type = 'image' or ./@type = 'button'][./@name = $locator or ./@title = $locator]",
            ".//button[./@name = $locator or ./@title = $locator]"
        );

        $els = $page->findElements(WebDriverBy::xpath($xpath));
        if (count($els)) {
            return reset($els);
        }

        return null;
    }

    /**
     * @param $selector
     * @return WebDriverElement[]
     * @throws \Codeception\Exception\ElementNotFound
     */
    protected function findFields($selector)
    {
        if ($selector instanceof WebDriverElement) {
            return [$selector];
        }
        if (is_array($selector) || ($selector instanceof WebDriverBy)) {
            $fields = $this->match($this->webDriver, $selector);

            if (empty($fields)) {
                throw new ElementNotFound($selector);
            }
            return $fields;
        }

        $locator = static::xpathLiteral(trim($selector));
        // by text or label
        $xpath = Locator::combine(
        // @codingStandardsIgnoreStart
            ".//*[self::input | self::textarea | self::select][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')][(((./@name = $locator) or ./@id = //label[contains(normalize-space(string(.)), $locator)]/@for) or ./@placeholder = $locator)]",
            ".//label[contains(normalize-space(string(.)), $locator)]//.//*[self::input | self::textarea | self::select][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]"
        // @codingStandardsIgnoreEnd
        );
        $fields = $this->webDriver->findElements(WebDriverBy::xpath($xpath));
        if (!empty($fields)) {
            return $fields;
        }

        // by name
        $xpath = ".//*[self::input | self::textarea | self::select][@name = $locator]";
        $fields = $this->webDriver->findElements(WebDriverBy::xpath($xpath));
        if (!empty($fields)) {
            return $fields;
        }

        // try to match by CSS or XPath
        $fields = $this->match($this->webDriver, $selector, false);
        if (!empty($fields)) {
            return $fields;
        }

        throw new ElementNotFound($selector, "Field by name, label, CSS or XPath");
    }

    /**
     * @param $selector
     * @return WebDriverElement
     * @throws \Codeception\Exception\ElementNotFound
     */
    protected function findField($selector)
    {
        $arr = $this->findFields($selector);
        return reset($arr);
    }

    public function seeLink($text, $url = null)
    {
        $this->enableImplicitWait();
        $nodes = $this->getBaseElement()->findElements(WebDriverBy::partialLinkText($text));
        $this->disableImplicitWait();
        $currentUri = $this->_getCurrentUri();

        if (empty($nodes)) {
            $this->fail("No links containing text '$text' were found in page $currentUri");
        }
        if ($url) {
            $nodes = $this->filterNodesByHref($url, $nodes);
        }
        $this->assertNotEmpty($nodes, "No links containing text '$text' and URL '$url' were found in page $currentUri");
    }

    public function dontSeeLink($text, $url = null)
    {
        $nodes = $this->getBaseElement()->findElements(WebDriverBy::partialLinkText($text));
        $currentUri = $this->_getCurrentUri();
        if (!$url) {
            $this->assertEmpty($nodes, "Link containing text '$text' was found in page $currentUri");
        } else {
            $nodes = $this->filterNodesByHref($url, $nodes);
            $this->assertEmpty($nodes, "Link containing text '$text' and URL '$url' was found in page $currentUri");
        }
    }

    /**
     * @param string $url
     * @param $nodes
     * @return array
     */
    private function filterNodesByHref($url, $nodes)
    {
        //current uri can be relative, merging it with configured base url gives absolute url
        $absoluteCurrentUrl = Uri::mergeUrls($this->_getUrl(), $this->_getCurrentUri());
        $expectedUrl = Uri::mergeUrls($absoluteCurrentUrl, $url);

        $nodes = array_filter(
            $nodes,
            function (WebDriverElement $e) use ($expectedUrl, $absoluteCurrentUrl) {
                $elementHref = Uri::mergeUrls($absoluteCurrentUrl, $e->getAttribute('href'));
                return $elementHref === $expectedUrl;
            }
        );
        return $nodes;
    }

    public function seeInCurrentUrl($uri)
    {
        $this->assertStringContainsString($uri, $this->_getCurrentUri());
    }

    public function seeCurrentUrlEquals($uri)
    {
        $this->assertEquals($uri, $this->_getCurrentUri());
    }

    public function seeCurrentUrlMatches($uri)
    {
        $this->assertRegExp($uri, $this->_getCurrentUri());
    }

    public function dontSeeInCurrentUrl($uri)
    {
        $this->assertStringNotContainsString($uri, $this->_getCurrentUri());
    }

    public function dontSeeCurrentUrlEquals($uri)
    {
        $this->assertNotEquals($uri, $this->_getCurrentUri());
    }

    public function dontSeeCurrentUrlMatches($uri)
    {
        $this->assertNotRegExp($uri, $this->_getCurrentUri());
    }

    public function grabFromCurrentUrl($uri = null)
    {
        if (!$uri) {
            return $this->_getCurrentUri();
        }
        $matches = [];
        $res = preg_match($uri, $this->_getCurrentUri(), $matches);
        if (!$res) {
            $this->fail("Couldn't match $uri in " . $this->_getCurrentUri());
        }
        if (!isset($matches[1])) {
            $this->fail("Nothing to grab. A regex parameter required. Ex: '/user/(\\d+)'");
        }
        return $matches[1];
    }

    public function seeCheckboxIsChecked($checkbox)
    {
        $this->assertTrue($this->findField($checkbox)->isSelected());
    }

    public function dontSeeCheckboxIsChecked($checkbox)
    {
        $this->assertFalse($this->findField($checkbox)->isSelected());
    }

    public function seeInField($field, $value)
    {
        $els = $this->findFields($field);
        $this->assert($this->proceedSeeInField($els, $value));
    }

    public function dontSeeInField($field, $value)
    {
        $els = $this->findFields($field);
        $this->assertNot($this->proceedSeeInField($els, $value));
    }

    public function seeInFormFields($formSelector, array $params)
    {
        $this->proceedSeeInFormFields($formSelector, $params, false);
    }

    public function dontSeeInFormFields($formSelector, array $params)
    {
        $this->proceedSeeInFormFields($formSelector, $params, true);
    }

    protected function proceedSeeInFormFields($formSelector, array $params, $assertNot)
    {
        $form = $this->match($this->getBaseElement(), $formSelector);
        if (empty($form)) {
            throw new ElementNotFound($formSelector, "Form via CSS or XPath");
        }
        $form = reset($form);

        $els = [];
        foreach ($params as $name => $values) {
            $this->pushFormField($els, $form, $name, $values);
        }

        foreach ($els as $arrayElement) {
            list($el, $values) = $arrayElement;

            if (!is_array($values)) {
                $values = [$values];
            }

            foreach ($values as $value) {
                $ret = $this->proceedSeeInField($el, $value);
                if ($assertNot) {
                    $this->assertNot($ret);
                } else {
                    $this->assert($ret);
                }
            }
        }
    }

    /**
     * Map an array element passed to seeInFormFields to its corresponding WebDriver element,
     * recursing through array values if the field is not found.
     *
     * @param array $els The previously found elements.
     * @param RemoteWebElement $form The form in which to search for fields.
     * @param string $name The field's name.
     * @param mixed $values
     * @return void
     */
    protected function pushFormField(&$els, $form, $name, $values)
    {
        $el = $form->findElements(WebDriverBy::name($name));

        if ($el) {
            $els[] = [$el, $values];
        } elseif (is_array($values)) {
            foreach ($values as $key => $value) {
                $this->pushFormField($els, $form, "{$name}[$key]", $value);
            }
        } else {
            throw new ElementNotFound($name);
        }
    }

    /**
     * @param RemoteWebElement[] $elements
     * @param $value
     * @return array
     */
    protected function proceedSeeInField(array $elements, $value)
    {
        $strField = reset($elements)->getAttribute('name');
        if (reset($elements)->getTagName() === 'select') {
            $el = reset($elements);
            $elements = $el->findElements(WebDriverBy::xpath('.//option'));
            if (empty($value) && empty($elements)) {
                return ['True', true];
            }
        }

        $currentValues = [];
        if (is_bool($value)) {
            $currentValues = [false];
        }
        foreach ($elements as $el) {
            switch ($el->getTagName()) {
                case 'input':
                    if ($el->getAttribute('type') === 'radio' || $el->getAttribute('type') === 'checkbox') {
                        if ($el->getAttribute('checked')) {
                            if (is_bool($value)) {
                                $currentValues = [true];
                                break;
                            } else {
                                $currentValues[] = $el->getAttribute('value');
                            }
                        }
                    } else {
                        $currentValues[] = $el->getAttribute('value');
                    }
                    break;
                case 'option':
                    // no break we need the trim text and the value also
                    if (!$el->isSelected()) {
                        break;
                    }
                    $currentValues[] = $el->getText();
                case 'textarea':
                    // we include trimmed and real value of textarea for check
                    $currentValues[] = trim($el->getText());
                default:
                    $currentValues[] = $el->getAttribute('value'); // raw value
                    break;
            }
        }

        return [
            'Contains',
            $value,
            $currentValues,
            "Failed testing for '$value' in $strField's value: '" . implode("', '", $currentValues) . "'"
        ];
    }

    public function selectOption($select, $option)
    {
        $el = $this->findField($select);
        if ($el->getTagName() != 'select') {
            $els = $this->matchCheckables($select);
            $radio = null;
            foreach ($els as $el) {
                $radio = $this->findCheckable($el, $option, true);
                if ($radio) {
                    break;
                }
            }
            if (!$radio) {
                throw new ElementNotFound($select, "Radiobutton with value or name '$option in");
            }
            $radio->click();
            return;
        }

        $wdSelect = new WebDriverSelect($el);
        if ($wdSelect->isMultiple()) {
            $wdSelect->deselectAll();
        }
        if (!is_array($option)) {
            $option = [$option];
        }

        $matched = false;

        if (key($option) !== 'value') {
            foreach ($option as $opt) {
                try {
                    $wdSelect->selectByVisibleText($opt);
                    $matched = true;
                } catch (NoSuchElementException $e) {
                }
            }
        }

        if ($matched) {
            return;
        }

        if (key($option) !== 'text') {
            foreach ($option as $opt) {
                try {
                    $wdSelect->selectByValue($opt);
                    $matched = true;
                } catch (NoSuchElementException $e) {
                }
            }
        }

        if ($matched) {
            return;
        }

        // partially matching
        foreach ($option as $opt) {
            try {
                $optElement = $el->findElement(WebDriverBy::xpath('.//option [contains (., "' . $opt . '")]'));
                $matched = true;
                if (!$optElement->isSelected()) {
                    $optElement->click();
                }
            } catch (NoSuchElementException $e) {
                // exception treated at the end
            }
        }
        if ($matched) {
            return;
        }
        throw new ElementNotFound(json_encode($option), "Option inside $select matched by name or value");
    }

    /**
     * Manually starts a new browser session.
     *
     * ```php
     * <?php
     * $this->getModule('WebDriver')->_initializeSession();
     * ```
     *
     * @api
     */
    public function _initializeSession()
    {
        try {
            $this->sessions[] = $this->webDriver;
            $this->webDriver = RemoteWebDriver::create(
                $this->wdHost,
                $this->capabilities,
                $this->connectionTimeoutInMs,
                $this->requestTimeoutInMs,
                $this->webdriverProxy,
                $this->webdriverProxyPort
            );
            if (!is_null($this->config['pageload_timeout'])) {
                $this->webDriver->manage()->timeouts()->pageLoadTimeout($this->config['pageload_timeout']);
            }
            $this->setBaseElement();
            $this->initialWindowSize();
        } catch (WebDriverCurlException $e) {
            codecept_debug('Curl error: ' . $e->getMessage());
            throw new ConnectionException("Can't connect to WebDriver at {$this->wdHost}. Make sure that ChromeDriver, GeckoDriver or Selenium Server is running.");
        }
    }

    /**
     * Loads current RemoteWebDriver instance as a session
     *
     * @api
     * @param RemoteWebDriver $session
     */
    public function _loadSession($session)
    {
        $this->webDriver = $session;
        $this->setBaseElement();
    }

    /**
     * Returns current WebDriver session for saving
     *
     * @api
     * @return RemoteWebDriver
     */
    public function _backupSession()
    {
        return $this->webDriver;
    }

    /**
     * Manually closes current WebDriver session.
     *
     * ```php
     * <?php
     * $this->getModule('WebDriver')->_closeSession();
     *
     * // close a specific session
     * $webDriver = $this->getModule('WebDriver')->webDriver;
     * $this->getModule('WebDriver')->_closeSession($webDriver);
     * ```
     *
     * @api
     * @param $webDriver (optional) a specific webdriver session instance
     */
    public function _closeSession($webDriver = null)
    {
        if (!$webDriver and $this->webDriver) {
            $webDriver = $this->webDriver;
        }
        if (!$webDriver) {
            return;
        }
        try {
            $webDriver->quit();
            unset($webDriver);
        } catch (UnknownServerException $e) {
            // Session already closed so nothing to do
        } catch (UnknownErrorException $e) {
            // Session already closed so nothing to do
        }
    }

    /**
     * Unselect an option in the given select box.
     *
     * @param $select
     * @param $option
     */
    public function unselectOption($select, $option)
    {
        $el = $this->findField($select);

        $wdSelect = new WebDriverSelect($el);

        if (!is_array($option)) {
            $option = [$option];
        }

        $matched = false;

        foreach ($option as $opt) {
            try {
                $wdSelect->deselectByVisibleText($opt);
                $matched = true;
            } catch (NoSuchElementException $e) {
                // exception treated at the end
            }

            try {
                $wdSelect->deselectByValue($opt);
                $matched = true;
            } catch (NoSuchElementException $e) {
                // exception treated at the end
            }
        }

        if ($matched) {
            return;
        }
        throw new ElementNotFound(json_encode($option), "Option inside $select matched by name or value");
    }

    /**
     * @param $context
     * @param $radioOrCheckbox
     * @param bool $byValue
     * @return mixed|null
     */
    protected function findCheckable($context, $radioOrCheckbox, $byValue = false)
    {
        if ($radioOrCheckbox instanceof WebDriverElement) {
            return $radioOrCheckbox;
        }

        if (is_array($radioOrCheckbox) or ($radioOrCheckbox instanceof WebDriverBy)) {
            return $this->matchFirstOrFail($this->getBaseElement(), $radioOrCheckbox);
        }

        $locator = static::xpathLiteral($radioOrCheckbox);
        if ($context instanceof WebDriverElement && $context->getTagName() === 'input') {
            $contextType = $context->getAttribute('type');
            if (!in_array($contextType, ['checkbox', 'radio'], true)) {
                return null;
            }
            $nameLiteral = static::xpathLiteral($context->getAttribute('name'));
            $typeLiteral = static::xpathLiteral($contextType);
            $inputLocatorFragment = "input[@type = $typeLiteral][@name = $nameLiteral]";
            $xpath = Locator::combine(
            // @codingStandardsIgnoreStart
                "ancestor::form//{$inputLocatorFragment}[(@id = ancestor::form//label[contains(normalize-space(string(.)), $locator)]/@for) or @placeholder = $locator]",
                // @codingStandardsIgnoreEnd
                "ancestor::form//label[contains(normalize-space(string(.)), $locator)]//{$inputLocatorFragment}"
            );
            if ($byValue) {
                $xpath = Locator::combine($xpath, "ancestor::form//{$inputLocatorFragment}[@value = $locator]");
            }
        } else {
            $xpath = Locator::combine(
            // @codingStandardsIgnoreStart
                "//input[@type = 'checkbox' or @type = 'radio'][(@id = //label[contains(normalize-space(string(.)), $locator)]/@for) or @placeholder = $locator or @name = $locator]",
                // @codingStandardsIgnoreEnd
                "//label[contains(normalize-space(string(.)), $locator)]//input[@type = 'radio' or @type = 'checkbox']"
            );
            if ($byValue) {
                $xpath = Locator::combine($xpath, "//input[@type = 'checkbox' or @type = 'radio'][@value = $locator]");
            }
        }
        $els = $context->findElements(WebDriverBy::xpath($xpath));
        if (count($els)) {
            return reset($els);
        }
        $els = $context->findElements(WebDriverBy::xpath(str_replace('ancestor::form', '', $xpath)));
        if (count($els)) {
            return reset($els);
        }
        $els = $this->match($context, $radioOrCheckbox);
        if (count($els)) {
            return reset($els);
        }
        return null;
    }

    protected function matchCheckables($selector)
    {
        $els = $this->match($this->webDriver, $selector);
        if (!count($els)) {
            throw new ElementNotFound($selector, "Element containing radio by CSS or XPath");
        }
        return $els;
    }

    public function checkOption($option)
    {
        $field = $this->findCheckable($this->webDriver, $option);
        if (!$field) {
            throw new ElementNotFound($option, "Checkbox or Radio by Label or CSS or XPath");
        }
        if ($field->isSelected()) {
            return;
        }
        $field->click();
    }

    public function uncheckOption($option)
    {
        $field = $this->findCheckable($this->getBaseElement(), $option);
        if (!$field) {
            throw new ElementNotFound($option, "Checkbox by Label or CSS or XPath");
        }
        if (!$field->isSelected()) {
            return;
        }
        $field->click();
    }

    public function fillField($field, $value)
    {
        $el = $this->findField($field);
        $el->clear();
        $el->sendKeys((string)$value);
    }

    /**
     * Clears given field which isn't empty.
     *
     * ``` php
     * <?php
     * $I->clearField('#username');
     * ```
     *
     * @param $field
     */
    public function clearField($field)
    {
        $el = $this->findField($field);
        $el->clear();
    }

    /**
     * Type in characters on active element.
     * With a second parameter you can specify delay between key presses. 
     * 
     * ```php
     * <?php
     * // activate input element
     * $I->click('#input');
     * 
     * // type text in active element
     * $I->type('Hello world');
     * 
     * // type text with a 1sec delay between chars
     * $I->type('Hello World', 1);
     * ```
     * 
     * This might be useful when you an input reacts to typing and you need to slow it down to emulate human behavior.
     * For instance, this is how Credit Card fields can be filled in.
     * 
     * @param $text
     * @param $delay [sec]
     */
    public function type($text, $delay = 0) {
        $keys = str_split($text);
        foreach ($keys as $key) {
            sleep($delay);
            $this->webDriver->getKeyboard()->pressKey($key);
        }
        sleep($delay);
    }

    public function attachFile($field, $filename)
    {
        $el = $this->findField($field);
        // in order to be compatible on different OS
        $filePath = codecept_data_dir() . $filename;
        if (!file_exists($filePath)) {
            throw new \InvalidArgumentException("File does not exist: $filePath");
        }
        if (!is_readable($filePath)) {
            throw new \InvalidArgumentException("File is not readable: $filePath");
        }
        // in order for remote upload to be enabled
        $el->setFileDetector(new LocalFileDetector());

        // skip file detector for phantomjs
        if ($this->isPhantom()) {
            $el->setFileDetector(new UselessFileDetector());
        }
        $el->sendKeys(realpath($filePath));
    }

    /**
     * Grabs all visible text from the current page.
     *
     * @return string
     */
    protected function getVisibleText()
    {
        if ($this->getBaseElement() instanceof RemoteWebElement) {
            return $this->getBaseElement()->getText();
        }
        $els = $this->getBaseElement()->findElements(WebDriverBy::cssSelector('body'));
        if (isset($els[0])) {
            return $els[0]->getText();
        }
        return '';
    }

    public function grabTextFrom($cssOrXPathOrRegex)
    {
        $els = $this->match($this->getBaseElement(), $cssOrXPathOrRegex, false);
        if (count($els)) {
            return $els[0]->getText();
        }
        if (@preg_match($cssOrXPathOrRegex, $this->webDriver->getPageSource(), $matches)) {
            return $matches[1];
        }
        throw new ElementNotFound($cssOrXPathOrRegex, 'CSS or XPath or Regex');
    }

    public function grabAttributeFrom($cssOrXpath, $attribute)
    {
        $el = $this->matchFirstOrFail($this->getBaseElement(), $cssOrXpath);
        return $el->getAttribute($attribute);
    }

    public function grabValueFrom($field)
    {
        $el = $this->findField($field);
        // value of multiple select is the value of the first selected option
        if ($el->getTagName() == 'select') {
            $select = new WebDriverSelect($el);
            return $select->getFirstSelectedOption()->getAttribute('value');
        }
        return $el->getAttribute('value');
    }

    public function grabMultiple($cssOrXpath, $attribute = null)
    {
        $els = $this->match($this->getBaseElement(), $cssOrXpath);
        return array_map(
            function (WebDriverElement $e) use ($attribute) {
                if ($attribute) {
                    return $e->getAttribute($attribute);
                }
                return $e->getText();
            },
            $els
        );
    }


    protected function filterByAttributes($els, array $attributes)
    {
        foreach ($attributes as $attr => $value) {
            $els = array_filter(
                $els,
                function (WebDriverElement $el) use ($attr, $value) {
                    return $el->getAttribute($attr) == $value;
                }
            );
        }
        return $els;
    }

    public function seeElement($selector, $attributes = [])
    {
        $this->enableImplicitWait();
        $els = $this->matchVisible($selector);
        $this->disableImplicitWait();
        $els = $this->filterByAttributes($els, $attributes);
        $this->assertNotEmpty($els);
    }

    public function dontSeeElement($selector, $attributes = [])
    {
        $els = $this->matchVisible($selector);
        $els = $this->filterByAttributes($els, $attributes);
        $this->assertEmpty($els);
    }

    /**
     * Checks that the given element exists on the page, even it is invisible.
     *
     * ``` php
     * <?php
     * $I->seeElementInDOM('//form/input[type=hidden]');
     * ?>
     * ```
     *
     * @param $selector
     * @param array $attributes
     */
    public function seeElementInDOM($selector, $attributes = [])
    {
        $this->enableImplicitWait();
        $els = $this->match($this->getBaseElement(), $selector);
        $els = $this->filterByAttributes($els, $attributes);
        $this->disableImplicitWait();
        $this->assertNotEmpty($els);
    }


    /**
     * Opposite of `seeElementInDOM`.
     *
     * @param $selector
     * @param array $attributes
     */
    public function dontSeeElementInDOM($selector, $attributes = [])
    {
        $els = $this->match($this->getBaseElement(), $selector);
        $els = $this->filterByAttributes($els, $attributes);
        $this->assertEmpty($els);
    }

    public function seeNumberOfElements($selector, $expected)
    {
        $counted = count($this->matchVisible($selector));
        if (is_array($expected)) {
            list($floor, $ceil) = $expected;
            $this->assertTrue(
                $floor <= $counted && $ceil >= $counted,
                'Number of elements counted differs from expected range'
            );
        } else {
            $this->assertEquals(
                $expected,
                $counted,
                'Number of elements counted differs from expected number'
            );
        }
    }

    public function seeNumberOfElementsInDOM($selector, $expected)
    {
        $counted = count($this->match($this->getBaseElement(), $selector));
        if (is_array($expected)) {
            list($floor, $ceil) = $expected;
            $this->assertTrue(
                $floor <= $counted && $ceil >= $counted,
                'Number of elements counted differs from expected range'
            );
        } else {
            $this->assertEquals(
                $expected,
                $counted,
                'Number of elements counted differs from expected number'
            );
        }
    }

    public function seeOptionIsSelected($selector, $optionText)
    {
        $el = $this->findField($selector);
        if ($el->getTagName() !== 'select') {
            $els = $this->matchCheckables($selector);
            foreach ($els as $k => $el) {
                $els[$k] = $this->findCheckable($el, $optionText, true);
            }
            $this->assertNotEmpty(
                array_filter(
                    $els,
                    function ($e) {
                        return $e && $e->isSelected();
                    }
                )
            );
            return;
        }
        $select = new WebDriverSelect($el);
        $this->assertNodesContain($optionText, $select->getAllSelectedOptions(), 'option');
    }

    public function dontSeeOptionIsSelected($selector, $optionText)
    {
        $el = $this->findField($selector);
        if ($el->getTagName() !== 'select') {
            $els = $this->matchCheckables($selector);
            foreach ($els as $k => $el) {
                $els[$k] = $this->findCheckable($el, $optionText, true);
            }
            $this->assertEmpty(
                array_filter(
                    $els,
                    function ($e) {
                        return $e && $e->isSelected();
                    }
                )
            );
            return;
        }
        $select = new WebDriverSelect($el);
        $this->assertNodesNotContain($optionText, $select->getAllSelectedOptions(), 'option');
    }

    public function seeInTitle($title)
    {
        $this->assertStringContainsString($title, $this->webDriver->getTitle());
    }

    public function dontSeeInTitle($title)
    {
        $this->assertStringNotContainsString($title, $this->webDriver->getTitle());
    }

    /**
     * Accepts the active JavaScript native popup window, as created by `window.alert`|`window.confirm`|`window.prompt`.
     * Don't confuse popups with modal windows,
     * as created by [various libraries](http://jster.net/category/windows-modals-popups).
     */
    public function acceptPopup()
    {
        if ($this->isPhantom()) {
            throw new ModuleException($this, 'PhantomJS does not support working with popups');
        }
        $this->webDriver->switchTo()->alert()->accept();
    }

    /**
     * Dismisses the active JavaScript popup, as created by `window.alert`, `window.confirm`, or `window.prompt`.
     */
    public function cancelPopup()
    {
        if ($this->isPhantom()) {
            throw new ModuleException($this, 'PhantomJS does not support working with popups');
        }
        $this->webDriver->switchTo()->alert()->dismiss();
    }

    /**
     * Checks that the active JavaScript popup,
     * as created by `window.alert`|`window.confirm`|`window.prompt`, contains the given string.
     *
     * @param $text
     *
     * @throws \Codeception\Exception\ModuleException
     */
    public function seeInPopup($text)
    {
        if ($this->isPhantom()) {
            throw new ModuleException($this, 'PhantomJS does not support working with popups');
        }
        $alert = $this->webDriver->switchTo()->alert();
        try {
            $this->assertStringContainsString($text, $alert->getText());
        } catch (\PHPUnit\Framework\AssertionFailedError $e) {
            $alert->dismiss();
            throw $e;
        }
    }

    /**
     * Checks that the active JavaScript popup,
     * as created by `window.alert`|`window.confirm`|`window.prompt`, does NOT contain the given string.
     *
     * @param $text
     *
     * @throws \Codeception\Exception\ModuleException
     */
    public function dontSeeInPopup($text)
    {
        if ($this->isPhantom()) {
            throw new ModuleException($this, 'PhantomJS does not support working with popups');
        }
        $alert = $this->webDriver->switchTo()->alert();
        try {
            $this->assertStringNotContainsString($text, $alert->getText());
        } catch (\PHPUnit\Framework\AssertionFailedError $e) {
            $alert->dismiss();
            throw $e;
        }
    }

    /**
     * Enters text into a native JavaScript prompt popup, as created by `window.prompt`.
     *
     * @param $keys
     *
     * @throws \Codeception\Exception\ModuleException
     */
    public function typeInPopup($keys)
    {
        if ($this->isPhantom()) {
            throw new ModuleException($this, 'PhantomJS does not support working with popups');
        }
        $this->webDriver->switchTo()->alert()->sendKeys($keys);
    }

    /**
     * Reloads the current page.
     */
    public function reloadPage()
    {
        $this->webDriver->navigate()->refresh();
    }

    /**
     * Moves back in history.
     */
    public function moveBack()
    {
        $this->webDriver->navigate()->back();
        $this->debug($this->_getCurrentUri());
    }

    /**
     * Moves forward in history.
     */
    public function moveForward()
    {
        $this->webDriver->navigate()->forward();
        $this->debug($this->_getCurrentUri());
    }

    protected function getSubmissionFormFieldName($name)
    {
        if (substr($name, -2) === '[]') {
            return substr($name, 0, -2);
        }
        return $name;
    }

    /**
     * Submits the given form on the page, optionally with the given form
     * values.  Give the form fields values as an array. Note that hidden fields
     * can't be accessed.
     *
     * Skipped fields will be filled by their values from the page.
     * You don't need to click the 'Submit' button afterwards.
     * This command itself triggers the request to form's action.
     *
     * You can optionally specify what button's value to include
     * in the request with the last parameter as an alternative to
     * explicitly setting its value in the second parameter, as
     * button values are not otherwise included in the request.
     *
     * Examples:
     *
     * ``` php
     * <?php
     * $I->submitForm('#login', [
     *     'login' => 'davert',
     *     'password' => '123456'
     * ]);
     * // or
     * $I->submitForm('#login', [
     *     'login' => 'davert',
     *     'password' => '123456'
     * ], 'submitButtonName');
     *
     * ```
     *
     * For example, given this sample "Sign Up" form:
     *
     * ``` html
     * <form action="/sign_up">
     *     Login:
     *     <input type="text" name="user[login]" /><br/>
     *     Password:
     *     <input type="password" name="user[password]" /><br/>
     *     Do you agree to our terms?
     *     <input type="checkbox" name="user[agree]" /><br/>
     *     Select pricing plan:
     *     <select name="plan">
     *         <option value="1">Free</option>
     *         <option value="2" selected="selected">Paid</option>
     *     </select>
     *     <input type="submit" name="submitButton" value="Submit" />
     * </form>
     * ```
     *
     * You could write the following to submit it:
     *
     * ``` php
     * <?php
     * $I->submitForm(
     *     '#userForm',
     *     [
     *         'user[login]' => 'Davert',
     *         'user[password]' => '123456',
     *         'user[agree]' => true
     *     ],
     *     'submitButton'
     * );
     * ```
     * Note that "2" will be the submitted value for the "plan" field, as it is
     * the selected option.
     *
     * Also note that this differs from PhpBrowser, in that
     * ```'user' => [ 'login' => 'Davert' ]``` is not supported at the moment.
     * Named array keys *must* be included in the name as above.
     *
     * Pair this with seeInFormFields for quick testing magic.
     *
     * ``` php
     * <?php
     * $form = [
     *      'field1' => 'value',
     *      'field2' => 'another value',
     *      'checkbox1' => true,
     *      // ...
     * ];
     * $I->submitForm('//form[@id=my-form]', $form, 'submitButton');
     * // $I->amOnPage('/path/to/form-page') may be needed
     * $I->seeInFormFields('//form[@id=my-form]', $form);
     * ?>
     * ```
     *
     * Parameter values must be set to arrays for multiple input fields
     * of the same name, or multi-select combo boxes.  For checkboxes,
     * either the string value can be used, or boolean values which will
     * be replaced by the checkbox's value in the DOM.
     *
     * ``` php
     * <?php
     * $I->submitForm('#my-form', [
     *      'field1' => 'value',
     *      'checkbox' => [
     *          'value of first checkbox',
     *          'value of second checkbox',
     *      ],
     *      'otherCheckboxes' => [
     *          true,
     *          false,
     *          false,
     *      ],
     *      'multiselect' => [
     *          'first option value',
     *          'second option value',
     *      ]
     * ]);
     * ?>
     * ```
     *
     * Mixing string and boolean values for a checkbox's value is not supported
     * and may produce unexpected results.
     *
     * Field names ending in "[]" must be passed without the trailing square
     * bracket characters, and must contain an array for its value.  This allows
     * submitting multiple values with the same name, consider:
     *
     * ```php
     * $I->submitForm('#my-form', [
     *     'field[]' => 'value',
     *     'field[]' => 'another value', // 'field[]' is already a defined key
     * ]);
     * ```
     *
     * The solution is to pass an array value:
     *
     * ```php
     * // this way both values are submitted
     * $I->submitForm('#my-form', [
     *     'field' => [
     *         'value',
     *         'another value',
     *     ]
     * ]);
     * ```
     *
     * The `$button` parameter can be either a string, an array or an instance
     * of Facebook\WebDriver\WebDriverBy. When it is a string, the
     * button will be found by its "name" attribute. If $button is an
     * array then it will be treated as a strict selector and a WebDriverBy
     * will be used verbatim.
     *
     * For example, given the following HTML:
     *
     * ``` html
     * <input type="submit" name="submitButton" value="Submit" />
     * ```
     *
     * `$button` could be any one of the following:
     *   - 'submitButton'
     *   - ['name' => 'submitButton']
     *   - WebDriverBy::name('submitButton')
     *
     * @param $selector
     * @param $params
     * @param $button
     */
    public function submitForm($selector, array $params, $button = null)
    {
        $form = $this->matchFirstOrFail($this->getBaseElement(), $selector);

        $fields = $form->findElements(
            WebDriverBy::cssSelector('input:enabled,textarea:enabled,select:enabled,input[type=hidden]')
        );
        foreach ($fields as $field) {
            $fieldName = $this->getSubmissionFormFieldName($field->getAttribute('name'));
            if (!isset($params[$fieldName])) {
                continue;
            }
            $value = $params[$fieldName];
            if (is_array($value) && $field->getTagName() !== 'select') {
                if ($field->getAttribute('type') === 'checkbox' || $field->getAttribute('type') === 'radio') {
                    $found = false;
                    foreach ($value as $index => $val) {
                        if (!is_bool($val) && $val === $field->getAttribute('value')) {
                            array_splice($params[$fieldName], $index, 1);
                            $value = $val;
                            $found = true;
                            break;
                        }
                    }
                    if (!$found && !empty($value) && is_bool(reset($value))) {
                        $value = array_pop($params[$fieldName]);
                    }
                } else {
                    $value = array_pop($params[$fieldName]);
                }
            }

            if ($field->getAttribute('type') === 'checkbox' || $field->getAttribute('type') === 'radio') {
                if ($value === true || $value === $field->getAttribute('value')) {
                    $this->checkOption($field);
                } else {
                    $this->uncheckOption($field);
                }
            } elseif ($field->getAttribute('type') === 'button' || $field->getAttribute('type') === 'submit') {
                continue;
            } elseif ($field->getTagName() === 'select') {
                $this->selectOption($field, $value);
            } else {
                $this->fillField($field, $value);
            }
        }

        $this->debugSection(
            'Uri',
            $form->getAttribute('action') ? $form->getAttribute('action') : $this->_getCurrentUri()
        );
        $this->debugSection('Method', $form->getAttribute('method') ? $form->getAttribute('method') : 'GET');
        $this->debugSection('Parameters', json_encode($params));

        $submitted = false;
        if (!empty($button)) {
            if (is_array($button)) {
                $buttonSelector = $this->getStrictLocator($button);
            } elseif ($button instanceof WebDriverBy) {
                $buttonSelector = $button;
            } else {
                $buttonSelector = WebDriverBy::name($button);
            }

            $els = $form->findElements($buttonSelector);

            if (!empty($els)) {
                $el = reset($els);
                $el->click();
                $submitted = true;
            }
        }

        if (!$submitted) {
            $form->submit();
        }
        $this->debugSection('Page', $this->_getCurrentUri());
    }

    /**
     * Waits up to $timeout seconds for the given element to change.
     * Element "change" is determined by a callback function which is called repeatedly
     * until the return value evaluates to true.
     *
     * ``` php
     * <?php
     * use \Facebook\WebDriver\WebDriverElement
     * $I->waitForElementChange('#menu', function(WebDriverElement $el) {
     *     return $el->isDisplayed();
     * }, 100);
     * ?>
     * ```
     *
     * @param $element
     * @param \Closure $callback
     * @param int $timeout seconds
     * @throws \Codeception\Exception\ElementNotFound
     */
    public function waitForElementChange($element, \Closure $callback, $timeout = 30)
    {
        $el = $this->matchFirstOrFail($this->getBaseElement(), $element);
        $checker = function () use ($el, $callback) {
            return $callback($el);
        };
        $this->webDriver->wait($timeout)->until($checker);
    }

    /**
     * Waits up to $timeout seconds for an element to appear on the page.
     * If the element doesn't appear, a timeout exception is thrown.
     *
     * ``` php
     * <?php
     * $I->waitForElement('#agree_button', 30); // secs
     * $I->click('#agree_button');
     * ?>
     * ```
     *
     * @param $element
     * @param int $timeout seconds
     * @throws \Exception
     */
    public function waitForElement($element, $timeout = 10)
    {
        $condition = WebDriverExpectedCondition::presenceOfElementLocated($this->getLocator($element));
        $this->webDriver->wait($timeout)->until($condition);
    }

    /**
     * Waits up to $timeout seconds for the given element to be visible on the page.
     * If element doesn't appear, a timeout exception is thrown.
     *
     * ``` php
     * <?php
     * $I->waitForElementVisible('#agree_button', 30); // secs
     * $I->click('#agree_button');
     * ?>
     * ```
     *
     * @param $element
     * @param int $timeout seconds
     * @throws \Exception
     */
    public function waitForElementVisible($element, $timeout = 10)
    {
        $condition = WebDriverExpectedCondition::visibilityOfElementLocated($this->getLocator($element));
        $this->webDriver->wait($timeout)->until($condition);
    }

    /**
     * Waits up to $timeout seconds for the given element to become invisible.
     * If element stays visible, a timeout exception is thrown.
     *
     * ``` php
     * <?php
     * $I->waitForElementNotVisible('#agree_button', 30); // secs
     * ?>
     * ```
     *
     * @param $element
     * @param int $timeout seconds
     * @throws \Exception
     */
    public function waitForElementNotVisible($element, $timeout = 10)
    {
        $condition = WebDriverExpectedCondition::invisibilityOfElementLocated($this->getLocator($element));
        $this->webDriver->wait($timeout)->until($condition);
    }

    /**
     * Waits up to $timeout seconds for the given element to be clickable.
     * If element doesn't become clickable, a timeout exception is thrown.
     *
     * ``` php
     * <?php
     * $I->waitForElementClickable('#agree_button', 30); // secs
     * $I->click('#agree_button');
     * ?>
     * ```
     *
     * @param $element
     * @param int $timeout seconds
     * @throws \Exception
     */
    public function waitForElementClickable($element, $timeout = 10)
    {
        $condition = WebDriverExpectedCondition::elementToBeClickable($this->getLocator($element));
        $this->webDriver->wait($timeout)->until($condition);
    }

    /**
     * Waits up to $timeout seconds for the given string to appear on the page.
     *
     * Can also be passed a selector to search in, be as specific as possible when using selectors.
     * waitForText() will only watch the first instance of the matching selector / text provided.
     * If the given text doesn't appear, a timeout exception is thrown.
     *
     * ``` php
     * <?php
     * $I->waitForText('foo', 30); // secs
     * $I->waitForText('foo', 30, '.title'); // secs
     * ?>
     * ```
     *
     * @param string $text
     * @param int $timeout seconds
     * @param string $selector optional
     * @throws \Exception
     */
    public function waitForText($text, $timeout = 10, $selector = null)
    {
        $message = sprintf(
            'Waited for %d secs but text %s still not found',
            $timeout,
            Locator::humanReadableString($text)
        );
        if (!$selector) {
            $condition = WebDriverExpectedCondition::textToBePresentInElement(WebDriverBy::xpath('//body'), $text);
            $this->webDriver->wait($timeout)->until($condition, $message);
            return;
        }

        $condition = WebDriverExpectedCondition::textToBePresentInElement($this->getLocator($selector), $text);
        $this->webDriver->wait($timeout)->until($condition, $message);
    }

    /**
     * Wait for $timeout seconds.
     *
     * @param int|float $timeout secs
     * @throws \Codeception\Exception\TestRuntimeException
     */
    public function wait($timeout)
    {
        if ($timeout >= 1000) {
            throw new TestRuntimeException(
                "
                Waiting for more then 1000 seconds: 16.6667 mins\n
                Please note that wait method accepts number of seconds as parameter."
            );
        }
        usleep($timeout * 1000000);
    }

    /**
     * Low-level API method.
     * If Codeception commands are not enough, this allows you to use Selenium WebDriver methods directly:
     *
     * ``` php
     * $I->executeInSelenium(function(\Facebook\WebDriver\Remote\RemoteWebDriver $webdriver) {
     *   $webdriver->get('http://google.com');
     * });
     * ```
     *
     * This runs in the context of the
     * [RemoteWebDriver class](https://github.com/php-webdriver/php-webdriver/blob/master/lib/remote/RemoteWebDriver.php).
     * Try not to use this command on a regular basis.
     * If Codeception lacks a feature you need, please implement it and submit a patch.
     *
     * @param callable $function
     */
    public function executeInSelenium(\Closure $function)
    {
        return $function($this->webDriver);
    }

    /**
     * Switch to another window identified by name.
     *
     * The window can only be identified by name. If the $name parameter is blank, the parent window will be used.
     *
     * Example:
     * ``` html
     * <input type="button" value="Open window" onclick="window.open('http://example.com', 'another_window')">
     * ```
     *
     * ``` php
     * <?php
     * $I->click("Open window");
     * # switch to another window
     * $I->switchToWindow("another_window");
     * # switch to parent window
     * $I->switchToWindow();
     * ?>
     * ```
     *
     * If the window has no name, match it by switching to next active tab using `switchToNextTab` method.
     *
     * Or use native Selenium functions to get access to all opened windows:
     *
     * ``` php
     * <?php
     * $I->executeInSelenium(function (\Facebook\WebDriver\Remote\RemoteWebDriver $webdriver) {
     *      $handles=$webdriver->getWindowHandles();
     *      $last_window = end($handles);
     *      $webdriver->switchTo()->window($last_window);
     * });
     * ?>
     * ```
     *
     * @param string|null $name
     */
    public function switchToWindow($name = null)
    {
        $this->webDriver->switchTo()->window($name);
    }

    /**
     * Switch to another iframe on the page.
     *
     * Example:
     * ``` html
     * <iframe name="another_frame" id="fr1" src="http://example.com">
     *
     * ```
     *
     * ``` php
     * <?php
     * # switch to iframe by name
     * $I->switchToIFrame("another_frame");
     * # switch to iframe by CSS or XPath
     * $I->switchToIFrame("#fr1");
     * # switch to parent page
     * $I->switchToIFrame();
     *
     * ```
     *
     * @param string|null $locator (name, CSS or XPath)
     */
    public function switchToIFrame($locator = null)
    {
        $this->findAndSwitchToFrame($locator, 'iframe');
    }

    /**
     * Switch to another frame on the page.
     *
     * Example:
     * ``` html
     * <frame name="another_frame" id="fr1" src="http://example.com">
     *
     * ```
     *
     * ``` php
     * <?php
     * # switch to frame by name
     * $I->switchToFrame("another_frame");
     * # switch to frame by CSS or XPath
     * $I->switchToFrame("#fr1");
     * # switch to parent page
     * $I->switchToFrame();
     *
     * ```
     *
     * @param string|null $locator (name, CSS or XPath)
     */
    public function switchToFrame($locator = null)
    {
        $this->findAndSwitchToFrame($locator, 'frame');
    }

    /**
     * @param string|null $locator
     * @param string $tag
     */
    private function findAndSwitchToFrame($locator = null, $tag = 'frame')
    {
        if ($locator === null) {
            $this->webDriver->switchTo()->defaultContent();
            return;
        }
        $els = null;
        try {
            $els = $this->_findElements("{$tag}[name='$locator']");
        } catch (\Exception $e) {
            $this->debug('Failed to find locator by name: ' . $e->getMessage());
        }

        if (!isset($els) || !is_array($els) || !count($els)) {
            $this->debug(ucfirst($tag) . ' was not found by name, locating ' . $tag . ' by CSS or XPath');
            $els = $this->_findElements($locator);
        }

        if (!count($els)) {
            throw new ElementNotFound($locator, ucfirst($tag));
        }

        $this->webDriver->switchTo()->frame($els[0]);
    }

    /**
     * Executes JavaScript and waits up to $timeout seconds for it to return true.
     *
     * In this example we will wait up to 60 seconds for all jQuery AJAX requests to finish.
     *
     * ``` php
     * <?php
     * $I->waitForJS("return $.active == 0;", 60);
     * ?>
     * ```
     *
     * @param string $script
     * @param int $timeout seconds
     */
    public function waitForJS($script, $timeout = 5)
    {
        $condition = function ($wd) use ($script) {
            return $wd->executeScript($script);
        };
        $message = sprintf(
            'Waited for %d secs but script %s still doesn\'t evaluate to true',
            $timeout,
            Locator::humanReadableString($script)
        );
        $this->webDriver->wait($timeout)->until($condition, $message);
    }

    /**
     * Executes custom JavaScript.
     *
     * This example uses jQuery to get a value and assigns that value to a PHP variable:
     *
     * ```php
     * <?php
     * $myVar = $I->executeJS('return $("#myField").val()');
     *
     * // additional arguments can be passed as array
     * // Example shows `Hello World` alert:
     * $I->executeJS("window.alert(arguments[0])", ['Hello world']);
     * ```
     *
     * @param $script
     * @param array $arguments
     * @return mixed
     */
    public function executeJS($script, array $arguments = [])
    {
        return $this->webDriver->executeScript($script, $arguments);
    }

    /**
     * Executes asynchronous JavaScript.
     * A callback should be executed by JavaScript to exit from a script.
     * Callback is passed as a last element in `arguments` array.
     * Additional arguments can be passed as array in second parameter.
     *
     * ```js
     * // wait for 1200 milliseconds my running `setTimeout`
     * * $I->executeAsyncJS('setTimeout(arguments[0], 1200)');
     *
     * $seconds = 1200; // or seconds are passed as argument
     * $I->executeAsyncJS('setTimeout(arguments[1], arguments[0])', [$seconds]);
     * ```
     *
     * @param $script
     * @param array $arguments
     * @return mixed
     */
    public function executeAsyncJS($script, array $arguments = [])
    {
        return $this->webDriver->executeAsyncScript($script, $arguments);
    }

    /**
     * Maximizes the current window.
     */
    public function maximizeWindow()
    {
        $this->webDriver->manage()->window()->maximize();
    }

    /**
     * Performs a simple mouse drag-and-drop operation.
     *
     * ``` php
     * <?php
     * $I->dragAndDrop('#drag', '#drop');
     * ?>
     * ```
     *
     * @param string $source (CSS ID or XPath)
     * @param string $target (CSS ID or XPath)
     */
    public function dragAndDrop($source, $target)
    {
        $snodes = $this->matchFirstOrFail($this->getBaseElement(), $source);
        $tnodes = $this->matchFirstOrFail($this->getBaseElement(), $target);

        $action = new WebDriverActions($this->webDriver);
        $action->dragAndDrop($snodes, $tnodes)->perform();
    }

    /**
     * Move mouse over the first element matched by the given locator.
     * If the first parameter null then the page is used.
     * If the second and third parameters are given,
     * then the mouse is moved to an offset of the element's top-left corner.
     * Otherwise, the mouse is moved to the center of the element.
     *
     * ``` php
     * <?php
     * $I->moveMouseOver(['css' => '.checkout']);
     * $I->moveMouseOver(null, 20, 50);
     * $I->moveMouseOver(['css' => '.checkout'], 20, 50);
     * ?>
     * ```
     *
     * @param string $cssOrXPath css or xpath of the web element
     * @param int $offsetX
     * @param int $offsetY
     *
     * @throws \Codeception\Exception\ElementNotFound
     */
    public function moveMouseOver($cssOrXPath = null, $offsetX = null, $offsetY = null)
    {
        $where = null;
        if (null !== $cssOrXPath) {
            $el = $this->matchFirstOrFail($this->getBaseElement(), $cssOrXPath);
            $where = $el->getCoordinates();
        }

        $this->webDriver->getMouse()->mouseMove($where, $offsetX, $offsetY);
    }

    /**
     * Performs click with the left mouse button on an element.
     * If the first parameter `null` then the offset is relative to the actual mouse position.
     * If the second and third parameters are given,
     * then the mouse is moved to an offset of the element's top-left corner.
     * Otherwise, the mouse is moved to the center of the element.
     *
     * ``` php
     * <?php
     * $I->clickWithLeftButton(['css' => '.checkout']);
     * $I->clickWithLeftButton(null, 20, 50);
     * $I->clickWithLeftButton(['css' => '.checkout'], 20, 50);
     * ?>
     * ```
     *
     * @param string $cssOrXPath css or xpath of the web element (body by default).
     * @param int $offsetX
     * @param int $offsetY
     *
     * @throws \Codeception\Exception\ElementNotFound
     */
    public function clickWithLeftButton($cssOrXPath = null, $offsetX = null, $offsetY = null)
    {
        $this->moveMouseOver($cssOrXPath, $offsetX, $offsetY);
        $this->webDriver->getMouse()->click();
    }

    /**
     * Performs contextual click with the right mouse button on an element.
     * If the first parameter `null` then the offset is relative to the actual mouse position.
     * If the second and third parameters are given,
     * then the mouse is moved to an offset of the element's top-left corner.
     * Otherwise, the mouse is moved to the center of the element.
     *
     * ``` php
     * <?php
     * $I->clickWithRightButton(['css' => '.checkout']);
     * $I->clickWithRightButton(null, 20, 50);
     * $I->clickWithRightButton(['css' => '.checkout'], 20, 50);
     * ?>
     * ```
     *
     * @param string $cssOrXPath css or xpath of the web element (body by default).
     * @param int $offsetX
     * @param int $offsetY
     *
     * @throws \Codeception\Exception\ElementNotFound
     */
    public function clickWithRightButton($cssOrXPath = null, $offsetX = null, $offsetY = null)
    {
        $this->moveMouseOver($cssOrXPath, $offsetX, $offsetY);
        $this->webDriver->getMouse()->contextClick();
    }


    /**
     * Performs a double-click on an element matched by CSS or XPath.
     *
     * @param $cssOrXPath
     * @throws \Codeception\Exception\ElementNotFound
     */
    public function doubleClick($cssOrXPath)
    {
        $el = $this->matchFirstOrFail($this->getBaseElement(), $cssOrXPath);
        $this->webDriver->getMouse()->doubleClick($el->getCoordinates());
    }

    /**
     * @param $page
     * @param $selector
     * @param bool $throwMalformed
     * @return array
     */
    protected function match($page, $selector, $throwMalformed = true)
    {
        if (is_array($selector)) {
            try {
                return $page->findElements($this->getStrictLocator($selector));
            } catch (InvalidSelectorException $e) {
                throw new MalformedLocatorException(key($selector) . ' => ' . reset($selector), "Strict locator");
            } catch (InvalidElementStateException $e) {
                if ($this->isPhantom() and $e->getResults()['status'] == 12) {
                    throw new MalformedLocatorException(
                        key($selector) . ' => ' . reset($selector),
                        "Strict locator " . $e->getCode()
                    );
                }
            }
        }
        if ($selector instanceof WebDriverBy) {
            try {
                return $page->findElements($selector);
            } catch (InvalidSelectorException $e) {
                throw new MalformedLocatorException(
                    sprintf(
                        "WebDriverBy::%s('%s')",
                        $selector->getMechanism(),
                        $selector->getValue()
                    ),
                    'WebDriver'
                );
            }
        }
        $isValidLocator = false;
        $nodes = [];
        try {
            if (Locator::isID($selector)) {
                $isValidLocator = true;
                $nodes = $page->findElements(WebDriverBy::id(substr($selector, 1)));
            }
            if (Locator::isClass($selector)) {
                $isValidLocator = true;
                $nodes = $page->findElements(WebDriverBy::className(substr($selector, 1)));
            }
            if (empty($nodes) and Locator::isCSS($selector)) {
                $isValidLocator = true;
                try {
                    $nodes = $page->findElements(WebDriverBy::cssSelector($selector));
                } catch (InvalidElementStateException $e) {
                    $nodes = $page->findElements(WebDriverBy::linkText($selector));
                }
            }
            if (empty($nodes) and Locator::isXPath($selector)) {
                $isValidLocator = true;
                $nodes = $page->findElements(WebDriverBy::xpath($selector));
            }
        } catch (InvalidSelectorException $e) {
            throw new MalformedLocatorException($selector);
        }
        if (!$isValidLocator and $throwMalformed) {
            throw new MalformedLocatorException($selector);
        }
        return $nodes;
    }

    /**
     * @param array $by
     * @return WebDriverBy
     */
    protected function getStrictLocator(array $by)
    {
        $type = key($by);
        $locator = $by[$type];
        switch ($type) {
            case 'id':
                return WebDriverBy::id($locator);
            case 'name':
                return WebDriverBy::name($locator);
            case 'css':
                return WebDriverBy::cssSelector($locator);
            case 'xpath':
                return WebDriverBy::xpath($locator);
            case 'link':
                return WebDriverBy::linkText($locator);
            case 'class':
                return WebDriverBy::className($locator);
            default:
                throw new MalformedLocatorException(
                    "$by => $locator",
                    "Strict locator can be either xpath, css, id, link, class, name: "
                );
        }
    }

    /**
     * @param $page
     * @param $selector
     * @return WebDriverElement
     * @throws \Codeception\Exception\ElementNotFound
     */
    protected function matchFirstOrFail($page, $selector)
    {
        $this->enableImplicitWait();
        $els = $this->match($page, $selector);
        $this->disableImplicitWait();
        if (!count($els)) {
            throw new ElementNotFound($selector, "CSS or XPath");
        }
        return reset($els);
    }

    /**
     * Presses the given key on the given element.
     * To specify a character and modifier (e.g. <kbd>Ctrl</kbd>, Alt, Shift, Meta), pass an array for `$char` with
     * the modifier as the first element and the character as the second.
     * For special keys, use the constants from [`Facebook\WebDriver\WebDriverKeys`](https://github.com/php-webdriver/php-webdriver/blob/main/lib/WebDriverKeys.php).
     *
     * ``` php
     * <?php
     * // <input id="page" value="old" />
     * $I->pressKey('#page','a'); // => olda
     * $I->pressKey('#page',array('ctrl','a'),'new'); //=> new
     * $I->pressKey('#page',array('shift','111'),'1','x'); //=> old!!!1x
     * $I->pressKey('descendant-or-self::*[@id='page']','u'); //=> oldu
     * $I->pressKey('#name', array('ctrl', 'a'), \Facebook\WebDriver\WebDriverKeys::DELETE); //=>''
     * ?>
     * ```
     *
     * @param $element
     * @param $char string|array Can be char or array with modifier. You can provide several chars.
     * @throws \Codeception\Exception\ElementNotFound
     */
    public function pressKey($element, $char)
    {
        $el = $this->matchFirstOrFail($this->getBaseElement(), $element);
        $args = func_get_args();
        array_shift($args);
        $keys = [];
        foreach ($args as $key) {
            $keys[] = $this->convertKeyModifier($key);
        }
        $el->sendKeys($keys);
    }

    protected function convertKeyModifier($keys)
    {
        if (!is_array($keys)) {
            return $keys;
        }
        if (!isset($keys[1])) {
            return $keys;
        }
        list($modifier, $key) = $keys;

        switch ($modifier) {
            case 'ctrl':
            case 'control':
                return [WebDriverKeys::CONTROL, $key];
            case 'alt':
                return [WebDriverKeys::ALT, $key];
            case 'shift':
                return [WebDriverKeys::SHIFT, $key];
            case 'meta':
                return [WebDriverKeys::META, $key];
        }
        return $keys;
    }

    protected function assertNodesContain($text, $nodes, $selector = null)
    {
        $this->assertNodeConstraint($nodes, new WebDriverConstraint($text, $this->_getCurrentUri()), $selector);
    }

    protected function assertNodesNotContain($text, $nodes, $selector = null)
    {
        $this->assertNodeConstraint($nodes, new WebDriverConstraintNot($text, $this->_getCurrentUri()), $selector);
    }

    protected function assertNodeConstraint($nodes, WebDriverConstraint $constraint, $selector = null)
    {
        $message = $selector;
        if (is_array($selector)) {
            $type = key($selector);
            $locator = $selector[$type];
            $message = $type . ':' . $locator;
        }
        $this->assertThat($nodes, $constraint, $message);
    }

    protected function assertPageContains($needle, $message = '')
    {
        $this->assertThat(
            htmlspecialchars_decode($this->getVisibleText()),
            new PageConstraint($needle, $this->_getCurrentUri()),
            $message
        );
    }

    protected function assertPageNotContains($needle, $message = '')
    {
        $this->assertThatItsNot(
            htmlspecialchars_decode($this->getVisibleText()),
            new PageConstraint($needle, $this->_getCurrentUri()),
            $message
        );
    }

    protected function assertPageSourceContains($needle, $message = '')
    {
        $this->assertThat(
            $this->webDriver->getPageSource(),
            new PageConstraint($needle, $this->_getCurrentUri()),
            $message
        );
    }

    protected function assertPageSourceNotContains($needle, $message = '')
    {
        $this->assertThatItsNot(
            $this->webDriver->getPageSource(),
            new PageConstraint($needle, $this->_getCurrentUri()),
            $message
        );
    }

    /**
     * Append the given text to the given element.
     * Can also add a selection to a select box.
     *
     * ``` php
     * <?php
     * $I->appendField('#mySelectbox', 'SelectValue');
     * $I->appendField('#myTextField', 'appended');
     * ?>
     * ```
     *
     * @param string $field
     * @param string $value
     * @throws \Codeception\Exception\ElementNotFound
     */
    public function appendField($field, $value)
    {
        $el = $this->findField($field);

        switch ($el->getTagName()) {
            //Multiple select
            case "select":
                $matched = false;
                $wdSelect = new WebDriverSelect($el);
                try {
                    $wdSelect->selectByVisibleText($value);
                    $matched = true;
                } catch (NoSuchElementException $e) {
                    // exception treated at the end
                }

                try {
                    $wdSelect->selectByValue($value);
                    $matched = true;
                } catch (NoSuchElementException $e) {
                    // exception treated at the end
                }
                if ($matched) {
                    return;
                }

                throw new ElementNotFound(json_encode($value), "Option inside $field matched by name or value");
            case "textarea":
                $el->sendKeys($value);
                return;
            case "div": //allows for content editable divs
                $el->sendKeys(WebDriverKeys::END);
                $el->sendKeys($value);
                return;
            //Text, Checkbox, Radio
            case "input":
                $type = $el->getAttribute('type');

                if ($type == 'checkbox') {
                    //Find by value or css,id,xpath
                    $field = $this->findCheckable($this->getBaseElement(), $value, true);
                    if (!$field) {
                        throw new ElementNotFound($value, "Checkbox or Radio by Label or CSS or XPath");
                    }
                    if ($field->isSelected()) {
                        return;
                    }
                    $field->click();
                    return;
                } elseif ($type == 'radio') {
                    $this->selectOption($field, $value);
                    return;
                }

                $el->sendKeys($value);
                return;
        }

        throw new ElementNotFound($field, "Field by name, label, CSS or XPath");
    }

    /**
     * @param $selector
     * @return array
     */
    protected function matchVisible($selector)
    {
        $els = $this->match($this->getBaseElement(), $selector);
        $nodes = array_filter(
            $els,
            function (WebDriverElement $el) {
                return $el->isDisplayed();
            }
        );
        return $nodes;
    }

    /**
     * @param $selector
     * @return WebDriverBy
     * @throws \InvalidArgumentException
     */
    protected function getLocator($selector)
    {
        if ($selector instanceof WebDriverBy) {
            return $selector;
        }
        if (is_array($selector)) {
            return $this->getStrictLocator($selector);
        }
        if (Locator::isID($selector)) {
            return WebDriverBy::id(substr($selector, 1));
        }
        if (Locator::isCSS($selector)) {
            return WebDriverBy::cssSelector($selector);
        }
        if (Locator::isXPath($selector)) {
            return WebDriverBy::xpath($selector);
        }
        throw new \InvalidArgumentException("Only CSS or XPath allowed");
    }

    public function saveSessionSnapshot($name)
    {
        $this->sessionSnapshots[$name] = [];

        foreach ($this->webDriver->manage()->getCookies() as $cookie) {
            if (in_array(trim($cookie['name']), [LocalServer::COVERAGE_COOKIE, LocalServer::COVERAGE_COOKIE_ERROR])) {
                continue;
            }

            if ($this->cookieDomainMatchesConfigUrl($cookie)) {
                $this->sessionSnapshots[$name][] = $cookie;
            }
        }

        $this->debugSection('Snapshot', "Saved \"$name\" session snapshot");
    }

    public function loadSessionSnapshot($name)
    {
        if (!isset($this->sessionSnapshots[$name])) {
            return false;
        }

        foreach ($this->webDriver->manage()->getCookies() as $cookie) {
            if (in_array(trim($cookie['name']), [LocalServer::COVERAGE_COOKIE, LocalServer::COVERAGE_COOKIE_ERROR])) {
                continue;
            }
            $this->webDriver->manage()->deleteCookieNamed($cookie['name']);
        }

        foreach ($this->sessionSnapshots[$name] as $cookie) {
            $this->setCookie($cookie['name'], $cookie['value'], (array)$cookie, false);
        }
        $this->debugCookies();
        $this->debugSection('Snapshot', "Restored \"$name\" session snapshot");
        return true;
    }

    public function deleteSessionSnapshot($name)
    {
        if (isset($this->sessionSnapshots[$name])) {
            unset($this->sessionSnapshots[$name]);
        }
        $this->debugSection('Snapshot', "Deleted \"$name\" session snapshot");
    }

    /**
     * Check if the cookie domain matches the config URL.
     *
     * Taken from Guzzle\Cookie\SetCookie
     *
     * @param array|Cookie $cookie
     * @return bool
     */
    private function cookieDomainMatchesConfigUrl($cookie)
    {
        if (!isset($cookie['domain'])) {
            return true;
        }

        $domain = parse_url($this->config['url'], PHP_URL_HOST);

        // Remove the leading '.' as per spec in RFC 6265.
        // http://tools.ietf.org/html/rfc6265#section-5.2.3
        $cookieDomain = ltrim($cookie['domain'], '.');
        // Domain not set or exact match.
        if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) {
            return true;
        }
        // Matching the subdomain according to RFC 6265.
        // http://tools.ietf.org/html/rfc6265#section-5.1.3
        if (filter_var($domain, FILTER_VALIDATE_IP)) {
            return false;
        }
        return (bool) preg_match('/\.' . preg_quote($cookieDomain, '/') . '$/', $domain);
    }

    /**
     * @return bool
     */
    protected function isPhantom()
    {
        return strpos($this->config['browser'], 'phantom') === 0;
    }

    /**
     * Move to the middle of the given element matched by the given locator.
     * Extra shift, calculated from the top-left corner of the element,
     * can be set by passing $offsetX and $offsetY parameters.
     *
     * ``` php
     * <?php
     * $I->scrollTo(['css' => '.checkout'], 20, 50);
     * ?>
     * ```
     *
     * @param $selector
     * @param int $offsetX
     * @param int $offsetY
     */
    public function scrollTo($selector, $offsetX = null, $offsetY = null)
    {
        $el = $this->matchFirstOrFail($this->getBaseElement(), $selector);
        $x = $el->getLocation()->getX() + $offsetX;
        $y = $el->getLocation()->getY() + $offsetY;
        $this->webDriver->executeScript("window.scrollTo($x, $y)");
    }

    /**
     * Opens a new browser tab and switches to it.
     *
     * ```php
     * <?php
     * $I->openNewTab();
     * ```
     * The tab is opened with JavaScript's `window.open()`, which means:
     * * Some adblockers might restrict it.
     * * The sessionStorage is copied to the new tab (contrary to a tab that was manually opened by the user)
     */
    public function openNewTab()
    {
        $this->executeJS("window.open('about:blank','_blank');");
        $this->switchToNextTab();
    }

    /**
     * Checks current number of opened tabs
     *
     * ```php
     * <?php
     * $I->seeNumberOfTabs(2);
     * ```
     * @param $number number of tabs
     */
    public function seeNumberOfTabs($number)
    {
        $this->assertEquals(count($this->webDriver->getWindowHandles()), $number);
    }    

    /**
     * Closes current browser tab and switches to previous active tab.
     *
     * ```php
     * <?php
     * $I->closeTab();
     * ```
     */
    public function closeTab()
    {
        $prevTab = $this->getRelativeTabHandle(-1);
        $this->webDriver->close();
        $this->webDriver->switchTo()->window($prevTab);
    }

    /**
     * Switches to next browser tab.
     * An offset can be specified.
     *
     * ```php
     * <?php
     * // switch to next tab
     * $I->switchToNextTab();
     * // switch to 2nd next tab
     * $I->switchToNextTab(2);
     * ```
     * @param int $offset 1
     */
    public function switchToNextTab($offset = 1)
    {
        $tab = $this->getRelativeTabHandle($offset);
        $this->webDriver->switchTo()->window($tab);
    }

    /**
     * Switches to previous browser tab.
     * An offset can be specified.
     *
     * ```php
     * <?php
     * // switch to previous tab
     * $I->switchToPreviousTab();
     * // switch to 2nd previous tab
     * $I->switchToPreviousTab(2);
     * ```
     * @param int $offset 1
     */
    public function switchToPreviousTab($offset = 1)
    {
        $this->switchToNextTab(0 - $offset);
    }

    protected function getRelativeTabHandle($offset)
    {
        if ($this->isPhantom()) {
            throw new ModuleException($this, "PhantomJS doesn't support tab actions");
        }
        $handle = $this->webDriver->getWindowHandle();
        $handles = $this->webDriver->getWindowHandles();
        $idx = array_search($handle, $handles);
        return $handles[($idx + $offset) % count($handles)];
    }

    /**
     * Waits for element and runs a sequence of actions inside its context.
     * Actions can be defined with array, callback, or `Codeception\Util\ActionSequence` instance.
     *
     * Actions as array are recommended for simple to combine "waitForElement" with assertions;
     * `waitForElement($el)` and `see('text', $el)` can be simplified to:
     *
     * ```php
     * <?php
     * $I->performOn($el, ['see' => 'text']);
     * ```
     *
     * List of actions can be pragmatically build using `Codeception\Util\ActionSequence`:
     *
     * ```php
     * <?php
     * $I->performOn('.model', ActionSequence::build()
     *     ->see('Warning')
     *     ->see('Are you sure you want to delete this?')
     *     ->click('Yes')
     * );
     * ```
     *
     * Actions executed from array or ActionSequence will print debug output for actions, and adds an action name to
     * exception on failure.
     *
     * Whenever you need to define more actions a callback can be used. A WebDriver module is passed for argument:
     *
     * ```php
     * <?php
     * $I->performOn('.rememberMe', function (WebDriver $I) {
     *      $I->see('Remember me next time');
     *      $I->seeElement('#LoginForm_rememberMe');
     *      $I->dontSee('Login');
     * });
     * ```
     *
     * In 3rd argument you can set number a seconds to wait for element to appear
     *
     * @param $element
     * @param $actions
     * @param int $timeout
     */
    public function performOn($element, $actions, $timeout = 10)
    {
        $this->waitForElement($element, $timeout);
        $this->setBaseElement($element);
        $this->debugSection('InnerText', $this->getBaseElement()->getText());

        if (is_callable($actions)) {
            $actions($this);
            $this->setBaseElement();
            return;
        }
        if (is_array($actions)) {
            $actions = ActionSequence::build()->fromArray($actions);
        }

        if (!$actions instanceof ActionSequence) {
            throw new \InvalidArgumentException("2nd parameter, actions should be callback, ActionSequence or array");
        }

        $actions->run($this);
        $this->setBaseElement();
    }

    protected function setBaseElement($element = null)
    {
        if ($element === null) {
            $this->baseElement = $this->webDriver;
            return;
        }
        $this->baseElement = $this->matchFirstOrFail($this->webDriver, $element);
    }

    protected function enableImplicitWait()
    {
        if (!$this->config['wait']) {
            return;
        }
        $this->webDriver->manage()->timeouts()->implicitlyWait($this->config['wait']);
    }

    protected function disableImplicitWait()
    {
        if (!$this->config['wait']) {
            return;
        }
        $this->webDriver->manage()->timeouts()->implicitlyWait(0);
    }

    /**
     * From symfony/dom-crawler
     *
     * Converts string for XPath expressions.
     *
     * Escaped characters are: quotes (") and apostrophe (').
     *
     *  Examples:
     *
     *     echo static::xpathLiteral('foo " bar');
     *     //prints 'foo " bar'
     *
     *     echo static::xpathLiteral("foo ' bar");
     *     //prints "foo ' bar"
     *
     *     echo static::xpathLiteral('a\'b"c');
     *     //prints concat('a', "'", 'b"c')
     *
     * @return string Converted string
     */
    private static function xpathLiteral($s)
        {
            if (false === strpos($s, "'")) {
                return sprintf("'%s'", $s);
            }
            if (false === strpos($s, '"')) {
                return sprintf('"%s"', $s);
            }
            $string = $s;
            $parts = [];
            while (true) {
                if (false !== $pos = strpos($string, "'")) {
                    $parts[] = sprintf("'%s'", substr($string, 0, $pos));
                    $parts[] = "\"'\"";
                    $string = substr($string, $pos + 1);
                } else {
                    $parts[] = "'$string'";
                    break;
                }
            }
            return sprintf('concat(%s)', implode(', ', $parts));
        }

}
<?php
namespace Codeception\Exception;

class ConnectionException extends \RuntimeException
{
}
<?php

namespace Codeception\Util;

/**
 * JsonType matches JSON structures against templates.
 * You can specify the type of fields in JSON or add additional validation rules.
 *
 * JsonType is used by REST module in `seeResponseMatchesJsonType` and `dontSeeResponseMatchesJsonType` methods.
 *
 * Usage example:
 *
 * ```php
 * <?php
 * $jsonType = new JsonType(['name' => 'davert', 'id' => 1]);
 * $jsonType->matches([
 *   'name' => 'string:!empty',
 *   'id' => 'integer:>0|string:>0',
 * ]); // => true
 *
 * $jsonType->matches([
 *   'id' => 'string',
 * ]); // => `id: 1` is not of type string
 * ?>
 * ```
 *
 * Class JsonType
 * @package Codeception\Util
 */
class JsonType
{
    protected $jsonArray;

    protected static $customFilters = [];

    /**
     * Creates instance of JsonType
     * Pass an array or `\Codeception\Util\JsonArray` with data.
     * If non-associative array is passed - the very first element of it will be used for matching.
     *
     * @param $jsonArray array|\Codeception\Util\JsonArray
     */
    public function __construct($jsonArray)
    {
        if ($jsonArray instanceof JsonArray) {
            $jsonArray = $jsonArray->toArray();
        }
        $this->jsonArray = $jsonArray;
    }

    /**
     * Adds custom filter to JsonType list.
     * You should specify a name and parameters of a filter.
     *
     * Example:
     *
     * ```php
     * <?php
     * JsonType::addCustomFilter('slug', function($value) {
     *     return strpos(' ', $value) !== false;
     * });
     * // => use it as 'string:slug'
     *
     * // add custom function to matcher with `len($val)` syntax
     * // parameter matching patterns should be valid regex and start with `/` char
     * JsonType::addCustomFilter('/len\((.*?)\)/', function($value, $len) {
     *   return strlen($value) == $len;
     * });
     * // use it as 'string:len(5)'
     * ?>
     * ```
     *
     * @param          $name
     * @param callable $callable
     */
    public static function addCustomFilter($name, callable $callable)
    {
        static::$customFilters[$name] = $callable;
    }

    /**
     * Removes all custom filters
     */
    public static function cleanCustomFilters()
    {
        static::$customFilters = [];
    }

    /**
     * Checks data against passed JsonType.
     * If matching fails function returns a string with a message describing failure.
     * On success returns `true`.
     *
     * @param array $jsonType
     * @return bool|string
     */
    public function matches(array $jsonType)
    {
        if (array_key_exists(0, $this->jsonArray) && is_array($this->jsonArray[0])) {
            // a list of items
            $msg = '';
            foreach ($this->jsonArray as $array) {
                $res = $this->typeComparison($array, $jsonType);
                if ($res !== true) {
                    $msg .= "\n" . $res;
                }
            }
            if ($msg) {
                return $msg;
            }
            return true;
        }
        return $this->typeComparison($this->jsonArray, $jsonType);
    }

    protected function typeComparison($data, $jsonType)
    {
        foreach ($jsonType as $key => $type) {
            if (!array_key_exists($key, $data)) {
                return "Key `$key` doesn't exist in " . json_encode($data);
            }

            if (is_array($jsonType[$key])) {
                $message = $this->typeComparison($data[$key], $jsonType[$key]);

                if (is_string($message)) {
                    return $message;
                }

                continue;
            }

            $regexMatcher = '/:regex\((((\()|(\{)|(\[)|(<)|(.)).*?(?(3)\)|(?(4)\}|(?(5)\]|(?(6)>|\7)))))\)/';
            $regexes = [];

            // Match the string ':regex(' and any characters until a ending regex delimiter followed by character ')'
            // Place the 'any character' + delimiter matches in to an array.
            preg_match_all($regexMatcher, $type, $regexes);

            // Do the same match as above, but replace the the 'any character' + delimiter with a place holder ($${count}).
            $filterType = preg_replace_callback($regexMatcher, function () {
                static $count = 0;
                return ':regex($$' . $count++ . ')';
            }, $type);

            $matchTypes  = preg_split("#(?![^]\(]*\))\|#", $filterType);
            $matched     = false;
            $currentType = strtolower(gettype($data[$key]));

            if ($currentType === 'double') {
                $currentType = 'float';
            }

            foreach ($matchTypes as $matchType) {
                $filters      = preg_split("#(?![^]\(]*\))\:#", $matchType);
                $expectedType = strtolower(trim(array_shift($filters)));

                if ($expectedType !== $currentType) {
                    continue;
                }

                $matched = true;

                foreach ($filters as $filter) {
                    // Fill regex pattern back into the filter.
                    $filter = preg_replace_callback('/\$\$\d+/', function ($m) use ($regexes) {
                        $pos = (int)substr($m[0], 2);

                        return $regexes[1][$pos];
                    }, $filter);

                    $matched = $matched && $this->matchFilter($filter, $data[$key]);
                }

                if ($matched) {
                    break;
                }
            }

            if (!$matched) {
                return sprintf("`$key: %s` is of type `$type`", var_export($data[$key], true));
            }
        }
        return true;
    }

    protected function matchFilter($filter, $value)
    {
        $filter = trim($filter);
        if (strpos($filter, '!') === 0) {
            return !$this->matchFilter(substr($filter, 1), $value);
        }

        // apply custom filters
        foreach (static::$customFilters as $customFilter => $callable) {
            if (strpos($customFilter, '/') === 0) {
                if (preg_match($customFilter, $filter, $matches)) {
                    array_shift($matches);
                    return call_user_func_array($callable, array_merge([$value], $matches));
                }
            }
            if ($customFilter == $filter) {
                return $callable($value);
            }
        }

        if (strpos($filter, '=') === 0) {
            return $value == substr($filter, 1);
        }
        if ($filter === 'url') {
            return filter_var($value, FILTER_VALIDATE_URL);
        }
        if ($filter === 'date') {
            return preg_match(
                '/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(?:Z|(\+|-)([\d|:]*))?$/',
                $value
            );
        }
        if ($filter === 'email') { // from http://emailregex.com/
            // @codingStandardsIgnoreStart
            return preg_match('/^(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){255,})(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){65,}@)(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22))(?:\.(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-[a-z0-9]+)*\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-[a-z0-9]+)*)|(?:\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\]))$/iD',
                $value);
            // @codingStandardsIgnoreEnd
        }
        if ($filter === 'empty') {
            return empty($value);
        }
        if (preg_match('~^regex\((.*?)\)$~', $filter, $matches)) {
            return preg_match($matches[1], $value);
        }
        if (preg_match('~^>=(-?[\d\.]+)$~', $filter, $matches)) {
            return (float)$value >= (float)$matches[1];
        }
        if (preg_match('~^<=(-?[\d\.]+)$~', $filter, $matches)) {
            return (float)$value <= (float)$matches[1];
        }
        if (preg_match('~^>(-?[\d\.]+)$~', $filter, $matches)) {
            return (float)$value > (float)$matches[1];
        }
        if (preg_match('~^<(-?[\d\.]+)$~', $filter, $matches)) {
            return (float)$value < (float)$matches[1];
        }

        return false;
    }
}
<?php
namespace Codeception\Util;

use Flow\JSONPath\JSONPath;
use InvalidArgumentException;
use DOMDocument;

class JsonArray
{
    /**
     * @var array
     */
    protected $jsonArray = [];
    
    /**
     * @var DOMDocument
     */
    protected $jsonXml = null;

    public function __construct($jsonString)
    {
        if (!is_string($jsonString)) {
            throw new InvalidArgumentException('$jsonString param must be a string.');
        }

        $jsonDecode = json_decode($jsonString, true);

        if (!is_array($jsonDecode)) {
            $jsonDecode = [$jsonDecode];
        }

        $this->jsonArray = $jsonDecode;

        if (JSON_ERROR_NONE !== json_last_error()) {
            throw new InvalidArgumentException(
                sprintf(
                    "Invalid json: %s. System message: %s.",
                    $jsonString,
                    json_last_error_msg()
                ),
                json_last_error()
            );
        }
    }

    public function toXml()
    {
        if ($this->jsonXml) {
            return $this->jsonXml;
        }

        $root = 'root';
        $jsonArray = $this->jsonArray;
        if (count($jsonArray) == 1) {
            $value = reset($jsonArray);
            if (is_array($value)) {
                $root = key($jsonArray);
                $jsonArray = $value;
            }
        }

        $dom = new DOMDocument('1.0', 'UTF-8');
        $dom->formatOutput = false;
        $root = $dom->createElement($root);
        $dom->appendChild($root);
        $this->arrayToXml($dom, $root, $jsonArray);
        $this->jsonXml = $dom;
        return $dom;
    }

    /**
     * @return array
     */
    public function toArray()
    {
        return $this->jsonArray;
    }

    public function filterByXPath($xpath)
    {
        $path = new \DOMXPath($this->toXml());
        return $path->query($xpath);
    }

    public function filterByJsonPath($jsonPath)
    {
        if (!class_exists('Flow\JSONPath\JSONPath')) {
            throw new \Exception('JSONPath library not installed. Please add `softcreatr/jsonpath` to composer.json');
        }
        return (new JSONPath($this->jsonArray))->find($jsonPath)->getData();
    }

    public function getXmlString()
    {
        return $this->toXml()->saveXML();
    }

    public function containsArray(array $needle)
    {
        return (new ArrayContainsComparator($this->jsonArray))->containsArray($needle);
    }

    private function arrayToXml(\DOMDocument $doc, \DOMNode $node, $array)
    {
        foreach ($array as $key => $value) {
            if (is_numeric($key)) {
                $subNode = $doc->createElement($node->nodeName);
                $node->parentNode->appendChild($subNode);
            } else {
                try {
                    $subNode = $doc->createElement($key);
                } catch (\Exception $e) {
                    $key = $this->getValidTagNameForInvalidKey($key);
                    $subNode = $doc->createElement($key);
                }
                $node->appendChild($subNode);
            }
            if (is_array($value)) {
                $this->arrayToXml($doc, $subNode, $value);
            } else {
                $subNode->nodeValue = htmlspecialchars((string)$value);
            }
        }
    }

    private function getValidTagNameForInvalidKey($key)
    {
        static $map = [];
        if (!isset($map[$key])) {
            $tagName = 'invalidTag' . (count($map) + 1);
            $map[$key] = $tagName;
            codecept_debug($tagName . ' is "' . $key . '"');
        }
        return $map[$key];
    }
}
<?php

namespace Codeception\Step;

use Codeception\Lib\ModuleContainer;
use Codeception\Util\Template;

class AsJson extends Action implements GeneratedStep
{
    public function run(ModuleContainer $container = null)
    {
        $container->getModule('REST')->haveHttpHeader('Content-Type', 'application/json');
        $resp = parent::run($container);
        $container->getModule('REST')->seeResponseIsJson();
        return json_decode($resp, true);
    }

    public static function getTemplate(Template $template)
    {
        $action = $template->getVar('action');

        // should only be applied to send* methods
        if (strpos($action, 'send') !== 0) return;

        $conditionalDoc = "* JSON response will be automatically decoded \n     " . $template->getVar('doc');

        return $template
            ->place('doc', $conditionalDoc)
            ->place('action', $action . 'AsJson')
            ->place('step', 'AsJson');
    }
}<?php

namespace Codeception\Module;

use Codeception\Exception\ConfigurationException;
use Codeception\Exception\ModuleConfigException;
use Codeception\Exception\ModuleException;
use Codeception\Lib\Interfaces\ConflictsWithModule;
use Codeception\Module as CodeceptionModule;
use Codeception\PHPUnit\Constraint\JsonContains;
use Codeception\PHPUnit\Constraint\JsonType as JsonTypeConstraint;
use Codeception\TestInterface;
use Codeception\Lib\Interfaces\API;
use Codeception\Lib\Framework;
use Codeception\Lib\InnerBrowser;
use Codeception\Lib\Interfaces\DependsOnModule;
use Codeception\Lib\Interfaces\PartedModule;
use Codeception\Util\JsonArray;
use Codeception\Util\JsonType;
use Codeception\Util\XmlStructure;
use Codeception\Util\Soap as XmlUtils;
use JsonSchema\Validator as JsonSchemaValidator;
use JsonSchema\Constraints\Constraint as JsonContraint;

/**
 * Module for testing REST WebService.
 *
 * This module requires either [PhpBrowser](https://codeception.com/docs/modules/PhpBrowser)
 * or a framework module (e.g. [Symfony](https://codeception.com/docs/modules/Symfony), [Laravel](https://codeception.com/docs/modules/Laravel5))
 * to send the actual HTTP request.
 *
 * ## Configuration
 *
 * * `url` *optional* - the url of api
 * * `shortDebugResponse` *optional* - number of chars to limit the API response length
 *
 * ### Example
 *
 * ```yaml
 * modules:
 *    enabled:
 *        - REST:
 *            depends: PhpBrowser
 *            url: 'https://example.com/api/v1/'
 *            shortDebugResponse: 300 # only the first 300 characters of the response
 * ```
 *
 * In case you need to configure low-level HTTP headers, that's done on the PhpBrowser level like so:
 *
 * ```yaml
 * modules:
 *    enabled:
 *        - REST:
 *            depends: PhpBrowser
 *            url: &url 'https://example.com/api/v1/'
 *    config:
 *        PhpBrowser:
 *            url: *url
 *            headers:
 *                Content-Type: application/json
 * ```
 *
 * ## JSONPath
 *
 * [JSONPath](http://goessner.net/articles/JsonPath/) is the equivalent to XPath, for querying JSON data structures.
 * Here's an [Online JSONPath Expressions Tester](http://jsonpath.curiousconcept.com/)
 *
 * ## Public Properties
 *
 * * headers - array of headers going to be sent.
 * * params - array of sent data
 * * response - last response (string)
 *
 * ## Parts
 *
 * * Json - actions for validating Json responses (no Xml responses)
 * * Xml - actions for validating XML responses (no Json responses)
 *
 * ## Conflicts
 *
 * Conflicts with SOAP module
 *
 */
class REST extends CodeceptionModule implements DependsOnModule, PartedModule, API, ConflictsWithModule
{
    const QUERY_PARAMS_AWARE_METHODS = ['GET', 'HEAD', 'OPTIONS'];

    protected $config = [
        'url' => '',
        'aws' => ''
    ];

    protected $dependencyMessage = <<<EOF
Example configuring PhpBrowser as backend for REST module.
--
modules:
    enabled:
        - REST:
            depends: PhpBrowser
            url: http://localhost/api/
            shortDebugResponse: 300
--
Framework modules can be used for testing of API as well.
EOF;

    protected $DEFAULT_SHORTEN_VALUE = 150;

    /**
     * @var \Symfony\Component\HttpKernel\HttpKernelBrowser|\Symfony\Component\BrowserKit\AbstractBrowser
     */
    public $client = null;
    public $isFunctional = false;

    /**
     * @var InnerBrowser
     */
    protected $connectionModule;

    public $params = [];
    public $response = "";

    public function _before(TestInterface $test)
    {
        $this->client = &$this->connectionModule->client;
        $this->resetVariables();
    }

    protected function resetVariables()
    {
        $this->params = [];
        $this->response = "";
        $this->connectionModule->headers = [];
    }

    public function _conflicts()
    {
        return 'Codeception\Lib\Interfaces\API';
    }

    public function _depends()
    {
        return ['Codeception\Lib\InnerBrowser' => $this->dependencyMessage];
    }

    public function _parts()
    {
        return ['xml', 'json'];
    }

    public function _inject(InnerBrowser $connection)
    {
        $this->connectionModule = $connection;
        if ($this->connectionModule instanceof Framework) {
            $this->isFunctional = true;
        }
        if ($this->connectionModule instanceof PhpBrowser) {
            if (!$this->connectionModule->_getConfig('url')) {
                $this->connectionModule->_setConfig(['url' => $this->config['url']]);
            }
        }
    }

    public function _failed(TestInterface $test, $fail)
    {
        if (!$this->response) {
            return;
        }
        $printedResponse = $this->response;
        if ($this->isBinaryData($printedResponse)) {
            $printedResponse = $this->binaryToDebugString($printedResponse);
        }
        $test->getMetadata()->addReport('body', $printedResponse);
    }


    protected function getRunningClient()
    {
        if ($this->client->getInternalRequest() === null) {
            throw new ModuleException($this, "Response is empty. Use `\$I->sendXXX()` methods to send HTTP request");
        }
        return $this->client;
    }

    /**
     * Sets a HTTP header to be used for all subsequent requests. Use [`deleteHeader`](#deleteHeader) to unset it.
     *
     * ```php
     * <?php
     * $I->haveHttpHeader('Content-Type', 'application/json');
     * // all next requests will contain this header
     * ?>
     * ```
     *
     * @param $name
     * @param $value
     * @part json
     * @part xml
     */
    public function haveHttpHeader($name, $value)
    {
        $this->connectionModule->haveHttpHeader($name, $value);
    }

    /**
     * Deletes a HTTP header (that was originally added by [haveHttpHeader()](#haveHttpHeader)),
     * so that subsequent requests will not send it anymore.
     *
     * Example:
     * ```php
     * <?php
     * $I->haveHttpHeader('X-Requested-With', 'Codeception');
     * $I->sendGet('test-headers.php');
     * // ...
     * $I->deleteHeader('X-Requested-With');
     * $I->sendPost('some-other-page.php');
     * ?>
     * ```
     *
     * @param string $name the name of the header to delete.
     * @part json
     * @part xml
     */
    public function deleteHeader($name)
    {
        $this->connectionModule->deleteHeader($name);
    }

    /**
     * Checks over the given HTTP header and (optionally)
     * its value, asserting that are there
     *
     * @param $name
     * @param $value
     * @part json
     * @part xml
     */
    public function seeHttpHeader($name, $value = null)
    {
        if ($value !== null) {
            $this->assertEquals(
                $value,
                $this->getRunningClient()->getInternalResponse()->getHeader($name)
            );
            return;
        }
        $this->assertNotNull($this->getRunningClient()->getInternalResponse()->getHeader($name));
    }

    /**
     * Checks over the given HTTP header and (optionally)
     * its value, asserting that are not there
     *
     * @param $name
     * @param $value
     * @part json
     * @part xml
     */
    public function dontSeeHttpHeader($name, $value = null)
    {
        if ($value !== null) {
            $this->assertNotEquals(
                $value,
                $this->getRunningClient()->getInternalResponse()->getHeader($name)
            );
            return;
        }
        $this->assertNull($this->getRunningClient()->getInternalResponse()->getHeader($name));
    }

    /**
     * Checks that http response header is received only once.
     * HTTP RFC2616 allows multiple response headers with the same name.
     * You can check that you didn't accidentally sent the same header twice.
     *
     * ``` php
     * <?php
     * $I->seeHttpHeaderOnce('Cache-Control');
     * ?>>
     * ```
     *
     * @param $name
     * @part json
     * @part xml
     */
    public function seeHttpHeaderOnce($name)
    {
        $headers = $this->getRunningClient()->getInternalResponse()->getHeader($name, false);
        $this->assertCount(1, $headers);
    }

    /**
     * Returns the value of the specified header name
     *
     * @param $name
     * @param Boolean $first Whether to return the first value or all header values
     *
     * @return string|array The first header value if $first is true, an array of values otherwise
     * @part json
     * @part xml
     */
    public function grabHttpHeader($name, $first = true)
    {
        return $this->getRunningClient()->getInternalResponse()->getHeader($name, $first);
    }

    /**
     * Adds HTTP authentication via username/password.
     *
     * @param $username
     * @param $password
     * @part json
     * @part xml
     */
    public function amHttpAuthenticated($username, $password)
    {
        if ($this->isFunctional) {
            $this->client->setServerParameter('PHP_AUTH_USER', $username);
            $this->client->setServerParameter('PHP_AUTH_PW', $password);
        } else {
            $this->client->setAuth($username, $password);
        }
    }

    /**
     * Adds Digest authentication via username/password.
     *
     * @param $username
     * @param $password
     * @part json
     * @part xml
     */
    public function amDigestAuthenticated($username, $password)
    {
        if ($this->isFunctional) {
            throw new ModuleException(__METHOD__, 'Not supported by functional modules');
        }
        $this->client->setAuth($username, $password, 'digest');
    }

    /**
     * Adds Bearer authentication via access token.
     *
     * @param $accessToken
     * @part json
     * @part xml
     */
    public function amBearerAuthenticated($accessToken)
    {
        $this->haveHttpHeader('Authorization', 'Bearer ' . $accessToken);
    }

    /**
     * Adds NTLM authentication via username/password.
     * Requires client to be Guzzle >=6.3.0
     * Out of scope for functional modules.
     *
     * Example:
     * ```php
     * <?php
     * $I->amNTLMAuthenticated('jon_snow', 'targaryen');
     * ?>
     * ```
     *
     * @param $username
     * @param $password
     * @throws ModuleException
     * @part json
     * @part xml
     */
    public function amNTLMAuthenticated($username, $password)
    {
        if ($this->isFunctional) {
            throw new ModuleException(__METHOD__, 'Not supported by functional modules');
        }
        if (!defined('\GuzzleHttp\Client::MAJOR_VERSION') && !defined('\GuzzleHttp\Client::VERSION')) {
            throw new ModuleException(__METHOD__, 'Not supported if not using a Guzzle client');
        }
        $this->client->setAuth($username, $password, 'ntlm');
    }

    /**
     * Allows to send REST request using AWS Authorization
     *
     * Only works with PhpBrowser
     * Example Config:
     * ```yml
     * modules:
     *      enabled:
     *          - REST:
     *              aws:
     *                  key: accessKey
     *                  secret: accessSecret
     *                  service: awsService
     *                  region: awsRegion
     * ```
     * Code:
     * ```php
     * <?php
     * $I->amAWSAuthenticated();
     * ?>
     * ```
     * @param array $additionalAWSConfig
     * @throws ConfigurationException
     */
    public function amAWSAuthenticated($additionalAWSConfig = [])
    {
        if (method_exists($this->client, 'setAwsAuth')) {
            $config = array_merge($this->config['aws'], $additionalAWSConfig);

            if (!isset($config['key'])) {
                throw new ConfigurationException('AWS Key is not set');
            }
            if (!isset($config['secret'])) {
                throw new ConfigurationException('AWS Secret is not set');
            }
            if (!isset($config['service'])) {
                throw new ConfigurationException('AWS Service is not set');
            }
            if (!isset($config['region'])) {
                throw new ConfigurationException('AWS Region is not set');
            }

            $this->client->setAwsAuth($config);
        }
    }

    /**
     * Sends a POST request to given uri. Parameters and files can be provided separately.
     *
     * Example:
     * ```php
     * <?php
     * //simple POST call
     * $response = $I->sendPost('/message', ['subject' => 'Read this!', 'to' => 'johndoe@example.com']);
     * //simple upload method
     * $I->sendPost('/message/24', ['inline' => 0], ['attachmentFile' => codecept_data_dir('sample_file.pdf')]);
     * //uploading a file with a custom name and mime-type. This is also useful to simulate upload errors.
     * $I->sendPost('/message/24', ['inline' => 0], [
     *     'attachmentFile' => [
     *          'name' => 'document.pdf',
     *          'type' => 'application/pdf',
     *          'error' => UPLOAD_ERR_OK,
     *          'size' => filesize(codecept_data_dir('sample_file.pdf')),
     *          'tmp_name' => codecept_data_dir('sample_file.pdf')
     *     ]
     * ]);
     * // If your field names contain square brackets (e.g. `<input type="text" name="form[task]">`),
     * // PHP parses them into an array. In this case you need to pass the fields like this:
     * $I->sendPost('/add-task', ['form' => [
     *     'task' => 'lorem ipsum',
     *     'category' => 'miscellaneous',
     * ]]);
     * ```
     *
     * @param $url
     * @param array|string|\JsonSerializable $params
     * @param array $files A list of filenames or "mocks" of $_FILES (each entry being an array with the following
     *                     keys: name, type, error, size, tmp_name (pointing to the real file path). Each key works
     *                     as the "name" attribute of a file input field.
     *
     * @see http://php.net/manual/en/features.file-upload.post-method.php
     * @see codecept_data_dir()
     * @part json
     * @part xml
     */
    public function sendPost($url, $params = [], $files = [])
    {
        return $this->execute('POST', $url, $params, $files);
    }

    /**
     * Sends a HEAD request to given uri.
     *
     * @param $url
     * @param array $params
     * @part json
     * @part xml
     */
    public function sendHead($url, $params = [])
    {
        return $this->execute('HEAD', $url, $params);
    }

    /**
     * Sends an OPTIONS request to given uri.
     *
     * @param $url
     * @param array $params
     * @part json
     * @part xml
     */
    public function sendOptions($url, $params = [])
    {
        $this->execute('OPTIONS', $url, $params);
    }

    /**
     * Sends a GET request to given uri.
     *
     * ```php
     * <?php
     * $response = $I->sendGet('/users');
     *
     * // send get with query params
     * $I->sendGet('/orders', ['id' => 1])
     * ```
     *
     * @param $url
     * @param array $params
     * @part json
     * @part xml
     */
    public function sendGet($url, $params = [])
    {
        return $this->execute('GET', $url, $params);
    }

    /**
     * Sends PUT request to given uri.
     *
     * ```php
     * <?php
     * $response = $I->sendPut('/message/1', ['subject' => 'Read this!']);
     * ```
     *
     * @param $url
     * @param array|string|\JsonSerializable $params
     * @param array $files
     * @part json
     * @part xml
     */
    public function sendPut($url, $params = [], $files = [])
    {
        return $this->execute('PUT', $url, $params, $files);
    }

    /**
     * Sends PATCH request to given uri.
     *
     * ```php
     * <?php
     * $response = $I->sendPatch('/message/1', ['subject' => 'Read this!']);
     * ```
     *
     * @param       $url
     * @param array|string|\JsonSerializable $params
     * @param array $files
     * @part json
     * @part xml
     */
    public function sendPatch($url, $params = [], $files = [])
    {
        return $this->execute('PATCH', $url, $params, $files);
    }

    /**
     * Sends DELETE request to given uri.
     *
     * ```php
     * <?php
     * $I->sendDelete('/message/1');
     * ```

     *
     * @param $url
     * @param array $params
     * @param array $files
     * @part json
     * @part xml
     */
    public function sendDelete($url, $params = [], $files = [])
    {
        return $this->execute('DELETE', $url, $params, $files);
    }

    /**
     * Sends a HTTP request.
     *
     * @param $method
     * @param $url
     * @param array|string|\JsonSerializable $params
     * @param array $files
     * @part json
     * @part xml
     */
    public function send($method, $url, $params = [], $files = [])
    {
        return $this->execute(strtoupper($method), $url, $params, $files);
    }

    /**
     * Sets Headers "Link" as one header "Link" based on linkEntries
     *
     * @param array $linkEntries (entry is array with keys "uri" and "link-param")
     *
     * @link http://tools.ietf.org/html/rfc2068#section-19.6.2.4
     *
     * @author samva.ua@gmail.com
     */
    private function setHeaderLink(array $linkEntries)
    {
        $values = [];
        foreach ($linkEntries as $linkEntry) {
            \PHPUnit\Framework\Assert::assertArrayHasKey(
                'uri',
                $linkEntry,
                'linkEntry should contain property "uri"'
            );
            \PHPUnit\Framework\Assert::assertArrayHasKey(
                'link-param',
                $linkEntry,
                'linkEntry should contain property "link-param"'
            );
            $values[] = $linkEntry['uri'] . '; ' . $linkEntry['link-param'];
        }

        $this->haveHttpHeader('Link', implode(', ', $values));
    }

    /**
     * Sends LINK request to given uri.
     *
     * @param       $url
     * @param array $linkEntries (entry is array with keys "uri" and "link-param")
     *
     * @link http://tools.ietf.org/html/rfc2068#section-19.6.2.4
     *
     * @author samva.ua@gmail.com
     * @part json
     * @part xml
     */
    public function sendLink($url, array $linkEntries)
    {
        $this->setHeaderLink($linkEntries);
        $this->execute('LINK', $url);
    }

    /**
     * Sends UNLINK request to given uri.
     *
     * @param       $url
     * @param array $linkEntries (entry is array with keys "uri" and "link-param")
     * @link http://tools.ietf.org/html/rfc2068#section-19.6.2.4
     * @author samva.ua@gmail.com
     * @part json
     * @part xml
     */
    public function sendUnlink($url, array $linkEntries)
    {
        $this->setHeaderLink($linkEntries);
        $this->execute('UNLINK', $url);
    }

    protected function execute($method, $url, $parameters = [], $files = [])
    {
        // allow full url to be requested
        if (!$url) {
            $url = $this->config['url'];
        } elseif (!is_string($url)) {
            throw new ModuleException(__CLASS__, 'URL must be string');
        } elseif (strpos($url, '://') === false && $this->config['url']) {
            $url = rtrim($this->config['url'], '/') . '/' . ltrim($url, '/');
        }

        $this->params = $parameters;

        $isQueryParamsAwareMethod = in_array($method, self::QUERY_PARAMS_AWARE_METHODS, true);

        if ($isQueryParamsAwareMethod) {
            if (!is_array($parameters)) {
                throw new ModuleException(__CLASS__, $method . ' parameters must be passed in array format');
            }
        } else {
            $parameters = $this->encodeApplicationJson($method, $parameters);
        }

        if (is_array($parameters) || $isQueryParamsAwareMethod) {
            if ($isQueryParamsAwareMethod) {
                if (!empty($parameters)) {
                    if (strpos($url, '?') !== false) {
                        $url .= '&';
                    } else {
                        $url .= '?';
                    }
                    $url .= http_build_query($parameters);
                }
                $this->debugSection("Request", "$method $url");
                $files = [];
            } else {
                $this->debugSection("Request", "$method $url " . json_encode($parameters, JSON_PRESERVE_ZERO_FRACTION));
                $files = $this->formatFilesArray($files);
            }
            $this->response = (string)$this->connectionModule->_request($method, $url, $parameters, $files);
        } else {
            $requestData = $parameters;
            if ($this->isBinaryData($requestData)) {
                $requestData = $this->binaryToDebugString($requestData);
            }
            $this->debugSection("Request", "$method $url " . $requestData);
            $this->response = (string)$this->connectionModule->_request($method, $url, [], $files, [], $parameters);
        }
        $printedResponse = $this->response;
        if ($this->isBinaryData($printedResponse)) {
            $printedResponse = $this->binaryToDebugString($printedResponse);
        }

        $short = $this->_getConfig('shortDebugResponse');

        if (!is_null($short)) {
            $printedResponse = $this->shortenMessage($printedResponse, $short);
            $this->debugSection("Shortened Response", $printedResponse);
        } else {
            $this->debugSection("Response", $printedResponse);
        }

        return $this->response;
    }

    /**
     * Check if data has non-printable bytes and it is not a valid unicode string
     *
     * @param string $data the text or binary data string
     * @return boolean
     */
    protected function isBinaryData($data)
    {
        return !ctype_print($data) && false === mb_detect_encoding($data, mb_detect_order(), true);
    }

    /**
     * Format a binary string for debug printing
     *
     * @param string $data the binary data string
     * @return string the debug string
     */
    protected function binaryToDebugString($data)
    {
        return '[binary-data length:' . strlen($data) . ' md5:' . md5($data) . ']';
    }

    protected function encodeApplicationJson($method, $parameters)
    {
        if (
            array_key_exists('Content-Type', $this->connectionModule->headers)
            && ($this->connectionModule->headers['Content-Type'] === 'application/json'
                || preg_match('!^application/.+\+json$!', $this->connectionModule->headers['Content-Type'])
            )
        ) {
            if ($parameters instanceof \JsonSerializable) {
                return json_encode($parameters, JSON_PRESERVE_ZERO_FRACTION);
            }
            if (is_array($parameters) || $parameters instanceof \ArrayAccess) {
                $parameters = $this->scalarizeArray($parameters);
                return json_encode($parameters, JSON_PRESERVE_ZERO_FRACTION);
            }
        }

        if ($parameters instanceof \JsonSerializable) {
            throw new ModuleException(__CLASS__, $method . ' parameters is JsonSerializable object, but Content-Type header is not set to application/json');
        }

        if (!is_string($parameters) && !is_array($parameters)) {
            throw new ModuleException(__CLASS__, $method . ' parameters must be array, string or object implementing JsonSerializable interface');
        }

        return $parameters;
    }

    private function formatFilesArray(array $files)
    {
        foreach ($files as $name => $value) {
            if (is_string($value)) {
                $this->checkFileBeforeUpload($value);

                $files[$name] = [
                    'name' => basename($value),
                    'tmp_name' => $value,
                    'size' => filesize($value),
                    'type' => $this->getFileType($value),
                    'error' => 0,
                ];
                continue;
            } elseif (is_array($value)) {
                if (isset($value['tmp_name'])) {
                    $this->checkFileBeforeUpload($value['tmp_name']);
                    if (!isset($value['name'])) {
                        $value['name'] = basename($value['tmp_name']);
                    }
                    if (!isset($value['size'])) {
                        $value['size'] = filesize($value['tmp_name']);
                    }
                    if (!isset($value['type'])) {
                        $value['type'] = $this->getFileType($value['tmp_name']);
                    }
                    if (!isset($value['error'])) {
                        $value['error'] = 0;
                    }
                } else {
                    $files[$name] = $this->formatFilesArray($value);
                }
            } elseif (is_object($value)) {
                /**
                 * do nothing, probably the user knows what he is doing
                 * @issue https://github.com/Codeception/Codeception/issues/3298
                 */
            } else {
                throw new ModuleException(__CLASS__, "Invalid value of key $name in files array");
            }
        }

        return $files;
    }

    private function getFileType($file)
    {
        if (function_exists('mime_content_type') && mime_content_type($file)) {
            return mime_content_type($file);
        }
        return 'application/octet-stream';
    }

    private function checkFileBeforeUpload($file)
    {
        if (!file_exists($file)) {
            throw new ModuleException(__CLASS__, "File $file does not exist");
        }
        if (!is_readable($file)) {
            throw new ModuleException(__CLASS__, "File $file is not readable");
        }
        if (!is_file($file)) {
            throw new ModuleException(__CLASS__, "File $file is not a regular file");
        }
    }

    /**
     * Extends the function Module::validateConfig for shorten messages
     *
     */
    protected function validateConfig()
    {
        parent::validateConfig();

        $short = $this->_getConfig('shortDebugResponse');

        if (!is_null($short)) {
            if (!is_int($short) || $short < 0) {
                throw new ModuleConfigException(__CLASS__, 'The value of "shortDebugMessage" should be integer and greater or equal "0".');
            }
        }
    }

    /**
     * Checks whether last response was valid JSON.
     * This is done with json_last_error function.
     *
     * @part json
     */
    public function seeResponseIsJson()
    {
        $responseContent = $this->connectionModule->_getResponseContent();
        \PHPUnit\Framework\Assert::assertNotEquals('', $responseContent, 'response is empty');
        $this->decodeAndValidateJson($responseContent);
    }

    /**
     * Checks whether the last response contains text.
     *
     * @param $text
     * @part json
     * @part xml
     */
    public function seeResponseContains($text)
    {
        $this->assertStringContainsString($text, $this->connectionModule->_getResponseContent(), "REST response contains");
    }

    /**
     * Checks whether last response do not contain text.
     *
     * @param $text
     * @part json
     * @part xml
     */
    public function dontSeeResponseContains($text)
    {
        $this->assertStringNotContainsString($text, $this->connectionModule->_getResponseContent(), "REST response contains");
    }

    /**
     * Checks whether the last JSON response contains provided array.
     * The response is converted to array with json_decode($response, true)
     * Thus, JSON is represented by associative array.
     * This method matches that response array contains provided array.
     *
     * Examples:
     *
     * ``` php
     * <?php
     * // response: {name: john, email: john@gmail.com}
     * $I->seeResponseContainsJson(array('name' => 'john'));
     *
     * // response {user: john, profile: { email: john@gmail.com }}
     * $I->seeResponseContainsJson(array('email' => 'john@gmail.com'));
     *
     * ?>
     * ```
     *
     * This method recursively checks if one array can be found inside of another.
     *
     * @param array $json
     * @part json
     */
    public function seeResponseContainsJson($json = [])
    {
        \PHPUnit\Framework\Assert::assertThat(
            $this->connectionModule->_getResponseContent(),
            new JsonContains($json)
        );
    }

    /**
     * Checks whether last response matches the supplied json schema (https://json-schema.org/)
     * Supply schema as json string.
     *
     * Examples:
     *
     * ``` php
     * <?php
     * // response: {"name": "john", "age": 20}
     * $I->seeResponseIsValidOnJsonSchemaString('{"type": "object"}');
     *
     * // response {"name": "john", "age": 20}
     * $schema = [
     *  "properties" => [
     *      "age" => [
     *          "type" => "integer",
     *          "minimum" => 18
     *      ]
     *  ]
     * ];
     * $I->seeResponseIsValidOnJsonSchemaString(json_encode($schema));
     *
     * ?>
     * ```
     *
     * @param string $schema
     * @part json
     */
    public function seeResponseIsValidOnJsonSchemaString($schema)
    {
        $responseContent = $this->connectionModule->_getResponseContent();
        \PHPUnit\Framework\Assert::assertNotEquals('', $responseContent, 'response is empty');
        $responseObject = $this->decodeAndValidateJson($responseContent);

        \PHPUnit\Framework\Assert::assertNotEquals('', $schema, 'schema is empty');
        $schemaObject = $this->decodeAndValidateJson($schema, "Invalid schema json: %s. System message: %s.");

        $validator = new JsonSchemaValidator();
        $validator->validate($responseObject, $schemaObject, JsonContraint::CHECK_MODE_VALIDATE_SCHEMA);
        $outcome = $validator->isValid();
        $error = "";
        if (!$outcome) {
            $errors = $validator->getErrors();
            $error = array_shift($errors)["message"];
        }
        \PHPUnit\Framework\Assert::assertTrue(
            $outcome,
            $error
        );
    }

    /**
     * Checks whether last response matches the supplied json schema (https://json-schema.org/)
     * Supply schema as relative file path in your project directory or an absolute path
     *
     * @see codecept_absolute_path()
     *
     * @param string $schemaFilename
     * @part json
     */
    public function seeResponseIsValidOnJsonSchema($schemaFilename)
    {
        $file = codecept_absolute_path($schemaFilename);
        if (!file_exists($file)) {
            throw new ModuleException(__CLASS__, "File $file does not exist");
        }
        $this->seeResponseIsValidOnJsonSchemaString(file_get_contents($file));
    }

    /**
     * Converts string to json and asserts that no error occured while decoding.
     *
     * @param string $jsonString the json encoded string
     * @param string $errorFormat optional string for custom sprintf format
     */
    protected function decodeAndValidateJson($jsonString, $errorFormat="Invalid json: %s. System message: %s.")
    {
        $json = json_decode($jsonString);
        $errorCode = json_last_error();
        $errorMessage = json_last_error_msg();
        \PHPUnit\Framework\Assert::assertEquals(
            JSON_ERROR_NONE,
            $errorCode,
            sprintf(
                $errorFormat,
                $jsonString,
                $errorMessage
            )
        );
        return $json;
    }

    /**
     * Returns current response so that it can be used in next scenario steps.
     *
     * Example:
     *
     * ``` php
     * <?php
     * $user_id = $I->grabResponse();
     * $I->sendPut('/user', array('id' => $user_id, 'name' => 'davert'));
     * ?>
     * ```
     *
     * @return string
     * @part json
     * @part xml
     */
    public function grabResponse()
    {
        return $this->connectionModule->_getResponseContent();
    }

    /**
     * See [#jsonpath](#jsonpath) for general info on JSONPath.
     * Even for a single value an array is returned.
     * Example:
     *
     * ``` php
     * <?php
     * // match the first `user.id` in json
     * $firstUserId = $I->grabDataFromResponseByJsonPath('$..users[0].id');
     * $I->sendPut('/user', array('id' => $firstUserId[0], 'name' => 'davert'));
     * ?>
     * ```
     *
     * @param string $jsonPath
     * @return array Array of matching items
     * @throws \Exception
     * @part json
     */
    public function grabDataFromResponseByJsonPath($jsonPath)
    {
        return (new JsonArray($this->connectionModule->_getResponseContent()))->filterByJsonPath($jsonPath);
    }

    /**
     * Checks if json structure in response matches the xpath provided.
     * JSON is not supposed to be checked against XPath, yet it can be converted to xml and used with XPath.
     * This assertion allows you to check the structure of response json.
     *     *
     * ```json
     *   { "store": {
     *       "book": [
     *         { "category": "reference",
     *           "author": "Nigel Rees",
     *           "title": "Sayings of the Century",
     *           "price": 8.95
     *         },
     *         { "category": "fiction",
     *           "author": "Evelyn Waugh",
     *           "title": "Sword of Honour",
     *           "price": 12.99
     *         }
     *    ],
     *       "bicycle": {
     *         "color": "red",
     *         "price": 19.95
     *       }
     *     }
     *   }
     * ```
     *
     * ```php
     * <?php
     * // at least one book in store has author
     * $I->seeResponseJsonMatchesXpath('//store/book/author');
     * // first book in store has author
     * $I->seeResponseJsonMatchesXpath('//store/book[1]/author');
     * // at least one item in store has price
     * $I->seeResponseJsonMatchesXpath('/store//price');
     * ?>
     * ```
     * @param string $xpath
     * @part json
     */
    public function seeResponseJsonMatchesXpath($xpath)
    {
        $response = $this->connectionModule->_getResponseContent();
        $this->assertGreaterThan(
            0,
            (new JsonArray($response))->filterByXPath($xpath)->length,
            "Received JSON did not match the XPath `$xpath`.\nJson Response: \n" . $response
        );
    }

    /**
     * Opposite to seeResponseJsonMatchesXpath
     *
     * @param string $xpath
     * @part json
     */
    public function dontSeeResponseJsonMatchesXpath($xpath)
    {
        $response = $this->connectionModule->_getResponseContent();
        $this->assertEquals(
            0,
            (new JsonArray($response))->filterByXPath($xpath)->length,
            "Received JSON matched the XPath `$xpath`.\nJson Response: \n" . $response
        );
    }

    /**
     * See [#jsonpath](#jsonpath) for general info on JSONPath.
     * Checks if JSON structure in response matches JSONPath.
     *
     * ```json
     *   { "store": {
     *       "book": [
     *         { "category": "reference",
     *           "author": "Nigel Rees",
     *           "title": "Sayings of the Century",
     *           "price": 8.95
     *         },
     *         { "category": "fiction",
     *           "author": "Evelyn Waugh",
     *           "title": "Sword of Honour",
     *           "price": 12.99
     *         }
     *    ],
     *       "bicycle": {
     *         "color": "red",
     *         "price": 19.95
     *       }
     *     }
     *   }
     * ```
     *
     * ```php
     * <?php
     * // at least one book in store has author
     * $I->seeResponseJsonMatchesJsonPath('$.store.book[*].author');
     * // first book in store has author
     * $I->seeResponseJsonMatchesJsonPath('$.store.book[0].author');
     * // at least one item in store has price
     * $I->seeResponseJsonMatchesJsonPath('$.store..price');
     * ?>
     * ```
     *
     * @param string $jsonPath
     * @part json
     */
    public function seeResponseJsonMatchesJsonPath($jsonPath)
    {
        $response = $this->connectionModule->_getResponseContent();
        $this->assertNotEmpty(
            (new JsonArray($response))->filterByJsonPath($jsonPath),
            "Received JSON did not match the JsonPath `$jsonPath`.\nJson Response: \n" . $response
        );
    }

    /**
     * See [#jsonpath](#jsonpath) for general info on JSONPath.
     * Opposite to [`seeResponseJsonMatchesJsonPath()`](#seeResponseJsonMatchesJsonPath)
     *
     * @param string $jsonPath
     * @part json
     */
    public function dontSeeResponseJsonMatchesJsonPath($jsonPath)
    {
        $response = $this->connectionModule->_getResponseContent();
        $this->assertEmpty(
            (new JsonArray($response))->filterByJsonPath($jsonPath),
            "Received JSON matched the JsonPath `$jsonPath`.\nJson Response: \n" . $response
        );
    }

    /**
     * Opposite to seeResponseContainsJson
     *
     * @part json
     * @param array $json
     */
    public function dontSeeResponseContainsJson($json = [])
    {
        $jsonResponseArray = new JsonArray($this->connectionModule->_getResponseContent());
        $this->assertFalse(
            $jsonResponseArray->containsArray($json),
            "Response JSON contains provided JSON\n"
            . "- <info>" . var_export($json, true) . "</info>\n"
            . "+ " . var_export($jsonResponseArray->toArray(), true)
        );
    }

    /**
     * Checks that JSON matches provided types.
     * In case you don't know the actual values of JSON data returned you can match them by type.
     * It starts the check with a root element. If JSON data is an array it will check all elements of it.
     * You can specify the path in the json which should be checked with JsonPath
     *
     * Basic example:
     *
     * ```php
     * <?php
     * // {'user_id': 1, 'name': 'davert', 'is_active': false}
     * $I->seeResponseMatchesJsonType([
     *      'user_id' => 'integer',
     *      'name' => 'string|null',
     *      'is_active' => 'boolean'
     * ]);
     *
     * // narrow down matching with JsonPath:
     * // {"users": [{ "name": "davert"}, {"id": 1}]}
     * $I->seeResponseMatchesJsonType(['name' => 'string'], '$.users[0]');
     * ?>
     * ```
     *
     * You can check if the record contains fields with the data types you expect.
     * The list of possible data types:
     *
     * * string
     * * integer
     * * float
     * * array (json object is array as well)
     * * boolean
     * * null
     *
     * You can also use nested data type structures, and define multiple types for the same field:
     *
     * ```php
     * <?php
     * // {'user_id': 1, 'name': 'davert', 'company': {'name': 'Codegyre'}}
     * $I->seeResponseMatchesJsonType([
     *      'user_id' => 'integer|string', // multiple types
     *      'company' => ['name' => 'string']
     * ]);
     * ?>
     * ```
     *
     * You can also apply filters to check values. Filter can be applied with a `:` char after the type declaration,
     * or after another filter if you need more than one.
     *
     * Here is the list of possible filters:
     *
     * * `integer:>{val}` - checks that integer is greater than {val} (works with float and string types too).
     * * `integer:<{val}` - checks that integer is lower than {val} (works with float and string types too).
     * * `string:url` - checks that value is valid url.
     * * `string:date` - checks that value is date in JavaScript format: https://weblog.west-wind.com/posts/2014/Jan/06/JavaScript-JSON-Date-Parsing-and-real-Dates
     * * `string:email` - checks that value is a valid email according to http://emailregex.com/
     * * `string:regex({val})` - checks that string matches a regex provided with {val}
     *
     * This is how filters can be used:
     *
     * ```php
     * <?php
     * // {'user_id': 1, 'email' => 'davert@codeception.com'}
     * $I->seeResponseMatchesJsonType([
     *      'user_id' => 'string:>0:<1000', // multiple filters can be used
     *      'email' => 'string:regex(~\@~)' // we just check that @ char is included
     * ]);
     *
     * // {'user_id': '1'}
     * $I->seeResponseMatchesJsonType([
     *      'user_id' => 'string:>0', // works with strings as well
     * ]);
     * ?>
     * ```
     *
     * You can also add custom filters by using `{@link JsonType::addCustomFilter()}`.
     * See [JsonType reference](http://codeception.com/docs/reference/JsonType).
     *
     * @part json
     * @param array $jsonType
     * @param string $jsonPath
     * @see JsonType
     */
    public function seeResponseMatchesJsonType(array $jsonType, $jsonPath = null)
    {
        $jsonArray = new JsonArray($this->connectionModule->_getResponseContent());
        if ($jsonPath) {
            $jsonArray = $jsonArray->filterByJsonPath($jsonPath);
        }

        \PHPUnit\Framework\Assert::assertThat($jsonArray, new JsonTypeConstraint($jsonType));
    }

    /**
     * Opposite to `seeResponseMatchesJsonType`.
     *
     * @part json
     * @param array $jsonType JsonType structure
     * @param string $jsonPath
     * @see seeResponseMatchesJsonType
     */
    public function dontSeeResponseMatchesJsonType(array $jsonType, $jsonPath = null)
    {
        $jsonArray = new JsonArray($this->connectionModule->_getResponseContent());
        if ($jsonPath) {
            $jsonArray = $jsonArray->filterByJsonPath($jsonPath);
        }

        \PHPUnit\Framework\Assert::assertThat($jsonArray, new JsonTypeConstraint($jsonType, false));
    }

    /**
     * Checks if response is exactly the same as provided.
     *
     * @part json
     * @part xml
     * @param $response
     */
    public function seeResponseEquals($expected)
    {
        $this->assertEquals($expected, $this->connectionModule->_getResponseContent());
    }

    /**
     * Checks response code equals to provided value.
     *
     * ```php
     * <?php
     * $I->seeResponseCodeIs(200);
     *
     * // preferred to use \Codeception\Util\HttpCode
     * $I->seeResponseCodeIs(\Codeception\Util\HttpCode::OK);
     * ```
     *
     * @part json
     * @part xml
     * @param $code
     */
    public function seeResponseCodeIs($code)
    {
        $this->connectionModule->seeResponseCodeIs($code);
    }

    /**
     * Checks that response code is not equal to provided value.
     *
     * ```php
     * <?php
     * $I->dontSeeResponseCodeIs(200);
     *
     * // preferred to use \Codeception\Util\HttpCode
     * $I->dontSeeResponseCodeIs(\Codeception\Util\HttpCode::OK);
     * ```
     *
     * @part json
     * @part xml
     * @param $code
     */
    public function dontSeeResponseCodeIs($code)
    {
        $this->connectionModule->dontSeeResponseCodeIs($code);
    }

    /**
     * Checks that the response code is 2xx
     *
     * @part json
     * @part xml
     */
    public function seeResponseCodeIsSuccessful()
    {
        $this->connectionModule->seeResponseCodeIsSuccessful();
    }

    /**
     * Checks that the response code 3xx
     *
     * @part json
     * @part xml
     */
    public function seeResponseCodeIsRedirection()
    {
        $this->connectionModule->seeResponseCodeIsRedirection();
    }

    /**
     * Checks that the response code is 4xx
     *
     * @part json
     * @part xml
     */
    public function seeResponseCodeIsClientError()
    {
        $this->connectionModule->seeResponseCodeIsClientError();
    }

    /**
     * Checks that the response code is 5xx
     *
     * @part json
     * @part xml
     */
    public function seeResponseCodeIsServerError()
    {
        $this->connectionModule->seeResponseCodeIsServerError();
    }


    /**
     * Checks whether last response was valid XML.
     * This is done with libxml_get_last_error function.
     *
     * @part xml
     */
    public function seeResponseIsXml()
    {
        libxml_use_internal_errors(true);
        $doc = simplexml_load_string($this->connectionModule->_getResponseContent());
        $num = "";
        $title = "";
        if ($doc === false) {
            $error = libxml_get_last_error();
            $num = $error->code;
            $title = trim($error->message);
            libxml_clear_errors();
        }
        libxml_use_internal_errors(false);
        \PHPUnit\Framework\Assert::assertNotSame(
            false,
            $doc,
            "xml decoding error #$num with message \"$title\", see http://www.xmlsoft.org/html/libxml-xmlerror.html"
        );
    }

    /**
     * Checks whether XML response matches XPath
     *
     * ```php
     * <?php
     * $I->seeXmlResponseMatchesXpath('//root/user[@id=1]');
     * ```
     * @part xml
     * @param $xpath
     */
    public function seeXmlResponseMatchesXpath($xpath)
    {
        $structure = new XmlStructure($this->connectionModule->_getResponseContent());
        $this->assertTrue($structure->matchesXpath($xpath), 'xpath not matched');
    }

    /**
     * Checks whether XML response does not match XPath
     *
     * ```php
     * <?php
     * $I->dontSeeXmlResponseMatchesXpath('//root/user[@id=1]');
     * ```
     * @part xml
     * @param $xpath
     */
    public function dontSeeXmlResponseMatchesXpath($xpath)
    {
        $structure = new XmlStructure($this->connectionModule->_getResponseContent());
        $this->assertFalse($structure->matchesXpath($xpath), 'accidentally matched xpath');
    }

    /**
     * Finds and returns text contents of element.
     * Element is matched by either CSS or XPath
     *
     * @param $cssOrXPath
     * @return string
     * @part xml
     */
    public function grabTextContentFromXmlElement($cssOrXPath)
    {
        $el = (new XmlStructure($this->connectionModule->_getResponseContent()))->matchElement($cssOrXPath);
        return $el->textContent;
    }

    /**
     * Finds and returns attribute of element.
     * Element is matched by either CSS or XPath
     *
     * @param $cssOrXPath
     * @param $attribute
     * @return string
     * @part xml
     */
    public function grabAttributeFromXmlElement($cssOrXPath, $attribute)
    {
        $el = (new XmlStructure($this->connectionModule->_getResponseContent()))->matchElement($cssOrXPath);
        if (!$el->hasAttribute($attribute)) {
            $this->fail("Attribute not found in element matched by '$cssOrXPath'");
        }
        return $el->getAttribute($attribute);
    }

    /**
     * Checks XML response equals provided XML.
     * Comparison is done by canonicalizing both xml`s.
     *
     * Parameters can be passed either as DOMDocument, DOMNode, XML string, or array (if no attributes).
     *
     * @param $xml
     * @part xml
     */
    public function seeXmlResponseEquals($xml)
    {
        \PHPUnit\Framework\Assert::assertXmlStringEqualsXmlString($this->connectionModule->_getResponseContent(), $xml);
    }


    /**
     * Checks XML response does not equal to provided XML.
     * Comparison is done by canonicalizing both xml`s.
     *
     * Parameter can be passed either as XmlBuilder, DOMDocument, DOMNode, XML string, or array (if no attributes).
     *
     * @param $xml
     * @part xml
     */
    public function dontSeeXmlResponseEquals($xml)
    {
        \PHPUnit\Framework\Assert::assertXmlStringNotEqualsXmlString(
            $this->connectionModule->_getResponseContent(),
            $xml
        );
    }

    /**
     * Checks XML response includes provided XML.
     * Comparison is done by canonicalizing both xml`s.
     * Parameter can be passed either as XmlBuilder, DOMDocument, DOMNode, XML string, or array (if no attributes).
     *
     * Example:
     *
     * ``` php
     * <?php
     * $I->seeXmlResponseIncludes("<result>1</result>");
     * ?>
     * ```
     *
     * @param $xml
     * @part xml
     */
    public function seeXmlResponseIncludes($xml)
    {
        $this->assertStringContainsString(
            XmlUtils::toXml($xml)->C14N(),
            XmlUtils::toXml($this->connectionModule->_getResponseContent())->C14N(),
            "found in XML Response"
        );
    }

    /**
     * Checks XML response does not include provided XML.
     * Comparison is done by canonicalizing both xml`s.
     * Parameter can be passed either as XmlBuilder, DOMDocument, DOMNode, XML string, or array (if no attributes).
     *
     * @param $xml
     * @part xml
     */
    public function dontSeeXmlResponseIncludes($xml)
    {
        $this->assertStringNotContainsString(
            XmlUtils::toXml($xml)->C14N(),
            XmlUtils::toXml($this->connectionModule->_getResponseContent())->C14N(),
            "found in XML Response"
        );
    }

    /**
     * Checks if the hash of a binary response is exactly the same as provided.
     * Parameter can be passed as any hash string supported by hash(), with an
     * optional second parameter to specify the hash type, which defaults to md5.
     *
     * Example: Using md5 hash key
     *
     * ```php
     * <?php
     * $I->seeBinaryResponseEquals("8c90748342f19b195b9c6b4eff742ded");
     * ?>
     * ```
     *
     * Example: Using md5 for a file contents
     *
     * ```php
     * <?php
     * $fileData = file_get_contents("test_file.jpg");
     * $I->seeBinaryResponseEquals(md5($fileData));
     * ?>
     * ```
     * Example: Using sha256 hash
     *
     * ```php
     * <?php
     * $fileData = '/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k='; // very small jpeg
     * $I->seeBinaryResponseEquals(hash("sha256", base64_decode($fileData)), 'sha256');
     * ?>
     * ```
     *
     * @param string $hash the hashed data response expected
     * @param string $algo the hash algorithm to use. Default md5.
     * @part json
     * @part xml
     */
    public function seeBinaryResponseEquals($hash, $algo = 'md5')
    {
        $responseHash = hash($algo, $this->connectionModule->_getResponseContent());
        $this->assertEquals($hash, $responseHash);
    }

    /**
     * Checks if the hash of a binary response is not the same as provided.
     *
     * ```php
     * <?php
     * $I->dontSeeBinaryResponseEquals("8c90748342f19b195b9c6b4eff742ded");
     * ?>
     * ```
     * Opposite to `seeBinaryResponseEquals`
     *
     * @param string $hash the hashed data response expected
     * @param string $algo the hash algorithm to use. Default md5.
     * @part json
     * @part xml
     */
    public function dontSeeBinaryResponseEquals($hash, $algo = 'md5')
    {
        $responseHash = hash($algo, $this->connectionModule->_getResponseContent());
        $this->assertNotEquals($hash, $responseHash);
    }

    /**
     * Prevents automatic redirects to be followed by the client
     *
     * ```php
     * <?php
     * $I->stopFollowingRedirects();
     * ```
     *
     * @part xml
     * @part json
     */
    public function stopFollowingRedirects()
    {
        $this->client->followRedirects(false);
    }

    /**
     * Enables automatic redirects to be followed by the client
     *
     * ```php
     * <?php
     * $I->startFollowingRedirects();
     * ```
     *
     * @part xml
     * @part json
     */
    public function startFollowingRedirects()
    {
        $this->client->followRedirects(true);
    }

    /**
     * Sets SERVER parameters valid for all next requests.
     * this will remove old ones.
     *
     * ```php
     * $I->setServerParameters([]);
     * ```
     */
    public function setServerParameters(array $params)
    {
        $this->client->setServerParameters($params);
    }

    /**
     * Sets SERVER parameter valid for all next requests.
     *
     * ```php
     * $I->haveServerParameter('name', 'value');
     * ```
     */
    public function haveServerParameter($name, $value)
    {
        $this->client->setServerParameter($name, $value);
    }
}
<?php
namespace Codeception\Lib\Interfaces;

interface Queue
{

    /**
     * Connect to the queueing server.
     * @param array $config
     * @return
     */
    public function openConnection($config);

    /**
     * Post/Put a message on to the queue server
     *
     * @param string $message Message Body to be send
     * @param string $queue Queue Name
     */
    public function addMessageToQueue($message, $queue);

    /**
     * Return a list of queues/tubes on the queueing server
     *
     * @return array Array of Queues
     */
    public function getQueues();

    /**
     * Count the current number of messages on the queue.
     *
     * @param $queue Queue Name
     *
     * @return int Count
     */
    public function getMessagesCurrentCountOnQueue($queue);

    /**
     * Count the total number of messages on the queue.
     *
     * @param $queue Queue Name
     *
     * @return int Count
     */
    public function getMessagesTotalCountOnQueue($queue);

    public function clearQueue($queue);

    public function getRequiredConfig();

    public function getDefaultConfig();
}
<?php
namespace Codeception\Lib\Driver;

use Codeception\Lib\Interfaces\Queue;

class Iron implements Queue
{
    /**
     * @var \IronMQ
     */
    protected $queue;

    /**
     * Connect to the queueing server. (AWS, Iron.io and Beanstalkd)
     * @param array $config
     * @return
     */
    public function openConnection($config)
    {
        $this->queue = new \IronMQ([
            "token"      => $config['token'],
            "project_id" => $config['project'],
            "host"       => $config['host']
        ]);
        if (!$this->queue) {
            \PHPUnit\Framework\Assert::fail('connection failed or timed-out.');
        }
    }

    /**
     * Post/Put a message on to the queue server
     *
     * @param string $message Message Body to be send
     * @param string $queue Queue Name
     */
    public function addMessageToQueue($message, $queue)
    {
        $this->queue->postMessage($queue, $message);
    }

    /**
     * Return a list of queues/tubes on the queueing server
     *
     * @return array Array of Queues
     */
    public function getQueues()
    {
        // Format the output to suit
        $queues = [];
        foreach ($this->queue->getQueues() as $queue) {
            $queues[] = $queue->name;
        }
        return $queues;
    }

    /**
     * Count the current number of messages on the queue.
     *
     * @param $queue Queue Name
     *
     * @return int Count
     */
    public function getMessagesCurrentCountOnQueue($queue)
    {
        try {
            return $this->queue->getQueue($queue)->size;
        } catch (\Http_Exception $ex) {
            \PHPUnit\Framework\Assert::fail("queue [$queue] not found");
        }
    }

    /**
     * Count the total number of messages on the queue.
     *
     * @param $queue Queue Name
     *
     * @return int Count
     */
    public function getMessagesTotalCountOnQueue($queue)
    {
        try {
            return $this->queue->getQueue($queue)->total_messages;
        } catch (\Http_Exception $e) {
            \PHPUnit\Framework\Assert::fail("queue [$queue] not found");
        }
    }

    public function clearQueue($queue)
    {
        try {
            $this->queue->clearQueue($queue);
        } catch (\Http_Exception $ex) {
            \PHPUnit\Framework\Assert::fail("queue [$queue] not found");
        }
    }

    public function getRequiredConfig()
    {
        return ['host', 'token', 'project'];
    }

    public function getDefaultConfig()
    {
        return [];
    }
}
<?php
namespace Codeception\Lib\Driver;

use Codeception\Exception\TestRuntimeException;
use Codeception\Lib\Interfaces\Queue;
use Aws\Sqs\SqsClient;
use Aws\Credentials\Credentials;

class  AmazonSQS implements Queue
{
    protected $queue;

    /**
     * Connect to the queueing server. (AWS, Iron.io and Beanstalkd)
     * @param array $config
     * @return
     */
    public function openConnection($config)
    {
        $params = [
            'region' => $config['region'],
        ];

        if (! empty($config['key']) && ! empty($config['secret'])) {
            $params['credentials'] = new Credentials($config['key'], $config['secret']);
        }

        if (! empty($config['profile'])) {
            $params['profile'] = $config['profile'];
        }

        if (! empty($config['version'])) {
            $params['version'] = $config['version'];
        }

        if (! empty($config['endpoint'])) {
            $params['endpoint'] = $config['endpoint'];
        }

        $this->queue = new SqsClient($params);
        if (!$this->queue) {
            throw new TestRuntimeException('connection failed or timed-out.');
        }
    }

    /**
     * Post/Put a message on to the queue server
     *
     * @param string $message Message Body to be send
     * @param string $queue Queue Name
     */
    public function addMessageToQueue($message, $queue)
    {
        $this->queue->sendMessage([
            'QueueUrl' => $this->getQueueURL($queue),
            'MessageBody' => $message,
        ]);
    }

    /**
     * Return a list of queues/tubes on the queueing server
     *
     * @return array Array of Queues
     */
    public function getQueues()
    {
        $queueNames = [];
        $queues = $this->queue->listQueues(['QueueNamePrefix' => ''])->get('QueueUrls');
        foreach ($queues as $queue) {
            $tokens = explode('/', $queue);
            $queueNames[] = $tokens[sizeof($tokens) - 1];
        }
        return $queueNames;
    }

    /**
     * Count the current number of messages on the queue.
     *
     * @param $queue Queue Name
     *
     * @return int Count
     */
    public function getMessagesCurrentCountOnQueue($queue)
    {
        return $this->queue->getQueueAttributes([
            'QueueUrl' => $this->getQueueURL($queue),
            'AttributeNames' => ['ApproximateNumberOfMessages'],
        ])->get('Attributes')['ApproximateNumberOfMessages'];
    }

    /**
     * Count the total number of messages on the queue.
     *
     * @param $queue Queue Name
     *
     * @return int Count
     */
    public function getMessagesTotalCountOnQueue($queue)
    {
        return $this->queue->getQueueAttributes([
            'QueueUrl' => $this->getQueueURL($queue),
            'AttributeNames' => ['ApproximateNumberOfMessages'],
        ])->get('Attributes')['ApproximateNumberOfMessages'];
    }

    public function clearQueue($queue)
    {
        $queueURL = $this->getQueueURL($queue);
        while (true) {
            $res = $this->queue->receiveMessage(['QueueUrl' => $queueURL]);

            if (!$res->getPath('Messages')) {
                return;
            }
            foreach ($res->getPath('Messages') as $msg) {
                $this->queue->deleteMessage([
                    'QueueUrl' => $queueURL,
                    'ReceiptHandle' => $msg['ReceiptHandle']
                ]);
            }
        }
    }

    /**
     * Get the queue/tube URL from the queue name (AWS function only)
     *
     * @param $queue Queue Name
     *
     * @return string Queue URL
     */
    private function getQueueURL($queue)
    {
        $queues = $this->queue->listQueues(['QueueNamePrefix' => ''])->get('QueueUrls');
        foreach ($queues as $queueURL) {
            $tokens = explode('/', $queueURL);
            if (strtolower($queue) == strtolower($tokens[sizeof($tokens) - 1])) {
                return $queueURL;
            }
        }
        throw new TestRuntimeException('queue [' . $queue . '] not found');
    }

    public function getRequiredConfig()
    {
        return ['region'];
    }

    public function getDefaultConfig()
    {
        return [];
    }
}
<?php
declare(strict_types=1);

namespace Codeception\Lib\Driver;


use Codeception\Lib\Interfaces\Queue;
use Pheanstalk\Contract\ResponseInterface;
use Pheanstalk\Pheanstalk;

class Pheanstalk4 implements Queue
{
    /**
     * @var Pheanstalk
     */
    private $queue;
    /**
     * @inheritDoc
     */
    public function openConnection($config)
    {
        $this->queue = Pheanstalk::create($config['host'], $config['port'], $config['timeout']);
    }

    /**
     * @inheritDoc
     */
    public function addMessageToQueue($message, $queue)
    {
        $this->queue->useTube($queue);
        $this->queue->put($message);
    }

    /**
     * @inheritDoc
     */
    public function getQueues()
    {
        return $this->queue->listTubes();
    }

    /**
     * @inheritDoc
     */
    public function getMessagesCurrentCountOnQueue($queue)
    {
        $response = $this->queue->statsTube($queue);
        return $response->getResponseName() !== ResponseInterface::RESPONSE_NOT_FOUND
            ? $response['current-jobs-ready']
            : 0;
    }

    /**
     * @inheritDoc
     */
    public function getMessagesTotalCountOnQueue($queue)
    {
        $response = $this->queue->statsTube($queue);
        return $response->getResponseName() !== ResponseInterface::RESPONSE_NOT_FOUND
            ? $response['total-jobs']
            : 0;
    }

    public function clearQueue($queue)
    {
        $this->queue->useTube($queue);
        while (null !== $job = $this->queue->peekBuried()) {
            $this->queue->delete($job);
        }
        while (null !== $job = $this->queue->peekDelayed()) {
            $this->queue->delete($job);
        }
        while (null !== $job = $this->queue->peekReady()) {
            $this->queue->delete($job);
        }
    }

    public function getRequiredConfig()
    {
        return [];
    }

    public function getDefaultConfig()
    {
        return ['port' => 11300, 'timeout' => 90, 'host' => 'localhost'];
    }
}<?php
namespace Codeception\Lib\Driver;

use Codeception\Lib\Interfaces\Queue;
use Pheanstalk\Pheanstalk;
use Pheanstalk\Exception\ConnectionException;

class Beanstalk implements Queue
{

    /**
     * @var Pheanstalk
     */
    protected $queue;

    public function openConnection($config)
    {
        $this->queue = new Pheanstalk($config['host'], $config['port'], $config['timeout']);
    }

    /**
     * Post/Put a message on to the queue server
     *
     * @param string $message Message Body to be send
     * @param string $queue Queue Name
     */
    public function addMessageToQueue($message, $queue)
    {
        $this->queue->putInTube($queue, $message);
    }

    /**
     * Count the total number of messages on the queue.
     *
     * @param $queue Queue Name
     *
     * @return int Count
     */
    public function getMessagesTotalCountOnQueue($queue)
    {
        try {
            return $this->queue->statsTube($queue)['total-jobs'];
        } catch (ConnectionException $ex) {
            \PHPUnit\Framework\Assert::fail("queue [$queue] not found");
        }
    }

    public function clearQueue($queue = 'default')
    {
        while ($job = $this->queue->reserveFromTube($queue, 0)) {
            $this->queue->delete($job);
        }
    }

    /**
     * Return a list of queues/tubes on the queueing server
     *
     * @return array Array of Queues
     */
    public function getQueues()
    {
        return $this->queue->listTubes();
    }

    /**
     * Count the current number of messages on the queue.
     *
     * @param $queue Queue Name
     *
     * @return int Count
     */
    public function getMessagesCurrentCountOnQueue($queue)
    {
        try {
            return $this->queue->statsTube($queue)['current-jobs-ready'];
        } catch (ConnectionException $e) {
            \PHPUnit\Framework\Assert::fail("queue [$queue] not found");
        }
    }

    public function getRequiredConfig()
    {
        return ['host'];
    }

    public function getDefaultConfig()
    {
        return ['port' => 11300, 'timeout' => 90];
    }
}
<?php
namespace Codeception\Module;

use Codeception\Lib\Driver\Pheanstalk4;
use Codeception\Module as CodeceptionModule;
use Codeception\TestInterface;
use Codeception\Exception\ModuleConfigException;
use Codeception\Lib\Driver\AmazonSQS;
use Codeception\Lib\Driver\Beanstalk;
use Codeception\Lib\Driver\Iron;

/**
 *
 * Works with Queue servers.
 *
 * Testing with a selection of remote/local queueing services, including Amazon's SQS service
 * Iron.io service and beanstalkd service.
 *
 * Supported and tested queue types are:
 *
 * * [Iron.io](http://iron.io/)
 * * [Beanstalkd](http://kr.github.io/beanstalkd/)
 * * [Amazon SQS](http://aws.amazon.com/sqs/)
 *
 * The following dependencies are needed for the listed queue servers:
 *
 * * Beanstalkd: pda/pheanstalk ~3.0
 * * Amazon SQS: aws/aws-sdk-php
 * * IronMQ: iron-io/iron_mq
 *
 * ## Status
 *
 * * Stability:
 *     - Iron.io:    **stable**
 *     - Beanstalkd: **stable**
 *     - Amazon SQS: **stable**
 *
 * ## Config
 *
 * The configuration settings depending on which queueing service is being used, all the options are listed
 * here. Refer to the configuration examples below to identify the configuration options required for your chosen
 * service.
 *
 * * type - type of queueing server (defaults to beanstalkd).
 * * host - hostname/ip address of the queue server or the host for the iron.io when using iron.io service.
 * * port: 11300 - port number for the queue server.
 * * timeout: 90 - timeout settings for connecting the queue server.
 * * token - Iron.io access token.
 * * project - Iron.io project ID.
 * * key - AWS access key ID.
 * * version - AWS version (e.g. latest)
 * * endpoint - The full URI of the webservice. This is only required when connecting to a custom endpoint (e.g., a local version of SQS).
 * * secret - AWS secret access key.
 *      Warning:
 *          Hard-coding your credentials can be dangerous, because it is easy to accidentally commit your credentials
 *          into an SCM repository, potentially exposing your credentials to more people than intended.
 *          It can also make it difficult to rotate credentials in the future.
 * * profile - AWS credential profile
 *           - it should be located in ~/.aws/credentials file
 *           - eg:  [default]
 *                  aws_access_key_id = YOUR_AWS_ACCESS_KEY_ID
 *                  aws_secret_access_key = YOUR_AWS_SECRET_ACCESS_KEY
 *                  [project1]
 *                  aws_access_key_id = YOUR_AWS_ACCESS_KEY_ID
 *                  aws_secret_access_key = YOUR_AWS_SECRET_ACCESS_KEY
 *          - Note: Using IAM roles is the preferred technique for providing credentials
 *                  to applications running on Amazon EC2
 *                  http://docs.aws.amazon.com/aws-sdk-php/v3/guide/guide/credentials.html?highlight=credentials
 *
 * * region - A region parameter is also required for AWS, refer to the AWS documentation for possible values list.
 *
 * ### Example
 * #### Example (beanstalkd)
 *
 *     modules:
 *        enabled: [Queue]
 *        config:
 *           Queue:
 *              type: 'beanstalkd'
 *              host: '127.0.0.1'
 *              port: 11300
 *              timeout: 120
 *
 * #### Example (Iron.io)
 *
 *     modules:
 *        enabled: [Queue]
 *        config:
 *           Queue:
 *              'type': 'iron',
 *              'host': 'mq-aws-us-east-1.iron.io',
 *              'token': 'your-token',
 *              'project': 'your-project-id'
 *
 * #### Example (AWS SQS)
 *
 *     modules:
 *        enabled: [Queue]
 *        config:
 *           Queue:
 *              'type': 'aws',
 *              'key': 'your-public-key',
 *              'secret': 'your-secret-key',
 *              'region': 'us-west-2'
 *
 * #### Example AWS SQS using profile credentials
 *
 *     modules:
 *        enabled: [Queue]
 *        config:
 *           Queue:
 *              'type': 'aws',
 *              'profile': 'project1', //see documentation
 *              'region': 'us-west-2'
 *
 * #### Example AWS SQS running on Amazon EC2 instance
 *
 *     modules:
 *        enabled: [Queue]
 *        config:
 *           Queue:
 *              'type': 'aws',
 *              'region': 'us-west-2'
 *
 */
class Queue extends CodeceptionModule
{
    /**
     * @var \Codeception\Lib\Interfaces\Queue
     */
    public $queueDriver;

    /**
     * Setup connection and open/setup the connection with config settings
     *
     * @param \Codeception\TestInterface $test
     */
    public function _before(TestInterface $test)
    {
        $this->queueDriver->openConnection($this->config);
    }

    /**
     * Provide and override for the config settings and allow custom settings depending on the service being used.
     */
    protected function validateConfig()
    {
        $this->queueDriver = $this->createQueueDriver();
        $this->requiredFields = $this->queueDriver->getRequiredConfig();
        $this->config = array_merge($this->queueDriver->getDefaultConfig(), $this->config);
        parent::validateConfig();
    }

    /**
     * @return \Codeception\Lib\Interfaces\Queue
     * @throws ModuleConfigException
     */
    protected function createQueueDriver()
    {
        switch ($this->config['type']) {
            case 'aws':
            case 'sqs':
            case 'aws_sqs':
                return new AmazonSQS();
            case 'iron':
            case 'iron_mq':
                return new Iron();
            case 'beanstalk':
            case 'beanstalkd':
            case 'beanstalkq':
                // Account for different versions of Pheanstalk.
                if (interface_exists(\Pheanstalk\Contract\JobIdInterface::class)) {
                    return new Pheanstalk4();
                } else {
                    return new Beanstalk();
                }
            default:
                throw new ModuleConfigException(
                    __CLASS__,
                    "Unknown queue type {$this->config}; Supported queue types are: aws, iron, beanstalk"
                );
        }
    }

    // ----------- SEARCH METHODS BELOW HERE ------------------------//

    /**
     * Check if a queue/tube exists on the queueing server.
     *
     * ```php
     * <?php
     * $I->seeQueueExists('default');
     * ?>
     * ```
     *
     * @param string $queue Queue Name
     */
    public function seeQueueExists($queue)
    {
        $this->assertContains($queue, $this->queueDriver->getQueues());
    }

    /**
     * Check if a queue/tube does NOT exist on the queueing server.
     *
     * ```php
     * <?php
     * $I->dontSeeQueueExists('default');
     * ?>
     * ```
     *
     * @param string $queue Queue Name
     */
    public function dontSeeQueueExists($queue)
    {
        $this->assertNotContains($queue, $this->queueDriver->getQueues());
    }

    /**
     * Check if a queue/tube is empty of all messages
     *
     * ```php
     * <?php
     * $I->seeEmptyQueue('default');
     * ?>
     * ```
     *
     * @param string $queue Queue Name
     */
    public function seeEmptyQueue($queue)
    {
        $this->assertEquals(0, $this->queueDriver->getMessagesCurrentCountOnQueue($queue));
    }

    /**
     * Check if a queue/tube is NOT empty of all messages
     *
     * ```php
     * <?php
     * $I->dontSeeEmptyQueue('default');
     * ?>
     * ```
     *
     * @param string $queue Queue Name
     */
    public function dontSeeEmptyQueue($queue)
    {
        $this->assertNotEquals(0, $this->queueDriver->getMessagesCurrentCountOnQueue($queue));
    }

    /**
     * Check if a queue/tube has a given current number of messages
     *
     * ```php
     * <?php
     * $I->seeQueueHasCurrentCount('default', 10);
     * ?>
     * ```
     *
     * @param string $queue Queue Name
     * @param int $expected Number of messages expected
     */
    public function seeQueueHasCurrentCount($queue, $expected)
    {
        $this->assertEquals($expected, $this->queueDriver->getMessagesCurrentCountOnQueue($queue));
    }

    /**
     * Check if a queue/tube does NOT have a given current number of messages
     *
     * ```php
     * <?php
     * $I->dontSeeQueueHasCurrentCount('default', 10);
     * ?>
     * ```
     *
     * @param string $queue Queue Name
     * @param int $expected Number of messages expected
     */
    public function dontSeeQueueHasCurrentCount($queue, $expected)
    {
        $this->assertNotEquals($expected, $this->queueDriver->getMessagesCurrentCountOnQueue($queue));
    }

    /**
     * Check if a queue/tube has a given total number of messages
     *
     * ```php
     * <?php
     * $I->seeQueueHasTotalCount('default', 10);
     * ?>
     * ```
     *
     * @param string $queue Queue Name
     * @param int $expected Number of messages expected
     */
    public function seeQueueHasTotalCount($queue, $expected)
    {
        $this->assertEquals($expected, $this->queueDriver->getMessagesTotalCountOnQueue($queue));
    }

    /**
     * Check if a queue/tube does NOT have a given total number of messages
     *
     * ```php
     * <?php
     * $I->dontSeeQueueHasTotalCount('default', 10);
     * ?>
     * ```
     *
     * @param string $queue Queue Name
     * @param int $expected Number of messages expected
     */
    public function dontSeeQueueHasTotalCount($queue, $expected)
    {
        $this->assertNotEquals($expected, $this->queueDriver->getMessagesTotalCountOnQueue($queue));
    }

    // ----------- UTILITY METHODS BELOW HERE -------------------------//

    /**
     * Add a message to a queue/tube
     *
     * ```php
     * <?php
     * $I->addMessageToQueue('this is a messages', 'default');
     * ?>
     * ```
     *
     * @param string $message Message Body
     * @param string $queue Queue Name
     */
    public function addMessageToQueue($message, $queue)
    {
        $this->queueDriver->addMessageToQueue($message, $queue);
    }

    /**
     * Clear all messages of the queue/tube
     *
     * ```php
     * <?php
     * $I->clearQueue('default');
     * ?>
     * ```
     *
     * @param string $queue Queue Name
     */
    public function clearQueue($queue)
    {
        $this->queueDriver->clearQueue($queue);
    }

    // ----------- GRABBER METHODS BELOW HERE -----------------------//

    /**
     * Grabber method to get the list of queues/tubes on the server
     *
     * ```php
     * <?php
     * $queues = $I->grabQueues();
     * ?>
     * ```
     *
     * @return array List of Queues/Tubes
     */
    public function grabQueues()
    {
        return $this->queueDriver->getQueues();
    }

    /**
     * Grabber method to get the current number of messages on the queue/tube (pending/ready)
     *
     * ```php
     * <?php
     *     $I->grabQueueCurrentCount('default');
     * ?>
     * ```
     * @param string $queue Queue Name
     *
     * @return int Count
     */
    public function grabQueueCurrentCount($queue)
    {
        return $this->queueDriver->getMessagesCurrentCountOnQueue($queue);
    }

    /**
     * Grabber method to get the total number of messages on the queue/tube
     *
     * ```php
     * <?php
     *     $I->grabQueueTotalCount('default');
     * ?>
     * ```
     *
     * @param $queue Queue Name
     *
     * @return int Count
     */
    public function grabQueueTotalCount($queue)
    {
        return $this->queueDriver->getMessagesTotalCountOnQueue($queue);
    }
}
<?php

declare(strict_types=1);

namespace Codeception\Module;

use Codeception\Lib\Interfaces\RequiresPackage;
use Codeception\Module;
use Codeception\Exception\ModuleException;
use Codeception\TestInterface;
use Exception;
use Predis\Client as RedisDriver;

/**
 * This module uses the [Predis](https://github.com/nrk/predis) library
 * to interact with a Redis server.
 *
 * ## Status
 *
 * * Stability: **beta**
 *
 * ## Configuration
 *
 * * **`host`** (`string`, default `'127.0.0.1'`) - The Redis host
 * * **`port`** (`int`, default `6379`) - The Redis port
 * * **`database`** (`int`, no default) - The Redis database. Needs to be specified.
 * * **`username`** (`string`, no default) - When ACLs are enabled on Redis >= 6.0, both username and password are required for user authentication.
 * * **`password`** (`string`, no default) - The Redis password/secret.
 * * **`cleanupBefore`**: (`string`, default `'never'`) - Whether/when to flush the database:
 *     * `suite`: at the beginning of every suite
 *     * `test`: at the beginning of every test
 *     * Any other value: never
 *
 * Note: The full configuration list can be found on Predis' github.
 *
 * ### Example (`unit.suite.yml`)
 *
 * ```yaml
 *    modules:
 *        - Redis:
 *            host: '127.0.0.1'
 *            port: 6379
 *            database: 0
 *            cleanupBefore: 'never'
 * ```
 *
 * ## Public Properties
 *
 * * **driver** - Contains the Predis client/driver
 *
 * @author Marc Verney <marc@marcverney.net>
 */
class Redis extends Module implements RequiresPackage
{
    /**
     * {@inheritdoc}
     *
     * No default value is set for the database, using this parameter.
     *
     * @var array
     */
    protected $config = [
        'host'          => '127.0.0.1',
        'port'          => 6379,
        'cleanupBefore' => 'never'
    ];

    /**
     * {@inheritdoc}
     *
     * @var string[]
     */
    protected $requiredFields = [
        'database'
    ];

    /**
     * The Redis driver
     *
     * @var RedisDriver
     */
    public $driver;

    public function _requires()
    {
        return [\Predis\Client::class => '"predis/predis": "^1.0"'];
    }

    /**
     * Instructions to run after configuration is loaded
     *
     * @throws ModuleException
     */
    public function _initialize()
    {
        try {
            $this->driver = new RedisDriver($this->config);
        } catch (Exception $e) {
            throw new ModuleException(
                __CLASS__,
                $e->getMessage()
            );
        }
    }

    /**
     * Code to run before each suite
     *
     * @param array $settings
     */
    public function _beforeSuite($settings = [])
    {
        if ($this->config['cleanupBefore'] === 'suite') {
            $this->cleanup();
        }
    }

    /**
     * Code to run before each test
     */
    public function _before(TestInterface $test)
    {
        if ($this->config['cleanupBefore'] === 'test') {
            $this->cleanup();
        }
    }

    /**
     * Delete all the keys in the Redis database
     *
     * @throws ModuleException
     */
    public function cleanup(): void
    {
        try {
            $this->debugSection('Redis', 'Performing cleanup');
            $this->driver->flushdb();
        } catch (Exception $e) {
            throw new ModuleException(
                __CLASS__,
                $e->getMessage()
            );
        }
    }

    /**
     * Returns the value of a given key
     *
     * Examples:
     *
     * ``` php
     * <?php
     * // Strings
     * $I->grabFromRedis('string');
     *
     * // Lists: get all members
     * $I->grabFromRedis('example:list');
     *
     * // Lists: get a specific member
     * $I->grabFromRedis('example:list', 2);
     *
     * // Lists: get a range of elements
     * $I->grabFromRedis('example:list', 2, 4);
     *
     * // Sets: get all members
     * $I->grabFromRedis('example:set');
     *
     * // ZSets: get all members
     * $I->grabFromRedis('example:zset');
     *
     * // ZSets: get a range of members
     * $I->grabFromRedis('example:zset', 3, 12);
     *
     * // Hashes: get all fields of a key
     * $I->grabFromRedis('example:hash');
     *
     * // Hashes: get a specific field of a key
     * $I->grabFromRedis('example:hash', 'foo');
     * ```
     *
     * @param string $key The key name
     *
     * @return array|string|null
     *
     * @throws ModuleException if the key does not exist
     */
    public function grabFromRedis(string $key)
    {
        $args = func_get_args();

        switch ($this->driver->type($key)) {
            case 'none':
                throw new ModuleException(
                    $this,
                    sprintf('Cannot grab key "%s" as it does not exist', $key)
                );

            case 'string':
                $reply = $this->driver->get($key);
                break;

            case 'list':
                if (count($args) === 2) {
                    $reply = $this->driver->lindex($key, $args[1]);
                } else {
                    $reply = $this->driver->lrange(
                        $key,
                        isset($args[1]) ? $args[1] : 0,
                        isset($args[2]) ? $args[2] : -1
                    );
                }
                break;

            case 'set':
                $reply = $this->driver->smembers($key);
                break;

            case 'zset':
                if (count($args) === 2) {
                    throw new ModuleException(
                        $this,
                        'The method grabFromRedis(), when used with sorted sets, expects either one argument or three'
                    );
                }
                $reply = $this->driver->zrange(
                    $key,
                    isset($args[2]) ? $args[1] : 0,
                    isset($args[2]) ? $args[2] : -1,
                    'WITHSCORES'
                );
                break;

            case 'hash':
                $reply = isset($args[1])
                    ? $this->driver->hget($key, $args[1])
                    : $this->driver->hgetall($key);
                break;

            default:
                $reply = null;
        }

        return $reply;
    }

    /**
     * Creates or modifies keys
     *
     * If $key already exists:
     *
     * - Strings: its value will be overwritten with $value
     * - Other types: $value items will be appended to its value
     *
     * Examples:
     *
     * ``` php
     * <?php
     * // Strings: $value must be a scalar
     * $I->haveInRedis('string', 'Obladi Oblada');
     *
     * // Lists: $value can be a scalar or an array
     * $I->haveInRedis('list', ['riri', 'fifi', 'loulou']);
     *
     * // Sets: $value can be a scalar or an array
     * $I->haveInRedis('set', ['riri', 'fifi', 'loulou']);
     *
     * // ZSets: $value must be an associative array with scores
     * $I->haveInRedis('zset', ['riri' => 1, 'fifi' => 2, 'loulou' => 3]);
     *
     * // Hashes: $value must be an associative array
     * $I->haveInRedis('hash', ['obladi' => 'oblada']);
     * ```
     *
     * @param string $type  The type of the key
     * @param string $key   The key name
     * @param mixed  $value The value
     *
     * @throws ModuleException
     */
    public function haveInRedis(string $type, string $key, $value): void
    {
        switch (strtolower($type)) {
            case 'string':
                if (!is_scalar($value)) {
                    throw new ModuleException(
                        $this,
                        'If second argument of haveInRedis() method is "string", third argument must be a scalar'
                    );
                }
                $this->driver->set($key, $value);
                break;

            case 'list':
                $this->driver->rpush($key, $value);
                break;

            case 'set':
                $this->driver->sadd($key, $value);
                break;

            case 'zset':
                if (!is_array($value)) {
                    throw new ModuleException(
                        $this,
                        'If second argument of haveInRedis() method is "zset", third argument must be an (associative) array'
                    );
                }
                $this->driver->zadd($key, $value);
                break;

            case 'hash':
                if (!is_array($value)) {
                    throw new ModuleException(
                        $this,
                        'If second argument of haveInRedis() method is "hash", third argument must be an array'
                    );
                }
                $this->driver->hmset($key, $value);
                break;

            default:
                throw new ModuleException(
                    $this,
                    sprintf('Unknown type "%s" for key "%s". Allowed types are ', $type, $key)
                    . '"string", "list", "set", "zset", "hash"'
                );
        }
    }

    /**
     * Asserts that a key does not exist or, optionally, that it doesn't have the
     * provided $value
     *
     * Examples:
     *
     * ``` php
     * <?php
     * // With only one argument, only checks the key does not exist
     * $I->dontSeeInRedis('example:string');
     *
     * // Checks a String does not exist or its value is not the one provided
     * $I->dontSeeInRedis('example:string', 'life');
     *
     * // Checks a List does not exist or its value is not the one provided (order of elements is compared).
     * $I->dontSeeInRedis('example:list', ['riri', 'fifi', 'loulou']);
     *
     * // Checks a Set does not exist or its value is not the one provided (order of members is ignored).
     * $I->dontSeeInRedis('example:set', ['riri', 'fifi', 'loulou']);
     *
     * // Checks a ZSet does not exist or its value is not the one provided (scores are required, order of members is compared)
     * $I->dontSeeInRedis('example:zset', ['riri' => 1, 'fifi' => 2, 'loulou' => 3]);
     *
     * // Checks a Hash does not exist or its value is not the one provided (order of members is ignored).
     * $I->dontSeeInRedis('example:hash', ['riri' => true, 'fifi' => 'Dewey', 'loulou' => 2]);
     * ```
     *
     * @param string $key   The key name
     * @param mixed  $value Optional. If specified, also checks the key has this
     * value. Booleans will be converted to 1 and 0 (even inside arrays)
     */
    public function dontSeeInRedis(string $key, $value = null): void
    {
        $this->assertFalse(
            $this->checkKeyExists($key, $value),
            sprintf('The key "%s" exists', $key) . ($value ? ' and its value matches the one provided' : '')
        );
    }

    /**
     * Asserts that a given key does not contain a given item
     *
     * Examples:
     *
     * ``` php
     * <?php
     * // Strings: performs a substring search
     * $I->dontSeeRedisKeyContains('string', 'bar');
     *
     * // Lists
     * $I->dontSeeRedisKeyContains('example:list', 'poney');
     *
     * // Sets
     * $I->dontSeeRedisKeyContains('example:set', 'cat');
     *
     * // ZSets: check whether the zset has this member
     * $I->dontSeeRedisKeyContains('example:zset', 'jordan');
     *
     * // ZSets: check whether the zset has this member with this score
     * $I->dontSeeRedisKeyContains('example:zset', 'jordan', 23);
     *
     * // Hashes: check whether the hash has this field
     * $I->dontSeeRedisKeyContains('example:hash', 'magic');
     *
     * // Hashes: check whether the hash has this field with this value
     * $I->dontSeeRedisKeyContains('example:hash', 'magic', 32);
     * ```
     *
     * @param string $key       The key
     * @param mixed  $item      The item
     * @param null   $itemValue Optional and only used for zsets and hashes. If
     * specified, the method will also check that the $item has this value/score
     */
    public function dontSeeRedisKeyContains(string $key, $item, $itemValue = null): void
    {
        $this->assertFalse(
            $this->checkKeyContains($key, $item, $itemValue),
            sprintf('The key "%s" contains ', $key) . (
                is_null($itemValue)
                ? sprintf('"%s"', $item)
                : sprintf('["%s" => "%s"]', $item, $itemValue)
            )
        );
    }

    /**
     * Asserts that a key exists, and optionally that it has the provided $value
     *
     * Examples:
     *
     * ``` php
     * <?php
     * // With only one argument, only checks the key exists
     * $I->seeInRedis('example:string');
     *
     * // Checks a String exists and has the value "life"
     * $I->seeInRedis('example:string', 'life');
     *
     * // Checks the value of a List. Order of elements is compared.
     * $I->seeInRedis('example:list', ['riri', 'fifi', 'loulou']);
     *
     * // Checks the value of a Set. Order of members is ignored.
     * $I->seeInRedis('example:set', ['riri', 'fifi', 'loulou']);
     *
     * // Checks the value of a ZSet. Scores are required. Order of members is compared.
     * $I->seeInRedis('example:zset', ['riri' => 1, 'fifi' => 2, 'loulou' => 3]);
     *
     * // Checks the value of a Hash. Order of members is ignored.
     * $I->seeInRedis('example:hash', ['riri' => true, 'fifi' => 'Dewey', 'loulou' => 2]);
     * ```
     *
     * @param string $key   The key name
     * @param mixed  $value Optional. If specified, also checks the key has this
     * value. Booleans will be converted to 1 and 0 (even inside arrays)
     */
    public function seeInRedis(string $key, $value = null): void
    {
        $this->assertTrue(
            $this->checkKeyExists($key, $value),
            sprintf('Cannot find key "%s"', $key) . ($value ? ' with the provided value' : '')
        );
    }

    /**
     * Sends a command directly to the Redis driver. See documentation at
     * https://github.com/nrk/predis
     * Every argument that follows the $command name will be passed to it.
     *
     * Examples:
     *
     * ``` php
     * <?php
     * $I->sendCommandToRedis('incr', 'example:string');
     * $I->sendCommandToRedis('strLen', 'example:string');
     * $I->sendCommandToRedis('lPop', 'example:list');
     * $I->sendCommandToRedis('zRangeByScore', 'example:set', '-inf', '+inf', ['withscores' => true, 'limit' => [1, 2]]);
     * $I->sendCommandToRedis('flushdb');
     * ```
     *
     * @param string $command The command name
     *
     * @return mixed
     */
    public function sendCommandToRedis(string $command)
    {
        return call_user_func_array(
            [$this->driver, $command],
            array_slice(func_get_args(), 1)
        );
    }

    /**
     * Asserts that a given key contains a given item
     *
     * Examples:
     *
     * ``` php
     * <?php
     * // Strings: performs a substring search
     * $I->seeRedisKeyContains('example:string', 'bar');
     *
     * // Lists
     * $I->seeRedisKeyContains('example:list', 'poney');
     *
     * // Sets
     * $I->seeRedisKeyContains('example:set', 'cat');
     *
     * // ZSets: check whether the zset has this member
     * $I->seeRedisKeyContains('example:zset', 'jordan');
     *
     * // ZSets: check whether the zset has this member with this score
     * $I->seeRedisKeyContains('example:zset', 'jordan', 23);
     *
     * // Hashes: check whether the hash has this field
     * $I->seeRedisKeyContains('example:hash', 'magic');
     *
     * // Hashes: check whether the hash has this field with this value
     * $I->seeRedisKeyContains('example:hash', 'magic', 32);
     * ```
     *
     * @param string $key       The key
     * @param mixed  $item      The item
     * @param null   $itemValue Optional and only used for zsets and hashes. If
     * specified, the method will also check that the $item has this value/score
     */
    public function seeRedisKeyContains(string $key, $item, $itemValue = null): void
    {
        $this->assertTrue(
            $this->checkKeyContains($key, $item, $itemValue),
            sprintf('The key "%s" does not contain ', $key) . (
            is_null($itemValue)
                ? sprintf('"%s"', $item)
                : sprintf('["%s" => "%s"]', $item, $itemValue)
            )
        );
    }

    /**
     * Converts boolean values to "0" and "1"
     *
     * @param mixed $var The variable
     *
     * @return mixed
     */
    private function boolToString($var)
    {
        $copy = is_array($var) ? $var : [$var];

        foreach ($copy as $key => $value) {
            if (is_bool($value)) {
                $copy[$key] = $value ? '1' : '0';
            }
        }

        return is_array($var) ? $copy : $copy[0];
    }

    /**
     * Checks whether a key contains a given item
     *
     * @param string $key       The key
     * @param mixed  $item      The item
     * @param null   $itemValue Optional and only used for zsets and hashes. If
     * specified, the method will also check that the $item has this value/score
     *
     * @return bool
     * @throws ModuleException
     */
    private function checkKeyContains(string $key, $item, $itemValue = null): bool
    {
        $result = null;

        if (!is_scalar($item)) {
            throw new ModuleException(
                $this,
                "All arguments of [dont]seeRedisKeyContains() must be scalars"
            );
        }

        switch ($this->driver->type($key)) {
            case 'string':
                $reply = $this->driver->get($key);
                $result = strpos($reply, $item) !== false;
                break;

            case 'list':
                $reply = $this->driver->lrange($key, 0, -1);
                $result = in_array($item, $reply);
                break;

            case 'set':
                $result = $this->driver->sismember($key, $item);
                break;

            case 'zset':
                $reply = $this->driver->zscore($key, $item);

                if (is_null($reply)) {
                    $result = false;
                } elseif (!is_null($itemValue)) {
                    $result = (float) $reply === (float) $itemValue;
                } else {
                    $result = true;
                }
                break;

            case 'hash':
                $reply = $this->driver->hget($key, $item);

                $result = is_null($itemValue)
                    ? !is_null($reply)
                    : (string) $reply === (string) $itemValue;
                break;

            case 'none':
                throw new ModuleException(
                    $this,
                    sprintf('Key "%s" does not exist', $key)
                );
        }

        return (bool) $result;
    }

    /**
     * Checks whether a key exists and, optionally, whether it has a given $value
     *
     * @param string $key   The key name
     * @param mixed  $value Optional. If specified, also checks the key has this
     * value. Booleans will be converted to 1 and 0 (even inside arrays)
     */
    private function checkKeyExists(string $key, $value = null): bool
    {
        $type = $this->driver->type($key);

        if (is_null($value)) {
            return $type != 'none';
        }

        $value = $this->boolToString($value);

        switch ($type) {
            case 'string':
                $reply = $this->driver->get($key);
                // Allow non strict equality (2 equals '2')
                $result = $reply == $value;
                break;

            case 'list':
                $reply = $this->driver->lrange($key, 0, -1);
                // Check both arrays have the same key/value pairs + same order
                $result = $reply === $value;
                break;

            case 'set':
                $reply = $this->driver->smembers($key);
                // Only check both arrays have the same values
                sort($reply);
                sort($value);
                $result = $reply === $value;
                break;

            case 'zset':
                $reply = $this->driver->zrange($key, 0, -1, 'WITHSCORES');
                // Check both arrays have the same key/value pairs + same order
                $reply = $this->scoresToFloat($reply);
                $value = $this->scoresToFloat($value);
                $result = $reply === $value;
                break;

            case 'hash':
                $reply = $this->driver->hgetall($key);
                // Only check both arrays have the same key/value pairs (==)
                $result = $reply == $value;
                break;

            default:
                $result = false;
        }

        return $result;
    }

    /**
     * Explicitly cast the scores of a Zset associative array as float/double
     *
     * @param array $arr The ZSet associative array
     *
     * @return array
     */
    private function scoresToFloat(array $arr): array
    {
        foreach ($arr as $member => $score) {
            $arr[$member] = (float) $score;
        }

        return $arr;
    }
}
<?php

namespace Codeception\Test\Feature;

/**
 * ### Usage in Codeception
 *
 * Since Codeception 2.3.8 this trait is enabled in `\Codeception\Test\Unit` class.
 *
 * ### Usage in PHPUnit
 *
 * Include this trait into a TestCase to be able to use Stubs and Mocks:
 *
 * ```php
 * <?php
 * class MyTest extends \PHPUnit\Framework\TestCase
 * {
 *      use Codeception\Test\Feature\Stub;
 * }
 * ```
 */
trait Stub
{
    private $mocks;

    protected function stubStart()
    {
        if ($this instanceof \PHPUnit\Framework\TestCase) {
            return;
        }
        $this->mocks = [];
    }

    protected function stubEnd($status, $time)
    {
        if ($this instanceof \PHPUnit\Framework\TestCase) {
            return;
        }
        if ($status !== 'ok') { // Codeception status
            return;
        }

        foreach ($this->mocks as $mockObject) {
            if ($mockObject->__phpunit_hasMatchers()) {
                $this->assertTrue(true); // incrementing assertions
            }

            $mockObject->__phpunit_verify(true);
        }
    }

    /**
     * Instantiates a class without executing a constructor.
     * Properties and methods can be set as a second parameter.
     * Even protected and private properties can be set.
     *
     * ``` php
     * <?php
     * $this->make('User');
     * $this->make('User', ['name' => 'davert']);
     * ?>
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * $this->make(new User, ['name' => 'davert']);
     * ?>
     * ```
     *
     * To replace method provide it's name as a key in second parameter
     * and it's return value or callback function as parameter
     *
     * ``` php
     * <?php
     * $this->make('User', ['save' => function () { return true; }]);
     * $this->make('User', ['save' => true]);
     * ```
     * @template RealInstanceType of object
     * @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
     * @param array $params - properties and methods to set
     *
     * @return \PHPUnit\Framework\MockObject\MockObject&RealInstanceType - mock
     * @throws \RuntimeException when class does not exist
     * @throws \Exception
     */
    public function make($class, $params = [])
    {
        return $this->mocks[] = \Codeception\Stub::make($class, $params, $this);
    }

    /**
     * Instantiates class having all methods replaced with dummies.
     * Constructor is not triggered.
     * Properties and methods can be set as a second parameter.
     * Even protected and private properties can be set.
     *
     * ``` php
     * <?php
     * $this->makeEmpty('User');
     * $this->makeEmpty('User', ['name' => 'davert']);
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * $this->makeEmpty(new User, ['name' => 'davert']);
     * ```
     *
     * To replace method provide it's name as a key in second parameter
     * and it's return value or callback function as parameter
     *
     * ``` php
     * <?php
     * $this->makeEmpty('User', ['save' => function () { return true; }]);
     * $this->makeEmpty('User', ['save' => true));
     * ```
     *
     * @template RealInstanceType of object
     * @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
     * @param array $params
     * @param bool|\PHPUnit\Framework\TestCase $testCase
     *
     * @return \PHPUnit\Framework\MockObject\MockObject&RealInstanceType
     * @throws \Exception
     */
    public function makeEmpty($class, $params = [])
    {
        return $this->mocks[] = \Codeception\Stub::makeEmpty($class, $params, $this);
    }

    /**
     * Instantiates class having all methods replaced with dummies except one.
     * Constructor is not triggered.
     * Properties and methods can be replaced.
     * Even protected and private properties can be set.
     *
     * ``` php
     * <?php
     * $this->makeEmptyExcept('User', 'save');
     * $this->makeEmptyExcept('User', 'save', ['name' => 'davert']);
     * ?>
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * * $this->makeEmptyExcept(new User, 'save');
     * ?>
     * ```
     *
     * To replace method provide it's name as a key in second parameter
     * and it's return value or callback function as parameter
     *
     * ``` php
     * <?php
     * $this->makeEmptyExcept('User', 'save', ['isValid' => function () { return true; }]);
     * $this->makeEmptyExcept('User', 'save', ['isValid' => true]);
     * ```
     *
     * @template RealInstanceType of object
     * @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
     * @param string $method
     * @param array $params
     *
     * @return \PHPUnit\Framework\MockObject\MockObject&RealInstanceType
     * @throws \Exception
     */
    public function makeEmptyExcept($class, $method, $params = [])
    {
        return $this->mocks[] = \Codeception\Stub::makeEmptyExcept($class, $method, $params, $this);
    }

    /**
     * Instantiates a class instance by running constructor.
     * Parameters for constructor passed as second argument
     * Properties and methods can be set in third argument.
     * Even protected and private properties can be set.
     *
     * ``` php
     * <?php
     * $this->construct('User', ['autosave' => false]);
     * $this->construct('User', ['autosave' => false], ['name' => 'davert']);
     * ?>
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * $this->construct(new User, ['autosave' => false), ['name' => 'davert']);
     * ?>
     * ```
     *
     * To replace method provide it's name as a key in third parameter
     * and it's return value or callback function as parameter
     *
     * ``` php
     * <?php
     * $this->construct('User', [], ['save' => function () { return true; }]);
     * $this->construct('User', [], ['save' => true]);
     * ?>
     * ```
     *
     * @template RealInstanceType of object
     * @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
     * @param array $constructorParams
     * @param array $params
     * @param bool|\PHPUnit\Framework\TestCase $testCase
     *
     * @return \PHPUnit\Framework\MockObject\MockObject&RealInstanceType
     * @throws \Exception
     */
    public function construct($class, $constructorParams = [], $params = [])
    {
        return $this->mocks[] = \Codeception\Stub::construct($class, $constructorParams, $params, $this);
    }

    /**
     * Instantiates a class instance by running constructor with all methods replaced with dummies.
     * Parameters for constructor passed as second argument
     * Properties and methods can be set in third argument.
     * Even protected and private properties can be set.
     *
     * ``` php
     * <?php
     * $this->constructEmpty('User', ['autosave' => false]);
     * $this->constructEmpty('User', ['autosave' => false), ['name' => 'davert']);
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * $this->constructEmpty(new User, ['autosave' => false], ['name' => 'davert']);
     * ```
     *
     * To replace method provide it's name as a key in third parameter
     * and it's return value or callback function as parameter
     *
     * ``` php
     * <?php
     * $this->constructEmpty('User', array(), array('save' => function () { return true; }));
     * $this->constructEmpty('User', array(), array('save' => true));
     * ```
     *
     * **To create a mock, pass current testcase name as last argument:**
     *
     * ```php
     * <?php
     * $this->constructEmpty('User', [], [
     *      'save' => \Codeception\Stub\Expected::once()
     * ]);
     * ```
     *
     * @template RealInstanceType of object
     * @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
     * @param array $constructorParams
     * @param array $params
     *
     * @return \PHPUnit\Framework\MockObject\MockObject&RealInstanceType
     */
    public function constructEmpty($class, $constructorParams = [], $params = [])
    {
        return $this->mocks[] = \Codeception\Stub::constructEmpty($class, $constructorParams, $params, $this);
    }

    /**
     * Instantiates a class instance by running constructor with all methods replaced with dummies, except one.
     * Parameters for constructor passed as second argument
     * Properties and methods can be set in third argument.
     * Even protected and private properties can be set.
     *
     * ``` php
     * <?php
     * $this->constructEmptyExcept('User', 'save');
     * $this->constructEmptyExcept('User', 'save', ['autosave' => false], ['name' => 'davert']);
     * ?>
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * $this->constructEmptyExcept(new User, 'save', ['autosave' => false], ['name' => 'davert']);
     * ?>
     * ```
     *
     * To replace method provide it's name as a key in third parameter
     * and it's return value or callback function as parameter
     *
     * ``` php
     * <?php
     * $this->constructEmptyExcept('User', 'save', [], ['save' => function () { return true; }]);
     * $this->constructEmptyExcept('User', 'save', [], ['save' => true]);
     * ?>
     * ```
     *
     * @template RealInstanceType of object
     * @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
     * @param string $method
     * @param array $constructorParams
     * @param array $params
     *
     * @return \PHPUnit\Framework\MockObject\MockObject&RealInstanceType
     */
    public function constructEmptyExcept($class, $method, $constructorParams = [], $params = [])
    {
        return $this->mocks[] = \Codeception\Stub::constructEmptyExcept($class, $method, $constructorParams, $params, $this);
    }

}<?php
namespace Codeception;

use Codeception\Stub\ConsecutiveMap;
use Codeception\Stub\StubMarshaler;
use PHPUnit\Framework\MockObject\Generator;
use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount;
use PHPUnit\Framework\MockObject\Stub\ConsecutiveCalls;
use PHPUnit\Framework\MockObject\Stub\ReturnCallback;
use PHPUnit\Framework\MockObject\Stub\ReturnStub;

class Stub
{
    public static $magicMethods = ['__isset', '__get', '__set'];

    /**
     * Instantiates a class without executing a constructor.
     * Properties and methods can be set as a second parameter.
     * Even protected and private properties can be set.
     *
     * ``` php
     * <?php
     * Stub::make('User');
     * Stub::make('User', ['name' => 'davert']);
     * ?>
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * Stub::make(new User, ['name' => 'davert']);
     * ?>
     * ```
     *
     * To replace method provide it's name as a key in second parameter
     * and it's return value or callback function as parameter
     *
     * ``` php
     * <?php
     * Stub::make('User', ['save' => function () { return true; }]);
     * Stub::make('User', ['save' => true]);
     * ?>
     * ```
     *
     * **To create a mock, pass current testcase name as last argument:**
     *
     * ```php
     * <?php
     * Stub::make('User', [
     *      'save' => \Codeception\Stub\Expected::once()
     * ], $this);
     * ```
     *
     * @template RealInstanceType of object
     * @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
     * @param array $params - properties and methods to set
     * @param bool|\PHPUnit\Framework\TestCase $testCase
     *
     * @return \PHPUnit\Framework\MockObject\MockObject&RealInstanceType - mock
     * @throws \RuntimeException when class does not exist
     * @throws \Exception
     */
    public static function make($class, $params = [], $testCase = false)
    {
        $class = self::getClassname($class);
        if (!class_exists($class)) {
            if (interface_exists($class)) {
                throw new \RuntimeException("Stub::make can't mock interfaces, please use Stub::makeEmpty instead.");
            }
            throw new \RuntimeException("Stubbed class $class doesn't exist.");
        }

        $reflection = new \ReflectionClass($class);
        $callables = self::getMethodsToReplace($reflection, $params);
        if ($reflection->isAbstract()) {
            $arguments = empty($callables) ? [] : array_keys($callables);
            $mock = self::generateMockForAbstractClass($class, $arguments, '', false, $testCase);
        } else {
            $arguments = empty($callables) ? null : array_keys($callables);
            $mock = self::generateMock($class, $arguments, [], '', false, $testCase);
        }

        self::bindParameters($mock, $params);

        return self::markAsMock($mock, $reflection);
    }

    /**
     * Set __mock flag, if at all possible
     *
     * @param object $mock
     * @param \ReflectionClass $reflection
     * @return object
     */
    private static function markAsMock($mock, \ReflectionClass $reflection)
    {
        if (!$reflection->hasMethod('__set')) {
            $mock->__mocked = $reflection->getName();
        }
        return $mock;
    }

    /**
     * Creates $num instances of class through `Stub::make`.
     *
     * @param mixed $class
     * @param int $num
     * @param array $params
     *
     * @return array
     * @throws \Exception
     */
    public static function factory($class, $num = 1, $params = [])
    {
        $objects = [];
        for ($i = 0; $i < $num; $i++) {
            $objects[] = self::make($class, $params);
        }

        return $objects;
    }

    /**
     * Instantiates class having all methods replaced with dummies except one.
     * Constructor is not triggered.
     * Properties and methods can be replaced.
     * Even protected and private properties can be set.
     *
     * ``` php
     * <?php
     * Stub::makeEmptyExcept('User', 'save');
     * Stub::makeEmptyExcept('User', 'save', ['name' => 'davert']);
     * ?>
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * * Stub::makeEmptyExcept(new User, 'save');
     * ?>
     * ```
     *
     * To replace method provide it's name as a key in second parameter
     * and it's return value or callback function as parameter
     *
     * ``` php
     * <?php
     * Stub::makeEmptyExcept('User', 'save', ['isValid' => function () { return true; }]);
     * Stub::makeEmptyExcept('User', 'save', ['isValid' => true]);
     * ?>
     * ```
     *
     * **To create a mock, pass current testcase name as last argument:**
     *
     * ```php
     * <?php
     * Stub::makeEmptyExcept('User', 'validate', [
     *      'save' => \Codeception\Stub\Expected::once()
     * ], $this);
     * ```
     * @template
     * @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
     * @param string $method
     * @param array $params
     * @param bool|\PHPUnit\Framework\TestCase $testCase
     *
     * @return \PHPUnit\Framework\MockObject\MockObject&RealInstanceType
     * @throws \Exception
     */
    public static function makeEmptyExcept($class, $method, $params = [], $testCase = false)
    {
        $class = self::getClassname($class);
        $reflectionClass = new \ReflectionClass($class);

        $methods = $reflectionClass->getMethods();

        $methods = array_filter(
            $methods,
            function ($m) {
                return !in_array($m->name, Stub::$magicMethods);
            }
        );

        $methods = array_filter(
            $methods,
            function ($m) use ($method) {
                return $method != $m->name;
            }
        );

        $methods = array_map(
            function ($m) {
                return $m->name;
            },
            $methods
        );

        $methods = count($methods) ? $methods : null;
        $mock = self::generateMock($class, $methods, [], '', false, $testCase);
        self::bindParameters($mock, $params);

        return self::markAsMock($mock, $reflectionClass);
    }

    /**
     * Instantiates class having all methods replaced with dummies.
     * Constructor is not triggered.
     * Properties and methods can be set as a second parameter.
     * Even protected and private properties can be set.
     *
     * ``` php
     * <?php
     * Stub::makeEmpty('User');
     * Stub::makeEmpty('User', ['name' => 'davert']);
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * Stub::makeEmpty(new User, ['name' => 'davert']);
     * ```
     *
     * To replace method provide it's name as a key in second parameter
     * and it's return value or callback function as parameter
     *
     * ``` php
     * <?php
     * Stub::makeEmpty('User', ['save' => function () { return true; }]);
     * Stub::makeEmpty('User', ['save' => true]);
     * ```
     *
     * **To create a mock, pass current testcase name as last argument:**
     *
     * ```php
     * <?php
     * Stub::makeEmpty('User', [
     *      'save' => \Codeception\Stub\Expected::once()
     * ], $this);
     * ```
     *
     * @template RealInstanceType of object
     * @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
     * @param array $params
     * @param bool|\PHPUnit\Framework\TestCase $testCase
     *
     * @return \PHPUnit\Framework\MockObject\MockObject&RealInstanceType
     * @throws \Exception
     */
    public static function makeEmpty($class, $params = [], $testCase = false)
    {
        $class = self::getClassname($class);
        $reflection = new \ReflectionClass($class);

        $methods = get_class_methods($class);
        $methods = array_filter(
            $methods,
            function ($i) {
                return !in_array($i, Stub::$magicMethods);
            }
        );
        $mock = self::generateMock($class, $methods, [], '', false, $testCase);
        self::bindParameters($mock, $params);

        return self::markAsMock($mock, $reflection);
    }

    /**
     * Clones an object and redefines it's properties (even protected and private)
     *
     * @param       $obj
     * @param array $params
     *
     * @return mixed
     * @throws \Exception
     */
    public static function copy($obj, $params = [])
    {
        $copy = clone($obj);
        self::bindParameters($copy, $params);

        return $copy;
    }

    /**
     * Instantiates a class instance by running constructor.
     * Parameters for constructor passed as second argument
     * Properties and methods can be set in third argument.
     * Even protected and private properties can be set.
     *
     * ``` php
     * <?php
     * Stub::construct('User', ['autosave' => false]);
     * Stub::construct('User', ['autosave' => false], ['name' => 'davert']);
     * ?>
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * Stub::construct(new User, ['autosave' => false], ['name' => 'davert']);
     * ?>
     * ```
     *
     * To replace method provide it's name as a key in third parameter
     * and it's return value or callback function as parameter
     *
     * ``` php
     * <?php
     * Stub::construct('User', [], ['save' => function () { return true; }]);
     * Stub::construct('User', [], ['save' => true]);
     * ?>
     * ```
     *
     * **To create a mock, pass current testcase name as last argument:**
     *
     * ```php
     * <?php
     * Stub::construct('User', [], [
     *      'save' => \Codeception\Stub\Expected::once()
     * ], $this);
     * ```
     *
     * @template RealInstanceType of object
     * @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
     * @param array $constructorParams
     * @param array $params
     * @param bool|\PHPUnit\Framework\TestCase $testCase
     *
     * @return \PHPUnit\Framework\MockObject\MockObject&RealInstanceType
     * @throws \Exception
     */
    public static function construct($class, $constructorParams = [], $params = [], $testCase = false)
    {
        $class = self::getClassname($class);
        $reflection = new \ReflectionClass($class);

        $callables = self::getMethodsToReplace($reflection, $params);

        $arguments = empty($callables) ? null : array_keys($callables);
        $mock = self::generateMock($class, $arguments, $constructorParams, $testCase);
        self::bindParameters($mock, $params);

        return self::markAsMock($mock, $reflection);
    }

    /**
     * Instantiates a class instance by running constructor with all methods replaced with dummies.
     * Parameters for constructor passed as second argument
     * Properties and methods can be set in third argument.
     * Even protected and private properties can be set.
     *
     * ``` php
     * <?php
     * Stub::constructEmpty('User', ['autosave' => false]);
     * Stub::constructEmpty('User', ['autosave' => false], ['name' => 'davert']);
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * Stub::constructEmpty(new User, ['autosave' => false], ['name' => 'davert']);
     * ```
     *
     * To replace method provide it's name as a key in third parameter
     * and it's return value or callback function as parameter
     *
     * ``` php
     * <?php
     * Stub::constructEmpty('User', [], ['save' => function () { return true; }]);
     * Stub::constructEmpty('User', [], ['save' => true]);
     * ```
     *
     * **To create a mock, pass current testcase name as last argument:**
     *
     * ```php
     * <?php
     * Stub::constructEmpty('User', [], [
     *      'save' => \Codeception\Stub\Expected::once()
     * ], $this);
     * ```
     *
     * @template RealInstanceType of object
     * @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
     * @param array $constructorParams
     * @param array $params
     * @param bool|\PHPUnit\Framework\TestCase $testCase
     *
     * @return \PHPUnit\Framework\MockObject\MockObject&RealInstanceType
     */
    public static function constructEmpty($class, $constructorParams = [], $params = [], $testCase = false)
    {
        $class = self::getClassname($class);
        $reflection = new \ReflectionClass($class);

        $methods = get_class_methods($class);
        $methods = array_filter(
            $methods,
            function ($i) {
                return !in_array($i, Stub::$magicMethods);
            }
        );
        $mock = self::generateMock($class, $methods, $constructorParams, $testCase);
        self::bindParameters($mock, $params);

        return self::markAsMock($mock, $reflection);
    }

    /**
     * Instantiates a class instance by running constructor with all methods replaced with dummies, except one.
     * Parameters for constructor passed as second argument
     * Properties and methods can be set in third argument.
     * Even protected and private properties can be set.
     *
     * ``` php
     * <?php
     * Stub::constructEmptyExcept('User', 'save');
     * Stub::constructEmptyExcept('User', 'save', ['autosave' => false], ['name' => 'davert']);
     * ?>
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * Stub::constructEmptyExcept(new User, 'save', ['autosave' => false], ['name' => 'davert']);
     * ?>
     * ```
     *
     * To replace method provide it's name as a key in third parameter
     * and it's return value or callback function as parameter
     *
     * ``` php
     * <?php
     * Stub::constructEmptyExcept('User', 'save', [], ['save' => function () { return true; }]);
     * Stub::constructEmptyExcept('User', 'save', [], ['save' => true]);
     * ?>
     * ```
     *
     * **To create a mock, pass current testcase name as last argument:**
     *
     * ```php
     * <?php
     * Stub::constructEmptyExcept('User', 'save', [], [
     *      'save' => \Codeception\Stub\Expected::once()
     * ], $this);
     * ```
     *
     * @template RealInstanceType of object
     * @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
     * @param string $method
     * @param array $constructorParams
     * @param array $params
     * @param bool|\PHPUnit\Framework\TestCase $testCase
     *
     * @return \PHPUnit\Framework\MockObject\MockObject&RealInstanceType
     */
    public static function constructEmptyExcept(
        $class,
        $method,
        $constructorParams = [],
        $params = [],
        $testCase = false
    ) {
        $class = self::getClassname($class);
        $reflectionClass = new \ReflectionClass($class);
        $methods = $reflectionClass->getMethods();
        $methods = array_filter(
            $methods,
            function ($m) {
                return !in_array($m->name, Stub::$magicMethods);
            }
        );
        $methods = array_filter(
            $methods,
            function ($m) use ($method) {
                return $method != $m->name;
            }
        );
        $methods = array_map(
            function ($m) {
                return $m->name;
            },
            $methods
        );
        $methods = count($methods) ? $methods : null;
        $mock = self::generateMock($class, $methods, $constructorParams, $testCase);
        self::bindParameters($mock, $params);

        return self::markAsMock($mock, $reflectionClass);
    }

    private static function generateMock()
    {
        return self::doGenerateMock(func_get_args());
    }

    /**
     * Returns a mock object for the specified abstract class with all abstract
     * methods of the class mocked. Concrete methods to mock can be specified with
     * the last parameter
     *
     * @return object
     * @since  Method available since Release 1.0.0
     */
    private static function generateMockForAbstractClass()
    {
        return self::doGenerateMock(func_get_args(), true);
    }

    private static function doGenerateMock($args, $isAbstract = false)
    {
        $testCase = self::extractTestCaseFromArgs($args);
        $methodName = $isAbstract ? 'getMockForAbstractClass' : 'getMock';
        $generatorClass = new Generator;

        // using PHPUnit 5.4 mocks registration
        if (version_compare(\PHPUnit\Runner\Version::series(), '5.4', '>=')
            && $testCase instanceof \PHPUnit\Framework\TestCase
        ) {
            $mock = call_user_func_array([$generatorClass, $methodName], $args);
            $testCase->registerMockObject($mock);
            return $mock;
        }
        if ($testCase instanceof  \PHPUnit\Framework\TestCase) {
            $generatorClass = $testCase;
        }
        return call_user_func_array([$generatorClass, $methodName], $args);
    }

    private static function extractTestCaseFromArgs(&$args)
    {
        $argsLength = count($args) - 1;
        $testCase = $args[$argsLength];

        unset($args[$argsLength]);

        return $testCase;
    }

    /**
     * Replaces properties of current stub
     *
     * @param \PHPUnit\Framework\MockObject\MockObject $mock
     * @param array $params
     *
     * @return mixed
     * @throws \LogicException
     */
    public static function update($mock, array $params)
    {
        //do not rely on __mocked property, check typ eof $mock
        if (!$mock instanceof \PHPUnit\Framework\MockObject\MockObject) {
            throw new \LogicException('You can update only stubbed objects');
        }

        self::bindParameters($mock, $params);

        return $mock;
    }

    /**
     * @param \PHPUnit\Framework\MockObject\MockObject $mock
     * @param array $params
     * @throws \LogicException
     */
    protected static function bindParameters($mock, $params)
    {
        $reflectionClass = new \ReflectionClass($mock);
        if ($mock instanceof \PHPUnit\Framework\MockObject\MockObject) {
            $parentClass = $reflectionClass->getParentClass();
            if ($parentClass !== false) {
                $reflectionClass = $reflectionClass->getParentClass();
            }
        }

        foreach ($params as $param => $value) {
            // redefine method
            if ($reflectionClass->hasMethod($param)) {
                if ($value instanceof StubMarshaler) {
                    $marshaler = $value;
                    $mock
                        ->expects($marshaler->getMatcher())
                        ->method($param)
                        ->will(new ReturnCallback($marshaler->getValue()));
                } elseif ($value instanceof \Closure) {
                    $mock
                        ->expects(new AnyInvokedCount)
                        ->method($param)
                        ->will(new ReturnCallback($value));
                } elseif ($value instanceof ConsecutiveMap) {
                    $consecutiveMap = $value;
                    $mock
                        ->expects(new AnyInvokedCount)
                        ->method($param)
                        ->will(new ConsecutiveCalls($consecutiveMap->getMap()));
                } else {
                    $mock
                        ->expects(new AnyInvokedCount)
                        ->method($param)
                        ->will(new ReturnStub($value));
                }
            } elseif ($reflectionClass->hasProperty($param)) {
                $reflectionProperty = $reflectionClass->getProperty($param);
                $reflectionProperty->setAccessible(true);
                $reflectionProperty->setValue($mock, $value);
                continue;
            } else {
                if ($reflectionClass->hasMethod('__set')) {
                    try {
                        $mock->{$param} = $value;
                    } catch (\Exception $e) {
                        throw new \LogicException(
                            sprintf(
                                'Could not add property %1$s, class %2$s implements __set method, '
                                . 'and no %1$s property exists',
                                $param,
                                $reflectionClass->getName()
                            ),
                            $e->getCode(),
                            $e
                        );
                    }
                } else {
                    $mock->{$param} = $value;
                }
                continue;
            }
        }
    }

    /**
     * @todo should be simplified
     */
    protected static function getClassname($object)
    {
        if (is_object($object)) {
            return get_class($object);
        }

        if (is_callable($object)) {
            return call_user_func($object);
        }

        return $object;
    }

    /**
     * @param \ReflectionClass $reflection
     * @param $params
     * @return array
     */
    protected static function getMethodsToReplace(\ReflectionClass $reflection, $params)
    {
        $callables = [];
        foreach ($params as $method => $value) {
            if ($reflection->hasMethod($method)) {
                $callables[$method] = $value;
            }
        }

        return $callables;
    }


    /**
     * Stubbing a method call to return a list of values in the specified order.
     *
     * ``` php
     * <?php
     * $user = Stub::make('User', ['getName' => Stub::consecutive('david', 'emma', 'sam', 'amy')]);
     * $user->getName(); //david
     * $user->getName(); //emma
     * $user->getName(); //sam
     * $user->getName(); //amy
     * ?>
     * ```
     *
     * @return ConsecutiveMap
     */
    public static function consecutive()
    {
        return new ConsecutiveMap(func_get_args());
    }
}
<?php

namespace Codeception\Stub;

use PHPUnit\Framework\MockObject\Rule\InvokedAtLeastOnce;
use PHPUnit\Framework\MockObject\Rule\InvokedCount;

class Expected
{
    /**
     * Checks if a method never has been invoked
     *
     * If method invoked, it will immediately throw an
     * exception.
     *
     * ```php
     * <?php
     * use \Codeception\Stub\Expected;
     *
     * $user = $this->make('User', [
     *      'getName' => Expected::never(),
     *      'someMethod' => function() {}
     * ]);
     * $user->someMethod();
     * ?>
     * ```
     *
     * @param mixed $params
     * @return StubMarshaler
     */
    public static function never($params = null)
    {
        return new StubMarshaler(
            new InvokedCount(0),
            self::closureIfNull($params)
        );
    }

    /**
     * Checks if a method has been invoked exactly one
     * time.
     *
     * If the number is less or greater it will later be checked in verify() and also throw an
     * exception.
     *
     * ```php
     * <?php
     * use \Codeception\Stub\Expected;
     *
     * $user = $this->make(
     *     'User',
     *     array(
     *         'getName' => Expected::once('Davert'),
     *         'someMethod' => function() {}
     *     )
     * );
     * $userName = $user->getName();
     * $this->assertEquals('Davert', $userName);
     * ?>
     * ```
     * Alternatively, a function can be passed as parameter:
     *
     * ```php
     * <?php
     * Expected::once(function() { return Faker::name(); });
     * ```
     *
     * @param mixed $params
     *
     * @return StubMarshaler
     */
    public static function once($params = null)
    {
        return new StubMarshaler(
            new InvokedCount(1),
            self::closureIfNull($params)
        );
    }

    /**
     * Checks if a method has been invoked at least one
     * time.
     *
     * If the number of invocations is 0 it will throw an exception in verify.
     *
     * ```php
     * <?php
     * use \Codeception\Stub\Expected;
     *
     * $user = $this->make(
     *     'User',
     *     array(
     *         'getName' => Expected::atLeastOnce('Davert')),
     *         'someMethod' => function() {}
     *     )
     * );
     * $user->getName();
     * $userName = $user->getName();
     * $this->assertEquals('Davert', $userName);
     * ?>
     * ```
     *
     * Alternatively, a function can be passed as parameter:
     *
     * ```php
     * <?php
     * Expected::atLeastOnce(function() { return Faker::name(); });
     * ```
     *
     * @param mixed $params
     *
     * @return StubMarshaler
     */
    public static function atLeastOnce($params = null)
    {
        return new StubMarshaler(
            new InvokedAtLeastOnce(),
            self::closureIfNull($params)
        );
    }

    /**
     * Checks if a method has been invoked a certain amount
     * of times.
     * If the number of invocations exceeds the value it will immediately throw an
     * exception,
     * If the number is less it will later be checked in verify() and also throw an
     * exception.
     *
     * ``` php
     * <?php
     * use \Codeception\Stub;
     * use \Codeception\Stub\Expected;
     *
     * $user = $this->make(
     *     'User',
     *     array(
     *         'getName' => Expected::exactly(3, 'Davert'),
     *         'someMethod' => function() {}
     *     )
     * );
     * $user->getName();
     * $user->getName();
     * $userName = $user->getName();
     * $this->assertEquals('Davert', $userName);
     * ?>
     * ```
     * Alternatively, a function can be passed as parameter:
     *
     * ```php
     * <?php
     * Expected::exactly(function() { return Faker::name() });
     * ```
     *
     * @param int $count
     * @param mixed $params
     *
     * @return StubMarshaler
     */
    public static function exactly($count, $params = null)
    {
        return new StubMarshaler(
            new InvokedCount($count),
            self::closureIfNull($params)
        );
    }

    private static function closureIfNull($params)
    {
        if ($params instanceof \Closure) {
            return $params;
        }
        return function() use ($params) {
            return $params;
        };
    }

}<?php

namespace Codeception\Stub;

/**
 * Holds matcher and value of mocked method
 */
class ConsecutiveMap
{
    private $consecutiveMap = [];
    public function __construct(array $consecutiveMap)
    {
        $this->consecutiveMap = $consecutiveMap;
    }
    public function getMap()
    {
        return $this->consecutiveMap;
    }
}<?php

namespace Codeception\Stub;

use PHPUnit\Framework\MockObject\Rule\InvocationOrder;

/**
 * Holds matcher and value of mocked method
 */
class StubMarshaler
{
    private $methodMatcher;

    private $methodValue;

    public function __construct(InvocationOrder $matcher, $value)
    {
        $this->methodMatcher = $matcher;
        $this->methodValue = $value;
    }

    public function getMatcher()
    {
        return $this->methodMatcher;
    }

    public function getValue()
    {
        return $this->methodValue;
    }
}
<?php
require_once 'vendor/autoload.php';
/**
 * This is project's console commands configuration for Robo task runner.
 *
 * @see http://robo.li/
 */
class RoboFile extends \Robo\Tasks
{
    protected $docs = [
        'docs/Stub.md' => 'Codeception\Stub',
        'docs/Expected.md' => 'Codeception\Stub\Expected',
        'docs/StubTrait.md' => 'Codeception\Test\Feature\Stub',
    ];

    public function docs()
    {
        foreach ($this->docs as $file => $class) {
            if (!class_exists($class, true) && !trait_exists($class, true)) {
                throw new Exception('ups');
            }
            $this->say("Here goes, $class");
            $this->taskGenDoc($file)
                ->docClass($class)
                ->filterMethods(function(\ReflectionMethod $method) {
                    if ($method->isConstructor() or $method->isDestructor()) return false;
                    if (!$method->isPublic()) return false;
                    if (strpos($method->name, '_') === 0) return false;
                    if (strpos($method->name, 'stub') === 0) return false;
                    return true;
                })
                ->processMethodDocBlock(
                    function (\ReflectionMethod $m, $doc) {
                        $doc = str_replace(array('@since'), array(' * available since version'), $doc);
                        $doc = str_replace(array(' @', "\n@"), array("  * ", "\n * "), $doc);
                        return $doc;
                    })
                ->processProperty(false)
                ->run();
        }
    }
}<?php
namespace Codeception\Module;

use Codeception\TestInterface;
use Codeception\Exception\ModuleException;

/**
 *
 * Works with SFTP/FTP servers.
 *
 * In order to test the contents of a specific file stored on any remote FTP/SFTP system
 * this module downloads a temporary file to the local system. The temporary directory is
 * defined by default as ```tests/_data``` to specify a different directory set the tmp config
 * option to your chosen path.
 *
 * Don't forget to create the folder and ensure its writable.
 *
 * Supported and tested FTP types are:
 *
 * * FTP
 * * SFTP
 *
 * Connection uses php build in FTP client for FTP,
 * connection to SFTP uses [phpseclib](http://phpseclib.sourceforge.net/) pulled in using composer.
 *
 * For SFTP, add [phpseclib](http://phpseclib.sourceforge.net/) to require list.
 * ```
 * "require": {
 *  "phpseclib/phpseclib": "^2.0.14"
 * }
 * ```
 *
 * ## Status
 *
 * * Stability:
 *     - FTP: **stable**
 *     - SFTP: **stable**
 *
 * ## Config
 *
 * * type: ftp - type of connection ftp/sftp (defaults to ftp).
 * * host *required* - hostname/ip address of the ftp server.
 * * port: 21 - port number for the ftp server
 * * timeout: 90 - timeout settings for connecting the ftp server.
 * * user: anonymous - user to access ftp server, defaults to anonymous authentication.
 * * password - password, defaults to empty for anonymous.
 * * key - path to RSA key for sftp.
 * * tmp - path to local directory for storing tmp files.
 * * passive: true - Turns on or off passive mode (FTP only)
 * * cleanup: true - remove tmp files from local directory on completion.
 *
 * ### Example
 * #### Example (FTP)
 *
 *     modules:
 *        enabled: [FTP]
 *        config:
 *           FTP:
 *              type: ftp
 *              host: '127.0.0.1'
 *              port: 21
 *              timeout: 120
 *              user: 'root'
 *              password: 'root'
 *              key: ~/.ssh/id_rsa
 *              tmp: 'tests/_data/ftp'
 *              passive: true
 *              cleanup: false
 *
 * #### Example (SFTP)
 *
 *     modules:
 *        enabled: [FTP]
 *        config:
 *           FTP:
 *              type: sftp
 *              host: '127.0.0.1'
 *              port: 22
 *              timeout: 120
 *              user: 'root'
 *              password: 'root'
 *              key: ''
 *              tmp: 'tests/_data/ftp'
 *              cleanup: false
 *
 *
 * This module extends the Filesystem module, file contents methods are inherited from this module.
 */

class FTP extends Filesystem
{
    /**
     * FTP/SFTP connection handler
     */
    protected $ftp = null;

    /**
     * Configuration options and default settings
     *
     * @var array
     */
    protected $config = [
        'type'     => 'ftp',
        'port'     => 21,
        'timeout'  => 90,
        'user'     => 'anonymous',
        'password' => '',
        'key'      => '',
        'tmp'      => 'tests/_data',
        'passive'  => false,
        'cleanup'  => true
    ];

    /**
     * Required configuration fields
     *
     * @var array
     */
    protected $requiredFields = ['host'];

    // ----------- SETUP METHODS BELOW HERE -------------------------//

    /**
     * Setup connection and login with config settings
     *
     * @param \Codeception\TestInterface $test
     */
    public function _before(TestInterface $test)
    {
        // Login using config settings
        $this->loginAs($this->config['user'], $this->config['password']);
    }

    /**
     * Close the FTP connection & Clear up
     */
    public function _after(TestInterface $test)
    {
        $this->_closeConnection();

        // Clean up temp files
        if ($this->config['cleanup']) {
            if (file_exists($this->config['tmp'] . '/ftp_data_file.tmp')) {
                unlink($this->config['tmp'] . '/ftp_data_file.tmp');
            }
        }
    }

    /**
     * Change the logged in user mid-way through your test, this closes the
     * current connection to the server and initialises and new connection.
     *
     * On initiation of this modules you are automatically logged into
     * the server using the specified config options or defaulted
     * to anonymous user if not provided.
     *
     * ``` php
     * <?php
     * $I->loginAs('user','password');
     * ?>
     * ```
     *
     * @param String $user
     * @param String $password
     */
    public function loginAs($user = 'anonymous', $password = '')
    {
        $this->_openConnection($user, $password); // Create new connection and login.
    }

    /**
     * Enters a directory on the ftp system - FTP root directory is used by default
     *
     * @param $path
     */
    public function amInPath($path)
    {
        $this->_changeDirectory($this->path = $this->absolutizePath($path) . ($path == '/' ? '' : DIRECTORY_SEPARATOR));
        $this->debug('Moved to ' . $this->path);
    }

    /**
     * Resolve path
     *
     * @param $path
     * @return string
     */
    protected function absolutizePath($path)
    {
        if (strpos($path, '/') === 0) {
            return $path;
        }
        return $this->path . $path;
    }

    // ----------- SEARCH METHODS BELOW HERE ------------------------//

    /**
     * Checks if file exists in path on the remote FTP/SFTP system.
     * DOES NOT OPEN the file when it's exists
     *
     * ``` php
     * <?php
     * $I->seeFileFound('UserModel.php','app/models');
     * ?>
     * ```
     *
     * @param $filename
     * @param string $path
     */
    public function seeFileFound($filename, $path = '')
    {
        $files = $this->grabFileList($path);
        $this->debug("see file: {$filename}");
        $this->assertContains($filename, $files, "file {$filename} not found in {$path}");
    }

    /**
     * Checks if file exists in path on the remote FTP/SFTP system, using regular expression as filename.
     * DOES NOT OPEN the file when it's exists
     *
     *  ``` php
     * <?php
     * $I->seeFileFoundMatches('/^UserModel_([0-9]{6}).php$/','app/models');
     * ?>
     * ```
     *
     * @param $regex
     * @param string $path
     */
    public function seeFileFoundMatches($regex, $path = '')
    {
        foreach ($this->grabFileList($path) as $filename) {
            preg_match($regex, $filename, $matches);
            if (!empty($matches)) {
                $this->debug("file '{$filename}' matches '{$regex}'");
                return;
            }
        }
        $this->fail("no file matches found for '{$regex}'");
    }

    /**
     * Checks if file does not exist in path on the remote FTP/SFTP system
     *
     * @param $filename
     * @param string $path
     */
    public function dontSeeFileFound($filename, $path = '')
    {
        $files = $this->grabFileList($path);
        $this->debug("don't see file: {$filename}");
        $this->assertNotContains($filename, $files);
    }

    /**
     * Checks if file does not exist in path on the remote FTP/SFTP system, using regular expression as filename.
     * DOES NOT OPEN the file when it's exists
     *
     * @param $regex
     * @param string $path
     */
    public function dontSeeFileFoundMatches($regex, $path = '')
    {
        foreach ($this->grabFileList($path) as $filename) {
            preg_match($regex, $filename, $matches);
            if (!empty($matches)) {
                $this->fail("file matches found for {$regex}");
            }
        }
        $this->assertTrue(true);
        $this->debug("no files match '{$regex}'");
    }

    // ----------- UTILITY METHODS BELOW HERE -------------------------//

    /**
     * Opens a file (downloads from the remote FTP/SFTP system to a tmp directory for processing)
     * and stores it's content.
     *
     * Usage:
     *
     * ``` php
     * <?php
     * $I->openFile('composer.json');
     * $I->seeInThisFile('codeception/codeception');
     * ?>
     * ```
     *
     * @param $filename
     */
    public function openFile($filename)
    {
        $this->_openFile($this->absolutizePath($filename));
    }

    /**
     * Saves contents to tmp file and uploads the FTP/SFTP system.
     * Overwrites current file on server if exists.
     *
     * ``` php
     * <?php
     * $I->writeToFile('composer.json', 'some data here');
     * ?>
     * ```
     *
     * @param $filename
     * @param $contents
     */
    public function writeToFile($filename, $contents)
    {
        $this->_writeToFile($this->absolutizePath($filename), $contents);
    }

    /**
     * Create a directory on the server
     *
     * ``` php
     * <?php
     * $I->makeDir('vendor');
     * ?>
     * ```
     *
     * @param $dirname
     */
    public function makeDir($dirname)
    {
        $this->makeDirectory($this->absolutizePath($dirname));
    }

    /**
     * Currently not supported in this module, overwrite inherited method
     *
     * @param $src
     * @param $dst
     */
    public function copyDir($src, $dst)
    {
        $this->fail('copyDir() currently unsupported by FTP module');
    }

    /**
     * Rename/Move file on the FTP/SFTP server
     *
     * ``` php
     * <?php
     * $I->renameFile('composer.lock', 'composer_old.lock');
     * ?>
     * ```
     *
     * @param $filename
     * @param $rename
     */
    public function renameFile($filename, $rename)
    {
        $this->renameDirectory($this->absolutizePath($filename), $this->absolutizePath($rename));
    }

    /**
     * Rename/Move directory on the FTP/SFTP server
     *
     * ``` php
     * <?php
     * $I->renameDir('vendor', 'vendor_old');
     * ?>
     * ```
     *
     * @param $dirname
     * @param $rename
     */
    public function renameDir($dirname, $rename)
    {
        $this->renameDirectory($this->absolutizePath($dirname), $this->absolutizePath($rename));
    }

    /**
     * Deletes a file on the remote FTP/SFTP system
     *
     * ``` php
     * <?php
     * $I->deleteFile('composer.lock');
     * ?>
     * ```
     *
     * @param $filename
     */
    public function deleteFile($filename)
    {
        $this->delete($this->absolutizePath($filename));
    }

    /**
     * Deletes directory with all subdirectories on the remote FTP/SFTP server
     *
     * ``` php
     * <?php
     * $I->deleteDir('vendor');
     * ?>
     * ```
     *
     * @param $dirname
     */
    public function deleteDir($dirname)
    {
        $this->delete($this->absolutizePath($dirname));
    }

    /**
     * Erases directory contents on the FTP/SFTP server
     *
     * ``` php
     * <?php
     * $I->cleanDir('logs');
     * ?>
     * ```
     *
     * @param $dirname
     */
    public function cleanDir($dirname)
    {
        $this->clearDirectory($this->absolutizePath($dirname));
    }

    // ----------- GRABBER METHODS BELOW HERE -----------------------//


    /**
     * Grabber method for returning file/folders listing in an array
     *
     * ```php
     * <?php
     * $files = $I->grabFileList();
     * $count = $I->grabFileList('TEST', false); // Include . .. .thumbs.db
     * ?>
     * ```
     *
     * @param string $path
     * @param bool $ignore - suppress '.', '..' and '.thumbs.db'
     * @return array
     */
    public function grabFileList($path = '', $ignore = true)
    {
        $absolutize_path = $this->absolutizePath($path)
            . ($path != '' && substr($path, -1) != '/' ? DIRECTORY_SEPARATOR : '');
        $files = $this->_listFiles($absolutize_path);

        $display_files = [];
        if (is_array($files) && !empty($files)) {
            $this->debug('File List:');
            foreach ($files as &$file) {
                if (strtolower($file) != '.' &&
                    strtolower($file) != '..' &&
                    strtolower($file) != 'thumbs.db'
                ) { // Ignore '.', '..' and 'thumbs.db'
                    // Replace full path from file listings if returned in listing
                    $file = str_replace(
                        $absolutize_path,
                        '',
                        $file
                    );
                    $display_files[] = $file;
                    $this->debug('    - ' . $file);
                }
            }
            return $ignore ? $display_files : $files;
        }
        $this->debug("File List: <empty>");
        return [];
    }

    /**
     * Grabber method for returning file/folders count in directory
     *
     * ```php
     * <?php
     * $count = $I->grabFileCount();
     * $count = $I->grabFileCount('TEST', false); // Include . .. .thumbs.db
     * ?>
     * ```
     *
     * @param string $path
     * @param bool $ignore - suppress '.', '..' and '.thumbs.db'
     * @return int
     */
    public function grabFileCount($path = '', $ignore = true)
    {
        $count = count($this->grabFileList($path, $ignore));
        $this->debug("File Count: {$count}");
        return $count;
    }

    /**
     * Grabber method to return file size
     *
     * ```php
     * <?php
     * $size = $I->grabFileSize('test.txt');
     * ?>
     * ```
     *
     * @param $filename
     * @return bool
     */
    public function grabFileSize($filename)
    {
        $fileSize = $this->size($filename);
        $this->debug("{$filename} has a file size of {$fileSize}");
        return $fileSize;
    }

    /**
     * Grabber method to return last modified timestamp
     *
     * ```php
     * <?php
     * $time = $I->grabFileModified('test.txt');
     * ?>
     * ```
     *
     * @param $filename
     * @return bool
     */
    public function grabFileModified($filename)
    {
        $time = $this->modified($filename);
        $this->debug("{$filename} was last modified at {$time}");
        return $time;
    }

    /**
     * Grabber method to return current working directory
     *
     * ```php
     * <?php
     * $pwd = $I->grabDirectory();
     * ?>
     * ```
     *
     * @return string
     */
    public function grabDirectory()
    {
        $pwd = $this->_directory();
        $this->debug("PWD: {$pwd}");
        return $pwd;
    }

    // ----------- SERVER CONNECTION METHODS BELOW HERE -------------//

    /**
     * Open a new FTP/SFTP connection and authenticate user.
     *
     * @param string $user
     * @param string $password
     */
    private function _openConnection($user = 'anonymous', $password = '')
    {
        $this->_closeConnection();   // Close connection if already open
        if ($this->isSFTP()) {
            $this->sftpConnect($user, $password);
        } else {
            $this->ftpConnect($user, $password);
        }
        $pwd = $this->grabDirectory();
        $this->path = $pwd . ($pwd == '/' ? '' : DIRECTORY_SEPARATOR);
    }

    /**
     * Close open FTP/SFTP connection
     */
    private function _closeConnection()
    {
        if (!$this->ftp) {
            return;
        }
        if (!$this->isSFTP()) {
            ftp_close($this->ftp);
            $this->ftp = null;
        }
    }

    /**
     * Get the file listing for FTP/SFTP connection
     *
     * @param String $path
     * @return array
     */
    private function _listFiles($path)
    {
        if ($this->isSFTP()) {
            $files = @$this->ftp->nlist($path);
        } else {
            $files = @ftp_nlist($this->ftp, $path);
        }
        if ($files === false) {
            $this->fail("couldn't list files");
        }
        return $files;
    }

    /**
     * Get the current directory for the FTP/SFTP connection
     *
     * @return string
     */
    private function _directory()
    {
        if ($this->isSFTP()) {
            // == DIRECTORY_SEPARATOR ? '' : $pwd;
            $pwd = @$this->ftp->pwd();
        } else {
            $pwd = @ftp_pwd($this->ftp);
        }
        if (!$pwd) {
            $this->fail("couldn't get current directory");
        }
        return $pwd;
    }

    /**
     * Change the working directory on the FTP/SFTP server
     *
     * @param $path
     */
    private function _changeDirectory($path)
    {
        if ($this->isSFTP()) {
            $changed = @$this->ftp->chdir($path);
        } else {
            $changed = @ftp_chdir($this->ftp, $path);
        }
        if (!$changed) {
            $this->fail("couldn't change directory {$path}");
        }
    }

    /**
     * Download remote file to local tmp directory and open contents.
     *
     * @param $filename
     */
    private function _openFile($filename)
    {
        // Check local tmp directory
        if (!is_dir($this->config['tmp']) || !is_writeable($this->config['tmp'])) {
            $this->fail('tmp directory not found or is not writable');
        }

        // Download file to local tmp directory
        $tmp_file = $this->config['tmp'] . "/ftp_data_file.tmp";

        if ($this->isSFTP()) {
            $downloaded = @$this->ftp->get($filename, $tmp_file);
        } else {
            $downloaded = @ftp_get($this->ftp, $tmp_file, $filename, FTP_BINARY);
        }
        if (!$downloaded) {
            $this->fail('failed to download file to tmp directory');
        }

        // Open file content to variable
        if ($this->file = file_get_contents($tmp_file)) {
            $this->filepath = $filename;
        } else {
            $this->fail('failed to open tmp file');
        }
    }

    /**
     * Write data to local tmp file and upload to server
     *
     * @param $filename
     * @param $contents
     */
    private function _writeToFile($filename, $contents)
    {
        // Check local tmp directory
        if (!is_dir($this->config['tmp']) || !is_writeable($this->config['tmp'])) {
            $this->fail('tmp directory not found or is not writable');
        }

        // Build temp file
        $tmp_file = $this->config['tmp'] . "/ftp_data_file.tmp";
        file_put_contents($tmp_file, $contents);

        // Update variables
        $this->filepath = $filename;
        $this->file = $contents;

        // Upload the file to server
        if ($this->isSFTP()) {
            $flag = defined('NET_SFTP_LOCAL_FILE') ? NET_SFTP_LOCAL_FILE : \phpseclib\Net\SFTP::SOURCE_LOCAL_FILE;

            $uploaded = @$this->ftp->put($filename, $tmp_file, $flag);
        } else {
            $uploaded = ftp_put($this->ftp, $filename, $tmp_file, FTP_BINARY);
        }
        if (!$uploaded) {
            $this->fail('failed to upload file to server');
        }
    }

    /**
     * Make new directory on server
     *
     * @param $path
     */
    private function makeDirectory($path)
    {
        if ($this->isSFTP()) {
            $created = @$this->ftp->mkdir($path, true);
        } else {
            $created = @ftp_mkdir($this->ftp, $path);
        }
        if (!$created) {
            $this->fail("couldn't make directory {$path}");
        }
        $this->debug("Make directory: {$path}");
    }

    /**
     * Rename/Move directory/file on server
     *
     * @param $path
     * @param $rename
     */
    private function renameDirectory($path, $rename)
    {
        if ($this->isSFTP()) {
            $renamed = @$this->ftp->rename($path, $rename);
        } else {
            $renamed = @ftp_rename($this->ftp, $path, $rename);
        }
        if (!$renamed) {
            $this->fail("couldn't rename directory {$path} to {$rename}");
        }
        $this->debug("Renamed directory: {$path} to {$rename}");
    }

    /**
     * Delete file on server
     *
     * @param $filename
     */
    private function delete($filename, $isDir = false)
    {
        if ($this->isSFTP()) {
            $deleted = @$this->ftp->delete($filename, $isDir);
        } else {
            $deleted = @$this->ftpDelete($filename);
        }
        if (!$deleted) {
            $this->fail("couldn't delete {$filename}");
        }
        $this->debug("Deleted: {$filename}");
    }


    /**
     * Function to recursively delete folder, used for PHP FTP build in client.
     *
     * @param $directory
     * @return bool
     */
    private function ftpDelete($directory)
    {
        // here we attempt to delete the file/directory
        if (!(@ftp_rmdir($this->ftp, $directory) || @ftp_delete($this->ftp, $directory))) {
            // if the attempt to delete fails, get the file listing
            $filelist = @ftp_nlist($this->ftp, $directory);

            // loop through the file list and recursively delete the FILE in the list
            foreach ($filelist as $file) {
                $this->ftpDelete($file);
            }

            // if the file list is empty, delete the DIRECTORY we passed
            $this->ftpDelete($directory);
        }
        return true;
    }

    /**
     * Clear directory on server of all content
     *
     * @param $path
     */
    private function clearDirectory($path)
    {
        $this->debug("Clear directory: {$path}");
        $this->delete($path);
        $this->makeDirectory($path);
    }

    /**
     * Return the size of a given file
     *
     * @param $filename
     * @return bool
     */
    private function size($filename)
    {
        if ($this->isSFTP()) {
            $size = (int)@$this->ftp->size($filename);
        } else {
            $size = @ftp_size($this->ftp, $filename);
        }
        if ($size > 0) {
            return $size;
        }
        $this->fail("couldn't get the file size for {$filename}");
    }

    /**
     * Return the last modified time of a given file
     *
     * @param $filename
     * @return bool
     */
    private function modified($filename)
    {
        if ($this->isSFTP()) {
            $info = @$this->ftp->lstat($filename);
            if ($info) {
                return $info['mtime'];
            }
        } else {
            if ($time = @ftp_mdtm($this->ftp, $filename)) {
                return $time;
            }
        }
        $this->fail("couldn't get the file size for {$filename}");
    }

    /**
     * @param $user
     * @param $password
     */
    protected function sftpConnect($user, $password)
    {
        if (class_exists('Net_SFTP')) {
            $this->ftp = new \Net_SFTP($this->config['host'], $this->config['port'], $this->config['timeout']);
        } elseif (class_exists('phpseclib\Net\SFTP')) {
            $this->ftp = new \phpseclib\Net\SFTP($this->config['host'], $this->config['port'], $this->config['timeout']);
        } else {
            throw new ModuleException('FTP', 'phpseclib/phpseclib library is not installed');
        }

        if ($this->ftp === false) {
            $this->ftp = null;
            $this->fail('failed to connect to ftp server');
        }

        if (!empty($this->config['key'])) {
            $keyFile = file_get_contents($this->config['key']);

            if (class_exists('Crypt_RSA')) {
                $password = new \Crypt_RSA();
            } elseif (class_exists('phpseclib\Crypt\RSA')) {
                $password = new \phpseclib\Crypt\RSA();
            } else {
                throw new ModuleException('FTP', 'phpseclib/phpseclib library is not installed');
            }

            $password->loadKey($keyFile);
        }

        if (!$this->ftp->login($user, $password)) {
            $this->fail('failed to authenticate user');
        }
    }

    /**
     * @param $user
     * @param $password
     */
    protected function ftpConnect($user, $password)
    {
        $this->ftp = ftp_connect($this->config['host'], $this->config['port'], $this->config['timeout']);
        if ($this->ftp === false) {
            $this->ftp = null;
            $this->fail('failed to connect to ftp server');
        }

        // Login using given access details
        if (!@ftp_login($this->ftp, $user, $password)) {
            $this->fail('failed to authenticate user');
        }

        // Set passive mode option (ftp only option)
        if (isset($this->config['passive'])) {
            ftp_pasv($this->ftp, $this->config['passive']);
        }
    }

    protected function isSFTP()
    {
        return strtolower($this->config['type']) == 'sftp';
    }
}
<?php
namespace Codeception\Module;

use Codeception\Module as CodeceptionModule;
use Codeception\TestInterface;
use Codeception\Exception\ModuleConfigException;

/**
 * Connects to [memcached](http://www.memcached.org/) using either _Memcache_ or _Memcached_ extension.
 *
 * Performs a cleanup by flushing all values after each test run.
 *
 * ## Status
 *
 * * Maintainer: **davert**
 * * Stability: **beta**
 * * Contact: davert@codeception.com
 *
 * ## Configuration
 *
 * * **`host`** (`string`, default `'localhost'`) - The memcached host
 * * **`port`** (`int`, default `11211`) - The memcached port
 *
 * ### Example (`unit.suite.yml`)
 *
 * ```yaml
 *    modules:
 *        - Memcache:
 *            host: 'localhost'
 *            port: 11211
 * ```
 *
 * Be sure you don't use the production server to connect.
 *
 * ## Public Properties
 *
 * * **memcache** - instance of _Memcache_ or _Memcached_ object
 *
 */
class Memcache extends CodeceptionModule
{
    /**
     * @var \Memcache|\Memcached
     */
    public $memcache = null;

    /**
     * {@inheritdoc}
     */
    protected $config = [
        'host' => 'localhost',
        'port' => 11211
    ];

    /**
     * Code to run before each test.
     *
     * @param TestInterface $test
     * @throws ModuleConfigException
     */
    public function _before(TestInterface $test)
    {
        if (class_exists('\Memcache')) {
            $this->memcache = new \Memcache;
            $this->memcache->connect($this->config['host'], $this->config['port']);
        } elseif (class_exists('\Memcached')) {
            $this->memcache = new \Memcached;
            $this->memcache->addServer($this->config['host'], $this->config['port']);
        } else {
            throw new ModuleConfigException(__CLASS__, 'Memcache classes not loaded');
        }
    }

    /**
     * Code to run after each test.
     *
     * @param TestInterface $test
     */
    public function _after(TestInterface $test)
    {
        if (empty($this->memcache)) {
            return;
        }

        $this->memcache->flush();
        switch (get_class($this->memcache)) {
            case 'Memcache':
                $this->memcache->close();
                break;
            case 'Memcached':
                $this->memcache->quit();
                break;
        }
    }

    /**
     * Grabs value from memcached by key.
     *
     * Example:
     *
     * ``` php
     * <?php
     * $users_count = $I->grabValueFromMemcached('users_count');
     * ?>
     * ```
     *
     * @param $key
     * @return array|string
     */
    public function grabValueFromMemcached($key)
    {
        $value = $this->memcache->get($key);
        $this->debugSection("Value", $value);

        return $value;
    }

    /**
     * Checks item in Memcached exists and the same as expected.
     *
     * Examples:
     *
     * ``` php
     * <?php
     * // With only one argument, only checks the key exists
     * $I->seeInMemcached('users_count');
     *
     * // Checks a 'users_count' exists and has the value 200
     * $I->seeInMemcached('users_count', 200);
     * ?>
     * ```
     *
     * @param $key
     * @param $value
     */
    public function seeInMemcached($key, $value = null)
    {
        $actual = $this->memcache->get($key);
        $this->debugSection("Value", $actual);

        if (null === $value) {
            $this->assertNotFalse($actual, "Cannot find key '$key' in Memcached");
        } else {
            $this->assertEquals($value, $actual, "Cannot find key '$key' in Memcached with the provided value");
        }
    }

    /**
     * Checks item in Memcached doesn't exist or is the same as expected.
     *
     * Examples:
     *
     * ``` php
     * <?php
     * // With only one argument, only checks the key does not exist
     * $I->dontSeeInMemcached('users_count');
     *
     * // Checks a 'users_count' exists does not exist or its value is not the one provided
     * $I->dontSeeInMemcached('users_count', 200);
     * ?>
     * ```
     *
     * @param $key
     * @param $value
     */
    public function dontSeeInMemcached($key, $value = null)
    {
        $actual = $this->memcache->get($key);
        $this->debugSection("Value", $actual);

        if (null === $value) {
            $this->assertFalse($actual, "The key '$key' exists in Memcached");
        } else {
            if (false !== $actual) {
                $this->assertEquals($value, $actual, "The key '$key' exists in Memcached with the provided value");
            }
        }
    }

    /**
     * Stores an item `$value` with `$key` on the Memcached server.
     *
     * @param string $key
     * @param mixed $value
     * @param int $expiration
     */
    public function haveInMemcached($key, $value, $expiration = null)
    {
        switch (get_class($this->memcache)) {
            case 'Memcache':
                $this->assertTrue($this->memcache->set($key, $value, null, $expiration));
                break;
            case 'Memcached':
                $this->assertTrue($this->memcache->set($key, $value, $expiration));
                break;
        }
    }

    /**
     * Flushes all Memcached data.
     */
    public function clearMemcache()
    {
        $this->memcache->flush();
    }
}
<?php
namespace Codeception\Module;

use Codeception\Module as CodeceptionModule;
use Codeception\TestInterface;

/**
 * Wrapper for basic shell commands and shell output
 *
 * ## Responsibility
 * * Maintainer: **davert**
 * * Status: **stable**
 * * Contact: codecept@davert.mail.ua
 *
 * *Please review the code of non-stable modules and provide patches if you have issues.*
 */
class Cli extends CodeceptionModule
{
    public $output = '';

    public $result = null;

    public function _before(TestInterface $test)
    {
        $this->output = '';
    }

    /**
     * Executes a shell command.
     * Fails if exit code is > 0. You can disable this by passing `false` as second argument
     *
     * ```php
     * <?php
     * $I->runShellCommand('phpunit');
     *
     * // do not fail test when command fails
     * $I->runShellCommand('phpunit', false);
     * ```
     *
     * @param $command
     * @param bool $failNonZero
     */
    public function runShellCommand($command, $failNonZero = true)
    {
        $data = [];
        exec("$command", $data, $resultCode);
        $this->result = $resultCode;
        $this->output = implode("\n", $data);
        if ($this->output === null) {
            \PHPUnit\Framework\Assert::fail("$command can't be executed");
        }
        if ($resultCode !== 0 && $failNonZero) {
            \PHPUnit\Framework\Assert::fail("Result code was $resultCode.\n\n" . $this->output);
        }
        $this->debug(preg_replace('~s/\e\[\d+(?>(;\d+)*)m//g~', '', $this->output));
    }

    /**
     * Checks that output from last executed command contains text
     *
     * @param $text
     */
    public function seeInShellOutput($text)
    {
        \Codeception\PHPUnit\TestCase::assertStringContainsString($text, $this->output);
    }

    /**
     * Checks that output from latest command doesn't contain text
     *
     * @param $text
     *
     */
    public function dontSeeInShellOutput($text)
    {
        $this->debug($this->output);
        \Codeception\PHPUnit\TestCase::assertStringNotContainsString($text, $this->output);
    }

    /**
     * @param $regex
     */
    public function seeShellOutputMatches($regex)
    {
        \Codeception\PHPUnit\TestCase::assertRegExp($regex, $this->output);
    }

    /**
     * Returns the output from latest command
     */
    public function grabShellOutput()
    {
        return $this->output;
    }

    /**
     * Checks result code. To verify a result code > 0, you need to pass `false` as second argument to `runShellCommand()`
     *
     * ```php
     * <?php
     * $I->seeResultCodeIs(0);
     * ```
     *
     * @param $code
     */
    public function seeResultCodeIs($code)
    {
        $this->assertEquals($this->result, $code, "result code is $code");
    }

    /**
     * Checks result code
     *
     * ```php
     * <?php
     * $I->seeResultCodeIsNot(0);
     * ```
     *
     * @param $code
     */
    public function seeResultCodeIsNot($code)
    {
        $this->assertNotEquals($this->result, $code, "result code is $code");
    }
}
<?php
namespace Codeception\Module;

use Codeception\Exception\ModuleException;
use Codeception\Module as CodeceptionModule;
use Codeception\TestInterface;
use Exception;
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Exception\AMQPProtocolChannelException;
use PhpAmqpLib\Message\AMQPMessage;

/**
 * This module interacts with message broker software that implements
 * the Advanced Message Queuing Protocol (AMQP) standard. For example, RabbitMQ (tested).
 *
 * <div class="alert alert-info">
 * To use this module with Composer you need <em>"php-amqplib/php-amqplib": "~2.4"</em> package.
 * </div>
 *
 * ## Config
 *
 * * host: localhost - host to connect
 * * username: guest - username to connect
 * * password: guest - password to connect
 * * vhost: '/' - vhost to connect
 * * cleanup: true - defined queues will be purged before running every test.
 * * queues: [mail, twitter] - queues to cleanup
 * * single_channel - create and use only one channel during test execution
 *
 * ### Example
 *
 *     modules:
 *         enabled:
 *             - AMQP:
 *                 host: 'localhost'
 *                 port: '5672'
 *                 username: 'guest'
 *                 password: 'guest'
 *                 vhost: '/'
 *                 queues: [queue1, queue2]
 *                 single_channel: false
 *
 * ## Public Properties
 *
 * * connection - AMQPStreamConnection - current connection
 */
class AMQP extends CodeceptionModule
{
    protected $config = [
        'host'           => 'localhost',
        'username'       => 'guest',
        'password'       => 'guest',
        'port'           => '5672',
        'vhost'          => '/',
        'cleanup'        => true,
        'single_channel' => false,
        'queues'         => []
    ];

    /**
     * @var AMQPStreamConnection
     */
    public $connection;

    /**
     * @var int
     */
    protected $channelId;

    protected $requiredFields = ['host', 'username', 'password', 'vhost'];

    public function _initialize()
    {
        $host = $this->config['host'];
        $port = $this->config['port'];
        $username = $this->config['username'];
        $password = $this->config['password'];
        $vhost = $this->config['vhost'];

        try {
            $this->connection = new AMQPStreamConnection($host, $port, $username, $password, $vhost);
        } catch (Exception $e) {
            throw new ModuleException(__CLASS__, $e->getMessage() . ' while establishing connection to MQ server');
        }
    }

    public function _before(TestInterface $test)
    {
        if ($this->config['cleanup']) {
            $this->cleanup();
        }
    }

    /**
     * Sends message to exchange by sending exchange name, message
     * and (optionally) a routing key
     *
     * ``` php
     * <?php
     * $I->pushToExchange('exchange.emails', 'thanks');
     * $I->pushToExchange('exchange.emails', new AMQPMessage('Thanks!'));
     * $I->pushToExchange('exchange.emails', new AMQPMessage('Thanks!'), 'severity');
     * ?>
     * ```
     *
     * @param string $exchange
     * @param string|\PhpAmqpLib\Message\AMQPMessage $message
     * @param string $routing_key
     */
    public function pushToExchange($exchange, $message, $routing_key = null)
    {
        $message = $message instanceof AMQPMessage
            ? $message
            : new AMQPMessage($message);
        $this->getChannel()->basic_publish($message, $exchange, $routing_key);
    }

    /**
     * Sends message to queue
     *
     * ``` php
     * <?php
     * $I->pushToQueue('queue.jobs', 'create user');
     * $I->pushToQueue('queue.jobs', new AMQPMessage('create'));
     * ?>
     * ```
     *
     * @param string $queue
     * @param string|\PhpAmqpLib\Message\AMQPMessage $message
     */
    public function pushToQueue($queue, $message)
    {
        $message = $message instanceof AMQPMessage
            ? $message
            : new AMQPMessage($message);

        $this->getChannel()->queue_declare($queue);
        $this->getChannel()->basic_publish($message, '', $queue);
    }

    /**
     * Declares an exchange
     *
     * This is an alias of method `exchange_declare` of `PhpAmqpLib\Channel\AMQPChannel`.
     *
     * ```php
     * <?php
     * $I->declareExchange(
     *     'nameOfMyExchange', // exchange name
     *     'topic' // exchange type
     * )
     * ```
     *
     * @param string $exchange
     * @param string $type
     * @param bool $passive
     * @param bool $durable
     * @param bool $auto_delete
     * @param bool $internal
     * @param bool $nowait
     * @param array $arguments
     * @param int $ticket
     * @return mixed|null
     */
    public function declareExchange(
        $exchange,
        $type,
        $passive = false,
        $durable = false,
        $auto_delete = true,
        $internal = false,
        $nowait = false,
        $arguments = null,
        $ticket = null
    ) {
        return $this->getChannel()->exchange_declare(
            $exchange,
            $type,
            $passive,
            $durable,
            $auto_delete,
            $internal,
            $nowait,
            $arguments,
            $ticket
        );
    }

    /**
     * Declares queue, creates if needed
     *
     * This is an alias of method `queue_declare` of `PhpAmqpLib\Channel\AMQPChannel`.
     *
     * ```php
     * <?php
     * $I->declareQueue(
     *     'nameOfMyQueue', // exchange name
     * )
     * ```
     *
     * @param string $queue
     * @param bool $passive
     * @param bool $durable
     * @param bool $exclusive
     * @param bool $auto_delete
     * @param bool $nowait
     * @param array $arguments
     * @param int $ticket
     * @return mixed|null
     */
    public function declareQueue(
        $queue = '',
        $passive = false,
        $durable = false,
        $exclusive = false,
        $auto_delete = true,
        $nowait = false,
        $arguments = null,
        $ticket = null
    ) {
        return $this->getChannel()->queue_declare(
            $queue,
            $passive,
            $durable,
            $exclusive,
            $auto_delete,
            $nowait,
            $arguments,
            $ticket
        );
    }

    /**
     * Binds a queue to an exchange
     *
     * This is an alias of method `queue_bind` of `PhpAmqpLib\Channel\AMQPChannel`.
     *
     * ```php
     * <?php
     * $I->bindQueueToExchange(
     *     'nameOfMyQueueToBind', // name of the queue
     *     'transactionTracking.transaction', // exchange name to bind to
     *     'your.routing.key' // Optionally, provide a binding key
     * )
     * ```
     *
     * @param string $queue
     * @param string $exchange
     * @param string $routing_key
     * @param bool $nowait
     * @param array $arguments
     * @param int $ticket
     * @return mixed|null
     */
    public function bindQueueToExchange(
        $queue,
        $exchange,
        $routing_key = '',
        $nowait = false,
        $arguments = null,
        $ticket = null
    ) {
        return $this->getChannel()->queue_bind(
            $queue,
            $exchange,
            $routing_key,
            $nowait,
            $arguments,
            $ticket
        );
    }

    /**
     * Add a queue to purge list
     *
     * @param string $queue
     */
    public function scheduleQueueCleanup($queue)
    {
        if (!in_array($queue, $this->config['queues'])) {
            $this->config['queues'][] = $queue;
        }
    }

    /**
     * Checks if message containing text received.
     *
     * **This method drops message from queue**
     * **This method will wait for message. If none is sent the script will stuck**.
     *
     * ``` php
     * <?php
     * $I->pushToQueue('queue.emails', 'Hello, davert');
     * $I->seeMessageInQueueContainsText('queue.emails','davert');
     * ?>
     * ```
     *
     * @param string $queue
     * @param string $text
     */
    public function seeMessageInQueueContainsText($queue, $text)
    {
        $msg = $this->getChannel()->basic_get($queue);
        if (!$msg) {
            $this->fail("Message was not received");
        }
        if (!$msg instanceof AMQPMessage) {
            $this->fail("Received message is not format of AMQPMessage");
        }
        $this->debugSection("Message", $msg->body);
        $this->assertStringContainsString($text, $msg->body);

        $msg->ack();
    }

    /**
     * Count messages in queue.
     *
     * @param string $queue
     *
     * @return int
     */
    public function _countMessage($queue)
    {
        list($queue, $messageCount) = $this->getChannel()->queue_declare($queue, true);
        return $messageCount;
    }

    /**
     * Checks that queue have expected number of message
     *
     * ``` php
     * <?php
     * $I->pushToQueue('queue.emails', 'Hello, davert');
     * $I->seeNumberOfMessagesInQueue('queue.emails',1);
     * ?>
     * ```
     *
     * @param string $queue
     * @param int $expected
     */
    public function seeNumberOfMessagesInQueue($queue, $expected)
    {
        $messageCount = $this->_countMessage($queue);
        $this->assertEquals($expected, $messageCount);
    }

    /**
     * Checks that queue is empty
     *
     * ``` php
     * <?php
     * $I->pushToQueue('queue.emails', 'Hello, davert');
     * $I->purgeQueue('queue.emails');
     * $I->seeQueueIsEmpty('queue.emails');
     * ?>
     * ```
     *
     * @param string $queue
     * @param int $expected
     */
    public function seeQueueIsEmpty($queue)
    {
        $messageCount = $this->_countMessage($queue);
        $this->assertEquals(0, $messageCount);
    }

    /**
     * Checks if queue is not empty.
     *
     * ``` php
     * <?php
     * $I->pushToQueue('queue.emails', 'Hello, davert');
     * $I->dontSeeQueueIsEmpty('queue.emails');
     * ?>
     * ```
     *
     * @param string $queue
     */
    public function dontSeeQueueIsEmpty($queue)
    {
        $messageCount = $this->_countMessage($queue);
        $this->assertNotEquals(0, $messageCount);
    }

    /**
     * Takes last message from queue.
     *
     * ``` php
     * <?php
     * $message = $I->grabMessageFromQueue('queue.emails');
     * ?>
     * ```
     *
     * @param string $queue
     * @return \PhpAmqpLib\Message\AMQPMessage
     */
    public function grabMessageFromQueue($queue)
    {
        $message = $this->getChannel()->basic_get($queue);
        return $message;
    }

    /**
     * Purge a specific queue defined in config.
     *
     * ``` php
     * <?php
     * $I->purgeQueue('queue.emails');
     * ?>
     * ```
     *
     * @param string $queueName
     */
    public function purgeQueue($queueName = '')
    {
        if (! in_array($queueName, $this->config['queues'])) {
            throw new ModuleException(__CLASS__, "'$queueName' doesn't exist in queues config list");
        }

        $this->getChannel()->queue_purge($queueName, true);
    }

    /**
     * Purge all queues defined in config.
     *
     * ``` php
     * <?php
     * $I->purgeAllQueues();
     * ?>
     * ```
     */
    public function purgeAllQueues()
    {
        $this->cleanup();
    }

    /**
     * @return \PhpAmqpLib\Channel\AMQPChannel
     */
    protected function getChannel()
    {
        if ($this->config['single_channel'] && $this->channelId === null) {
            $this->channelId = $this->connection->get_free_channel_id();
        }
        return $this->connection->channel($this->channelId);
    }

    protected function cleanup()
    {
        if (!isset($this->config['queues'])) {
            throw new ModuleException(__CLASS__, "please set queues for cleanup");
        }
        if (!$this->connection) {
            return;
        }
        foreach ($this->config['queues'] as $queue) {
            try {
                $this->getChannel()->queue_purge($queue);
            } catch (AMQPProtocolChannelException $e) {
                // ignore if exchange/queue doesn't exist and rethrow exception if it's something else
                if ($e->getCode() !== 404) {
                    throw $e;
                }
            }
        }
    }
}
<?php
namespace Codeception\Lib\Connector;

use Aws\Credentials\Credentials;
use Aws\Signature\SignatureV4;
use Codeception\Util\Uri;
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Cookie\SetCookie;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\Handler\StreamHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Request as Psr7Request;
use GuzzleHttp\Psr7\Response as Psr7Response;
use GuzzleHttp\Psr7\Uri as Psr7Uri;
use Symfony\Component\BrowserKit\AbstractBrowser as Client;
use Symfony\Component\BrowserKit\Request as BrowserKitRequest;
use Symfony\Component\BrowserKit\Response as BrowserKitResponse;

class Guzzle extends Client
{
    protected $requestOptions = [
        'allow_redirects' => false,
        'headers'         => [],
    ];
    protected $refreshMaxInterval = 0;

    protected $awsCredentials;
    protected $awsSignature;

    /** @var GuzzleClient */
    protected $client;

    /**
     * Sets the maximum allowable timeout interval for a meta tag refresh to
     * automatically redirect a request.
     *
     * A meta tag detected with an interval equal to or greater than $seconds
     * would not result in a redirect.  A meta tag without a specified interval
     * or one with a value less than $seconds would result in the client
     * automatically redirecting to the specified URL
     *
     * @param int $seconds Number of seconds
     */
    public function setRefreshMaxInterval($seconds)
    {
        $this->refreshMaxInterval = $seconds;
    }

    public function setClient(GuzzleClient $client)
    {
        $this->client = $client;
    }

    /**
     * Sets the request header to the passed value.  The header will be
     * sent along with the next request.
     *
     * Passing an empty value clears the header, which is the equivalent
     * of calling deleteHeader.
     *
     * @param string $name the name of the header
     * @param string $value the value of the header
     */
    public function setHeader($name, $value)
    {
        if ((string)$value === '') {
            $this->deleteHeader($name);
        } else {
            $this->requestOptions['headers'][$name] = $value;
        }
    }

    /**
     * Deletes the header with the passed name from the list of headers
     * that will be sent with the request.
     *
     * @param string $name the name of the header to delete.
     */
    public function deleteHeader($name)
    {
        unset($this->requestOptions['headers'][$name]);
    }

    /**
     * @param string $username
     * @param string $password
     * @param string $type  Default: 'basic'
     */
    public function setAuth($username, $password, $type = 'basic')
    {
        if (!$username) {
            unset($this->requestOptions['auth']);
            return;
        }
        $this->requestOptions['auth'] = [$username, $password, $type];
    }

    /**
     * Taken from Mink\BrowserKitDriver
     *
     * @param Psr7Response $response
     *
     * @return BrowserKitResponse
     */
    protected function createResponse(Psr7Response $response)
    {
        $body = (string) $response->getBody();
        $headers = $response->getHeaders();

        $contentType = null;

        if (isset($headers['Content-Type'])) {
            $contentType = reset($headers['Content-Type']);
        }
        if (!$contentType) {
            $contentType = 'text/html';
        }

        if (strpos($contentType, 'charset=') === false) {
            if (preg_match('/<meta[^>]+charset *= *["\']?([a-zA-Z\-0-9]+)/i', $body, $matches)) {
                $contentType .= ';charset=' . $matches[1];
            }
            $headers['Content-Type'] = [$contentType];
        }

        $status = $response->getStatusCode();
        if ($status < 300 || $status >= 400) {
            $matches = [];

            $matchesMeta = preg_match(
                '/<meta[^>]+http-equiv="refresh" content="\s*(\d*)\s*;\s*url=(.*?)"/i',
                $body,
                $matches
            );

            if (!$matchesMeta && isset($headers['Refresh'])) {
                // match by header
                preg_match(
                    '/^\s*(\d*)\s*;\s*url=(.*)/i',
                    (string) reset($headers['Refresh']),
                    $matches
                );
            }

            if ((!empty($matches)) && (empty($matches[1]) || $matches[1] < $this->refreshMaxInterval)) {
                $uri = new Psr7Uri($this->getAbsoluteUri($matches[2]));
                $currentUri = new Psr7Uri($this->getHistory()->current()->getUri());

                if ($uri->withFragment('') !== $currentUri->withFragment('')) {
                    $status = 302;
                    $headers['Location'] = $matchesMeta ? htmlspecialchars_decode($uri) : (string)$uri;
                }
            }
        }

        return new BrowserKitResponse($body, $status, $headers);
    }

    public function getAbsoluteUri($uri)
    {
        $baseUri = $this->client->getConfig('base_uri');
        if (strpos($uri, '://') === false && strpos($uri, '//') !== 0) {
            if (strpos($uri, '/') === 0) {
                $baseUriPath = $baseUri->getPath();
                if (!empty($baseUriPath) && strpos($uri, $baseUriPath) === 0) {
                    $uri = substr($uri, strlen($baseUriPath));
                }

                return Uri::appendPath((string)$baseUri, $uri);
            }
            // relative url
            if (!$this->getHistory()->isEmpty()) {
                return Uri::mergeUrls((string)$this->getHistory()->current()->getUri(), $uri);
            }
        }
        return Uri::mergeUrls($baseUri, $uri);
    }

    protected function doRequest($request)
    {
        /** @var $request BrowserKitRequest  **/
        $guzzleRequest = new Psr7Request(
            $request->getMethod(),
            $request->getUri(),
            $this->extractHeaders($request),
            $request->getContent()
        );
        $options = $this->requestOptions;
        $options['cookies'] = $this->extractCookies($guzzleRequest->getUri()->getHost());
        $multipartData = $this->extractMultipartFormData($request);
        if (!empty($multipartData)) {
            $options['multipart'] = $multipartData;
        }

        $formData = $this->extractFormData($request);
        if (empty($multipartData) && $formData) {
            $options['form_params'] = $formData;
        }

        try {
            if (null !== $this->awsCredentials) {
                $response = $this->client->send($this->awsSignature->signRequest($guzzleRequest, $this->awsCredentials), $options);
            } else {
                $response = $this->client->send($guzzleRequest, $options);
            }
        } catch (RequestException $e) {
            if (!$e->hasResponse()) {
                throw $e;
            }
            $response = $e->getResponse();
        }
        return $this->createResponse($response);
    }

    protected function extractHeaders(BrowserKitRequest $request)
    {
        $headers = [];
        $server = $request->getServer();

        $contentHeaders = ['Content-Length' => true, 'Content-Md5' => true, 'Content-Type' => true];
        foreach ($server as $header => $val) {
            $header = html_entity_decode(implode('-', array_map('ucfirst', explode('-', strtolower(str_replace('_', '-', $header))))), ENT_NOQUOTES);
            if (strpos($header, 'Http-') === 0) {
                $headers[substr($header, 5)] = $val;
            } elseif (isset($contentHeaders[$header])) {
                $headers[$header] = $val;
            }
        }
        return $headers;
    }

    protected function extractFormData(BrowserKitRequest $request)
    {
        if (!in_array(strtoupper($request->getMethod()), ['POST', 'PUT', 'PATCH', 'DELETE'])) {
            return null;
        }

        // guessing if it is a form data
        $headers = $request->getServer();
        if (isset($headers['HTTP_CONTENT_TYPE'])) {
            // not a form
            if ($headers['HTTP_CONTENT_TYPE'] !== 'application/x-www-form-urlencoded') {
                return null;
            }
        }
        if ($request->getContent() !== null) {
            return null;
        }
        return $request->getParameters();
    }

    protected function extractMultipartFormData(BrowserKitRequest $request)
    {
        if (!in_array(strtoupper($request->getMethod()), ['POST', 'PUT', 'PATCH'])) {
            return [];
        }

        $parts = $this->mapFiles($request->getFiles());
        if (empty($parts)) {
            return [];
        }

        foreach ($request->getParameters() as $k => $v) {
            $parts = $this->formatMultipart($parts, $k, $v);
        }
        return $parts;
    }

    protected function formatMultipart($parts, $key, $value)
    {
        if (is_array($value)) {
            foreach ($value as $subKey => $subValue) {
                $parts = array_merge($this->formatMultipart([], $key."[$subKey]", $subValue), $parts);
            }
            return $parts;
        }
        $parts[] = ['name' => $key, 'contents' => (string) $value];
        return $parts;
    }

    protected function mapFiles($requestFiles, $arrayName = '')
    {
        $files = [];
        foreach ($requestFiles as $name => $info) {
            if (!empty($arrayName)) {
                $name = $arrayName . '[' . $name . ']';
            }

            if (is_array($info)) {
                if (isset($info['tmp_name'])) {
                    if ($info['tmp_name']) {
                        $handle = fopen($info['tmp_name'], 'rb');
                        $filename = isset($info['name']) ? $info['name'] : null;
                        $file = [
                            'name' => $name,
                            'contents' => $handle,
                            'filename' => $filename
                        ];
                        if (isset($info['type'])) {
                            $file['headers'] = [
                                'content-type' => $info['type']
                            ];
                        }
                        $files[] = $file;
                    }
                } else {
                    $files = array_merge($files, $this->mapFiles($info, $name));
                }
            } else {
                $files[] = [
                    'name' => $name,
                    'contents' => fopen($info, 'rb')
                ];
            }
        }

        return $files;
    }

    protected function extractCookies($host)
    {
        $jar = [];
        $cookies = $this->getCookieJar()->all();
        foreach ($cookies as $cookie) {
            $setCookie = SetCookie::fromString((string)$cookie);
            if (!$setCookie->getDomain()) {
                $setCookie->setDomain($host);
            }
            $jar[] = $setCookie;
        }
        return new CookieJar(false, $jar);
    }

    public static function createHandler($handler)
    {
        if ($handler instanceof HandlerStack) {
            return $handler;
        }
        if ($handler === 'curl') {
            return HandlerStack::create(new CurlHandler());
        }
        if ($handler === 'stream') {
            return HandlerStack::create(new StreamHandler());
        }
        if (is_string($handler) && class_exists($handler)) {
            return HandlerStack::create(new $handler);
        }
        if (is_callable($handler)) {
            return HandlerStack::create($handler);
        }
        return HandlerStack::create();
    }

    public function setAwsAuth($config)
    {
        $this->awsCredentials = new Credentials($config['key'], $config['secret']);
        $this->awsSignature = new SignatureV4($config['service'], $config['region']);
    }
}
<?php
namespace Codeception\Module;

use Closure;
use Codeception\Lib\Connector\Guzzle;
use Codeception\Lib\InnerBrowser;
use Codeception\Lib\Interfaces\MultiSession;
use Codeception\Lib\Interfaces\Remote;
use Codeception\TestInterface;
use Codeception\Util\Uri;
use GuzzleHttp\Client as GuzzleClient;

/**
 * Uses [Guzzle](http://guzzlephp.org/) to interact with your application over CURL.
 * Module works over CURL and requires **PHP CURL extension** to be enabled.
 *
 * Use to perform web acceptance tests with non-javascript browser.
 *
 * If test fails stores last shown page in 'output' dir.
 *
 * ## Status
 *
 * * Maintainer: **davert**
 * * Stability: **stable**
 * * Contact: codeception@codeception.com
 *
 *
 * ## Configuration
 *
 * * url *required* - start url of your app
 * * headers - default headers are set before each test.
 * * handler (default: curl) -  Guzzle handler to use. By default curl is used, also possible to pass `stream`, or any valid class name as [Handler](http://docs.guzzlephp.org/en/latest/handlers-and-middleware.html#handlers).
 * * middleware - Guzzle middlewares to add. An array of valid callables is required.
 * * curl - curl options
 * * cookies - ...
 * * auth - ...
 * * verify - ...
 * * .. those and other [Guzzle Request options](http://docs.guzzlephp.org/en/latest/request-options.html)
 *
 *
 * ### Example (`acceptance.suite.yml`)
 *
 *     modules:
 *        enabled:
 *            - PhpBrowser:
 *                url: 'http://localhost'
 *                auth: ['admin', '123345']
 *                curl:
 *                    CURLOPT_RETURNTRANSFER: true
 *                cookies:
 *                    cookie-1:
 *                        Name: userName
 *                        Value: john.doe
 *                    cookie-2:
 *                        Name: authToken
 *                        Value: 1abcd2345
 *                        Domain: subdomain.domain.com
 *                        Path: /admin/
 *                        Expires: 1292177455
 *                        Secure: true
 *                        HttpOnly: false
 *
 *
 * All SSL certification checks are disabled by default.
 * Use Guzzle request options to configure certifications and others.
 *
 * ## Public API
 *
 * Those properties and methods are expected to be used in Helper classes:
 *
 * Properties:
 *
 * * `guzzle` - contains [Guzzle](http://guzzlephp.org/) client instance: `\GuzzleHttp\Client`
 * * `client` - Symfony BrowserKit instance.
 *
 */
class PhpBrowser extends InnerBrowser implements Remote, MultiSession
{

    protected $requiredFields = ['url'];

    protected $config = [
        'headers' => [],
        'verify' => false,
        'expect' => false,
        'timeout' => 30,
        'curl' => [],
        'refresh_max_interval' => 10,
        'handler' => 'curl',
        'middleware' => null,

        // required defaults (not recommended to change)
        'allow_redirects' => false,
        'http_errors' => false,
        'cookies' => true,
    ];

    protected $guzzleConfigFields = [
        'auth',
        'proxy',
        'verify',
        'cert',
        'query',
        'ssl_key',
        'proxy',
        'expect',
        'version',
        'timeout',
        'connect_timeout'
    ];

    /**
     * @var Guzzle
     */
    public $client;

    /**
     * @var GuzzleClient
     */
    public $guzzle;

    public function _initialize()
    {
        $this->_initializeSession();
    }

    public function _before(TestInterface $test)
    {
        if (!$this->client) {
            $this->client = new Guzzle();
        }
        $this->_prepareSession();
    }

    public function _getUrl()
    {
        return $this->config['url'];
    }

    /**
     * Alias to `haveHttpHeader`
     *
     * @param $name
     * @param $value
     */
    public function setHeader($name, $value)
    {
        $this->haveHttpHeader($name, $value);
    }

    public function amHttpAuthenticated($username, $password)
    {
        $this->client->setAuth($username, $password);
    }

    public function amOnUrl($url)
    {
        $host = Uri::retrieveHost($url);
        $config = $this->config;
        $config['url'] = $host;
        $this->_reconfigure($config);
        $page = substr($url, strlen($host));
        if ($page === '') {
            $page = '/';
        }
        $this->debugSection('Host', $host);
        $this->amOnPage($page);
    }

    public function amOnSubdomain($subdomain)
    {
        $url = $this->config['url'];
        $url = preg_replace('~(https?://)(.*\.)(.*\.)~', "$1$3", $url); // removing current subdomain
        $url = preg_replace('~(https?://)(.*)~', "$1$subdomain.$2", $url); // inserting new
        $config = $this->config;
        $config['url'] = $url;
        $this->_reconfigure($config);
    }

    protected function onReconfigure()
    {
        $this->_prepareSession();
    }

    /**
     * Low-level API method.
     * If Codeception commands are not enough, use [Guzzle HTTP Client](http://guzzlephp.org/) methods directly
     *
     * Example:
     *
     * ``` php
     * <?php
     * $I->executeInGuzzle(function (\GuzzleHttp\Client $client) {
     *      $client->get('/get', ['query' => ['foo' => 'bar']]);
     * });
     * ?>
     * ```
     *
     * It is not recommended to use this command on a regular basis.
     * If Codeception lacks important Guzzle Client methods, implement them and submit patches.
     *
     * @param Closure $function
     * @return mixed
     */
    public function executeInGuzzle(Closure $function)
    {
        return $function($this->guzzle);
    }


    public function _getResponseCode()
    {
        return $this->getResponseStatusCode();
    }

    public function _initializeSession()
    {
        // independent sessions need independent cookies
        $this->client = new Guzzle();
        $this->_prepareSession();
    }

    public function _prepareSession()
    {
        $defaults = array_intersect_key($this->config, array_flip($this->guzzleConfigFields));
        $curlOptions = [];

        foreach ($this->config['curl'] as $key => $val) {
            if (defined($key)) {
                $curlOptions[constant($key)] = $val;
            }
        }

        $this->headers = $this->config['headers'];
        $this->setCookiesFromOptions();

        $defaults['base_uri'] = $this->config['url'];
        $defaults['curl'] = $curlOptions;
        $handler = Guzzle::createHandler($this->config['handler']);
        if ($handler && is_array($this->config['middleware'])) {
            foreach ($this->config['middleware'] as $middleware) {
                $handler->push($middleware);
            }
        }
        $defaults['handler'] = $handler;
        $this->guzzle = new GuzzleClient($defaults);

        $this->client->setRefreshMaxInterval($this->config['refresh_max_interval']);
        $this->client->setClient($this->guzzle);
    }

    public function _backupSession()
    {
        return [
            'client' => $this->client,
            'guzzle' => $this->guzzle,
            'crawler' => $this->crawler,
            'headers' => $this->headers,
        ];
    }

    public function _loadSession($session)
    {
        foreach ($session as $key => $val) {
            $this->$key = $val;
        }
    }

    public function _closeSession($session = null)
    {
        unset($session);
    }
}
<?php

namespace Codeception\Util\Shared;

use Codeception\PHPUnit\TestCase;
use PHPUnit\Framework\Constraint\Constraint;
use PHPUnit\Framework\Constraint\LogicalNot;

trait Asserts
{
    use InheritedAsserts;

    /**
     * @param $arguments
     * @param bool $not
     */
    protected function assert($arguments, $not = false)
    {
        $not = $not ? 'Not' : '';
        $method = ucfirst(array_shift($arguments));
        if (($method === 'True') && $not) {
            $method = 'False';
            $not = '';
        }
        if (($method === 'False') && $not) {
            $method = 'True';
            $not = '';
        }

        call_user_func_array(['\PHPUnit\Framework\Assert', 'assert' . $not . $method], $arguments);
    }

    protected function assertNot($arguments)
    {
        $this->assert($arguments, true);
    }

    /**
     * Asserts that a file does not exist.
     *
     * @param string $filename
     * @param string $message
     */
    protected function assertFileNotExists($filename, $message = '')
    {
        TestCase::assertFileNotExists($filename, $message);
    }

    /**
     * Asserts that a value is greater than or equal to another value.
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertGreaterOrEquals($expected, $actual, $message = '')
    {
        TestCase::assertGreaterThanOrEqual($expected, $actual, $message);
    }

    /**
     * Asserts that a variable is empty.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsEmpty($actual, $message = '')
    {
        TestCase::assertEmpty($actual, $message);
    }

    /**
     * Asserts that a value is smaller than or equal to another value.
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertLessOrEquals($expected, $actual, $message = '')
    {
        TestCase::assertLessThanOrEqual($expected, $actual, $message);
    }

    /**
     * Asserts that a string does not match a given regular expression.
     *
     * @param string $pattern
     * @param string $string
     * @param string $message
     */
    protected function assertNotRegExp($pattern, $string, $message = '')
    {
        TestCase::assertNotRegExp($pattern, $string, $message);
    }

    /**
     * Asserts that a string matches a given regular expression.
     *
     * @param string $pattern
     * @param string $string
     * @param string $message
     */
    protected function assertRegExp($pattern, $string, $message = '')
    {
        TestCase::assertRegExp($pattern, $string, $message);
    }

    /**
     * Evaluates a PHPUnit\Framework\Constraint matcher object.
     *
     * @param $value
     * @param Constraint $constraint
     * @param string $message
     */
    protected function assertThatItsNot($value, $constraint, $message = '')
    {
        $constraint = new LogicalNot($constraint);
        TestCase::assertThat($value, $constraint, $message);
    }
}
<?php

namespace Codeception\Util\Shared;

use ArrayAccess;
use Codeception\PHPUnit\TestCase;
use Countable;
use DOMDocument;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\Constraint\Constraint;

trait InheritedAsserts
{
    /**
     * Asserts that an array has a specified key.
     *
     * @param int|string $key
     * @param array|ArrayAccess $array
     * @param string $message
     */
    protected function assertArrayHasKey($key, $array, $message = '')
    {
        Assert::assertArrayHasKey($key, $array, $message);
    }

    /**
     * Asserts that an array does not have a specified key.
     *
     * @param int|string $key
     * @param array|ArrayAccess $array
     * @param string $message
     */
    protected function assertArrayNotHasKey($key, $array, $message = '')
    {
        Assert::assertArrayNotHasKey($key, $array, $message);
    }

    /**
     * Asserts that a class has a specified attribute.
     *
     * @param string $attributeName
     * @param string $className
     * @param string $message
     */
    protected function assertClassHasAttribute($attributeName, $className, $message = '')
    {
        Assert::assertClassHasAttribute($attributeName, $className, $message);
    }

    /**
     * Asserts that a class has a specified static attribute.
     *
     * @param string $attributeName
     * @param string $className
     * @param string $message
     */
    protected function assertClassHasStaticAttribute($attributeName, $className, $message = '')
    {
        Assert::assertClassHasStaticAttribute($attributeName, $className, $message);
    }

    /**
     * Asserts that a class does not have a specified attribute.
     *
     * @param string $attributeName
     * @param string $className
     * @param string $message
     */
    protected function assertClassNotHasAttribute($attributeName, $className, $message = '')
    {
        Assert::assertClassNotHasAttribute($attributeName, $className, $message);
    }

    /**
     * Asserts that a class does not have a specified static attribute.
     *
     * @param string $attributeName
     * @param string $className
     * @param string $message
     */
    protected function assertClassNotHasStaticAttribute($attributeName, $className, $message = '')
    {
        Assert::assertClassNotHasStaticAttribute($attributeName, $className, $message);
    }

    /**
     * Asserts that a haystack contains a needle.
     *
     * @param $needle
     * @param $haystack
     * @param string $message
     */
    protected function assertContains($needle, $haystack, $message = '')
    {
        Assert::assertContains($needle, $haystack, $message);
    }

    /**
     * @param $needle
     * @param $haystack
     * @param string $message
     */
    protected function assertContainsEquals($needle, $haystack, $message = '')
    {
        Assert::assertContainsEquals($needle, $haystack, $message);
    }

    /**
     * Asserts that a haystack contains only values of a given type.
     *
     * @param string $type
     * @param $haystack
     * @param bool|null $isNativeType
     * @param string $message
     */
    protected function assertContainsOnly($type, $haystack, $isNativeType = null, $message = '')
    {
        Assert::assertContainsOnly($type, $haystack, $isNativeType, $message);
    }

    /**
     * Asserts that a haystack contains only instances of a given class name.
     *
     * @param string $className
     * @param $haystack
     * @param string $message
     */
    protected function assertContainsOnlyInstancesOf($className, $haystack, $message = '')
    {
        Assert::assertContainsOnlyInstancesOf($className, $haystack, $message);
    }

    /**
     * Asserts the number of elements of an array, Countable or Traversable.
     *
     * @param int $expectedCount
     * @param Countable|iterable $haystack
     * @param string $message
     */
    protected function assertCount($expectedCount, $haystack, $message = '')
    {
        Assert::assertCount($expectedCount, $haystack, $message);
    }

    /**
     * Asserts that a directory does not exist.
     *
     * @param string $directory
     * @param string $message
     */
    protected function assertDirectoryDoesNotExist($directory, $message = '')
    {
        Assert::assertDirectoryDoesNotExist($directory, $message);
    }

    /**
     * Asserts that a directory exists.
     *
     * @param string $directory
     * @param string $message
     */
    protected function assertDirectoryExists($directory, $message = '')
    {
        Assert::assertDirectoryExists($directory, $message);
    }

    /**
     * Asserts that a directory exists and is not readable.
     *
     * @param string $directory
     * @param string $message
     */
    protected function assertDirectoryIsNotReadable($directory, $message = '')
    {
        Assert::assertDirectoryIsNotReadable($directory, $message);
    }

    /**
     * Asserts that a directory exists and is not writable.
     *
     * @param string $directory
     * @param string $message
     */
    protected function assertDirectoryIsNotWritable($directory, $message = '')
    {
        Assert::assertDirectoryIsNotWritable($directory, $message);
    }

    /**
     * Asserts that a directory exists and is readable.
     *
     * @param string $directory
     * @param string $message
     */
    protected function assertDirectoryIsReadable($directory, $message = '')
    {
        Assert::assertDirectoryIsReadable($directory, $message);
    }

    /**
     * Asserts that a directory exists and is writable.
     *
     * @param string $directory
     * @param string $message
     */
    protected function assertDirectoryIsWritable($directory, $message = '')
    {
        Assert::assertDirectoryIsWritable($directory, $message);
    }

    /**
     * Asserts that a string does not match a given regular expression.
     *
     * @param string $pattern
     * @param string $string
     * @param string $message
     */
    protected function assertDoesNotMatchRegularExpression($pattern, $string, $message = '')
    {
        TestCase::assertNotRegExp($pattern, $string, $message);
    }

    /**
     * Asserts that a variable is empty.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertEmpty($actual, $message = '')
    {
        Assert::assertEmpty($actual, $message);
    }

    /**
     * Asserts that two variables are equal.
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertEquals($expected, $actual, $message = '')
    {
        Assert::assertEquals($expected, $actual, $message);
    }

    /**
     * Asserts that two variables are equal (canonicalizing).
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertEqualsCanonicalizing($expected, $actual, $message = '')
    {
        TestCase::assertEqualsCanonicalizing($expected, $actual, $message);
    }

    /**
     * Asserts that two variables are equal (ignoring case).
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertEqualsIgnoringCase($expected, $actual, $message = '')
    {
        TestCase::assertEqualsIgnoringCase($expected, $actual, $message);
    }

    /**
     * Asserts that two variables are equal (with delta).
     *
     * @param $expected
     * @param $actual
     * @param float $delta
     * @param string $message
     */
    protected function assertEqualsWithDelta($expected, $actual, $delta, $message = '')
    {
        TestCase::assertEqualsWithDelta($expected, $actual, $delta, $message);
    }

    /**
     * Asserts that a condition is false.
     *
     * @param $condition
     * @param string $message
     */
    protected function assertFalse($condition, $message = '')
    {
        Assert::assertFalse($condition, $message);
    }

    /**
     * Asserts that a file does not exist.
     *
     * @param string $filename
     * @param string $message
     */
    protected function assertFileDoesNotExist($filename, $message = '')
    {
        TestCase::assertFileNotExists($filename, $message);
    }

    /**
     * Asserts that the contents of one file is equal to the contents of another file.
     *
     * @param string $expected
     * @param string $actual
     * @param string $message
     */
    protected function assertFileEquals($expected, $actual, $message = '')
    {
        Assert::assertFileEquals($expected, $actual, $message);
    }

    /**
     * Asserts that the contents of one file is equal to the contents of another file (canonicalizing).
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertFileEqualsCanonicalizing($expected, $actual, $message = '')
    {
        Assert::assertFileEqualsCanonicalizing($expected, $actual, $message);
    }

    /**
     * Asserts that the contents of one file is equal to the contents of another file (ignoring case).
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertFileEqualsIgnoringCase($expected, $actual, $message = '')
    {
        Assert::assertFileEqualsIgnoringCase($expected, $actual, $message);
    }

    /**
     * Asserts that a file exists.
     *
     * @param string $filename
     * @param string $message
     */
    protected function assertFileExists($filename, $message = '')
    {
        Assert::assertFileExists($filename, $message);
    }

    /**
     * Asserts that a file exists and is not readable.
     *
     * @param string $file
     * @param string $message
     */
    protected function assertFileIsNotReadable($file, $message = '')
    {
        Assert::assertFileIsNotReadable($file, $message);
    }

    /**
     * Asserts that a file exists and is not writable.
     *
     * @param string $file
     * @param string $message
     */
    protected function assertFileIsNotWritable($file, $message = '')
    {
        Assert::assertFileIsNotWritable($file, $message);
    }

    /**
     * Asserts that a file exists and is readable.
     *
     * @param string $file
     * @param string $message
     */
    protected function assertFileIsReadable($file, $message = '')
    {
        Assert::assertFileIsReadable($file, $message);
    }

    /**
     * Asserts that a file exists and is writable.
     *
     * @param string $file
     * @param string $message
     */
    protected function assertFileIsWritable($file, $message = '')
    {
        Assert::assertFileIsWritable($file, $message);
    }

    /**
     * Asserts that the contents of one file is not equal to the contents of another file.
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertFileNotEquals($expected, $actual, $message = '')
    {
        Assert::assertFileNotEquals($expected, $actual, $message);
    }

    /**
     * Asserts that the contents of one file is not equal to the contents of another file (canonicalizing).
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertFileNotEqualsCanonicalizing($expected, $actual, $message = '')
    {
        Assert::assertFileNotEqualsCanonicalizing($expected, $actual, $message);
    }

    /**
     * Asserts that the contents of one file is not equal to the contents of another file (ignoring case).
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertFileNotEqualsIgnoringCase($expected, $actual, $message = '')
    {
        Assert::assertFileNotEqualsIgnoringCase($expected, $actual, $message);
    }

    /**
     * Asserts that a variable is finite.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertFinite($actual, $message = '')
    {
        Assert::assertFinite($actual, $message);
    }

    /**
     * Asserts that a value is greater than another value.
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertGreaterThan($expected, $actual, $message = '')
    {
        Assert::assertGreaterThan($expected, $actual, $message);
    }

    /**
     * Asserts that a value is greater than or equal to another value.
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertGreaterThanOrEqual($expected, $actual, $message = '')
    {
        Assert::assertGreaterThanOrEqual($expected, $actual, $message);
    }

    /**
     * Asserts that a variable is infinite.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertInfinite($actual, $message = '')
    {
        Assert::assertInfinite($actual, $message);
    }

    /**
     * Asserts that a variable is of a given type.
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertInstanceOf($expected, $actual, $message = '')
    {
        Assert::assertInstanceOf($expected, $actual, $message);
    }

    /**
     * Asserts that a variable is of type array.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsArray($actual, $message = '')
    {
        TestCase::assertIsArray($actual, $message);
    }

    /**
     * Asserts that a variable is of type bool.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsBool($actual, $message = '')
    {
        TestCase::assertIsBool($actual, $message);
    }

    /**
     * Asserts that a variable is of type callable.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsCallable($actual, $message = '')
    {
        TestCase::assertIsCallable($actual, $message);
    }

    /**
     * Asserts that a variable is of type resource and is closed.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsClosedResource($actual, $message = '')
    {
        TestCase::assertIsClosedResource($actual, $message);
    }

    /**
     * Asserts that a variable is of type float.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsFloat($actual, $message = '')
    {
        TestCase::assertIsFloat($actual, $message);
    }

    /**
     * Asserts that a variable is of type int.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsInt($actual, $message = '')
    {
        TestCase::assertIsInt($actual, $message);
    }

    /**
     * Asserts that a variable is of type iterable.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsIterable($actual, $message = '')
    {
        TestCase::assertIsIterable($actual, $message);
    }

    /**
     * Asserts that a variable is not of type array.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsNotArray($actual, $message = '')
    {
        TestCase::assertIsNotArray($actual, $message);
    }

    /**
     * Asserts that a variable is not of type bool.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsNotBool($actual, $message = '')
    {
        TestCase::assertIsNotBool($actual, $message);
    }

    /**
     * Asserts that a variable is not of type callable.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsNotCallable($actual, $message = '')
    {
        TestCase::assertIsNotCallable($actual, $message);
    }

    /**
     * Asserts that a variable is not of type resource.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsNotClosedResource($actual, $message = '')
    {
        TestCase::assertIsNotClosedResource($actual, $message);
    }

    /**
     * Asserts that a variable is not of type float.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsNotFloat($actual, $message = '')
    {
        TestCase::assertIsNotFloat($actual, $message);
    }

    /**
     * Asserts that a variable is not of type int.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsNotInt($actual, $message = '')
    {
        TestCase::assertIsNotInt($actual, $message);
    }

    /**
     * Asserts that a variable is not of type iterable.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsNotIterable($actual, $message = '')
    {
        TestCase::assertIsNotIterable($actual, $message);
    }

    /**
     * Asserts that a variable is not of type numeric.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsNotNumeric($actual, $message = '')
    {
        TestCase::assertIsNotNumeric($actual, $message);
    }

    /**
     * Asserts that a variable is not of type object.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsNotObject($actual, $message = '')
    {
        TestCase::assertIsNotObject($actual, $message);
    }

    /**
     * Asserts that a file/dir exists and is not readable.
     *
     * @param string $filename
     * @param string $message
     */
    protected function assertIsNotReadable($filename, $message = '')
    {
        TestCase::assertIsNotReadable($filename, $message);
    }

    /**
     * Asserts that a variable is not of type resource.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsNotResource($actual, $message = '')
    {
        TestCase::assertIsNotResource($actual, $message);
    }

    /**
     * Asserts that a variable is not of type scalar.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsNotScalar($actual, $message = '')
    {
        TestCase::assertIsNotScalar($actual, $message);
    }

    /**
     * Asserts that a variable is not of type string.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsNotString($actual, $message = '')
    {
        TestCase::assertIsNotString($actual, $message);
    }

    /**
     * Asserts that a file/dir exists and is not writable.
     *
     * @param $filename
     * @param string $message
     */
    protected function assertIsNotWritable($filename, $message = '')
    {
        TestCase::assertIsNotWritable($filename, $message);
    }

    /**
     * Asserts that a variable is of type numeric.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsNumeric($actual, $message = '')
    {
        TestCase::assertIsNumeric($actual, $message);
    }

    /**
     * Asserts that a variable is of type object.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsObject($actual, $message = '')
    {
        TestCase::assertIsObject($actual, $message);
    }

    /**
     * Asserts that a file/dir is readable.
     *
     * @param $filename
     * @param string $message
     */
    protected function assertIsReadable($filename, $message = '')
    {
        TestCase::assertIsReadable($filename, $message);
    }

    /**
     * Asserts that a variable is of type resource.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsResource($actual, $message = '')
    {
        TestCase::assertIsResource($actual, $message);
    }

    /**
     * Asserts that a variable is of type scalar.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsScalar($actual, $message = '')
    {
        TestCase::assertIsScalar($actual, $message);
    }

    /**
     * Asserts that a variable is of type string.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertIsString($actual, $message = '')
    {
        TestCase::assertIsString($actual, $message);
    }

    /**
     * Asserts that a file/dir exists and is writable.
     *
     * @param $filename
     * @param string $message
     */
    protected function assertIsWritable($filename, $message = '')
    {
        TestCase::assertIsWritable($filename, $message);
    }

    /**
     * Asserts that a string is a valid JSON string.
     *
     * @param string $actualJson
     * @param string $message
     */
    protected function assertJson($actualJson, $message = '')
    {
        Assert::assertJson($actualJson, $message);
    }

    /**
     * Asserts that two JSON files are equal.
     *
     * @param string $expectedFile
     * @param string $actualFile
     * @param string $message
     */
    protected function assertJsonFileEqualsJsonFile($expectedFile, $actualFile, $message = '')
    {
        Assert::assertJsonFileEqualsJsonFile($expectedFile, $actualFile, $message);
    }

    /**
     * Asserts that two JSON files are not equal.
     *
     * @param string $expectedFile
     * @param string $actualFile
     * @param string $message
     */
    protected function assertJsonFileNotEqualsJsonFile($expectedFile, $actualFile, $message = '')
    {
        Assert::assertJsonFileNotEqualsJsonFile($expectedFile, $actualFile, $message);
    }

    /**
     * Asserts that the generated JSON encoded object and the content of the given file are equal.
     *
     * @param string $expectedFile
     * @param string $actualJson
     * @param string $message
     */
    protected function assertJsonStringEqualsJsonFile($expectedFile, $actualJson, $message = '')
    {
        Assert::assertJsonStringEqualsJsonFile($expectedFile, $actualJson, $message);
    }

    /**
     * Asserts that two given JSON encoded objects or arrays are equal.
     *
     * @param string $expectedJson
     * @param string $actualJson
     * @param string $message
     */
    protected function assertJsonStringEqualsJsonString($expectedJson, $actualJson, $message = '')
    {
        Assert::assertJsonStringEqualsJsonString($expectedJson, $actualJson, $message);
    }

    /**
     * Asserts that the generated JSON encoded object and the content of the given file are not equal.
     *
     * @param string $expectedFile
     * @param string $actualJson
     * @param string $message
     */
    protected function assertJsonStringNotEqualsJsonFile($expectedFile, $actualJson, $message = '')
    {
        Assert::assertJsonStringNotEqualsJsonFile($expectedFile, $actualJson, $message);
    }

    /**
     * Asserts that two given JSON encoded objects or arrays are not equal.
     *
     * @param string $expectedJson
     * @param string $actualJson
     * @param string $message
     */
    protected function assertJsonStringNotEqualsJsonString($expectedJson, $actualJson, $message = '')
    {
        Assert::assertJsonStringNotEqualsJsonString($expectedJson, $actualJson, $message);
    }

    /**
     * Asserts that a value is smaller than another value.
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertLessThan($expected, $actual, $message = '')
    {
        Assert::assertLessThan($expected, $actual, $message);
    }

    /**
     * Asserts that a value is smaller than or equal to another value.
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertLessThanOrEqual($expected, $actual, $message = '')
    {
        Assert::assertLessThanOrEqual($expected, $actual, $message);
    }

    /**
     * Asserts that a string matches a given regular expression.
     *
     * @param string $pattern
     * @param string $string
     * @param string $message
     */
    protected function assertMatchesRegularExpression($pattern, $string, $message = '')
    {
        TestCase::assertRegExp($pattern, $string, $message);
    }

    /**
     * Asserts that a variable is nan.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertNan($actual, $message = '')
    {
        Assert::assertNan($actual, $message);
    }

    /**
     * Asserts that a haystack does not contain a needle.
     *
     * @param $needle
     * @param $haystack
     * @param string $message
     */
    protected function assertNotContains($needle, $haystack, $message = '')
    {
        Assert::assertNotContains($needle, $haystack, $message);
    }

    protected function assertNotContainsEquals($needle, $haystack, $message = '')
    {
        Assert::assertNotContainsEquals($needle, $haystack, $message);
    }

    /**
     * Asserts that a haystack does not contain only values of a given type.
     *
     * @param string $type
     * @param $haystack
     * @param bool|null $isNativeType
     * @param string $message
     */
    protected function assertNotContainsOnly($type, $haystack, $isNativeType = null, $message = '')
    {
        Assert::assertNotContainsOnly($type, $haystack, $isNativeType, $message);
    }

    /**
     * Asserts the number of elements of an array, Countable or Traversable.
     *
     * @param int $expectedCount
     * @param Countable|iterable $haystack
     * @param string $message
     */
    protected function assertNotCount($expectedCount, $haystack, $message = '')
    {
        Assert::assertNotCount($expectedCount, $haystack, $message);
    }

    /**
     * Asserts that a variable is not empty.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertNotEmpty($actual, $message = '')
    {
        Assert::assertNotEmpty($actual, $message);
    }

    /**
     * Asserts that two variables are not equal.
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertNotEquals($expected, $actual, $message = '')
    {
        TestCase::assertNotEquals($expected, $actual, $message);
    }

    /**
     * Asserts that two variables are not equal (canonicalizing).
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertNotEqualsCanonicalizing($expected, $actual, $message = '')
    {
        TestCase::assertNotEqualsCanonicalizing($expected, $actual, $message);
    }

    /**
     * Asserts that two variables are not equal (ignoring case).
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertNotEqualsIgnoringCase($expected, $actual, $message = '')
    {
        TestCase::assertNotEqualsIgnoringCase($expected, $actual, $message);
    }

    /**
     * Asserts that two variables are not equal (with delta).
     *
     * @param $expected
     * @param $actual
     * @param float $delta
     * @param string $message
     */
    protected function assertNotEqualsWithDelta($expected, $actual, $delta, $message = '')
    {
        TestCase::assertNotEqualsWithDelta($expected, $actual, $delta, $message);
    }

    /**
     * Asserts that a condition is not false.
     *
     * @param $condition
     * @param string $message
     */
    protected function assertNotFalse($condition, $message = '')
    {
        Assert::assertNotFalse($condition, $message);
    }

    /**
     * Asserts that a variable is not of a given type.
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertNotInstanceOf($expected, $actual, $message = '')
    {
        Assert::assertNotInstanceOf($expected, $actual, $message);
    }

    /**
     * Asserts that a variable is not null.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertNotNull($actual, $message = '')
    {
        Assert::assertNotNull($actual, $message);
    }

    /**
     * Asserts that two variables do not have the same type and value.
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertNotSame($expected, $actual, $message = '')
    {
        Assert::assertNotSame($expected, $actual, $message);
    }

    /**
     * Assert that the size of two arrays (or `Countable` or `Traversable` objects) is not the same.
     *
     * @param Countable|iterable $expected
     * @param Countable|iterable $actual
     * @param string $message
     */
    protected function assertNotSameSize($expected, $actual, $message = '')
    {
        Assert::assertNotSameSize($expected, $actual, $message);
    }

    /**
     * Asserts that a condition is not true.
     *
     * @param $condition
     * @param string $message
     */
    protected function assertNotTrue($condition, $message = '')
    {
        Assert::assertNotTrue($condition, $message);
    }

    /**
     * Asserts that a variable is null.
     *
     * @param $actual
     * @param string $message
     */
    protected function assertNull($actual, $message = '')
    {
        Assert::assertNull($actual, $message);
    }

    /**
     * Asserts that an object has a specified attribute.
     *
     * @param string $attributeName
     * @param object $object
     * @param string $message
     */
    protected function assertObjectHasAttribute($attributeName, $object, $message = '')
    {
        Assert::assertObjectHasAttribute($attributeName, $object, $message);
    }

    /**
     * Asserts that an object does not have a specified attribute.
     *
     * @param string $attributeName
     * @param object $object
     * @param string $message
     */
    protected function assertObjectNotHasAttribute($attributeName, $object, $message = '')
    {
        Assert::assertObjectNotHasAttribute($attributeName, $object, $message);
    }

    /**
     * Asserts that two variables have the same type and value.
     *
     * @param $expected
     * @param $actual
     * @param string $message
     */
    protected function assertSame($expected, $actual, $message = '')
    {
        Assert::assertSame($expected, $actual, $message);
    }

    /**
     * Assert that the size of two arrays (or `Countable` or `Traversable` objects) is the same.
     *
     * @param Countable|iterable $expected
     * @param Countable|iterable $actual
     * @param string $message
     */
    protected function assertSameSize($expected, $actual, $message = '')
    {
        Assert::assertSameSize($expected, $actual, $message);
    }

    /**
     * @param string $needle
     * @param string $haystack
     * @param string $message
     */
    protected function assertStringContainsString($needle, $haystack, $message = '')
    {
        TestCase::assertStringContainsString($needle, $haystack, $message);
    }

    protected function assertStringContainsStringIgnoringCase($needle, $haystack, $message = '')
    {
        TestCase::assertStringContainsStringIgnoringCase($needle, $haystack, $message);
    }

    /**
     * Asserts that a string ends not with a given suffix.
     *
     * @param string $suffix
     * @param string $string
     * @param string $message
     */
    protected function assertStringEndsNotWith($suffix, $string, $message = '')
    {
        TestCase::assertStringEndsNotWith($suffix, $string, $message);
    }

    /**
     * Asserts that a string ends with a given suffix.
     *
     * @param string $suffix
     * @param string $string
     * @param string $message
     */
    protected function assertStringEndsWith($suffix, $string, $message = '')
    {
        TestCase::assertStringEndsWith($suffix, $string, $message);
    }

    /**
     * Asserts that the contents of a string is equal to the contents of a file.
     *
     * @param string $expectedFile
     * @param string $actualString
     * @param string $message
     */
    protected function assertStringEqualsFile($expectedFile, $actualString, $message = '')
    {
        Assert::assertStringEqualsFile($expectedFile, $actualString, $message);
    }

    /**
     * Asserts that the contents of a string is equal to the contents of a file (canonicalizing).
     *
     * @param string $expectedFile
     * @param string $actualString
     * @param string $message
     */
    protected function assertStringEqualsFileCanonicalizing($expectedFile, $actualString, $message = '')
    {
        Assert::assertStringEqualsFileCanonicalizing($expectedFile, $actualString, $message);
    }

    /**
     * Asserts that the contents of a string is equal to the contents of a file (ignoring case).
     *
     * @param string $expectedFile
     * @param string $actualString
     * @param string $message
     */
    protected function assertStringEqualsFileIgnoringCase($expectedFile, $actualString, $message = '')
    {
        Assert::assertStringEqualsFileIgnoringCase($expectedFile, $actualString, $message);
    }

    /**
     * Asserts that a string matches a given format string.
     *
     * @param string $format
     * @param string $string
     * @param string $message
     */
    protected function assertStringMatchesFormat($format, $string, $message = '')
    {
        Assert::assertStringMatchesFormat($format, $string, $message);
    }

    /**
     * Asserts that a string matches a given format file.
     *
     * @param string $formatFile
     * @param string $string
     * @param string $message
     */
    protected function assertStringMatchesFormatFile($formatFile, $string, $message = '')
    {
        Assert::assertStringMatchesFormatFile($formatFile, $string, $message);
    }

    /**
     * @param string $needle
     * @param string $haystack
     * @param string $message
     */
    protected function assertStringNotContainsString($needle, $haystack, $message = '')
    {
        TestCase::assertStringNotContainsString($needle, $haystack, $message);
    }

    /**
     * @param string $needle
     * @param string $haystack
     * @param string $message
     */
    protected function assertStringNotContainsStringIgnoringCase($needle, $haystack, $message = '')
    {
        TestCase::assertStringNotContainsStringIgnoringCase($needle, $haystack, $message);
    }

    /**
     * Asserts that the contents of a string is not equal to the contents of a file.
     *
     * @param string $expectedFile
     * @param string $actualString
     * @param string $message
     */
    protected function assertStringNotEqualsFile($expectedFile, $actualString, $message = '')
    {
        Assert::assertStringNotEqualsFile($expectedFile, $actualString, $message);
    }

    /**
     * Asserts that the contents of a string is not equal to the contents of a file (canonicalizing).
     * @param string $expectedFile
     * @param string $actualString
     * @param string $message
     */
    protected function assertStringNotEqualsFileCanonicalizing($expectedFile, $actualString, $message = '')
    {
        Assert::assertStringNotEqualsFileCanonicalizing($expectedFile, $actualString, $message);
    }

    /**
     * Asserts that the contents of a string is not equal to the contents of a file (ignoring case).
     *
     * @param string $expectedFile
     * @param string $actualString
     * @param string $message
     */
    protected function assertStringNotEqualsFileIgnoringCase($expectedFile, $actualString, $message = '')
    {
        Assert::assertStringNotEqualsFileIgnoringCase($expectedFile, $actualString, $message);
    }

    /**
     * Asserts that a string does not match a given format string.
     *
     * @param string $format
     * @param string $string
     * @param string $message
     */
    protected function assertStringNotMatchesFormat($format, $string, $message = '')
    {
        Assert::assertStringNotMatchesFormat($format, $string, $message);
    }

    /**
     * Asserts that a string does not match a given format string.
     *
     * @param string $formatFile
     * @param string $string
     * @param string $message
     */
    protected function assertStringNotMatchesFormatFile($formatFile, $string, $message = '')
    {
        Assert::assertStringNotMatchesFormatFile($formatFile, $string, $message);
    }

    /**
     * Asserts that a string starts not with a given prefix.
     *
     * @param string $prefix
     * @param string $string
     * @param string $message
     */
    protected function assertStringStartsNotWith($prefix, $string, $message = '')
    {
        Assert::assertStringStartsNotWith($prefix, $string, $message);
    }

    /**
     * Asserts that a string starts with a given prefix.
     *
     * @param string $prefix
     * @param string $string
     * @param string $message
     */
    protected function assertStringStartsWith($prefix, $string, $message = '')
    {
        Assert::assertStringStartsWith($prefix, $string, $message);
    }

    /**
     * Evaluates a PHPUnit\Framework\Constraint matcher object.
     *
     * @param $value
     * @param Constraint $constraint
     * @param string $message
     */
    protected function assertThat($value, $constraint, $message = '')
    {
        Assert::assertThat($value, $constraint, $message);
    }

    /**
     * Asserts that a condition is true.
     *
     * @param $condition
     * @param string $message
     */
    protected function assertTrue($condition, $message = '')
    {
        Assert::assertTrue($condition, $message);
    }

    /**
     * Asserts that two XML files are equal.
     *
     * @param string $expectedFile
     * @param string $actualFile
     * @param string $message
     */
    protected function assertXmlFileEqualsXmlFile($expectedFile, $actualFile, $message = '')
    {
        Assert::assertXmlFileEqualsXmlFile($expectedFile, $actualFile, $message);
    }

    /**
     * Asserts that two XML files are not equal.
     *
     * @param string $expectedFile
     * @param string $actualFile
     * @param string $message
     */
    protected function assertXmlFileNotEqualsXmlFile($expectedFile, $actualFile, $message = '')
    {
        Assert::assertXmlFileNotEqualsXmlFile($expectedFile, $actualFile, $message);
    }

    /**
     * Asserts that two XML documents are equal.
     *
     * @param string $expectedFile
     * @param DOMDocument|string $actualXml
     * @param string $message
     */
    protected function assertXmlStringEqualsXmlFile($expectedFile, $actualXml, $message = '')
    {
        Assert::assertXmlStringEqualsXmlFile($expectedFile, $actualXml, $message);
    }

    /**
     * Asserts that two XML documents are equal.
     *
     * @param DOMDocument|string $expectedXml
     * @param DOMDocument|string $actualXml
     * @param string $message
     */
    protected function assertXmlStringEqualsXmlString($expectedXml, $actualXml, $message = '')
    {
        Assert::assertXmlStringEqualsXmlString($expectedXml, $actualXml, $message);
    }

    /**
     * Asserts that two XML documents are not equal.
     *
     * @param string $expectedFile
     * @param DOMDocument|string $actualXml
     * @param string $message
     */
    protected function assertXmlStringNotEqualsXmlFile($expectedFile, $actualXml, $message = '')
    {
        Assert::assertXmlStringNotEqualsXmlFile($expectedFile, $actualXml, $message);
    }

    /**
     * Asserts that two XML documents are not equal.
     *
     * @param DOMDocument|string $expectedXml
     * @param DOMDocument|string $actualXml
     * @param string $message
     */
    protected function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, $message = '')
    {
        Assert::assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, $message);
    }

    /**
     * Fails a test with the given message.
     *
     * @param string $message
     */
    protected function fail($message = '')
    {
        Assert::fail($message);
    }

    /**
     * Mark the test as incomplete.
     *
     * @param string $message
     */
    protected function markTestIncomplete($message = '')
    {
        Assert::markTestIncomplete($message);
    }

    /**
     * Mark the test as skipped.
     *
     * @param string $message
     */
    protected function markTestSkipped($message = '')
    {
        Assert::markTestSkipped($message);
    }
}<?php
namespace Codeception\Lib\Interfaces;

interface Db
{
    /**
     * Asserts that a row with the given column values exists.
     * Provide table name and column values.
     *
     * ```php
     * <?php
     * $I->seeInDatabase('users', ['name' => 'Davert', 'email' => 'davert@mail.com']);
     * ```
     * Fails if no such user found.
     *
     * Comparison expressions can be used as well:
     *
     * ```php
     * <?php
     * $I->seeInDatabase('posts', ['num_comments >=' => '0']);
     * $I->seeInDatabase('users', ['email like' => 'miles@davis.com']);
     * ```
     *
     * Supported operators: `<`, `>`, `>=`, `<=`, `!=`, `like`.
     *
     *
     * @param string $table
     * @param array $criteria
     */
    public function seeInDatabase($table, $criteria = []);

    /**
     * Effect is opposite to ->seeInDatabase
     *
     * Asserts that there is no record with the given column values in a database.
     * Provide table name and column values.
     *
     * ``` php
     * <?php
     * $I->dontSeeInDatabase('users', ['name' => 'Davert', 'email' => 'davert@mail.com']);
     * ```
     * Fails if such user was found.
     *
     * Comparison expressions can be used as well:
     *
     * ```php
     * <?php
     * $I->dontSeeInDatabase('posts', ['num_comments >=' => '0']);
     * $I->dontSeeInDatabase('users', ['email like' => 'miles%']);
     * ```
     *
     * Supported operators: `<`, `>`, `>=`, `<=`, `!=`, `like`.
     *
     * @param string $table
     * @param array $criteria
     */
    public function dontSeeInDatabase($table, $criteria = []);

    /**
     * Fetches a single column value from a database.
     * Provide table name, desired column and criteria.
     *
     * ``` php
     * <?php
     * $mail = $I->grabFromDatabase('users', 'email', array('name' => 'Davert'));
     * ```
     * Comparison expressions can be used as well:
     *
     * ```php
     * <?php
     * $post = $I->grabFromDatabase('posts', ['num_comments >=' => 100]);
     * $user = $I->grabFromDatabase('users', ['email like' => 'miles%']);
     * ```
     *
     * Supported operators: `<`, `>`, `>=`, `<=`, `!=`, `like`.
     *
     * @param string $table
     * @param string $column
     * @param array $criteria
     *
     * @return mixed
     */
    public function grabFromDatabase($table, $column, $criteria = []);
}
<?php

namespace Codeception\Lib\Driver;

use Codeception\Exception\ModuleException;

class Db
{
    /**
     * @var \PDO
     */
    protected $dbh;

    /**
     * @var string
     */
    protected $dsn;

    protected $user;
    protected $password;

    /**
     * @var array
     *
     * @see http://php.net/manual/de/pdo.construct.php
     */
    protected $options;

    /**
     * associative array with table name => primary-key
     *
     * @var array
     */
    protected $primaryKeys = [];

    public static function connect($dsn, $user, $password, $options = null)
    {
        $dbh = new \PDO($dsn, $user, $password, $options);
        $dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);

        return $dbh;
    }

    /**
     * @static
     *
     * @param $dsn
     * @param $user
     * @param $password
     * @param [optional] $options
     *
     * @see http://php.net/manual/en/pdo.construct.php
     * @see http://php.net/manual/de/ref.pdo-mysql.php#pdo-mysql.constants
     *
     * @return Db|SqlSrv|MySql|Oci|PostgreSql|Sqlite
     */
    public static function create($dsn, $user, $password, $options = null)
    {
        $provider = self::getProvider($dsn);

        switch ($provider) {
            case 'sqlite':
                return new Sqlite($dsn, $user, $password, $options);
            case 'mysql':
                return new MySql($dsn, $user, $password, $options);
            case 'pgsql':
                return new PostgreSql($dsn, $user, $password, $options);
            case 'mssql':
            case 'dblib':
            case 'sqlsrv':
                return new SqlSrv($dsn, $user, $password, $options);
            case 'oci':
                return new Oci($dsn, $user, $password, $options);
            default:
                return new Db($dsn, $user, $password, $options);
        }
    }

    public static function getProvider($dsn)
    {
        return substr($dsn, 0, strpos($dsn, ':'));
    }

    /**
     * @param $dsn
     * @param $user
     * @param $password
     * @param [optional] $options
     *
     * @see http://php.net/manual/en/pdo.construct.php
     * @see http://php.net/manual/de/ref.pdo-mysql.php#pdo-mysql.constants
     */
    public function __construct($dsn, $user, $password, $options = null)
    {
        $this->dbh = new \PDO($dsn, $user, $password, $options);
        $this->dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);

        $this->dsn = $dsn;
        $this->user = $user;
        $this->password = $password;
        $this->options = $options;
    }

    public function __destruct()
    {
        if ($this->dbh->inTransaction()) {
            $this->dbh->rollBack();
        }
        $this->dbh = null;
    }

    public function getDbh()
    {
        return $this->dbh;
    }

    public function getDb()
    {
        $matches = [];
        $matched = preg_match('~dbname=(\w+)~s', $this->dsn, $matches);
        if (!$matched) {
            return false;
        }

        return $matches[1];
    }

    public function cleanup()
    {
    }

    /**
     * Set the lock waiting interval for the database session
     * @param int $seconds
     * @return void
     */
    public function setWaitLock($seconds)
    {
    }

    public function load($sql)
    {
        $query = '';
        $delimiter = ';';
        $delimiterLength = 1;

        foreach ($sql as $sqlLine) {
            if (preg_match('/DELIMITER ([\;\$\|\\\\]+)/i', $sqlLine, $match)) {
                $delimiter = $match[1];
                $delimiterLength = strlen($delimiter);
                continue;
            }

            $parsed = $this->sqlLine($sqlLine);
            if ($parsed) {
                continue;
            }

            $query .= "\n" . rtrim($sqlLine);

            if (substr($query, -1 * $delimiterLength, $delimiterLength) == $delimiter) {
                $this->sqlQuery(substr($query, 0, -1 * $delimiterLength));
                $query = '';
            }
        }

        if ($query !== '') {
            $this->sqlQuery($query);
        }
    }

    public function insert($tableName, array &$data)
    {
        $columns = array_map(
            [$this, 'getQuotedName'],
            array_keys($data)
        );

        return sprintf(
            "INSERT INTO %s (%s) VALUES (%s)",
            $this->getQuotedName($tableName),
            implode(', ', $columns),
            implode(', ', array_fill(0, count($data), '?'))
        );
    }

    public function select($column, $table, array &$criteria)
    {
        $where = $this->generateWhereClause($criteria);

        $query = "SELECT %s FROM %s %s";
        return sprintf($query, $column, $this->getQuotedName($table), $where);
    }

    private function getSupportedOperators()
    {
        return [
            'like',
            '!=',
            '<=',
            '>=',
            '<',
            '>',
        ];
    }

    protected function generateWhereClause(array &$criteria)
    {
        if (empty($criteria)) {
            return '';
        }

        $operands = $this->getSupportedOperators();

        $params = [];
        foreach ($criteria as $k => $v) {
            if ($v === null) {
                if (strpos($k, ' !=') > 0) {
                    $params[] = $this->getQuotedName(str_replace(" !=", '', $k)) . " IS NOT NULL ";
                } else {
                    $params[] = $this->getQuotedName($k) . " IS NULL ";
                }

                unset($criteria[$k]);
                continue;
            }

            $hasOperand = false; // search for equals - no additional operand given

            foreach ($operands as $operand) {
                if (!stripos($k, " $operand") > 0) {
                    continue;
                }

                $hasOperand = true;
                $k = str_ireplace(" $operand", '', $k);
                $operand = strtoupper($operand);
                $params[] = $this->getQuotedName($k) . " $operand ? ";
                break;
            }

            if (!$hasOperand) {
                $params[] = $this->getQuotedName($k) . " = ? ";
            }
        }

        return 'WHERE ' . implode('AND ', $params);
    }

    public function deleteQueryByCriteria($table, array $criteria)
    {
        $where = $this->generateWhereClause($criteria);

        $query = 'DELETE FROM ' . $this->getQuotedName($table) . ' ' . $where;
        $this->executeQuery($query, array_values($criteria));
    }

    public function lastInsertId($table)
    {
        return $this->getDbh()->lastInsertId();
    }

    public function getQuotedName($name)
    {
        return '"' . str_replace('.', '"."', $name) . '"';
    }

    protected function sqlLine($sql)
    {
        $sql = trim($sql);
        return (
            $sql === ''
            || $sql === ';'
            || preg_match('~^((--.*?)|(#))~s', $sql)
        );
    }

    protected function sqlQuery($query)
    {
        try {
            $this->dbh->exec($query);
        } catch (\PDOException $e) {
            throw new ModuleException(
                'Codeception\Module\Db',
                $e->getMessage() . "\nSQL query being executed: " . $query
            );
        }
    }

    public function executeQuery($query, array $params)
    {
        $sth = $this->dbh->prepare($query);
        if (!$sth) {
            throw new \Exception("Query '$query' can't be prepared.");
        }

        $i = 0;
        foreach ($params as $value) {
            $i++;
            if (is_bool($value)) {
                $type = \PDO::PARAM_BOOL;
            } elseif (is_int($value)) {
                $type = \PDO::PARAM_INT;
            } else {
                $type = \PDO::PARAM_STR;
            }
            $sth->bindValue($i, $value, $type);
        }

        $sth->execute();
        return $sth;
    }

    /**
     * @param string $tableName
     *
     * @return array[string]
     */
    public function getPrimaryKey($tableName)
    {
        return [];
    }

    /**
     * @return bool
     */
    protected function flushPrimaryColumnCache()
    {
        $this->primaryKeys = [];

        return empty($this->primaryKeys);
    }

    public function update($table, array $data, array $criteria)
    {
        if (empty($data)) {
            throw new \InvalidArgumentException(
                "Query update can't be prepared without data."
            );
        }

        $set = [];
        foreach ($data as $column => $value) {
            $set[] = $this->getQuotedName($column) . " = ?";
        }

        $where = $this->generateWhereClause($criteria);

        return sprintf('UPDATE %s SET %s %s', $this->getQuotedName($table), implode(', ', $set), $where);
    }

    public function getOptions()
    {
        return $this->options;
    }
}
<?php
namespace Codeception\Lib\Driver;

class MySql extends Db
{
    public function cleanup()
    {
        $this->dbh->exec('SET FOREIGN_KEY_CHECKS=0;');
        $res = $this->dbh->query("SHOW FULL TABLES WHERE TABLE_TYPE LIKE '%TABLE';")->fetchAll();
        foreach ($res as $row) {
            $this->dbh->exec('drop table `' . $row[0] . '`');
        }
        $this->dbh->exec('SET FOREIGN_KEY_CHECKS=1;');
    }

    protected function sqlQuery($query)
    {
        $this->dbh->exec('SET FOREIGN_KEY_CHECKS=0;');
        parent::sqlQuery($query);
        $this->dbh->exec('SET FOREIGN_KEY_CHECKS=1;');
    }

    public function getQuotedName($name)
    {
        return '`' . str_replace('.', '`.`', $name) . '`';
    }

    /**
     * @param string $tableName
     *
     * @return array[string]
     */
    public function getPrimaryKey($tableName)
    {
        if (!isset($this->primaryKeys[$tableName])) {
            $primaryKey = [];
            $stmt = $this->getDbh()->query(
                'SHOW KEYS FROM ' . $this->getQuotedName($tableName) . " WHERE Key_name = 'PRIMARY'"
            );
            $columns = $stmt->fetchAll(\PDO::FETCH_ASSOC);

            foreach ($columns as $column) {
                $primaryKey []= $column['Column_name'];
            }
            $this->primaryKeys[$tableName] = $primaryKey;
        }

        return $this->primaryKeys[$tableName];
    }
}
<?php
namespace Codeception\Lib\Driver;

class Oci extends Db
{
    public function setWaitLock($seconds)
    {
        $this->dbh->exec('ALTER SESSION SET ddl_lock_timeout = ' . (int) $seconds);
    }

    public function cleanup()
    {
        $this->dbh->exec(
            "BEGIN
                        FOR i IN (SELECT trigger_name FROM user_triggers)
                          LOOP
                            EXECUTE IMMEDIATE('DROP TRIGGER ' || user || '.\"' || i.trigger_name || '\"');
                          END LOOP;
                      END;"
        );
        $this->dbh->exec(
            "BEGIN
                        FOR i IN (SELECT table_name FROM user_tables)
                          LOOP
                            EXECUTE IMMEDIATE('DROP TABLE ' || user || '.\"' || i.table_name || '\" CASCADE CONSTRAINTS');
                          END LOOP;
                      END;"
        );
        $this->dbh->exec(
            "BEGIN
                        FOR i IN (SELECT sequence_name FROM user_sequences)
                          LOOP
                            EXECUTE IMMEDIATE('DROP SEQUENCE ' || user || '.\"' || i.sequence_name || '\"');
                          END LOOP;
                      END;"
        );
        $this->dbh->exec(
            "BEGIN
                        FOR i IN (SELECT view_name FROM user_views)
                          LOOP
                            EXECUTE IMMEDIATE('DROP VIEW ' || user || '.\"' || i.view_name || '\"');
                          END LOOP;
                      END;"
        );
    }

    /**
     * SQL commands should ends with `//` in the dump file
     * IF you want to load triggers too.
     * IF you do not want to load triggers you can use the `;` characters
     * but in this case you need to change the $delimiter from `//` to `;`
     *
     * @param $sql
     */
    public function load($sql)
    {
        $query = '';
        $delimiter = '//';
        $delimiterLength = 2;

        foreach ($sql as $sqlLine) {
            if (preg_match('/DELIMITER ([\;\$\|\\\\]+)/i', $sqlLine, $match)) {
                $delimiter = $match[1];
                $delimiterLength = strlen($delimiter);
                continue;
            }

            $parsed = $this->sqlLine($sqlLine);
            if ($parsed) {
                continue;
            }

            $query .= "\n" . rtrim($sqlLine);

            if (substr($query, -1 * $delimiterLength, $delimiterLength) == $delimiter) {
                $this->sqlQuery(substr($query, 0, -1 * $delimiterLength));
                $query = "";
            }
        }

        if ($query !== '') {
            $this->sqlQuery($query);
        }
    }

    /**
     * @param string $tableName
     *
     * @return array[string]
     */
    public function getPrimaryKey($tableName)
    {
        if (!isset($this->primaryKeys[$tableName])) {
            $primaryKey = [];
            $query = "SELECT cols.column_name
                FROM all_constraints cons, all_cons_columns cols
                WHERE cols.table_name = ?
                AND cons.constraint_type = 'P'
                AND cons.constraint_name = cols.constraint_name
                AND cons.owner = cols.owner
                ORDER BY cols.table_name, cols.position";
            $stmt = $this->executeQuery($query, [$tableName]);
            $columns = $stmt->fetchAll(\PDO::FETCH_ASSOC);

            foreach ($columns as $column) {
                $primaryKey []= $column['COLUMN_NAME'];
            }
            $this->primaryKeys[$tableName] = $primaryKey;
        }

        return $this->primaryKeys[$tableName];
    }
}
<?php
namespace Codeception\Lib\Driver;

class SqlSrv extends Db
{
    public function getDb()
    {
        $matches = [];
        $matched = preg_match('~Database=(.*);?~s', $this->dsn, $matches);

        if (!$matched) {
            return false;
        }

        return $matches[1];
    }

    public function cleanup()
    {
        $this->dbh->exec(
            "
            DECLARE constraints_cursor CURSOR FOR SELECT name, parent_object_id FROM sys.foreign_keys;
            OPEN constraints_cursor
            DECLARE @constraint sysname;
            DECLARE @parent int;
            DECLARE @table nvarchar(128);
            FETCH NEXT FROM constraints_cursor INTO @constraint, @parent;
            WHILE (@@FETCH_STATUS <> -1)
            BEGIN
                SET @table = OBJECT_NAME(@parent)
                EXEC ('ALTER TABLE [' + @table + '] DROP CONSTRAINT [' + @constraint + ']')
                FETCH NEXT FROM constraints_cursor INTO @constraint, @parent;
            END
            DEALLOCATE constraints_cursor;"
        );

        $this->dbh->exec(
            "
            DECLARE tables_cursor CURSOR FOR SELECT name FROM sysobjects WHERE type = 'U';
            OPEN tables_cursor DECLARE @tablename sysname;
            FETCH NEXT FROM tables_cursor INTO @tablename;
            WHILE (@@FETCH_STATUS <> -1)
            BEGIN
                EXEC ('DROP TABLE [' + @tablename + ']')
                FETCH NEXT FROM tables_cursor INTO @tablename;
            END
            DEALLOCATE tables_cursor;"
        );
    }

    public function getQuotedName($name)
    {
        return '[' . str_replace('.', '].[', $name) . ']';
    }

    /**
     * @param string $tableName
     *
     * @return array[string]
     */
    public function getPrimaryKey($tableName)
    {
        if (!isset($this->primaryKeys[$tableName])) {
            $primaryKey = [];
            $query = "
                SELECT Col.Column_Name from
                    INFORMATION_SCHEMA.TABLE_CONSTRAINTS Tab,
                    INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE Col
                WHERE
                    Col.Constraint_Name = Tab.Constraint_Name
                    AND Col.Table_Name = Tab.Table_Name
                    AND Constraint_Type = 'PRIMARY KEY' AND Col.Table_Name = ?";
            $stmt = $this->executeQuery($query, [$tableName]);
            $columns = $stmt->fetchAll(\PDO::FETCH_ASSOC);

            foreach ($columns as $column) {
                $primaryKey []= $column['Column_Name'];
            }
            $this->primaryKeys[$tableName] = $primaryKey;
        }

        return $this->primaryKeys[$tableName];
    }
}
<?php

namespace Codeception\Lib\Driver;

use Codeception\Exception\ModuleException;

class PostgreSql extends Db
{
    protected $putline = false;

    protected $connection = null;

    protected $searchPath = null;

    /**
     * Loads a SQL file.
     *
     * @param string $sql sql file
     */
    public function load($sql)
    {
        $query = '';
        $delimiter = ';';
        $delimiterLength = 1;

        $dollarsOpen = false;
        foreach ($sql as $sqlLine) {
            if (preg_match('/DELIMITER ([\;\$\|\\\\]+)/i', $sqlLine, $match)) {
                $delimiter = $match[1];
                $delimiterLength = strlen($delimiter);
                continue;
            }

            $parsed = trim($query) == '' && $this->sqlLine($sqlLine);
            if ($parsed) {
                continue;
            }

            // Ignore $$ inside SQL standard string syntax such as in INSERT statements.
            if (!preg_match('/\'.*\$\$.*\'/', $sqlLine)) {
                $pos = strpos($sqlLine, '$$');
                if (($pos !== false) && ($pos >= 0)) {
                    $dollarsOpen = !$dollarsOpen;
                }
            }

            if (preg_match('/SET search_path = .*/i', $sqlLine, $match)) {
                $this->searchPath = $match[0];
            }

            $query .= "\n" . rtrim($sqlLine);

            if (!$dollarsOpen && substr($query, -1 * $delimiterLength, $delimiterLength) == $delimiter) {
                $this->sqlQuery(substr($query, 0, -1 * $delimiterLength));
                $query = '';
            }
        }

        if ($query !== '') {
            $this->sqlQuery($query);
        }
    }

    public function cleanup()
    {
        $this->dbh->exec('DROP SCHEMA IF EXISTS public CASCADE;');
        $this->dbh->exec('CREATE SCHEMA public;');
    }

    public function sqlLine($sql)
    {
        if (!$this->putline) {
            return parent::sqlLine($sql);
        }

        if ($sql == '\.') {
            $this->putline = false;
            pg_put_line($this->connection, $sql . "\n");
            pg_end_copy($this->connection);
            pg_close($this->connection);
        } else {
            pg_put_line($this->connection, $sql . "\n");
        }

        return true;
    }

    public function sqlQuery($query)
    {
        if (strpos(trim($query), 'COPY ') === 0) {
            if (!extension_loaded('pgsql')) {
                throw new ModuleException(
                    '\Codeception\Module\Db',
                    "To run 'COPY' commands 'pgsql' extension should be installed"
                );
            }
            $constring = str_replace(';', ' ', substr($this->dsn, 6));
            $constring .= ' user=' . $this->user;
            $constring .= ' password=' . $this->password;
            $this->connection = pg_connect($constring);

            if ($this->searchPath !== null) {
                pg_query($this->connection, $this->searchPath);
            }

            pg_query($this->connection, $query);
            $this->putline = true;
        } else {
            $this->dbh->exec($query);
        }
    }

    /**
     * Get the last inserted ID of table.
     */
    public function lastInsertId($table)
    {
        /*
         * We make an assumption that the sequence name for this table
         * is based on how postgres names sequences for SERIAL columns
         */

        $sequenceName = $this->getQuotedName($table . '_id_seq');
        $lastSequence = null;

        try {
            $lastSequence = $this->getDbh()->lastInsertId($sequenceName);
        } catch (\PDOException $e) {
            // in this case, the sequence name might be combined with the primary key name
        }

        // here we check if for instance, it's something like table_primary_key_seq instead of table_id_seq
        // this could occur when you use some kind of import tool like pgloader
        if (!$lastSequence) {
            $primaryKeys = $this->getPrimaryKey($table);
            $pkName = array_shift($primaryKeys);
            $lastSequence = $this->getDbh()->lastInsertId($this->getQuotedName($table . '_' . $pkName . '_seq'));
        }

        return $lastSequence;
    }

    /**
     * Returns the primary key(s) of the table, based on:
     * https://wiki.postgresql.org/wiki/Retrieve_primary_key_columns.
     *
     * @param string $tableName
     *
     * @return array[string]
     */
    public function getPrimaryKey($tableName)
    {
        if (!isset($this->primaryKeys[$tableName])) {
            $primaryKey = [];
            $query = "SELECT a.attname
                FROM   pg_index i
                JOIN   pg_attribute a ON a.attrelid = i.indrelid
                                     AND a.attnum = ANY(i.indkey)
                WHERE  i.indrelid = '$tableName'::regclass
                AND    i.indisprimary";
            $stmt = $this->executeQuery($query, []);
            $columns = $stmt->fetchAll(\PDO::FETCH_ASSOC);
            foreach ($columns as $column) {
                $primaryKey []= $column['attname'];
            }
            $this->primaryKeys[$tableName] = $primaryKey;
        }

        return $this->primaryKeys[$tableName];
    }
}
<?php
namespace Codeception\Lib\Driver;

use Codeception\Configuration;
use Codeception\Exception\ModuleException;

class Sqlite extends Db
{
    protected $hasSnapshot = false;
    protected $filename = '';
    protected $con = null;

    public function __construct($dsn, $user, $password, $options = null)
    {
        $filename = substr($dsn, 7);
        if ($filename === ':memory:') {
            throw new ModuleException(__CLASS__, ':memory: database is not supported');
        }

        $this->filename = Configuration::projectDir() . $filename;
        $this->dsn = 'sqlite:' . $this->filename;
        parent::__construct($this->dsn, $user, $password, $options);
    }

    public function cleanup()
    {
        $this->dbh = null;
        gc_collect_cycles();
        file_put_contents($this->filename, '');
        $this->dbh = self::connect($this->dsn, $this->user, $this->password);
    }

    public function load($sql)
    {
        if ($this->hasSnapshot) {
            $this->dbh = null;
            copy($this->filename . '_snapshot', $this->filename);
            $this->dbh = new \PDO($this->dsn, $this->user, $this->password);
        } else {
            if (file_exists($this->filename . '_snapshot')) {
                unlink($this->filename . '_snapshot');
            }
            parent::load($sql);
            copy($this->filename, $this->filename . '_snapshot');
            $this->hasSnapshot = true;
        }
    }

    /**
     * @param string $tableName
     *
     * @return array[string]
     */
    public function getPrimaryKey($tableName)
    {
        if (!isset($this->primaryKeys[$tableName])) {
            if ($this->hasRowId($tableName)) {
                return $this->primaryKeys[$tableName] = ['_ROWID_'];
            }

            $primaryKey = [];
            $query = 'PRAGMA table_info(' . $this->getQuotedName($tableName) . ')';
            $stmt = $this->executeQuery($query, []);
            $columns = $stmt->fetchAll(\PDO::FETCH_ASSOC);

            foreach ($columns as $column) {
                if ($column['pk'] !== '0') {
                    $primaryKey []= $column['name'];
                }
            }

            $this->primaryKeys[$tableName] = $primaryKey;
        }

        return $this->primaryKeys[$tableName];
    }

    /**
     * @param $tableName
     * @return bool
     */
    private function hasRowId($tableName)
    {
        $params = ['type' => 'table', 'name' => $tableName];
        $select = $this->select('sql', 'sqlite_master', $params);
        $result = $this->executeQuery($select, $params);
        $sql = $result->fetchColumn(0);
        return strpos($sql, ') WITHOUT ROWID') === false;
    }
}
<?php

namespace Codeception\Lib;

/**
 * Populates a db using a parameterized command built from the Db module configuration.
 */
class DbPopulator
{
    /**
     * @var array
     */
    protected $config;

    /**
     * @var array
     */
    protected $commands;

    /**
     * Constructs a DbPopulator object for the given command and Db module.
     *
     * @param $config
     * @internal param string $command The parameterized command to evaluate and execute later.
     * @internal param Codeception\Module\Db|null $dbModule The Db module used to build the populator command or null.
     */
    public function __construct($config)
    {
        $this->config = $config;

        //Convert To Array Format
        if (isset($this->config['dump']) && !is_array($this->config['dump'])) {
            $this->config['dump'] = [$this->config['dump']];
        }
    }

    /**
     * Builds out a command replacing any found `$key` with its value if found in the given configuration.
     *
     * Process any $key found in the configuration array as a key of the array and replaces it with
     * the found value for the key. Example:
     *
     * ```php
     * <?php
     *
     * $command = 'Hello $name';
     * $config = ['name' => 'Mauro'];
     *
     * // With the above parameters it will return `'Hello Mauro'`.
     * ```
     *
     * @param string $command The command to be evaluated using the given config
     * @param string|null $dumpFile The dump file to build the command with.
     * @return string The resulting command string after evaluating any configuration's key
     */
    protected function buildCommand($command, $dumpFile = null)
    {
        $dsn = isset($this->config['dsn']) ? $this->config['dsn'] : '';
        $dsnVars = [];
        $dsnWithoutDriver = preg_replace('/^[a-z]+:/i', '', $dsn);
        foreach (explode(';', $dsnWithoutDriver) as $item) {
            $keyValueTuple = explode('=', $item);
            if (count($keyValueTuple) > 1) {
                list($k, $v) = array_values($keyValueTuple);
                $dsnVars[$k] = $v;
            }
        }

        $vars = array_merge($dsnVars, $this->config);

        if ($dumpFile !== null) {
            $vars['dump'] = $dumpFile;
        }

        foreach ($vars as $key => $value) {
            if (!is_array($value)) {
                $vars['$'.$key] = $value;
            }

            unset($vars[$key]);
        }
        return str_replace(array_keys($vars), $vars, $command);
    }

    /**
     * Executes the command built using the Db module configuration.
     *
     * Uses the PHP `exec` to spin off a child process for the built command.
     *
     * @return bool
     */
    public function run()
    {
        foreach ($this->buildCommands() as $command) {
            $this->runCommand($command);
        }

        return true;
    }

    private function runCommand($command)
    {
        codecept_debug("[Db] Executing Populator: `$command`");

        exec($command, $output, $exitCode);

        if (0 !== $exitCode) {
            throw new \RuntimeException(
                "The populator command did not end successfully: \n" .
                "  Exit code: $exitCode \n" .
                "  Output:" . implode("\n", $output)
            );
        }

        codecept_debug("[Db] Populator Finished.");
    }

    public function buildCommands()
    {
        if ($this->commands !== null) {
            return $this->commands;
        } elseif (!isset($this->config['dump']) || $this->config['dump'] === false) {
            return [$this->buildCommand($this->config['populator'])];
        }

        $this->commands = [];

        foreach ($this->config['dump'] as $dumpFile) {
            $this->commands[] = $this->buildCommand($this->config['populator'], $dumpFile);
        }

        return $this->commands;
    }
}
<?php
namespace Codeception\Module;

use Codeception\Module as CodeceptionModule;
use Codeception\Configuration;
use Codeception\Exception\ModuleException;
use Codeception\Exception\ModuleConfigException;
use Codeception\Lib\Interfaces\Db as DbInterface;
use Codeception\Lib\Driver\Db as Driver;
use Codeception\Lib\DbPopulator;
use Codeception\TestInterface;
use Codeception\Lib\Notification;
use Codeception\Util\ActionSequence;

/**
 * Access a database.
 *
 * The most important function of this module is to clean a database before each test.
 * This module also provides actions to perform checks in a database, e.g. [seeInDatabase()](http://codeception.com/docs/modules/Db#seeInDatabase)
 *
 * In order to have your database populated with data you need a raw SQL dump.
 * Simply put the dump in the `tests/_data` directory (by default) and specify the path in the config.
 * The next time after the database is cleared, all your data will be restored from the dump.
 * Don't forget to include `CREATE TABLE` statements in the dump.
 *
 * Supported and tested databases are:
 *
 * * MySQL
 * * SQLite (i.e. just one file)
 * * PostgreSQL
 *
 * Also available:
 *
 * * MS SQL
 * * Oracle
 *
 * Connection is done by database Drivers, which are stored in the `Codeception\Lib\Driver` namespace.
 * [Check out the drivers](https://github.com/Codeception/Codeception/tree/2.4/src/Codeception/Lib/Driver)
 * if you run into problems loading dumps and cleaning databases.
 *
 * ## Config
 *
 * * dsn *required* - PDO DSN
 * * user *required* - username to access database
 * * password *required* - password
 * * dump - path to database dump
 * * populate: false - whether the the dump should be loaded before the test suite is started
 * * cleanup: false - whether the dump should be reloaded before each test
 * * reconnect: false - whether the module should reconnect to the database before each test
 * * waitlock: 0 - wait lock (in seconds) that the database session should use for DDL statements
 * * ssl_key - path to the SSL key (MySQL specific, @see http://php.net/manual/de/ref.pdo-mysql.php#pdo.constants.mysql-attr-key)
 * * ssl_cert - path to the SSL certificate (MySQL specific, @see http://php.net/manual/de/ref.pdo-mysql.php#pdo.constants.mysql-attr-ssl-cert)
 * * ssl_ca - path to the SSL certificate authority (MySQL specific, @see http://php.net/manual/de/ref.pdo-mysql.php#pdo.constants.mysql-attr-ssl-ca)
 * * ssl_verify_server_cert - disables certificate CN verification (MySQL specific, @see http://php.net/manual/de/ref.pdo-mysql.php)
 * * ssl_cipher - list of one or more permissible ciphers to use for SSL encryption (MySQL specific, @see http://php.net/manual/de/ref.pdo-mysql.php#pdo.constants.mysql-attr-cipher)
 * * databases - include more database configs and switch between them in tests.
 * * initial_queries - list of queries to be executed right after connection to the database has been initiated, i.e. creating the database if it does not exist or preparing the database collation
 *
 * ## Example
 *
 *     modules:
 *        enabled:
 *           - Db:
 *              dsn: 'mysql:host=localhost;dbname=testdb'
 *              user: 'root'
 *              password: ''
 *              dump: 'tests/_data/dump.sql'
 *              populate: true
 *              cleanup: true
 *              reconnect: true
 *              waitlock: 10
 *              ssl_key: '/path/to/client-key.pem'
 *              ssl_cert: '/path/to/client-cert.pem'
 *              ssl_ca: '/path/to/ca-cert.pem'
 *              ssl_verify_server_cert: false
 *              ssl_cipher: 'AES256-SHA'
 *              initial_queries:
 *                  - 'CREATE DATABASE IF NOT EXISTS temp_db;'
 *                  - 'USE temp_db;'
 *                  - 'SET NAMES utf8;'
 *
 * ## Example with multi-dumps
 *     modules:
 *          enabled:
 *             - Db:
 *                dsn: 'mysql:host=localhost;dbname=testdb'
 *                user: 'root'
 *                password: ''
 *                dump:
 *                   - 'tests/_data/dump.sql'
 *                   - 'tests/_data/dump-2.sql'
 *
 * ## Example with multi-databases
 *
 *     modules:
 *        enabled:
 *           - Db:
 *              dsn: 'mysql:host=localhost;dbname=testdb'
 *              user: 'root'
 *              password: ''
 *              databases:
 *                 db2:
 *                    dsn: 'mysql:host=localhost;dbname=testdb2'
 *                    user: 'userdb2'
 *                    password: ''
 *
 * ## Example with Sqlite
 *
 *     modules:
 *        enabled:
 *           - Db:
 *              dsn: 'sqlite:relative/path/to/sqlite-database.db'
 *              user: ''
 *              password: ''
 *
 * ## SQL data dump
 *
 * There are two ways of loading the dump into your database:
 *
 * ### Populator
 *
 * The recommended approach is to configure a `populator`, an external command to load a dump. Command parameters like host, username, password, database
 * can be obtained from the config and inserted into placeholders:
 *
 * For MySQL:
 *
 * ```yaml
 * modules:
 *    enabled:
 *       - Db:
 *          dsn: 'mysql:host=localhost;dbname=testdb'
 *          user: 'root'
 *          password: ''
 *          dump: 'tests/_data/dump.sql'
 *          populate: true # run populator before all tests
 *          cleanup: true # run populator before each test
 *          populator: 'mysql -u $user -h $host $dbname < $dump'
 * ```
 *
 * For PostgreSQL (using pg_restore)
 *
 * ```
 * modules:
 *    enabled:
 *       - Db:
 *          dsn: 'pgsql:host=localhost;dbname=testdb'
 *          user: 'root'
 *          password: ''
 *          dump: 'tests/_data/db_backup.dump'
 *          populate: true # run populator before all tests
 *          cleanup: true # run populator before each test
 *          populator: 'pg_restore -u $user -h $host -D $dbname < $dump'
 * ```
 *
 *  Variable names are being taken from config and DSN which has a `keyword=value` format, so you should expect to have a variable named as the
 *  keyword with the full value inside it.
 *
 *  PDO dsn elements for the supported drivers:
 *  * MySQL: [PDO_MYSQL DSN](https://secure.php.net/manual/en/ref.pdo-mysql.connection.php)
 *  * SQLite: [PDO_SQLITE DSN](https://secure.php.net/manual/en/ref.pdo-sqlite.connection.php) - use _relative_ path from the project root
 *  * PostgreSQL: [PDO_PGSQL DSN](https://secure.php.net/manual/en/ref.pdo-pgsql.connection.php)
 *  * MSSQL: [PDO_SQLSRV DSN](https://secure.php.net/manual/en/ref.pdo-sqlsrv.connection.php)
 *  * Oracle: [PDO_OCI DSN](https://secure.php.net/manual/en/ref.pdo-oci.connection.php)
 *
 * ### Dump
 *
 * Db module by itself can load SQL dump without external tools by using current database connection.
 * This approach is system-independent, however, it is slower than using a populator and may have parsing issues (see below).
 *
 * Provide a path to SQL file in `dump` config option:
 *
 * ```yaml
 * modules:
 *    enabled:
 *       - Db:
 *          dsn: 'mysql:host=localhost;dbname=testdb'
 *          user: 'root'
 *          password: ''
 *          populate: true # load dump before all tests
 *          cleanup: true # load dump for each test
 *          dump: 'tests/_data/dump.sql'
 * ```
 *
 *  To parse SQL Db file, it should follow this specification:
 *  * Comments are permitted.
 *  * The `dump.sql` may contain multiline statements.
 *  * The delimiter, a semi-colon in this case, must be on the same line as the last statement:
 *
 * ```sql
 * -- Add a few contacts to the table.
 * REPLACE INTO `Contacts` (`created`, `modified`, `status`, `contact`, `first`, `last`) VALUES
 * (NOW(), NOW(), 1, 'Bob Ross', 'Bob', 'Ross'),
 * (NOW(), NOW(), 1, 'Fred Flintstone', 'Fred', 'Flintstone');
 *
 * -- Remove existing orders for testing.
 * DELETE FROM `Order`;
 * ```
 * ## Query generation
 *
 * `seeInDatabase`, `dontSeeInDatabase`, `seeNumRecords`, `grabFromDatabase` and `grabNumRecords` methods
 * accept arrays as criteria. WHERE condition is generated using item key as a field name and
 * item value as a field value.
 *
 * Example:
 * ```php
 * <?php
 * $I->seeInDatabase('users', ['name' => 'Davert', 'email' => 'davert@mail.com']);
 *
 * ```
 * Will generate:
 *
 * ```sql
 * SELECT COUNT(*) FROM `users` WHERE `name` = 'Davert' AND `email` = 'davert@mail.com'
 * ```
 * Since version 2.1.9 it's possible to use LIKE in a condition, as shown here:
 *
 * ```php
 * <?php
 * $I->seeInDatabase('users', ['name' => 'Davert', 'email like' => 'davert%']);
 *
 * ```
 * Will generate:
 *
 * ```sql
 * SELECT COUNT(*) FROM `users` WHERE `name` = 'Davert' AND `email` LIKE 'davert%'
 * ```
 * Null comparisons are also available, as shown here:
 *
 * ```php
 * <?php
 * $I->seeInDatabase('users', ['name' => null, 'email !=' => null]);
 *
 * ```
 * Will generate:
 *
 * ```sql
 * SELECT COUNT(*) FROM `users` WHERE `name` IS NULL AND `email` IS NOT NULL
 * ```
 * ## Public Properties
 * * dbh - contains the PDO connection
 * * driver - contains the Connection Driver
 *
 */
class Db extends CodeceptionModule implements DbInterface
{
    /**
     * @var array
     */
    protected $config = [
        'populate' => false,
        'cleanup' => false,
        'reconnect' => false,
        'waitlock' => 0,
        'dump' => null,
        'populator' => null,
    ];

    /**
     * @var array
     */
    protected $requiredFields = ['dsn', 'user', 'password'];
    const DEFAULT_DATABASE = 'default';

    /**
     * @var Driver[]
     */
    public $drivers = [];
    /**
     * @var \PDO[]
     */
    public $dbhs = [];
    public $databasesPopulated = [];
    public $databasesSql = [];
    protected $insertedRows = [];
    public $currentDatabase = self::DEFAULT_DATABASE;

    protected function getDatabases()
    {
        $databases = [$this->currentDatabase => $this->config];

        if (!empty($this->config['databases'])) {
            foreach ($this->config['databases'] as $databaseKey => $databaseConfig) {
                $databases[$databaseKey] = array_merge([
                    'populate' => false,
                    'cleanup' => false,
                    'reconnect' => false,
                    'waitlock' => 0,
                    'dump' => null,
                    'populator' => null,
                ], $databaseConfig);
            }
        }
        return $databases;
    }
    protected function connectToDatabases()
    {
        foreach ($this->getDatabases() as $databaseKey => $databaseConfig) {
            $this->connect($databaseKey, $databaseConfig);
        }
    }
    protected function cleanUpDatabases()
    {
        foreach ($this->getDatabases() as $databaseKey => $databaseConfig) {
            $this->_cleanup($databaseKey, $databaseConfig);
        }
    }
    protected function populateDatabases($configKey)
    {
        foreach ($this->getDatabases() as $databaseKey => $databaseConfig) {
            if ($databaseConfig[$configKey]) {
                if (!$databaseConfig['populate']) {
                    return;
                }

                if (isset($this->databasesPopulated[$databaseKey]) && $this->databasesPopulated[$databaseKey]) {
                    return;
                }
                $this->_loadDump($databaseKey, $databaseConfig);
            }
        }
    }
    protected function readSqlForDatabases()
    {
        foreach ($this->getDatabases() as $databaseKey => $databaseConfig) {
            $this->readSql($databaseKey, $databaseConfig);
        }
    }
    protected function removeInsertedForDatabases()
    {
        foreach ($this->getDatabases() as $databaseKey => $databaseConfig) {
            $this->amConnectedToDatabase($databaseKey);
            $this->removeInserted($databaseKey);
        }
    }
    protected function disconnectDatabases()
    {
        foreach ($this->getDatabases() as $databaseKey => $databaseConfig) {
            $this->disconnect($databaseKey);
        }
    }
    protected function reconnectDatabases()
    {
        foreach ($this->getDatabases() as $databaseKey => $databaseConfig) {
            if ($databaseConfig['reconnect']) {
                $this->disconnect($databaseKey);
                $this->connect($databaseKey, $databaseConfig);
            }
        }
    }

    public function __get($name)
    {
        Notification::deprecate("Properties dbh and driver are deprecated in favor of Db::_getDbh and Db::_getDriver", "Db module");

        if ($name == 'driver') {
            return $this->_getDriver();
        }
        if ($name == 'dbh') {
            return $this->_getDbh();
        }
    }

    /**
     * @return Driver
     */
    public function _getDriver()
    {
        return $this->drivers[$this->currentDatabase];
    }
    public function _getDbh()
    {
        return $this->dbhs[$this->currentDatabase];
    }

    /**
     * Make sure you are connected to the right database.
     *
     * ```php
     * <?php
     * $I->seeNumRecords(2, 'users');   //executed on default database
     * $I->amConnectedToDatabase('db_books');
     * $I->seeNumRecords(30, 'books');  //executed on db_books database
     * //All the next queries will be on db_books
     * ```
     * @param $databaseKey
     * @throws ModuleConfigException
     */
    public function amConnectedToDatabase($databaseKey)
    {
        if (empty($this->getDatabases()[$databaseKey]) && $databaseKey != self::DEFAULT_DATABASE) {
            throw new ModuleConfigException(
                __CLASS__,
                "\nNo database $databaseKey in the key databases.\n"
            );
        }
        $this->currentDatabase = $databaseKey;
    }

    /**
     * Can be used with a callback if you don't want to change the current database in your test.
     *
     * ```php
     * <?php
     * $I->seeNumRecords(2, 'users');   //executed on default database
     * $I->performInDatabase('db_books', function($I) {
     *     $I->seeNumRecords(30, 'books');  //executed on db_books database
     * });
     * $I->seeNumRecords(2, 'users');  //executed on default database
     * ```
     * List of actions can be pragmatically built using `Codeception\Util\ActionSequence`:
     *
     * ```php
     * <?php
     * $I->performInDatabase('db_books', ActionSequence::build()
     *     ->seeNumRecords(30, 'books')
     * );
     * ```
     * Alternatively an array can be used:
     *
     * ```php
     * $I->performInDatabase('db_books', ['seeNumRecords' => [30, 'books']]);
     * ```
     *
     * Choose the syntax you like the most and use it,
     *
     * Actions executed from array or ActionSequence will print debug output for actions, and adds an action name to
     * exception on failure.
     *
     * @param $databaseKey
     * @param \Codeception\Util\ActionSequence|array|callable $actions
     * @throws ModuleConfigException
     */
    public function performInDatabase($databaseKey, $actions)
    {
        $backupDatabase = $this->currentDatabase;
        $this->amConnectedToDatabase($databaseKey);

        if (is_callable($actions)) {
            $actions($this);
            $this->amConnectedToDatabase($backupDatabase);
            return;
        }
        if (is_array($actions)) {
            $actions = ActionSequence::build()->fromArray($actions);
        }

        if (!$actions instanceof ActionSequence) {
            throw new \InvalidArgumentException("2nd parameter, actions should be callback, ActionSequence or array");
        }

        $actions->run($this);
        $this->amConnectedToDatabase($backupDatabase);
    }

    public function _initialize()
    {
        $this->connectToDatabases();
    }

    public function __destruct()
    {
        $this->disconnectDatabases();
    }

    public function _beforeSuite($settings = [])
    {
        $this->readSqlForDatabases();
        $this->connectToDatabases();
        $this->cleanUpDatabases();
        $this->populateDatabases('populate');
    }

    private function readSql($databaseKey = null, $databaseConfig = null)
    {
        if ($databaseConfig['populator']) {
            return;
        }
        if (!$databaseConfig['cleanup'] && !$databaseConfig['populate']) {
            return;
        }
        if (empty($databaseConfig['dump'])) {
            return;
        }

        if (!is_array($databaseConfig['dump'])) {
            $databaseConfig['dump'] = [$databaseConfig['dump']];
        }

        $sql = '';

        foreach ($databaseConfig['dump'] as $filePath) {
            $sql .= $this->readSqlFile($filePath);
        }

        if (!empty($sql)) {
            // split SQL dump into lines
            $this->databasesSql[$databaseKey] = preg_split('/\r\n|\n|\r/', $sql, -1, PREG_SPLIT_NO_EMPTY);
        }
    }

    /**
     * @param $filePath
     *
     * @return bool|null|string|string[]
     * @throws \Codeception\Exception\ModuleConfigException
     */
    private function readSqlFile($filePath)
    {
        if (!file_exists(Configuration::projectDir() . $filePath)) {
            throw new ModuleConfigException(
                __CLASS__,
                "\nFile with dump doesn't exist.\n"
                . "Please, check path for sql file: "
                . $filePath
            );
        }

        $sql = file_get_contents(Configuration::projectDir() . $filePath);

        // remove C-style comments (except MySQL directives)
        $sql = preg_replace('%/\*(?!!\d+).*?\*/%s', '', $sql);

        return $sql;
    }

    private function connect($databaseKey, $databaseConfig)
    {
        if (!empty($this->drivers[$databaseKey]) && !empty($this->dbhs[$databaseKey])) {
            return;
        }
        $options = [];

        /**
         * @see http://php.net/manual/en/pdo.construct.php
         * @see http://php.net/manual/de/ref.pdo-mysql.php#pdo-mysql.constants
         */
        if (array_key_exists('ssl_key', $databaseConfig)
            && !empty($databaseConfig['ssl_key'])
            && defined('\PDO::MYSQL_ATTR_SSL_KEY')
        ) {
            $options[\PDO::MYSQL_ATTR_SSL_KEY] = (string) $databaseConfig['ssl_key'];
        }

        if (array_key_exists('ssl_cert', $databaseConfig)
            && !empty($databaseConfig['ssl_cert'])
            && defined('\PDO::MYSQL_ATTR_SSL_CERT')
        ) {
            $options[\PDO::MYSQL_ATTR_SSL_CERT] = (string) $databaseConfig['ssl_cert'];
        }

        if (array_key_exists('ssl_ca', $databaseConfig)
            && !empty($databaseConfig['ssl_ca'])
            && defined('\PDO::MYSQL_ATTR_SSL_CA')
        ) {
            $options[\PDO::MYSQL_ATTR_SSL_CA] = (string) $databaseConfig['ssl_ca'];
        }

        if (array_key_exists('ssl_cipher', $databaseConfig)
            && !empty($databaseConfig['ssl_cipher'])
            && defined('\PDO::MYSQL_ATTR_SSL_CIPHER')
        ) {
            $options[\PDO::MYSQL_ATTR_SSL_CIPHER] = (string) $databaseConfig['ssl_cipher'];
        }

        if (array_key_exists('ssl_verify_server_cert', $databaseConfig)
            && defined('\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT')
        ) {
            $options[\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (boolean) $databaseConfig[ 'ssl_verify_server_cert' ];
        }

        try {
            $this->debugSection('Connecting To Db', ['config' => $databaseConfig, 'options' => $options]);
            $this->drivers[$databaseKey] = Driver::create($databaseConfig['dsn'], $databaseConfig['user'], $databaseConfig['password'], $options);
        } catch (\PDOException $e) {
            $message = $e->getMessage();
            if ($message === 'could not find driver') {
                list ($missingDriver, ) = explode(':', $databaseConfig['dsn'], 2);
                $message = "could not find $missingDriver driver";
            }

            throw new ModuleException(__CLASS__, $message . ' while creating PDO connection');
        }

        if ($databaseConfig['waitlock']) {
            $this->_getDriver()->setWaitLock($databaseConfig['waitlock']);
        }

        if (isset($databaseConfig['initial_queries'])) {
            foreach ($databaseConfig['initial_queries'] as $initialQuery) {
                $this->drivers[$databaseKey]->executeQuery($initialQuery, []);
            }
        }

        $this->debugSection('Db', 'Connected to ' . $databaseKey . ' ' . $this->drivers[$databaseKey]->getDb());
        $this->dbhs[$databaseKey] = $this->drivers[$databaseKey]->getDbh();
    }

    private function disconnect($databaseKey)
    {
        $this->debugSection('Db', 'Disconnected from ' . $databaseKey);
        $this->dbhs[$databaseKey] = null;
        $this->drivers[$databaseKey] = null;
    }

    public function _before(TestInterface $test)
    {
        $this->reconnectDatabases();
        $this->amConnectedToDatabase(self::DEFAULT_DATABASE);

        $this->cleanUpDatabases();

        $this->populateDatabases('cleanup');

        parent::_before($test);
    }

    public function _after(TestInterface $test)
    {
        $this->removeInsertedForDatabases();
        parent::_after($test);
    }

    protected function removeInserted($databaseKey = null)
    {
        $databaseKey = empty($databaseKey) ?  self::DEFAULT_DATABASE : $databaseKey;

        if (empty($this->insertedRows[$databaseKey])) {
            return;
        }

        foreach (array_reverse($this->insertedRows[$databaseKey]) as $row) {
            try {
                $this->_getDriver()->deleteQueryByCriteria($row['table'], $row['primary']);
            } catch (\Exception $e) {
                $this->debug("Couldn't delete record " . json_encode($row['primary']) ." from {$row['table']}");
            }
        }
        $this->insertedRows[$databaseKey] = [];
    }

    public function _cleanup($databaseKey = null, $databaseConfig = null)
    {
        $databaseKey = empty($databaseKey) ?  self::DEFAULT_DATABASE : $databaseKey;
        $databaseConfig = empty($databaseConfig) ?  $this->config : $databaseConfig;

        if (!$databaseConfig['populate']) {
            return;
        }
        if (!$databaseConfig['cleanup']) {
            return;
        }
        if (isset($this->databasesPopulated[$databaseKey]) && !$this->databasesPopulated[$databaseKey]) {
            return;
        }
        $dbh = $this->dbhs[$databaseKey];
        if (!$dbh) {
            throw new ModuleConfigException(
                __CLASS__,
                'No connection to database. Remove this module from config if you don\'t need database repopulation'
            );
        }
        try {
            if (false === $this->shouldCleanup($databaseConfig, $databaseKey)) {
                return;
            }
            $this->drivers[$databaseKey]->cleanup();
            $this->databasesPopulated[$databaseKey] = false;
        } catch (\Exception $e) {
            throw new ModuleException(__CLASS__, $e->getMessage());
        }
    }

    /**
     * @param  array  $databaseConfig
     * @param  string $databaseKey
     * @return bool
     */
    protected function shouldCleanup($databaseConfig, $databaseKey)
    {
        // If using populator and it's not empty, clean up regardless
        if (!empty($databaseConfig['populator'])) {
            return true;
        }

        // If no sql dump for $databaseKey or sql dump is empty, don't clean up
        return !empty($this->databasesSql[$databaseKey]);
    }

    public function _isPopulated()
    {
        return $this->databasesPopulated[$this->currentDatabase];
    }

    public function _loadDump($databaseKey = null, $databaseConfig = null)
    {
        $databaseKey = empty($databaseKey) ?  self::DEFAULT_DATABASE : $databaseKey;
        $databaseConfig = empty($databaseConfig) ?  $this->config : $databaseConfig;

        if ($databaseConfig['populator']) {
            $this->loadDumpUsingPopulator($databaseKey, $databaseConfig);
            return;
        }
        $this->loadDumpUsingDriver($databaseKey);
    }

    protected function loadDumpUsingPopulator($databaseKey, $databaseConfig)
    {
        $populator = new DbPopulator($databaseConfig);
        $this->databasesPopulated[$databaseKey] = $populator->run();
    }

    protected function loadDumpUsingDriver($databaseKey)
    {
        if (!isset($this->databasesSql[$databaseKey])) {
            return;
        }
        if (!$this->databasesSql[$databaseKey]) {
            $this->debugSection('Db', 'No SQL loaded, loading dump skipped');
            return;
        }
        $this->drivers[$databaseKey]->load($this->databasesSql[$databaseKey]);
        $this->databasesPopulated[$databaseKey] = true;
    }

    /**
     * Inserts an SQL record into a database. This record will be erased after the test.
     *
     * ```php
     * <?php
     * $I->haveInDatabase('users', array('name' => 'miles', 'email' => 'miles@davis.com'));
     * ?>
     * ```
     *
     * @param string $table
     * @param array $data
     *
     * @return integer $id
     */
    public function haveInDatabase($table, array $data)
    {
        $lastInsertId = $this->_insertInDatabase($table, $data);

        $this->addInsertedRow($table, $data, $lastInsertId);

        return $lastInsertId;
    }

    public function _insertInDatabase($table, array $data)
    {
        $query = $this->_getDriver()->insert($table, $data);
        $parameters = array_values($data);
        $this->debugSection('Query', $query);
        $this->debugSection('Parameters', $parameters);
        $this->_getDriver()->executeQuery($query, $parameters);

        try {
            $lastInsertId = (int)$this->_getDriver()->lastInsertId($table);
        } catch (\PDOException $e) {
            // ignore errors due to uncommon DB structure,
            // such as tables without _id_seq in PGSQL
            $lastInsertId = 0;
            $this->debugSection('DB error', $e->getMessage());
        }
        return $lastInsertId;
    }

    private function addInsertedRow($table, array $row, $id)
    {
        $primaryKey = $this->_getDriver()->getPrimaryKey($table);
        $primary = [];
        if ($primaryKey) {
            if ($id && count($primaryKey) === 1) {
                $primary [$primaryKey[0]] = $id;
            } else {
                foreach ($primaryKey as $column) {
                    if (isset($row[$column])) {
                        $primary[$column] = $row[$column];
                    } else {
                        throw new \InvalidArgumentException(
                            'Primary key field ' . $column . ' is not set for table ' . $table
                        );
                    }
                }
            }
        } else {
            $primary = $row;
        }

        $this->insertedRows[$this->currentDatabase][] = [
            'table' => $table,
            'primary' => $primary,
        ];
    }

    public function seeInDatabase($table, $criteria = [])
    {
        $res = $this->countInDatabase($table, $criteria);
        $this->assertGreaterThan(
            0,
            $res,
            'No matching records found for criteria ' . json_encode($criteria) . ' in table ' . $table
        );
    }

    /**
     * Asserts that the given number of records were found in the database.
     *
     * ```php
     * <?php
     * $I->seeNumRecords(1, 'users', ['name' => 'davert'])
     * ?>
     * ```
     *
     * @param int $expectedNumber Expected number
     * @param string $table Table name
     * @param array $criteria Search criteria [Optional]
     */
    public function seeNumRecords($expectedNumber, $table, array $criteria = [])
    {
        $actualNumber = $this->countInDatabase($table, $criteria);
        $this->assertEquals(
            $expectedNumber,
            $actualNumber,
            sprintf(
                'The number of found rows (%d) does not match expected number %d for criteria %s in table %s',
                $actualNumber,
                $expectedNumber,
                json_encode($criteria),
                $table
            )
        );
    }

    public function dontSeeInDatabase($table, $criteria = [])
    {
        $count = $this->countInDatabase($table, $criteria);
        $this->assertLessThan(
            1,
            $count,
            'Unexpectedly found matching records for criteria ' . json_encode($criteria) . ' in table ' . $table
        );
    }

    /**
     * Count rows in a database
     *
     * @param string $table    Table name
     * @param array  $criteria Search criteria [Optional]
     *
     * @return int
     */
    protected function countInDatabase($table, array $criteria = [])
    {
        return (int) $this->proceedSeeInDatabase($table, 'count(*)', $criteria);
    }

    /**
     * Fetches all values from the column in database.
     * Provide table name, desired column and criteria.
     *
     * @param string $table
     * @param string $column
     * @param array  $criteria
     *
     * @return mixed
     */
    protected function proceedSeeInDatabase($table, $column, $criteria)
    {
        $query = $this->_getDriver()->select($column, $table, $criteria);
        $parameters = array_values($criteria);
        $this->debugSection('Query', $query);
        if (!empty($parameters)) {
            $this->debugSection('Parameters', $parameters);
        }
        $sth = $this->_getDriver()->executeQuery($query, $parameters);

        return $sth->fetchColumn();
    }

    /**
     * Fetches all values from the column in database.
     * Provide table name, desired column and criteria.
     *
     * ``` php
     * <?php
     * $mails = $I->grabColumnFromDatabase('users', 'email', array('name' => 'RebOOter'));
     * ```
     *
     * @param string $table
     * @param string $column
     * @param array $criteria
     *
     * @return array
     */
    public function grabColumnFromDatabase($table, $column, array $criteria = [])
    {
        $query      = $this->_getDriver()->select($column, $table, $criteria);
        $parameters = array_values($criteria);
        $this->debugSection('Query', $query);
        $this->debugSection('Parameters', $parameters);
        $sth = $this->_getDriver()->executeQuery($query, $parameters);

        return $sth->fetchAll(\PDO::FETCH_COLUMN, 0);
    }

    /**
     * Fetches a single column value from a database.
     * Provide table name, desired column and criteria.
     *
     * ``` php
     * <?php
     * $mail = $I->grabFromDatabase('users', 'email', array('name' => 'Davert'));
     * ```
     * Comparison expressions can be used as well:
     *
     * ```php
     * <?php
     * $post = $I->grabFromDatabase('posts', ['num_comments >=' => 100]);
     * $user = $I->grabFromDatabase('users', ['email like' => 'miles%']);
     * ```
     *
     * Supported operators: `<`, `>`, `>=`, `<=`, `!=`, `like`.
     *
     * @param string $table
     * @param string $column
     * @param array $criteria
     *
     * @return mixed Returns a single column value or false
     */
    public function grabFromDatabase($table, $column, $criteria = [])
    {
        return $this->proceedSeeInDatabase($table, $column, $criteria);
    }

    /**
     * Returns the number of rows in a database
     *
     * @param string $table    Table name
     * @param array  $criteria Search criteria [Optional]
     *
     * @return int
     */
    public function grabNumRecords($table, array $criteria = [])
    {
        return $this->countInDatabase($table, $criteria);
    }

    /**
     * Update an SQL record into a database.
     *
     * ```php
     * <?php
     * $I->updateInDatabase('users', array('isAdmin' => true), array('email' => 'miles@davis.com'));
     * ?>
     * ```
     *
     * @param string $table
     * @param array $data
     * @param array $criteria
     */
    public function updateInDatabase($table, array $data, array $criteria = [])
    {
        $query = $this->_getDriver()->update($table, $data, $criteria);
        $parameters = array_merge(array_values($data), array_values($criteria));
        $this->debugSection('Query', $query);
        if (!empty($parameters)) {
            $this->debugSection('Parameters', $parameters);
        }
        $this->_getDriver()->executeQuery($query, $parameters);
    }
}
<?php

namespace Codeception\Extension;

use Codeception\Event\StepEvent;
use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\Exception\ExtensionException;
use Codeception\Lib\Interfaces\ScreenshotSaver;
use Codeception\Module\WebDriver;
use Codeception\Step;
use Codeception\Step\Comment as CommentStep;
use Codeception\Test\Descriptor;
use Codeception\Util\FileSystem;
use Codeception\Util\Template;

/**
 * Saves a screenshot of each step in acceptance tests and shows them as a slideshow on one HTML page (here's an [example](http://codeception.com/images/recorder.gif))
 * Activated only for suites with WebDriver module enabled.
 *
 * The screenshots are saved to `tests/_output/record_*` directories, open `index.html` to see them as a slideshow.
 *
 * #### Installation
 *
 * Add this to the list of enabled extensions in `codeception.yml` or `acceptance.suite.yml`:
 *
 * ``` yaml
 * extensions:
 *     enabled:
 *         - Codeception\Extension\Recorder
 * ```
 *
 * #### Configuration
 *
 * * `delete_successful` (default: true) - delete screenshots for successfully passed tests  (i.e. log only failed and errored tests).
 * * `module` (default: WebDriver) - which module for screenshots to use. Set `AngularJS` if you want to use it with AngularJS module. Generally, the module should implement `Codeception\Lib\Interfaces\ScreenshotSaver` interface.
 * * `ignore_steps` (default: []) - array of step names that should not be recorded (given the step passed), * wildcards supported. Meta steps can also be ignored.
 * * `success_color` (default: success) - bootstrap values to be used for color representation for passed tests
 * * `failure_color` (default: danger) - bootstrap values to be used for color representation for failed tests
 * * `error_color` (default: dark) - bootstrap values to be used for color representation for scenarios where there's an issue occurred while generating a recording
 * * `delete_orphaned` (default: false) - delete recording folders created via previous runs
 * * `include_microseconds` (default: false) - enable microsecond precision for recorded step time details
 *
 * #### Examples:
 *
 * ``` yaml
 * extensions:
 *     enabled:
 *         - Codeception\Extension\Recorder:
 *             module: AngularJS # enable for Angular
 *             delete_successful: false # keep screenshots of successful tests
 *             ignore_steps: [have, grab*]
 * ```
 * #### Skipping recording of steps with annotations
 *
 * It is also possible to skip recording of steps for specified tests by using the @skipRecording annotation.
 *
 * ```php
 * /**
 * * @skipRecording login
 * * @skipRecording amOnUrl
 * *\/
 * public function testLogin(AcceptanceTester $I)
 * {
 *     $I->login();
 *     $I->amOnUrl('http://codeception.com');
 * }
 * ```
 *
 */
class Recorder extends \Codeception\Extension
{
    /** @var array */
    protected $config = [
        'delete_successful'    => true,
        'module'               => 'WebDriver',
        'template'             => null,
        'animate_slides'       => true,
        'ignore_steps'         => [],
        'success_color'        => 'success',
        'failure_color'        => 'danger',
        'error_color'          => 'dark',
        'delete_orphaned'      => false,
        'include_microseconds' => false,
    ];

    /** @var string */
    protected $template = <<<EOF
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Recorder Result</title>

    <!-- Bootstrap Core CSS -->
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet">

    <style>
        html,
        body {
            height: 100%;
        }
        .active {
            height: 100%;
        }
        .carousel-caption {
            background: rgba(0,0,0,0.8);
        }
        .carousel-caption.error {
            background: #c0392b !important;
        }
        .carousel-item {
            min-height: 100vh;
        }
        .fill {
            width: 100%;
            height: 100%;
            text-align: center;
            overflow-y: scroll;
            background-position: top;
            -webkit-background-size: cover;
            -moz-background-size: cover;
            background-size: cover;
            -o-background-size: cover;
        }
        .gradient-right {
             background:
                linear-gradient(to left, rgba(0,0,0,.4), rgba(0,0,0,.0))
        }
        .gradient-left {
            background:
                linear-gradient(to right, rgba(0,0,0,.4), rgba(0,0,0,.0))
        }
    </style>
</head>
<body>
    <!-- Navigation -->
        <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <div class="navbar-header">
            <a class="navbar-brand" href="../records.html"></span>Recorded Tests</a>
        </div>
        <div class="collapse navbar-collapse" id="navbarText">
            <ul class="navbar-nav mr-auto">
                <span class="navbar-text">{{feature}}</span>
            </ul>
            <span class="navbar-text">{{test}}</span>
        </div>
    </nav>
    <header id="steps" class="carousel slide" data-ride="carousel">
        <!-- Indicators -->
        <ol class="carousel-indicators">
            {{indicators}}
        </ol>

        <!-- Wrapper for Slides -->
        <div class="carousel-inner">
            {{slides}}
        </div>

        <!-- Controls -->
        <a class="carousel-control-prev gradient-left" href="#steps" role="button" data-slide="prev">
            <span class="carousel-control-prev-icon" aria-hidden="false"></span>
            <span class="sr-only">Previous</span>
        </a>
        <a class="carousel-control-next gradient-right" href="#steps" role="button" data-slide="next">
            <span class="carousel-control-next-icon" aria-hidden="false"></span>
            <span class="sr-only">Next</span>
        </a>
    </header>

    <!-- jQuery -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>

    <!-- Script to Activate the Carousel -->
    <script>
    $('.carousel').carousel({
        wrap: true,
        interval: false
    })

    $(document).bind('keyup', function(e) {
      if(e.keyCode==39){
      jQuery('a.carousel-control.right').trigger('click');
      }

      else if(e.keyCode==37){
      jQuery('a.carousel-control.left').trigger('click');
      }

    });

    </script>

</body>

</html>
EOF;

    /** @var string */
    protected $indicatorTemplate = <<<EOF
<li data-target="#steps" data-slide-to="{{step}}" class="{{isActive}}"></li>
EOF;

    /** @var string */
    protected $indexTemplate = <<<EOF
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Recorder Results Index</title>

    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <!-- Navigation -->
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <div class="navbar-header">
            <a class="navbar-brand" href="#">Recorded Tests
            </a>
        </div>
    </nav>
    <div class="container py-4">
        <h1>Record #{{seed}}</h1>
        <ul>
            {{records}}
        </ul>
    </div>
</body>

</html>

EOF;

    /** @var string */
    protected $slidesTemplate = <<<EOF
<div class="carousel-item {{isActive}}">
    <img class="mx-auto d-block mh-100" src="{{image}}">
    <div class="carousel-caption {{isError}}">
        <h5>{{caption}}</h5>
        <p>Step finished at <span style="color: #3498db">"{{timeStamp}}"</span></p>
    </div>
</div>
EOF;

    /** @var array */
    public static $events = [
        Events::SUITE_BEFORE => 'beforeSuite',
        Events::SUITE_AFTER  => 'afterSuite',
        Events::TEST_BEFORE  => 'before',
        Events::TEST_ERROR   => 'persist',
        Events::TEST_FAIL    => 'persist',
        Events::TEST_SUCCESS => 'cleanup',
        Events::STEP_AFTER   => 'afterStep',
    ];

    /** @var WebDriver */
    protected $webDriverModule;

    /** @var string */
    protected $dir;

    /** @var array */
    protected $slides = [];

    /** @var int */
    protected $stepNum = 0;

    /** @var string */
    protected $seed;

    /** @var array */
    protected $seeds;

    /** @var array */
    protected $recordedTests = [];

    /** @var array */
    protected $skipRecording = [];

    /** @var array */
    protected $errorMessages = [];

    /** @var bool */
    protected $colors;

    /** @var bool */
    protected $ansi;

    /** @var array */
    protected $timeStamps = [];

    /** @var string */
    private $dateFormat;

    public function beforeSuite()
    {
        $this->webDriverModule = null;
        if (!$this->hasModule($this->config['module'])) {
            $this->writeln('Recorder is disabled, no available modules');

            return;
        }

        $this->seed = uniqid();
        $this->seeds[] = $this->seed;
        $this->webDriverModule = $this->getModule($this->config['module']);
        $this->skipRecording = [];
        $this->errorMessages = [];
        $this->dateFormat = $this->config['include_microseconds'] ? 'Y-m-d\TH:i:s.uP' : DATE_ATOM;
        $this->ansi = !isset($this->options['no-ansi']);
        $this->colors = !isset($this->options['no-colors']);

        if (!$this->webDriverModule instanceof ScreenshotSaver) {
            throw new ExtensionException(
                $this,
                'You should pass module which implements ' . ScreenshotSaver::class . ' interface'
            );
        }

        $this->writeln(
            sprintf(
                '⏺ <bold>Recording</bold> ⏺ step-by-step screenshots will be saved to <info>%s</info>',
                codecept_output_dir()
            )
        );
        $this->writeln("Directory Format: <debug>record_{$this->seed}_{filename}_{testname}</debug> ----");
    }

    public function afterSuite()
    {
        if (!$this->webDriverModule) {
            return;
        }
        $links = '';

        if (count($this->slides)) {
            foreach ($this->recordedTests as $suiteName => $suite) {
                $links .= "<ul><li><b>{$suiteName}</b></li><ul>";
                foreach ($suite as $fileName => $tests) {
                    $links .= "<li>{$fileName}</li><ul>";

                    foreach ($tests as $test) {
                        $links .= in_array($test['path'], $this->skipRecording, true)
                            ? "<li class=\"text{$this->config['error_color']}\">{$test['name']}</li>\n"
                            : '<li class="text-' . $this->config[$test['status'] . '_color']
                            . "\"><a href='{$test['index']}'>{$test['name']}</a></li>\n";
                    }

                    $links .= '</ul>';
                }
                $links .= '</ul></ul>';
            }

            $indexHTML = (new Template($this->indexTemplate))
                ->place('seed', $this->seed)
                ->place('records', $links)
                ->produce();

            try {
                file_put_contents(codecept_output_dir() . 'records.html', $indexHTML);
            } catch (\Exception $exception) {
                $this->writeln(
                    "⏺ An exception occurred while saving records.html: <info>{$exception->getMessage()}</info>"
                );
            }

            $this->writeln('⏺ Records saved into: <info>file://' . codecept_output_dir() . 'records.html</info>');
        }

        foreach ($this->errorMessages as $message) {
            $this->writeln($message);
        }
    }

    /**
     * @param TestEvent $e
     */
    public function before(TestEvent $e)
    {
        if (!$this->webDriverModule) {
            return;
        }
        $this->dir = null;
        $this->stepNum = 0;
        $this->slides = [];
        $this->timeStamps = [];

        $this->dir = codecept_output_dir() . "record_{$this->seed}_{$this->getTestName($e)}";
        $testPath = codecept_relative_path(Descriptor::getTestFullName($e->getTest()));

        try {
            !is_dir($this->dir) && !mkdir($this->dir) && !is_dir($this->dir);
        } catch (\Exception $exception) {
            $this->skipRecording[] = $testPath;
            $this->appendErrorMessage(
                $testPath,
                "⏺ An exception occurred while creating directory: <info>{$this->dir}</info>"
            );
        }
    }

    /**
     * @param TestEvent $e
     */
    public function cleanup(TestEvent $e)
    {
        if ($this->config['delete_orphaned']) {
            $recordingDirectories = [];
            $directories = new \DirectoryIterator(codecept_output_dir());

            // getting a list of currently present recording directories
            foreach ($directories as $directory) {
                preg_match('/^record_(.*?)_[^\n]+.php_[^\n]+$/', $directory->getFilename(), $match);
                if (isset($match[1])) {
                    $recordingDirectories[$match[1]][] = codecept_output_dir() . $directory->getFilename();
                }
            }

            // removing orphaned recording directories
            foreach (array_diff(array_keys($recordingDirectories), $this->seeds) as $orphanedSeed) {
                foreach ($recordingDirectories[$orphanedSeed] as $orphanedDirectory) {
                    FileSystem::deleteDir($orphanedDirectory);
                }
            }
        }

        if (!$this->webDriverModule || !$this->dir) {
            return;
        }
        if (!$this->config['delete_successful']) {
            $this->persist($e);

            return;
        }

        // deleting successfully executed tests
        FileSystem::deleteDir($this->dir);
    }

    /**
     * @param TestEvent $e
     */
    public function persist(TestEvent $e)
    {
        if (!$this->webDriverModule) {
            return;
        }
        $indicatorHtml = '';
        $slideHtml = '';
        $testName = $this->getTestName($e);
        $testPath = codecept_relative_path(Descriptor::getTestFullName($e->getTest()));
        $dir = codecept_output_dir() . "record_{$this->seed}_$testName";
        $status = 'success';

        if (strcasecmp($this->dir, $dir) !== 0) {
            $filename = str_pad(0, 3, '0', STR_PAD_LEFT) . '.png';

            try {
                !is_dir($dir) && !mkdir($dir) && !is_dir($dir);
                $this->dir = $dir;
            } catch (\Exception $exception) {
                $this->skipRecording[] = $testPath;
                $this->appendErrorMessage(
                    $testPath,
                    "⏺ An exception occurred while creating directory: <info>{$dir}</info>"
                );
            }

            $this->slides = [];
            $this->timeStamps = [];
            $this->slides[$filename] = new Step\Action('encountered an unexpected error prior to the test execution');
            $this->timeStamps[$filename] = (new \DateTime())->format($this->dateFormat);
            $status = 'error';

            try {
                if ($this->webDriverModule->webDriver === null) {
                    throw new ExtensionException($this, 'Failed to save screenshot as webDriver is not set');
                }

                $this->webDriverModule->webDriver->takeScreenshot($this->dir . DIRECTORY_SEPARATOR . $filename);
            } catch (\Exception $exception) {
                $this->appendErrorMessage(
                    $testPath,
                    "⏺ Unable to capture a screenshot for <info>{$testPath}/before</info>"
                );
            }
        }

        if (!in_array($testPath, $this->skipRecording, true)) {
            foreach ($this->slides as $i => $step) {
                /** @var Step $step */
                if ($step->hasFailed()) {
                    $status = 'failure';
                }

                $indicatorHtml .= (new Template($this->indicatorTemplate))
                    ->place('step', (int)$i)
                    ->place('isActive', (int)$i ? '' : 'active')
                    ->produce();

                $slideHtml .= (new Template($this->slidesTemplate))
                    ->place('image', $i)
                    ->place('caption', $step->getHtml('#3498db'))
                    ->place('isActive', (int)$i ? '' : 'active')
                    ->place('isError', $status === 'success' ? '' : 'error')
                    ->place('timeStamp', $this->timeStamps[$i])
                    ->produce();
            }

            $html = (new Template($this->template))
                ->place('indicators', $indicatorHtml)
                ->place('slides', $slideHtml)
                ->place('feature', ucfirst($e->getTest()->getFeature()))
                ->place('test', Descriptor::getTestSignature($e->getTest()))
                ->place('carousel_class', $this->config['animate_slides'] ? ' slide' : '')
                ->produce();

            $indexFile = $this->dir . DIRECTORY_SEPARATOR . 'index.html';
            $environment = $e->getTest()->getMetadata()->getCurrent('env') ?: '';
            $suite = ucfirst(basename(\dirname($e->getTest()->getMetadata()->getFilename())));
            $testName = basename($e->getTest()->getMetadata()->getFilename());

            try {
                file_put_contents($indexFile, $html);
            } catch (\Exception $exception) {
                $this->skipRecording[] = $testPath;
                $this->appendErrorMessage(
                    $testPath,
                    "⏺ An exception occurred while saving index.html for <info>{$testPath}: "
                    . "{$exception->getMessage()}</info>"
                );
            }

            $this->recordedTests["{$suite} ({$environment})"][$testName][] = [
                'name' => $e->getTest()->getMetadata()->getName(),
                'path' => $testPath,
                'status' => $status,
                'index' => substr($indexFile, strlen(codecept_output_dir())),
            ];
        }
    }

    /**
     * @param StepEvent $e
     */
    public function afterStep(StepEvent $e)
    {
        if ($this->webDriverModule === null || $this->dir === null) {
            return;
        }

        if ($e->getStep() instanceof CommentStep) {
            return;
        }

        // only taking the ignore step into consideration if that step has passed
        if ($this->isStepIgnored($e) && !$e->getStep()->hasFailed()) {
            return;
        }

        $filename = str_pad($this->stepNum, 3, '0', STR_PAD_LEFT) . '.png';

        try {
            if ($this->webDriverModule->webDriver === null) {
                throw new ExtensionException($this, 'Failed to save screenshot as webDriver is not set');
            }

            $this->webDriverModule->webDriver->takeScreenshot($this->dir . DIRECTORY_SEPARATOR . $filename);
        } catch (\Exception $exception) {
            $testPath = codecept_relative_path(Descriptor::getTestFullName($e->getTest()));
            $this->appendErrorMessage(
                $testPath,
                "⏺ Unable to capture a screenshot for <info>{$testPath}/{$e->getStep()->getAction()}</info>"
            );
        }

        $this->stepNum++;
        $this->slides[$filename] = $e->getStep();
        $this->timeStamps[$filename] = (new \DateTime())->format($this->dateFormat);
    }

    /**
     * @param StepEvent $e
     *
     * @return bool
     */
    protected function isStepIgnored(StepEvent $e)
    {
        $configIgnoredSteps = $this->config['ignore_steps'];
        $annotationIgnoredSteps = $e->getTest()->getMetadata()->getParam('skipRecording');

        $ignoredSteps = array_unique(
            array_merge(
                $configIgnoredSteps,
                is_array($annotationIgnoredSteps) ? $annotationIgnoredSteps : []
            )
        );

        foreach ($ignoredSteps as $stepPattern) {
            $stepRegexp = '/^' . str_replace('*', '.*?', $stepPattern) . '$/i';

            if (preg_match($stepRegexp, $e->getStep()->getAction())) {
                return true;
            }

            if ($e->getStep()->getMetaStep() !== null &&
                preg_match($stepRegexp, $e->getStep()->getMetaStep()->getAction())
            ) {
                return true;
            }
        }

        return false;
    }

    /**
     * @param StepEvent|TestEvent $e
     *
     * @return string
     */
    private function getTestName($e)
    {
        return basename($e->getTest()->getMetadata()->getFilename()) . '_' . preg_replace('/[^A-Za-z0-9\-\_]/', '_', $e->getTest()->getMetadata()->getName());
    }

    /**
     * @param string $message
     */
    protected function writeln($message)
    {
        parent::writeln(
            $this->ansi
            ? $message
            : trim(preg_replace('/[ ]{2,}/', ' ', str_replace('⏺', '', $message)))
        );
    }

    /**
     * @param string $testPath
     * @param string $message
     */
    private function appendErrorMessage($testPath, $message)
    {
        $this->errorMessages[$testPath] = array_merge(
            array_key_exists($testPath, $this->errorMessages) ? $this->errorMessages[$testPath]: [],
            [$message]
        );
    }
}
<?php

namespace Codeception\Extension;

use Codeception\Events;
use Codeception\Exception\ExtensionException;
use Codeception\Extension;
use Symfony\Component\Process\Process;

/**
 * Extension for execution of some processes before running tests.
 *
 * Processes can be independent and dependent.
 * Independent processes run independently of each other.
 * Dependent processes run sequentially one by one.
 *
 * Can be configured in suite config:
 *
 * ```yaml
 * # acceptance.suite.yml
 * extensions:
 *     enabled:
 *         - Codeception\Extension\RunBefore:
 *             - independent_process_1
 *             -
 *                 - dependent_process_1_1
 *                 - dependent_process_1_2
 *             - independent_process_2
 *             -
 *                 - dependent_process_2_1
 *                 - dependent_process_2_2
 * ```
 *
 * HINT: you can use different configurations per environment.
 */
class RunBefore extends Extension
{
    protected $config = [];

    protected static $events = [
        Events::SUITE_BEFORE => 'runBefore'
    ];

    /** @var array[] */
    private $processes = [];

    public function _initialize()
    {
        if (!class_exists('Symfony\Component\Process\Process')) {
            throw new ExtensionException($this, 'symfony/process package is required');
        }
    }

    public function runBefore()
    {
        $this->runProcesses();
        $this->processMonitoring();
    }

    private function runProcesses()
    {
        foreach ($this->config as $item) {
            if (is_array($item)) {
                $currentCommand = array_shift($item);
                $followingCommands = $item;
            } else {
                $currentCommand = $item;
                $followingCommands = [];
            }

            $process = $this->runProcess($currentCommand);
            $this->addProcessToMonitoring($process, $followingCommands);
        }
    }

    /**
     * @param string $command
     * @return Process
     */
    private function runProcess($command)
    {
        $this->output->debug('[RunBefore] Starting ' . $command);

        if (method_exists(Process::class, 'fromShellCommandline')) {
            //Symfony 4.2+
            $process = Process::fromShellCommandline($command, $this->getRootDir());
        } else {
            $process = new Process($command, $this->getRootDir());
        }
        $process->start();

        return $process;
    }

    /**
     * @param string[] $followingCommands
     */
    private function addProcessToMonitoring(Process $process, array $followingCommands)
    {
        $this->processes[] = [
            'instance' => $process,
            'following' => $followingCommands
        ];
    }

    /**
     * @param int $index
     */
    private function removeProcessFromMonitoring($index)
    {
        unset($this->processes[$index]);
    }

    private function processMonitoring()
    {
        while (count($this->processes) !== 0) {
            $this->checkProcesses();
            sleep(1);
        }
    }

    private function checkProcesses()
    {
        foreach ($this->processes as $index => $process) {
            if (!$this->isRunning($process['instance'])) {
                $this->output->debug('[RunBefore] Completing ' . $process['instance']->getCommandLine());
                $this->runFollowingCommand($process['following']);
                $this->removeProcessFromMonitoring($index);
            }
        }
    }

    /**
     * @param string[] $followingCommands
     */
    private function runFollowingCommand(array $followingCommands)
    {
        if (count($followingCommands) > 0) {
            $process = $this->runProcess(array_shift($followingCommands));
            $this->addProcessToMonitoring($process, $followingCommands);
        }
    }

    private function isRunning(Process $process)
    {
        if ($process->isRunning()) {
            return true;
        }
        return false;
    }
}
<?php
namespace Codeception\Extension;

use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\Extension;
use Codeception\Test\Descriptor;

/**
 * This extension demonstrates how you can implement console output of your own.
 * Recommended to be used for development purposes only.
 */
class SimpleReporter extends Extension
{
    public function _initialize()
    {
        $this->options['silent'] = false; // turn on printing for this extension
        $this->_reconfigure(['settings' => ['silent' => true]]); // turn off printing for everything else
    }

    // we are listening for events
    public static $events = [
        Events::SUITE_BEFORE => 'beforeSuite',
        Events::TEST_END     => 'after',
        Events::TEST_SUCCESS => 'success',
        Events::TEST_FAIL    => 'fail',
        Events::TEST_ERROR   => 'error',
    ];

    public function beforeSuite()
    {
        $this->writeln("");
    }

    public function success()
    {
        $this->write('[+] ');
    }

    public function fail()
    {
        $this->write('[-] ');
    }

    public function error()
    {
        $this->write('[E] ');
    }

    // we are printing test status and time taken
    public function after(TestEvent $e)
    {
        $seconds_input = $e->getTime();
        // stack overflow: http://stackoverflow.com/questions/16825240/how-to-convert-microtime-to-hhmmssuu
        $seconds = (int)($milliseconds = (int)($seconds_input * 1000)) / 1000;
        $time = ($seconds % 60) . (($milliseconds === 0) ? '' : '.' . $milliseconds);

        $this->write(Descriptor::getTestSignature($e->getTest()));
        $this->writeln(' (' . $time . 's)');
    }
}
<?php
namespace Codeception\Extension;

use Codeception\Event\FailEvent;
use Codeception\Events;
use Codeception\Extension;
use Codeception\Subscriber\Console;

/**
 * DotReporter provides less verbose output for test execution.
 * Like PHPUnit printer it prints dots "." for successful testes and "F" for failures.
 *
 * ![](https://cloud.githubusercontent.com/assets/220264/26132800/4d23f336-3aab-11e7-81ba-2896a4c623d2.png)
 *
 * ```bash
 *  ..........
 *  ..........
 *  ..........
 *  ..........
 *  ..........
 *  ..........
 *  ..........
 *  ..........
 *
 * Time: 2.07 seconds, Memory: 20.00MB
 *
 * OK (80 tests, 124 assertions)
 * ```
 *
 *
 * Enable this reporter with `--ext option`
 *
 * ```
 * codecept run --ext DotReporter
 * ```
 *
 * Failures and Errors are printed by a standard Codeception reporter.
 * Use this extension as an example for building custom reporters.
 */
class DotReporter extends Extension
{
    /**
     * @var Console
     */
    protected $standardReporter;

    protected $errors = [];
    protected $failures = [];

    protected $width = 10;
    protected $currentPos = 0;

    public function _initialize()
    {
        $this->options['silent'] = false; // turn on printing for this extension
        $this->_reconfigure(['settings' => ['silent' => true]]); // turn off printing for everything else
        $this->standardReporter = new Console($this->options);
        $this->width = $this->standardReporter->detectWidth();
    }

    // we are listening for events
    public static $events = [
        Events::SUITE_BEFORE => 'beforeSuite',
        Events::TEST_SUCCESS => 'success',
        Events::TEST_FAIL    => 'fail',
        Events::TEST_ERROR   => 'error',
        Events::TEST_SKIPPED => 'skipped',
        Events::TEST_FAIL_PRINT => 'printFailed'
    ];

    public function beforeSuite()
    {
        $this->writeln("");
    }

    public function success()
    {
        $this->printChar('.');
    }

    public function fail(FailEvent $e)
    {
        $this->printChar("<error>F</error>");
    }

    public function error(FailEvent $e)
    {
        $this->printChar('<error>E</error>');
    }

    public function skipped()
    {
        $this->printChar('S');
    }
    
    protected function printChar($char)
    {
        if ($this->currentPos >= $this->width) {
            $this->writeln('');
            $this->currentPos = 0;
        }
        $this->write($char);
        $this->currentPos++;
    }

    public function printFailed(FailEvent $event)
    {
        $this->standardReporter->printFail($event);
    }
}
<?php
namespace Codeception\Extension;

use Codeception\Event\PrintResultEvent;
use Codeception\Events;
use Codeception\Extension;
use Codeception\Test\Descriptor;

/**
 * Saves failed tests into tests/_output/failed in order to rerun failed tests.
 *
 * To rerun failed tests just run the `failed` group:
 *
 * ```
 * php codecept run -g failed
 * ```
 *
 * To change failed group name add:
 * ```
 * --override "extensions: config: Codeception\Extension\RunFailed: fail-group: another_group1"
 * ```
 * Remember: if you run tests and they generated custom-named fail group, to run this group, you should add override too
 *
 * Starting from Codeception 2.1 **this extension is enabled by default**.
 *
 * ``` yaml
 * extensions:
 *     enabled: [Codeception\Extension\RunFailed]
 * ```
 *
 * On each execution failed tests are logged and saved into `tests/_output/failed` file.
 */
class RunFailed extends Extension
{
    public static $events = [
        Events::RESULT_PRINT_AFTER => 'saveFailed'
    ];

    /** @var string filename/groupname for failed tests */
    protected $group = 'failed';

    public function _initialize()
    {
        if (array_key_exists('fail-group', $this->config) && $this->config['fail-group']) {
            $this->group = $this->config['fail-group'];
        }
        $logPath = str_replace($this->getRootDir(), '', $this->getLogDir()); // get local path to logs
        $this->_reconfigure(['groups' => [$this->group => $logPath . $this->group]]);
    }

    public function saveFailed(PrintResultEvent $e)
    {
        $file = $this->getLogDir() . $this->group;
        $result = $e->getResult();
        if ($result->wasSuccessful()) {
            if (is_file($file)) {
                unlink($file);
            }
            return;
        }
        $output = [];
        foreach ($result->failures() as $fail) {
            $output[] = $this->localizePath(Descriptor::getTestFullName($fail->failedTest()));
        }
        foreach ($result->errors() as $fail) {
            $output[] = $this->localizePath(Descriptor::getTestFullName($fail->failedTest()));
        }

        file_put_contents($file, implode("\n", $output));
    }

    protected function localizePath($path)
    {
        $root = realpath($this->getRootDir()) . DIRECTORY_SEPARATOR;
        if (substr($path, 0, strlen($root)) == $root) {
            return substr($path, strlen($root));
        }
        return $path;
    }
}
<?php
namespace Codeception\Extension;

use Codeception\Event\FailEvent;
use Codeception\Event\StepEvent;
use Codeception\Event\SuiteEvent;
use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\Exception\ConfigurationException;
use Codeception\Exception\ExtensionException;
use Codeception\Extension;
use Codeception\Test\Descriptor;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\RotatingFileHandler;

/**
 * Log suites/tests/steps using Monolog library.
 * Monolog should be installed additionally by Composer.
 *
 * ```
 * composer require monolog/monolog
 * ```
 *
 * Codeception's core/internal stuff is logged into `tests/_output/codeception.log`.
 * Test suites' steps are logged into `tests/_output/<test_full_name>-<rotation_date>.log`.
 *
 * To enable this module add to your `codeception.yml`:
 *
 * ``` yaml
 * extensions:
 *     enabled: [Codeception\Extension\Logger]
 * ```
 *
 * #### Config
 *
 * * `max_files` (default: 3) - how many log files to keep
 *
 */
class Logger extends Extension
{
    public static $events = [
        Events::SUITE_BEFORE    => 'beforeSuite',
        Events::TEST_BEFORE     => 'beforeTest',
        Events::TEST_AFTER      => 'afterTest',
        Events::TEST_END        => 'endTest',
        Events::STEP_BEFORE     => 'beforeStep',
        Events::TEST_FAIL       => 'testFail',
        Events::TEST_ERROR      => 'testError',
        Events::TEST_INCOMPLETE => 'testIncomplete',
        Events::TEST_SKIPPED    => 'testSkipped',
    ];

    protected $logHandler;

    /**
     * @var \Monolog\Logger
     */
    protected static $logger;

    protected $path;

    protected $config = ['max_files' => 3];

    public function _initialize()
    {
        if (!class_exists('\Monolog\Logger')) {
            throw new ConfigurationException("Logger extension requires Monolog library to be installed");
        }
        $this->path = $this->getLogDir();

        // internal log
        $logHandler = new RotatingFileHandler($this->path . 'codeception.log', $this->config['max_files']);

        $formatter = $logHandler->getFormatter();
        if ($formatter instanceof LineFormatter) {
            $formatter->ignoreEmptyContextAndExtra(true);
        }

        self::$logger = new \Monolog\Logger('Codeception');
        self::$logger->pushHandler($logHandler);
    }

    public static function getLogger()
    {
        return self::$logger;
    }

    public function beforeSuite(SuiteEvent $e)
    {
        $suiteLogFile = str_replace('\\', '_', $e->getSuite()->getName()) . '.log';
        $this->logHandler = new RotatingFileHandler($this->path . $suiteLogFile, $this->config['max_files']);
    }

    public function beforeTest(TestEvent $e)
    {
        self::$logger = new \Monolog\Logger(Descriptor::getTestFullName($e->getTest()));
        self::$logger->pushHandler($this->logHandler);
        self::$logger->info('------------------------------------');
        self::$logger->info("STARTED: " . ucfirst(Descriptor::getTestAsString($e->getTest())));
    }

    public function afterTest(TestEvent $e)
    {
    }

    public function endTest(TestEvent $e)
    {
        self::$logger->info("PASSED");
    }

    public function testFail(FailEvent $e)
    {
        self::$logger->alert($e->getFail()->getMessage());
        self::$logger->info("# FAILED #");
    }

    public function testError(FailEvent $e)
    {
        self::$logger->alert($e->getFail()->getMessage());
        self::$logger->info("# ERROR #");
    }

    public function testSkipped(FailEvent $e)
    {
        self::$logger->info("# Skipped #");
    }

    public function testIncomplete(FailEvent $e)
    {
        self::$logger->info("# Incomplete #");
    }

    public function beforeStep(StepEvent $e)
    {
        self::$logger->info((string) $e->getStep());
    }
}

if (!function_exists('codecept_log')) {
    function codecept_log()
    {
        return Logger::getLogger();
    }
} else {
    throw new ExtensionException('Codeception\Extension\Logger', "function 'codecept_log' already defined");
}
<?php

namespace Codeception\Extension;

use Codeception\Events;
use Codeception\Exception\ExtensionException;
use Codeception\Extension;
use Symfony\Component\Process\Process;

/**
 * Extension to start and stop processes per suite.
 * Can be used to start/stop selenium server, chromedriver, mailcatcher, etc.
 *
 * Can be configured in suite config:
 *
 * ```yaml
 * # acceptance.suite.yml
 * extensions:
 *     enabled:
 *         - Codeception\Extension\RunProcess:
 *             - chromedriver
 * ```
 *
 * Multiple parameters can be passed as array:
 *
 * ```yaml
 * # acceptance.suite.yml
 *
 * extensions:
 *     enabled:
 *         - Codeception\Extension\RunProcess:
 *             - php -S 127.0.0.1:8000 -t tests/data/app
 *             - java -jar ~/selenium-server.jar
 * ```
 *
 * In the end of a suite all launched processes will be stopped.
 *
 * To wait for the process to be launched use `sleep` option.
 * In this case you need configuration to be specified as object:
 *
 * ```yaml
 * extensions:
 *     enabled:
 *         - Codeception\Extension\RunProcess:
 *             0: java -jar ~/selenium-server.jar
 *             1: mailcatcher
 *             sleep: 5 # wait 5 seconds for processes to boot
 * ```
 *
 * HINT: you can use different configurations per environment.
 */
class RunProcess extends Extension
{
    protected $config = ['sleep' => 0];

    protected static $events = [
        Events::SUITE_BEFORE => 'runProcess',
        Events::SUITE_AFTER => 'stopProcess'
    ];

    private $processes = [];

    public function _initialize()
    {
        if (!class_exists('Symfony\Component\Process\Process')) {
            throw new ExtensionException($this, 'symfony/process package is required');
        }
    }

    public function runProcess()
    {
        $this->processes = [];
        foreach ($this->config as $key => $command) {
            if (!$command) {
                continue;
            }
            if (!is_int($key)) {
                continue; // configuration options
            }
            if (method_exists(Process::class, 'fromShellCommandline')) {
                //Symfony 4.2+
                $process = Process::fromShellCommandline($command, $this->getRootDir(), null, null, null);
            } else {
                $process = new Process($command, $this->getRootDir(), null, null, null);
            }
            $process->start();
            $this->processes[] = $process;
            $this->output->debug('[RunProcess] Starting '.$command);
        }
        sleep($this->config['sleep']);
    }

    public function __destruct()
    {
        $this->stopProcess();
    }

    public function stopProcess()
    {
        foreach (array_reverse($this->processes) as $process) {
            /** @var $process Process  **/
            if (!$process->isRunning()) {
                continue;
            }
            $this->output->debug('[RunProcess] Stopping ' . $process->getCommandLine());
            $process->stop();
        }
        $this->processes = [];
    }

    /**
     * Disable the deserialization of the class to prevent attacker executing
     * code by leveraging the __destruct method.
     *
     * @see https://owasp.org/www-community/vulnerabilities/PHP_Object_Injection
     */
    public function __sleep()
    {
        throw new \BadMethodCallException('Cannot serialize ' . __CLASS__);
    }

    /**
     * Disable the deserialization of the class to prevent attacker executing
     * code by leveraging the __destruct method.
     *
     * @see https://owasp.org/www-community/vulnerabilities/PHP_Object_Injection
     */
    public function __wakeup()
    {
        throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__);
    }
}
<?php
namespace Codeception\Lib\Interfaces;

/**
 * Modules for API testing
 */
interface API
{
}
<?php
namespace Codeception\Lib\Interfaces;

interface DoctrineProvider
{
    public function _getEntityManager();
}
<?php
namespace Codeception\Lib\Interfaces;

interface ElementLocator
{
    /**
     * Locates element using available Codeception locator types:
     *
     * * XPath
     * * CSS
     * * Strict Locator
     *
     * Use it in Helpers or GroupObject or Extension classes:
     *
     * ```php
     * <?php
     * $els = $this->getModule('{{MODULE_NAME}}')->_findElements('.items');
     * $els = $this->getModule('{{MODULE_NAME}}')->_findElements(['name' => 'username']);
     *
     * $editLinks = $this->getModule('{{MODULE_NAME}}')->_findElements(['link' => 'Edit']);
     * // now you can iterate over $editLinks and check that all them have valid hrefs
     * ```
     *
     * WebDriver module returns `Facebook\WebDriver\Remote\RemoteWebElement` instances
     * PhpBrowser and Framework modules return `Symfony\Component\DomCrawler\Crawler` instances
     *
     * @api
     * @param $locator
     * @return array of interactive elements
     */
    public function _findElements($locator);
}
<?php
namespace Codeception\Lib\Interfaces;

interface Remote
{
    /**
     * Changes the subdomain for the 'url' configuration parameter.
     * Does not open a page; use `amOnPage` for that.
     *
     * ``` php
     * <?php
     * // If config is: 'http://mysite.com'
     * // or config is: 'http://www.mysite.com'
     * // or config is: 'http://company.mysite.com'
     *
     * $I->amOnSubdomain('user');
     * $I->amOnPage('/');
     * // moves to http://user.mysite.com/
     * ?>
     * ```
     *
     * @param $subdomain
     *
     * @return mixed
     */
    public function amOnSubdomain($subdomain);

    /**
     * Open web page at the given absolute URL and sets its hostname as the base host.
     *
     * ``` php
     * <?php
     * $I->amOnUrl('http://codeception.com');
     * $I->amOnPage('/quickstart'); // moves to http://codeception.com/quickstart
     * ?>
     * ```
     */
    public function amOnUrl($url);

    public function _getUrl();
}
<?php
namespace Codeception\Lib\Interfaces;

interface DependsOnModule
{
    /**
     * Specifies class or module which is required for current one.
     *
     * THis method should return array with key as class name and value as error message
     * [className => errorMessage
     * ]
     * @return mixed
     */
    public function _depends();
}
<?php
namespace Codeception\Lib\Interfaces;

interface ConflictsWithModule
{
    /**
     * Returns class name or interface of module which can conflict with current.
     * @return string
     */
    public function _conflicts();
}
<?php
namespace Codeception\Lib\Interfaces;

interface DataMapper extends ORM, DoctrineProvider
{
    public function haveInRepository($entity, array $data);

    public function seeInRepository($entity, $params = []);

    public function dontSeeInRepository($entity, $params = []);

    public function grabFromRepository($entity, $field, $params = []);
}
<?php
namespace Codeception\Lib\Interfaces;

/**
 * Interface PartedModule
 *
 * Module implementing this interface can be loaded partly.
 * Parts can be defined by marking methods with `@part` annotations.
 * Part of modules can be loaded by specifying part (or several parts) in config:
 *
 * ```
 * modules:
 *      enabled: [MyModule]
 *      config:
 *          MyModule:
 *              part: usefulActions
 * ```
 *
 *
 * @package Codeception\Lib\Interfaces
 */
interface PartedModule
{
    public function _parts();
}
<?php
namespace Codeception\Lib\Interfaces;

interface PageSourceSaver
{
    /**
     * Saves page source of to a file
     *
     * ```php
     * $this->getModule('{{MODULE_NAME}}')->_savePageSource(codecept_output_dir().'page.html');
     * ```
     * @api
     * @param $filename
     */
    public function _savePageSource($filename);

    /**
     * Use this method within an [interactive pause](https://codeception.com/docs/02-GettingStarted#Interactive-Pause) to save the HTML source code of the current page.
     *
     * ```php
     * <?php
     * $I->makeHtmlSnapshot('edit_page');
     * // saved to: tests/_output/debug/edit_page.html
     * $I->makeHtmlSnapshot();
     * // saved to: tests/_output/debug/2017-05-26_14-24-11_4b3403665fea6.html
     * ```
     *
     * @param null $name
     */
    public function makeHtmlSnapshot($name = null);
}
<?php
namespace Codeception\Lib\Interfaces;

interface RequiresPackage
{

    /**
     * Returns list of classes and corresponding packages required for this module
     */
    public function _requires();
}
<?php
namespace Codeception\Lib\Interfaces;

interface MultiSession
{
    public function _initializeSession();

    public function _loadSession($session);

    public function _backupSession();

    public function _closeSession($session = null);

    public function _getName();
}
<?php
namespace Codeception\Lib\Interfaces;

interface Web
{
    /**
     * Opens the page for the given relative URI.
     *
     * ``` php
     * <?php
     * // opens front page
     * $I->amOnPage('/');
     * // opens /register page
     * $I->amOnPage('/register');
     * ```
     *
     * @param string $page
     */
    public function amOnPage($page);

    /**
     * Checks that the current page contains the given string (case insensitive).
     *
     * You can specify a specific HTML element (via CSS or XPath) as the second
     * parameter to only search within that element.
     *
     * ``` php
     * <?php
     * $I->see('Logout');                        // I can suppose user is logged in
     * $I->see('Sign Up', 'h1');                 // I can suppose it's a signup page
     * $I->see('Sign Up', '//body/h1');          // with XPath
     * $I->see('Sign Up', ['css' => 'body h1']); // with strict CSS locator
     * ```
     *
     * Note that the search is done after stripping all HTML tags from the body,
     * so `$I->see('strong')` will return true for strings like:
     *
     *   - `<p>I am Stronger than thou</p>`
     *   - `<script>document.createElement('strong');</script>`
     *
     * But will *not* be true for strings like:
     *
     *   - `<strong>Home</strong>`
     *   - `<div class="strong">Home</strong>`
     *   - `<!-- strong -->`
     *
     * For checking the raw source code, use `seeInSource()`.
     *
     * @param string $text
     * @param array|string $selector optional
     */
    public function see($text, $selector = null);

    /**
     * Checks that the current page doesn't contain the text specified (case insensitive).
     * Give a locator as the second parameter to match a specific region.
     *
     * ```php
     * <?php
     * $I->dontSee('Login');                         // I can suppose user is already logged in
     * $I->dontSee('Sign Up','h1');                  // I can suppose it's not a signup page
     * $I->dontSee('Sign Up','//body/h1');           // with XPath
     * $I->dontSee('Sign Up', ['css' => 'body h1']); // with strict CSS locator
     * ```
     *
     * Note that the search is done after stripping all HTML tags from the body,
     * so `$I->dontSee('strong')` will fail on strings like:
     *
     *   - `<p>I am Stronger than thou</p>`
     *   - `<script>document.createElement('strong');</script>`
     *
     * But will ignore strings like:
     *
     *   - `<strong>Home</strong>`
     *   - `<div class="strong">Home</strong>`
     *   - `<!-- strong -->`
     *
     * For checking the raw source code, use `seeInSource()`.
     *
     * @param string $text
     * @param array|string $selector optional
     */
    public function dontSee($text, $selector = null);
    
    /**
     * Checks that the current page contains the given string in its
     * raw source code.
     *
     * ``` php
     * <?php
     * $I->seeInSource('<h1>Green eggs &amp; ham</h1>');
     * ```
     *
     * @param      $raw
     */
    public function seeInSource($raw);

    /**
     * Checks that the current page contains the given string in its
     * raw source code.
     *
     * ```php
     * <?php
     * $I->dontSeeInSource('<h1>Green eggs &amp; ham</h1>');
     * ```
     *
     * @param      $raw
     */
    public function dontSeeInSource($raw);

    /**
     * Submits the given form on the page, with the given form
     * values.  Pass the form field's values as an array in the second
     * parameter.
     *
     * Although this function can be used as a short-hand version of
     * `fillField()`, `selectOption()`, `click()` etc. it has some important
     * differences:
     *
     *  * Only field *names* may be used, not CSS/XPath selectors nor field labels
     *  * If a field is sent to this function that does *not* exist on the page,
     *    it will silently be added to the HTTP request.  This is helpful for testing
     *    some types of forms, but be aware that you will *not* get an exception
     *    like you would if you called `fillField()` or `selectOption()` with
     *    a missing field.
     *
     * Fields that are not provided will be filled by their values from the page,
     * or from any previous calls to `fillField()`, `selectOption()` etc.
     * You don't need to click the 'Submit' button afterwards.
     * This command itself triggers the request to form's action.
     *
     * You can optionally specify which button's value to include
     * in the request with the last parameter (as an alternative to
     * explicitly setting its value in the second parameter), as
     * button values are not otherwise included in the request.
     *
     * Examples:
     *
     * ``` php
     * <?php
     * $I->submitForm('#login', [
     *     'login' => 'davert',
     *     'password' => '123456'
     * ]);
     * // or
     * $I->submitForm('#login', [
     *     'login' => 'davert',
     *     'password' => '123456'
     * ], 'submitButtonName');
     *
     * ```
     *
     * For example, given this sample "Sign Up" form:
     *
     * ``` html
     * <form id="userForm">
     *     Login:
     *     <input type="text" name="user[login]" /><br/>
     *     Password:
     *     <input type="password" name="user[password]" /><br/>
     *     Do you agree to our terms?
     *     <input type="checkbox" name="user[agree]" /><br/>
     *     Subscribe to our newsletter?
     *     <input type="checkbox" name="user[newsletter]" value="1" checked="checked" /><br/>
     *     Select pricing plan:
     *     <select name="plan">
     *         <option value="1">Free</option>
     *         <option value="2" selected="selected">Paid</option>
     *     </select>
     *     <input type="submit" name="submitButton" value="Submit" />
     * </form>
     * ```
     *
     * You could write the following to submit it:
     *
     * ``` php
     * <?php
     * $I->submitForm(
     *     '#userForm',
     *     [
     *         'user' => [
     *             'login' => 'Davert',
     *             'password' => '123456',
     *             'agree' => true
     *         ]
     *     ],
     *     'submitButton'
     * );
     * ```
     * Note that "2" will be the submitted value for the "plan" field, as it is
     * the selected option.
     *
     * To uncheck the pre-checked checkbox "newsletter", call `$I->uncheckOption(['name' => 'user[newsletter]']);` *before*,
     * then submit the form as shown here (i.e. without the "newsletter" field in the `$params` array).
     *
     * You can also emulate a JavaScript submission by not specifying any
     * buttons in the third parameter to submitForm.
     *
     * ```php
     * <?php
     * $I->submitForm(
     *     '#userForm',
     *     [
     *         'user' => [
     *             'login' => 'Davert',
     *             'password' => '123456',
     *             'agree' => true
     *         ]
     *     ]
     * );
     * ```
     *
     * This function works well when paired with `seeInFormFields()`
     * for quickly testing CRUD interfaces and form validation logic.
     *
     * ``` php
     * <?php
     * $form = [
     *      'field1' => 'value',
     *      'field2' => 'another value',
     *      'checkbox1' => true,
     *      // ...
     * ];
     * $I->submitForm('#my-form', $form, 'submitButton');
     * // $I->amOnPage('/path/to/form-page') may be needed
     * $I->seeInFormFields('#my-form', $form);
     * ```
     *
     * Parameter values can be set to arrays for multiple input fields
     * of the same name, or multi-select combo boxes.  For checkboxes,
     * you can use either the string value or boolean `true`/`false` which will
     * be replaced by the checkbox's value in the DOM.
     *
     * ``` php
     * <?php
     * $I->submitForm('#my-form', [
     *      'field1' => 'value',
     *      'checkbox' => [
     *          'value of first checkbox',
     *          'value of second checkbox',
     *      ],
     *      'otherCheckboxes' => [
     *          true,
     *          false,
     *          false
     *      ],
     *      'multiselect' => [
     *          'first option value',
     *          'second option value'
     *      ]
     * ]);
     * ```
     *
     * Mixing string and boolean values for a checkbox's value is not supported
     * and may produce unexpected results.
     *
     * Field names ending in `[]` must be passed without the trailing square
     * bracket characters, and must contain an array for its value.  This allows
     * submitting multiple values with the same name, consider:
     *
     * ```php
     * <?php
     * // This will NOT work correctly
     * $I->submitForm('#my-form', [
     *     'field[]' => 'value',
     *     'field[]' => 'another value',  // 'field[]' is already a defined key
     * ]);
     * ```
     *
     * The solution is to pass an array value:
     *
     * ```php
     * <?php
     * // This way both values are submitted
     * $I->submitForm('#my-form', [
     *     'field' => [
     *         'value',
     *         'another value',
     *     ]
     * ]);
     * ```
     *
     * @param $selector
     * @param $params
     * @param $button
     */
    public function submitForm($selector, array $params, $button = null);

    /**
     * Perform a click on a link or a button, given by a locator.
     * If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string.
     * For buttons, the "value" attribute, "name" attribute, and inner text are searched.
     * For links, the link text is searched.
     * For images, the "alt" attribute and inner text of any parent links are searched.
     *
     * The second parameter is a context (CSS or XPath locator) to narrow the search.
     *
     * Note that if the locator matches a button of type `submit`, the form will be submitted.
     *
     * ``` php
     * <?php
     * // simple link
     * $I->click('Logout');
     * // button of form
     * $I->click('Submit');
     * // CSS button
     * $I->click('#form input[type=submit]');
     * // XPath
     * $I->click('//form/*[@type="submit"]');
     * // link in context
     * $I->click('Logout', '#nav');
     * // using strict locator
     * $I->click(['link' => 'Login']);
     * ?>
     * ```
     *
     * @param $link
     * @param $context
     */
    public function click($link, $context = null);

    /**
     * Checks that there's a link with the specified text.
     * Give a full URL as the second parameter to match links with that exact URL.
     *
     * ``` php
     * <?php
     * $I->seeLink('Logout'); // matches <a href="#">Logout</a>
     * $I->seeLink('Logout','/logout'); // matches <a href="/logout">Logout</a>
     * ?>
     * ```
     *
     * @param string $text
     * @param string $url optional
     */
    public function seeLink($text, $url = null);

    /**
     * Checks that the page doesn't contain a link with the given string.
     * If the second parameter is given, only links with a matching "href" attribute will be checked.
     *
     * ``` php
     * <?php
     * $I->dontSeeLink('Logout'); // I suppose user is not logged in
     * $I->dontSeeLink('Checkout now', '/store/cart.php');
     * ?>
     * ```
     *
     * @param string $text
     * @param string $url optional
     */
    public function dontSeeLink($text, $url = null);

    /**
     * Checks that current URI contains the given string.
     *
     * ``` php
     * <?php
     * // to match: /home/dashboard
     * $I->seeInCurrentUrl('home');
     * // to match: /users/1
     * $I->seeInCurrentUrl('/users/');
     * ?>
     * ```
     *
     * @param string $uri
     */
    public function seeInCurrentUrl($uri);

    /**
     * Checks that the current URL is equal to the given string.
     * Unlike `seeInCurrentUrl`, this only matches the full URL.
     *
     * ``` php
     * <?php
     * // to match root url
     * $I->seeCurrentUrlEquals('/');
     * ?>
     * ```
     *
     * @param string $uri
     */
    public function seeCurrentUrlEquals($uri);

    /**
     * Checks that the current URL matches the given regular expression.
     *
     * ``` php
     * <?php
     * // to match root url
     * $I->seeCurrentUrlMatches('~^/users/(\d+)~');
     * ?>
     * ```
     *
     * @param string $uri
     */
    public function seeCurrentUrlMatches($uri);

    /**
     * Checks that the current URI doesn't contain the given string.
     *
     * ``` php
     * <?php
     * $I->dontSeeInCurrentUrl('/users/');
     * ?>
     * ```
     *
     * @param string $uri
     */
    public function dontSeeInCurrentUrl($uri);

    /**
     * Checks that the current URL doesn't equal the given string.
     * Unlike `dontSeeInCurrentUrl`, this only matches the full URL.
     *
     * ``` php
     * <?php
     * // current url is not root
     * $I->dontSeeCurrentUrlEquals('/');
     * ?>
     * ```
     *
     * @param string $uri
     */
    public function dontSeeCurrentUrlEquals($uri);

    /**
     * Checks that current url doesn't match the given regular expression.
     *
     * ``` php
     * <?php
     * // to match root url
     * $I->dontSeeCurrentUrlMatches('~^/users/(\d+)~');
     * ?>
     * ```
     *
     * @param string $uri
     */
    public function dontSeeCurrentUrlMatches($uri);

    /**
     * Executes the given regular expression against the current URI and returns the first capturing group.
     * If no parameters are provided, the full URI is returned.
     *
     * ``` php
     * <?php
     * $user_id = $I->grabFromCurrentUrl('~^/user/(\d+)/~');
     * $uri = $I->grabFromCurrentUrl();
     * ?>
     * ```
     *
     * @param string $uri optional
     *
     * @return mixed
     */
    public function grabFromCurrentUrl($uri = null);

    /**
     * Checks that the specified checkbox is checked.
     *
     * ``` php
     * <?php
     * $I->seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms
     * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user agreed to terms, If there is only one checkbox in form.
     * $I->seeCheckboxIsChecked('//form/input[@type=checkbox and @name=agree]');
     * ?>
     * ```
     *
     * @param $checkbox
     */
    public function seeCheckboxIsChecked($checkbox);

    /**
     * Check that the specified checkbox is unchecked.
     *
     * ``` php
     * <?php
     * $I->dontSeeCheckboxIsChecked('#agree'); // I suppose user didn't agree to terms
     * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user didn't check the first checkbox in form.
     * ?>
     * ```
     *
     * @param $checkbox
     */
    public function dontSeeCheckboxIsChecked($checkbox);

    /**
     * Checks that the given input field or textarea *equals* (i.e. not just contains) the given value.
     * Fields are matched by label text, the "name" attribute, CSS, or XPath.
     *
     * ``` php
     * <?php
     * $I->seeInField('Body','Type your comment here');
     * $I->seeInField('form textarea[name=body]','Type your comment here');
     * $I->seeInField('form input[type=hidden]','hidden_value');
     * $I->seeInField('#searchform input','Search');
     * $I->seeInField('//form/*[@name=search]','Search');
     * $I->seeInField(['name' => 'search'], 'Search');
     * ?>
     * ```
     *
     * @param $field
     * @param $value
     */
    public function seeInField($field, $value);

    /**
     * Checks that an input field or textarea doesn't contain the given value.
     * For fuzzy locators, the field is matched by label text, CSS and XPath.
     *
     * ``` php
     * <?php
     * $I->dontSeeInField('Body','Type your comment here');
     * $I->dontSeeInField('form textarea[name=body]','Type your comment here');
     * $I->dontSeeInField('form input[type=hidden]','hidden_value');
     * $I->dontSeeInField('#searchform input','Search');
     * $I->dontSeeInField('//form/*[@name=search]','Search');
     * $I->dontSeeInField(['name' => 'search'], 'Search');
     * ?>
     * ```
     *
     * @param $field
     * @param $value
     */
    public function dontSeeInField($field, $value);

    /**
     * Checks if the array of form parameters (name => value) are set on the form matched with the
     * passed selector.
     *
     * ``` php
     * <?php
     * $I->seeInFormFields('form[name=myform]', [
     *      'input1' => 'value',
     *      'input2' => 'other value',
     * ]);
     * ?>
     * ```
     *
     * For multi-select elements, or to check values of multiple elements with the same name, an
     * array may be passed:
     *
     * ``` php
     * <?php
     * $I->seeInFormFields('.form-class', [
     *      'multiselect' => [
     *          'value1',
     *          'value2',
     *      ],
     *      'checkbox[]' => [
     *          'a checked value',
     *          'another checked value',
     *      ],
     * ]);
     * ?>
     * ```
     *
     * Additionally, checkbox values can be checked with a boolean.
     *
     * ``` php
     * <?php
     * $I->seeInFormFields('#form-id', [
     *      'checkbox1' => true,        // passes if checked
     *      'checkbox2' => false,       // passes if unchecked
     * ]);
     * ?>
     * ```
     *
     * Pair this with submitForm for quick testing magic.
     *
     * ``` php
     * <?php
     * $form = [
     *      'field1' => 'value',
     *      'field2' => 'another value',
     *      'checkbox1' => true,
     *      // ...
     * ];
     * $I->submitForm('//form[@id=my-form]', $form, 'submitButton');
     * // $I->amOnPage('/path/to/form-page') may be needed
     * $I->seeInFormFields('//form[@id=my-form]', $form);
     * ?>
     * ```
     *
     * @param $formSelector
     * @param $params
     */
    public function seeInFormFields($formSelector, array $params);

    /**
     * Checks if the array of form parameters (name => value) are not set on the form matched with
     * the passed selector.
     *
     * ``` php
     * <?php
     * $I->dontSeeInFormFields('form[name=myform]', [
     *      'input1' => 'non-existent value',
     *      'input2' => 'other non-existent value',
     * ]);
     * ?>
     * ```
     *
     * To check that an element hasn't been assigned any one of many values, an array can be passed
     * as the value:
     *
     * ``` php
     * <?php
     * $I->dontSeeInFormFields('.form-class', [
     *      'fieldName' => [
     *          'This value shouldn\'t be set',
     *          'And this value shouldn\'t be set',
     *      ],
     * ]);
     * ?>
     * ```
     *
     * Additionally, checkbox values can be checked with a boolean.
     *
     * ``` php
     * <?php
     * $I->dontSeeInFormFields('#form-id', [
     *      'checkbox1' => true,        // fails if checked
     *      'checkbox2' => false,       // fails if unchecked
     * ]);
     * ?>
     * ```
     *
     * @param $formSelector
     * @param $params
     */
    public function dontSeeInFormFields($formSelector, array $params);

    /**
     * Selects an option in a select tag or in radio button group.
     *
     * ``` php
     * <?php
     * $I->selectOption('form select[name=account]', 'Premium');
     * $I->selectOption('form input[name=payment]', 'Monthly');
     * $I->selectOption('//form/select[@name=account]', 'Monthly');
     * ?>
     * ```
     *
     * Provide an array for the second argument to select multiple options:
     *
     * ``` php
     * <?php
     * $I->selectOption('Which OS do you use?', array('Windows','Linux'));
     * ?>
     * ```
     *
     * Or provide an associative array for the second argument to specifically define which selection method should be used:
     *
     * ``` php
     * <?php
     * $I->selectOption('Which OS do you use?', array('text' => 'Windows')); // Only search by text 'Windows'
     * $I->selectOption('Which OS do you use?', array('value' => 'windows')); // Only search by value 'windows'
     * ?>
     * ```
     *
     * @param $select
     * @param $option
     */
    public function selectOption($select, $option);

    /**
     * Ticks a checkbox. For radio buttons, use the `selectOption` method instead.
     *
     * ``` php
     * <?php
     * $I->checkOption('#agree');
     * ?>
     * ```
     *
     * @param $option
     */
    public function checkOption($option);

    /**
     * Unticks a checkbox.
     *
     * ``` php
     * <?php
     * $I->uncheckOption('#notify');
     * ?>
     * ```
     *
     * @param $option
     */
    public function uncheckOption($option);

    /**
     * Fills a text field or textarea with the given string.
     *
     * ``` php
     * <?php
     * $I->fillField("//input[@type='text']", "Hello World!");
     * $I->fillField(['name' => 'email'], 'jon@example.com');
     * ?>
     * ```
     *
     * @param $field
     * @param $value
     */
    public function fillField($field, $value);
    
    /**
     * Attaches a file relative to the Codeception `_data` directory to the given file upload field.
     *
     * ``` php
     * <?php
     * // file is stored in 'tests/_data/prices.xls'
     * $I->attachFile('input[@type="file"]', 'prices.xls');
     * ?>
     * ```
     *
     * @param $field
     * @param $filename
     */
    public function attachFile($field, $filename);

    /**
     * Finds and returns the text contents of the given element.
     * If a fuzzy locator is used, the element is found using CSS, XPath,
     * and by matching the full page source by regular expression.
     *
     * ``` php
     * <?php
     * $heading = $I->grabTextFrom('h1');
     * $heading = $I->grabTextFrom('descendant-or-self::h1');
     * $value = $I->grabTextFrom('~<input value=(.*?)]~sgi'); // match with a regex
     * ?>
     * ```
     *
     * @param $cssOrXPathOrRegex
     *
     * @return mixed
     */
    public function grabTextFrom($cssOrXPathOrRegex);

    /**
     * Finds the value for the given form field.
     * If a fuzzy locator is used, the field is found by field name, CSS, and XPath.
     *
     * ``` php
     * <?php
     * $name = $I->grabValueFrom('Name');
     * $name = $I->grabValueFrom('input[name=username]');
     * $name = $I->grabValueFrom('descendant-or-self::form/descendant::input[@name = 'username']');
     * $name = $I->grabValueFrom(['name' => 'username']);
     * ?>
     * ```
     *
     * @param $field
     *
     * @return mixed
     */
    public function grabValueFrom($field);


    /**
     * Grabs the value of the given attribute value from the given element.
     * Fails if element is not found.
     *
     * ``` php
     * <?php
     * $I->grabAttributeFrom('#tooltip', 'title');
     * ?>
     * ```
     *
     *
     * @param $cssOrXpath
     * @param $attribute
     *
     * @return mixed
     */
    public function grabAttributeFrom($cssOrXpath, $attribute);
    
    /**
     * Grabs either the text content, or attribute values, of nodes
     * matched by $cssOrXpath and returns them as an array.
     *
     * ```html
     * <a href="#first">First</a>
     * <a href="#second">Second</a>
     * <a href="#third">Third</a>
     * ```
     *
     * ```php
     * <?php
     * // would return ['First', 'Second', 'Third']
     * $aLinkText = $I->grabMultiple('a');
     *
     * // would return ['#first', '#second', '#third']
     * $aLinks = $I->grabMultiple('a', 'href');
     * ?>
     * ```
     *
     * @param $cssOrXpath
     * @param $attribute
     * @return string[]
     */
    public function grabMultiple($cssOrXpath, $attribute = null);

    /**
     * Checks that the given element exists on the page and is visible.
     * You can also specify expected attributes of this element.
     *
     * ``` php
     * <?php
     * $I->seeElement('.error');
     * $I->seeElement('//form/input[1]');
     * $I->seeElement('input', ['name' => 'login']);
     * $I->seeElement('input', ['value' => '123456']);
     *
     * // strict locator in first arg, attributes in second
     * $I->seeElement(['css' => 'form input'], ['name' => 'login']);
     * ?>
     * ```
     *
     * @param $selector
     * @param array $attributes
     * @return
     */
    public function seeElement($selector, $attributes = []);

    /**
     * Checks that the given element is invisible or not present on the page.
     * You can also specify expected attributes of this element.
     *
     * ``` php
     * <?php
     * $I->dontSeeElement('.error');
     * $I->dontSeeElement('//form/input[1]');
     * $I->dontSeeElement('input', ['name' => 'login']);
     * $I->dontSeeElement('input', ['value' => '123456']);
     * ?>
     * ```
     *
     * @param $selector
     * @param array $attributes
     */
    public function dontSeeElement($selector, $attributes = []);

    /**
     * Checks that there are a certain number of elements matched by the given locator on the page.
     *
     * ``` php
     * <?php
     * $I->seeNumberOfElements('tr', 10);
     * $I->seeNumberOfElements('tr', [0,10]); // between 0 and 10 elements
     * ?>
     * ```
     * @param $selector
     * @param mixed $expected int or int[]
     */
    public function seeNumberOfElements($selector, $expected);

    /**
     * Checks that the given option is selected.
     *
     * ``` php
     * <?php
     * $I->seeOptionIsSelected('#form input[name=payment]', 'Visa');
     * ?>
     * ```
     *
     * @param $selector
     * @param $optionText
     *
     * @return mixed
     */
    public function seeOptionIsSelected($selector, $optionText);

    /**
     * Checks that the given option is not selected.
     *
     * ``` php
     * <?php
     * $I->dontSeeOptionIsSelected('#form input[name=payment]', 'Visa');
     * ?>
     * ```
     *
     * @param $selector
     * @param $optionText
     *
     * @return mixed
     */
    public function dontSeeOptionIsSelected($selector, $optionText);

    /**
     * Checks that the page title contains the given string.
     *
     * ``` php
     * <?php
     * $I->seeInTitle('Blog - Post #1');
     * ?>
     * ```
     *
     * @param $title
     *
     * @return mixed
     */
    public function seeInTitle($title);

    /**
     * Checks that the page title does not contain the given string.
     *
     * @param $title
     *
     * @return mixed
     */
    public function dontSeeInTitle($title);

    /**
     * Checks that a cookie with the given name is set.
     * You can set additional cookie params like `domain`, `path` as array passed in last argument.
     *
     * ``` php
     * <?php
     * $I->seeCookie('PHPSESSID');
     * ?>
     * ```
     *
     * @param $cookie
     * @param array $params
     * @return mixed
     */
    public function seeCookie($cookie, array $params = []);

    /**
     * Checks that there isn't a cookie with the given name.
     * You can set additional cookie params like `domain`, `path` as array passed in last argument.
     *
     * @param $cookie
     *
     * @param array $params
     * @return mixed
     */
    public function dontSeeCookie($cookie, array $params = []);

    /**
     * Sets a cookie with the given name and value.
     * You can set additional cookie params like `domain`, `path`, `expires`, `secure` in array passed as last argument.
     *
     * ``` php
     * <?php
     * $I->setCookie('PHPSESSID', 'el4ukv0kqbvoirg7nkp4dncpk3');
     * ?>
     * ```
     *
     * @param $name
     * @param $val
     * @param array $params
     *
     * @return mixed
     */
    public function setCookie($name, $val, array $params = []);

    /**
     * Unsets cookie with the given name.
     * You can set additional cookie params like `domain`, `path` in array passed as last argument.
     *
     * @param $cookie
     *
     * @param array $params
     * @return mixed
     */
    public function resetCookie($cookie, array $params = []);

    /**
     * Grabs a cookie value.
     * You can set additional cookie params like `domain`, `path` in array passed as last argument.
     * If the cookie is set by an ajax request (XMLHttpRequest), there might be some delay caused by the browser, so try `$I->wait(0.1)`.
     *
     * @param $cookie
     *
     * @param array $params
     * @return mixed
     */
    public function grabCookie($cookie, array $params = []);

    /**
     * Grabs current page source code.
     *
     * @return string Current page source code.
     */
    public function grabPageSource();
}
<?php
namespace Codeception\Lib\Interfaces;

interface ActiveRecord extends ORM
{
    public function haveRecord($model, $attributes = []);

    public function seeRecord($model, $attributes = []);

    public function dontSeeRecord($model, $attributes = []);

    public function grabRecord($model, $attributes = []);
}
<?php
namespace Codeception\Lib\Interfaces;

interface ORM
{
}
<?php
namespace Codeception\Lib;

use Codeception\Configuration;
use Codeception\Exception\ConfigurationException;
use Codeception\Exception\ModuleConflictException;
use Codeception\Exception\ModuleException;
use Codeception\Exception\ModuleRequireException;
use Codeception\Lib\Interfaces\ConflictsWithModule;
use Codeception\Lib\Interfaces\DependsOnModule;
use Codeception\Lib\Interfaces\PartedModule;
use Codeception\Util\Annotation;

/**
 * Class ModuleContainer
 * @package Codeception\Lib
 */
class ModuleContainer
{
    /**
     * @var string
     */
    const MODULE_NAMESPACE = '\\Codeception\\Module\\';

    /**
     * @var integer
     */
    const MAXIMUM_LEVENSHTEIN_DISTANCE = 5;

    public static $packages = [
        'AMQP' => 'codeception/module-amqp',
        'Apc' => 'codeception/module-apc',
        'Asserts' => 'codeception/module-asserts',
        'Cli' => 'codeception/module-cli',
        'DataFactory' => 'codeception/module-datafactory',
        'Db' => 'codeception/module-db',
        'Doctrine2' => "codeception/module-doctrine2",
        'Filesystem' => 'codeception/module-filesystem',
        'FTP' => 'codeception/module-ftp',
        'Laravel5' => 'codeception/module-laravel5',
        'Lumen' => 'codeception/module-lumen',
        'Memcache' => 'codeception/module-memcache',
        'MongoDb' => 'codeception/module-mongodb',
        'Phalcon' => 'codeception/module-phalcon',
        'PhpBrowser' => 'codeception/module-phpbrowser',
        'Queue' => 'codeception/module-queue',
        'Redis' => 'codeception/module-redis',
        'REST' => 'codeception/module-rest',
        'Sequence' => 'codeception/module-sequence',
        'SOAP' => 'codeception/module-soap',
        'Symfony' => 'codeception/module-symfony',
        'WebDriver' => "codeception/module-webdriver",
        'Yii2' => "codeception/module-yii2",
        'ZendExpressive' => 'codeception/module-zendexpressive',
        'ZF2' => 'codeception/module-zf2',
    ];

    /**
     * @var array
     */
    private $config;

    /**
     * @var Di
     */
    private $di;

    /**
     * @var array
     */
    private $modules = [];

    /**
     * @var array
     */
    private $active = [];

    /**
     * @var array
     */
    private $actions = [];

    /**
     * Constructor.
     *
     * @param Di $di
     * @param array $config
     */
    public function __construct(Di $di, $config)
    {
        $this->di = $di;
        $this->di->set($this);
        $this->config = $config;
    }

    /**
     * Create a module.
     *
     * @param string $moduleName
     * @param bool $active
     * @return \Codeception\Module
     * @throws \Codeception\Exception\ConfigurationException
     * @throws \Codeception\Exception\ModuleException
     * @throws \Codeception\Exception\ModuleRequireException
     * @throws \Codeception\Exception\InjectionException
     */
    public function create($moduleName, $active = true)
    {
        $this->active[$moduleName] = $active;

        $moduleClass = $this->getModuleClass($moduleName);
        if (!class_exists($moduleClass)) {
            if (isset(self::$packages[$moduleName])) {
                $package = self::$packages[$moduleName];
                throw new ConfigurationException("Module $moduleName is not installed.\nUse Composer to install corresponding package:\n\ncomposer require $package --dev");
            }
            throw new ConfigurationException("Module $moduleName could not be found and loaded");
        }

        $config = $this->getModuleConfig($moduleName);

        if (empty($config) && !$active) {
            // For modules that are a dependency of other modules we want to skip the validation of the config.
            // This config validation is performed in \Codeception\Module::__construct().
            // Explicitly setting $config to null skips this validation.
            $config = null;
        }

        $this->modules[$moduleName] = $module = $this->di->instantiate($moduleClass, [$this, $config], false);

        if ($this->moduleHasDependencies($module)) {
            $this->injectModuleDependencies($moduleName, $module);
        }

        // If module is not active its actions should not be included in the actor class
        $actions = $active ? $this->getActionsForModule($module, $config) : [];

        foreach ($actions as $action) {
            $this->actions[$action] = $moduleName;
        };

        return $module;
    }

    /**
     * Does a module have dependencies?
     *
     * @param \Codeception\Module $module
     * @return bool
     */
    private function moduleHasDependencies($module)
    {
        if (!$module instanceof DependsOnModule) {
            return false;
        }

        return (bool) $module->_depends();
    }

    /**
     * Get the actions of a module.
     *
     * @param \Codeception\Module $module
     * @param array $config
     * @return array
     */
    private function getActionsForModule($module, $config)
    {
        $reflectionClass = new \ReflectionClass($module);

        // Only public methods can be actions
        $methods = $reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC);

        // Should this module be loaded partially?
        $configuredParts = null;
        if ($module instanceof PartedModule && isset($config['part'])) {
            $configuredParts = is_array($config['part']) ? $config['part'] : [$config['part']];
        }

        $actions = [];
        foreach ($methods as $method) {
            if ($this->includeMethodAsAction($module, $method, $configuredParts)) {
                $actions[] = $method->name;
            }
        }

        return $actions;
    }

    /**
     * Should a method be included as an action?
     *
     * @param \Codeception\Module $module
     * @param \ReflectionMethod $method
     * @param array|null $configuredParts
     * @return bool
     */
    private function includeMethodAsAction($module, $method, $configuredParts = null)
    {
        // Filter out excluded actions
        if ($module::$excludeActions && in_array($method->name, $module::$excludeActions)) {
            return false;
        }

        // Keep only the $onlyActions if they are specified
        if ($module::$onlyActions && !in_array($method->name, $module::$onlyActions)) {
            return false;
        }

        // Do not include inherited actions if the static $includeInheritedActions property is set to false.
        // However, if an inherited action is also specified in the static $onlyActions property
        // it should be included as an action.
        if (!$module::$includeInheritedActions &&
            !in_array($method->name, $module::$onlyActions) &&
            $method->getDeclaringClass()->getName() != get_class($module)
        ) {
            return false;
        }

        // Do not include hidden methods, methods with a name starting with an underscore
        if (strpos($method->name, '_') === 0) {
            return false;
        };

        // If a part is configured for the module, only include actions from that part
        if ($configuredParts) {
            $moduleParts = Annotation::forMethod($module, $method->name)->fetchAll('part');
            if (!array_uintersect($moduleParts, $configuredParts, 'strcasecmp')) {
                return false;
            }
        }

        return true;
    }

    /**
     * Is the module a helper?
     *
     * @param string $moduleName
     * @return bool
     */
    private function isHelper($moduleName)
    {
        return strpos($moduleName, '\\') !== false;
    }

    /**
     * Get the fully qualified class name for a module.
     *
     * @param string $moduleName
     * @return string
     */
    private function getModuleClass($moduleName)
    {
        if ($this->isHelper($moduleName)) {
            return $moduleName;
        }

        return self::MODULE_NAMESPACE . $moduleName;
    }

    /**
     * Is a module instantiated in this ModuleContainer?
     *
     * @param string $moduleName
     * @return bool
     */
    public function hasModule($moduleName)
    {
        return isset($this->modules[$moduleName]);
    }

    /**
     * Get a module from this ModuleContainer.
     *
     * @param string $moduleName
     * @return \Codeception\Module
     * @throws \Codeception\Exception\ModuleException
     */
    public function getModule($moduleName)
    {
        if (!$this->hasModule($moduleName)) {
            $this->throwMissingModuleExceptionWithSuggestion(__CLASS__, $moduleName);
        }

        return $this->modules[$moduleName];
    }

    public function throwMissingModuleExceptionWithSuggestion($className, $moduleName)
    {
        $suggestedModuleNameInfo = $this->getModuleSuggestion($moduleName);
        throw new ModuleException($className, "Module $moduleName couldn't be connected" . $suggestedModuleNameInfo);
    }

    protected function getModuleSuggestion($missingModuleName)
    {
        $shortestLevenshteinDistance = null;
        $suggestedModuleName = null;
        foreach ($this->modules as $moduleName => $module) {
            $levenshteinDistance = levenshtein($missingModuleName, $moduleName);
            if ($shortestLevenshteinDistance === null || $levenshteinDistance <= $shortestLevenshteinDistance) {
                $shortestLevenshteinDistance = $levenshteinDistance;
                $suggestedModuleName = $moduleName;
            }
        }

        if ($suggestedModuleName !== null && $shortestLevenshteinDistance <= self::MAXIMUM_LEVENSHTEIN_DISTANCE) {
            return " (did you mean '$suggestedModuleName'?)";
        }

        return '';
    }

    /**
     * Get the module for an action.
     *
     * @param string $action
     * @return \Codeception\Module|null This method returns null if there is no module for $action
     */
    public function moduleForAction($action)
    {
        if (!isset($this->actions[$action])) {
            return null;
        }

        return $this->modules[$this->actions[$action]];
    }

    /**
     * Get all actions.
     *
     * @return array An array with actions as keys and module names as values.
     */
    public function getActions()
    {
        return $this->actions;
    }

    /**
     * Get all modules.
     *
     * @return array An array with module names as keys and modules as values.
     */
    public function all()
    {
        return $this->modules;
    }

    /**
     * Mock a module in this ModuleContainer.
     *
     * @param string $moduleName
     * @param object $mock
     */
    public function mock($moduleName, $mock)
    {
        $this->modules[$moduleName] = $mock;
    }

    /**
     * Inject the dependencies of a module.
     *
     * @param string $moduleName
     * @param \Codeception\Lib\Interfaces\DependsOnModule $module
     * @throws \Codeception\Exception\ModuleException
     * @throws \Codeception\Exception\ModuleRequireException
     */
    private function injectModuleDependencies($moduleName, DependsOnModule $module)
    {
        $this->checkForMissingDependencies($moduleName, $module);

        if (!method_exists($module, '_inject')) {
            throw new ModuleException($module, 'Module requires method _inject to be defined to accept dependencies');
        }

        $dependencies = array_map(function ($dependency) {
            return $this->create($dependency, false);
        }, $this->getConfiguredDependencies($moduleName));

        call_user_func_array([$module, '_inject'], $dependencies);
    }

    /**
     * Check for missing dependencies.
     *
     * @param string $moduleName
     * @param \Codeception\Lib\Interfaces\DependsOnModule $module
     * @throws \Codeception\Exception\ModuleException
     * @throws \Codeception\Exception\ModuleRequireException
     */
    private function checkForMissingDependencies($moduleName, DependsOnModule $module)
    {
        $dependencies = $this->getModuleDependencies($module);
        $configuredDependenciesCount = count($this->getConfiguredDependencies($moduleName));

        if ($configuredDependenciesCount < count($dependencies)) {
            $missingDependency = array_keys($dependencies)[$configuredDependenciesCount];

            $message = sprintf(
                "\nThis module depends on %s\n\n\n%s",
                $missingDependency,
                $this->getErrorMessageForDependency($module, $missingDependency)
            );

            throw new ModuleRequireException($moduleName, $message);
        }
    }

    /**
     * Get the dependencies of a module.
     *
     * @param \Codeception\Lib\Interfaces\DependsOnModule $module
     * @return array
     * @throws \Codeception\Exception\ModuleException
     */
    private function getModuleDependencies(DependsOnModule $module)
    {
        $depends = $module->_depends();

        if (!$depends) {
            return [];
        }

        if (!is_array($depends)) {
            $message = sprintf("Method _depends of module '%s' must return an array", get_class($module));
            throw new ModuleException($module, $message);
        }

        return $depends;
    }

    /**
     * Get the configured dependencies for a module.
     *
     * @param string $moduleName
     * @return array
     */
    private function getConfiguredDependencies($moduleName)
    {
        $config = $this->getModuleConfig($moduleName);

        if (!isset($config['depends'])) {
            return [];
        }

        return is_array($config['depends']) ? $config['depends'] : [$config['depends']];
    }

    /**
     * Get the error message for a module dependency that is missing.
     *
     * @param \Codeception\Module $module
     * @param string $missingDependency
     * @return string
     */
    private function getErrorMessageForDependency($module, $missingDependency)
    {
        $depends = $module->_depends();

        return $depends[$missingDependency];
    }

    /**
     * Get the configuration for a module.
     *
     * A module with name $moduleName can be configured at two paths in a configuration file:
     * - modules.config.$moduleName
     * - modules.enabled.$moduleName
     *
     * This method checks both locations for configuration. If there is configuration at both locations
     * this method merges them, where the configuration at modules.enabled.$moduleName takes precedence
     * over modules.config.$moduleName if the same parameters are configured at both locations.
     *
     * @param string $moduleName
     * @return array
     */
    private function getModuleConfig($moduleName)
    {
        $config = isset($this->config['modules']['config'][$moduleName])
            ? $this->config['modules']['config'][$moduleName]
            : [];

        if (!isset($this->config['modules']['enabled'])) {
            return $config;
        }

        if (!is_array($this->config['modules']['enabled'])) {
            return $config;
        }

        foreach ($this->config['modules']['enabled'] as $enabledModuleConfig) {
            if (!is_array($enabledModuleConfig)) {
                continue;
            }

            $enabledModuleName = key($enabledModuleConfig);
            if ($enabledModuleName === $moduleName) {
                return Configuration::mergeConfigs(reset($enabledModuleConfig), $config);
            }
        }

        return $config;
    }

    /**
     * Check if there are conflicting modules in this ModuleContainer.
     *
     * @throws \Codeception\Exception\ModuleConflictException
     */
    public function validateConflicts()
    {
        $canConflict = [];
        foreach ($this->modules as $moduleName => $module) {
            $parted = $module instanceof PartedModule && $module->_getConfig('part');

            if ($this->active[$moduleName] && !$parted) {
                $canConflict[] = $module;
            }
        }

        foreach ($canConflict as $module) {
            foreach ($canConflict as $otherModule) {
                $this->validateConflict($module, $otherModule);
            }
        }
    }

    /**
     * Check if the modules passed as arguments to this method conflict with each other.
     *
     * @param \Codeception\Module $module
     * @param \Codeception\Module $otherModule
     * @throws \Codeception\Exception\ModuleConflictException
     */
    private function validateConflict($module, $otherModule)
    {
        if ($module === $otherModule || !$module instanceof ConflictsWithModule) {
            return;
        }

        $conflicts = $this->normalizeConflictSpecification($module->_conflicts());
        if ($otherModule instanceof $conflicts) {
            throw new ModuleConflictException($module, $otherModule);
        }
    }

    /**
     * Normalize the return value of ConflictsWithModule::_conflicts() to a class name.
     * This is necessary because it can return a module name instead of the name of a class or interface.
     *
     * @param string $conflicts
     * @return string
     */
    private function normalizeConflictSpecification($conflicts)
    {
        if (interface_exists($conflicts) || class_exists($conflicts)) {
            return $conflicts;
        }

        if ($this->hasModule($conflicts)) {
            return $this->getModule($conflicts);
        }

        return $conflicts;
    }
}
<?php
namespace Codeception\Lib;

use Codeception\Exception\InjectionException;
use Codeception\Util\ReflectionHelper;

class Di
{
    const DEFAULT_INJECT_METHOD_NAME = '_inject';

    protected $container = [];

    /**
     * @var Di
     */
    protected $fallback;

    public function __construct($fallback = null)
    {
        $this->fallback = $fallback;
    }

    public function get($className)
    {
        // normalize namespace
        $className = ltrim($className, '\\');
        return isset($this->container[$className]) ? $this->container[$className] : null;
    }

    public function set($class)
    {
        $this->container[get_class($class)] = $class;
    }

    /**
     * @param string $className
     * @param array $constructorArgs
     * @param string $injectMethodName Method which will be invoked after object creation;
     *                                 Resolved dependencies will be passed to it as arguments
     * @throws InjectionException
     * @return null|object
     */
    public function instantiate(
        $className,
        $constructorArgs = null,
        $injectMethodName = self::DEFAULT_INJECT_METHOD_NAME
    ) {
        // normalize namespace
        $className = ltrim($className, '\\');

        // get class from container
        if (isset($this->container[$className])) {
            if ($this->container[$className] instanceof $className) {
                return $this->container[$className];
            }

            throw new InjectionException("Failed to resolve cyclic dependencies for class '$className'");
        }

        // get class from parent container
        if ($this->fallback) {
            if ($class = $this->fallback->get($className)) {
                return $class;
            }
        }

        $this->container[$className] = false; // flag that object is being instantiated

        $reflectedClass = new \ReflectionClass($className);
        if (!$reflectedClass->isInstantiable()) {
            return null;
        }

        $reflectedConstructor = $reflectedClass->getConstructor();
        if (is_null($reflectedConstructor)) {
            $object = new $className;
        } else {
            try {
                if (!$constructorArgs) {
                    $constructorArgs = $this->prepareArgs($reflectedConstructor);
                }
            } catch (\Exception $e) {
                throw new InjectionException("Failed to create instance of '$className'. " . $e->getMessage());
            }
            $object = $reflectedClass->newInstanceArgs($constructorArgs);
        }

        if ($injectMethodName) {
            $this->injectDependencies($object, $injectMethodName);
        }

        $this->container[$className] = $object;
        return $object;
    }

    /**
     * @param $object
     * @param string $injectMethodName Method which will be invoked with resolved dependencies as its arguments
     * @throws InjectionException
     */
    public function injectDependencies($object, $injectMethodName = self::DEFAULT_INJECT_METHOD_NAME, $defaults = [])
    {
        if (!is_object($object)) {
            return;
        }

        $reflectedObject = new \ReflectionObject($object);
        if (!$reflectedObject->hasMethod($injectMethodName)) {
            return;
        }

        $reflectedMethod = $reflectedObject->getMethod($injectMethodName);
        try {
            $args = $this->prepareArgs($reflectedMethod, $defaults);
        } catch (\Exception $e) {
            $msg = $e->getMessage();
            if ($e->getPrevious()) { // injection failed because PHP code is invalid. See #3869
                $msg .= '; '. $e->getPrevious();
            }
            throw new InjectionException(
                "Failed to inject dependencies in instance of '{$reflectedObject->name}'. $msg"
            );
        }

        if (!$reflectedMethod->isPublic()) {
            $reflectedMethod->setAccessible(true);
        }
        $reflectedMethod->invokeArgs($object, $args);
    }

    /**
     * @param \ReflectionMethod $method
     * @param $defaults
     * @throws InjectionException
     * @return array
     */
    protected function prepareArgs(\ReflectionMethod $method, $defaults = [])
    {
        $args = [];
        $parameters = $method->getParameters();
        foreach ($parameters as $k => $parameter) {
            $dependency = ReflectionHelper::getClassFromParameter($parameter);
            if (is_null($dependency)) {
                if (!$parameter->isOptional()) {
                    if (!isset($defaults[$k])) {
                        throw new InjectionException("Parameter '$parameter->name' must have default value.");
                    }
                    $args[] = $defaults[$k];
                    continue;
                }
                $args[] = $parameter->getDefaultValue();
            } else {
                $arg = $this->instantiate($dependency);
                if (is_null($arg)) {
                    throw new InjectionException("Failed to resolve dependency '$dependency'.");
                }
                $args[] = $arg;
            }
        }
        return $args;
    }
}
<?php
namespace Codeception\Lib;

use Codeception\Actor;
use Codeception\Exception\TestRuntimeException;

class Friend
{
    protected $name;
    protected $actor;
    protected $data = [];
    protected $multiSessionModules = [];

    public function __construct($name, Actor $actor, $modules = [])
    {
        $this->name = $name;
        $this->actor = $actor;

        $this->multiSessionModules = array_filter($modules, function ($m) {
            return $m instanceof Interfaces\MultiSession;
        });

        if (empty($this->multiSessionModules)) {
            throw new TestRuntimeException("No multisession modules used. Can't instantiate friend");
        }
    }

    public function does($closure)
    {
        $currentUserData = [];

        foreach ($this->multiSessionModules as $module) {
            $name = $module->_getName();
            $currentUserData[$name] = $module->_backupSession();
            if (empty($this->data[$name])) {
                $module->_initializeSession();
                $this->data[$name] = $module->_backupSession();
                continue;
            }
            $module->_loadSession($this->data[$name]);
        };

        $this->actor->comment(strtoupper("{$this->name} does ---"));
        $ret = $closure($this->actor);
        $this->actor->comment(strtoupper("--- {$this->name} finished"));

        foreach ($this->multiSessionModules as $module) {
            $name = $module->_getName();
            $this->data[$name] = $module->_backupSession();
            $module->_loadSession($currentUserData[$name]);
        };
        return $ret;
    }

    public function isGoingTo($argumentation)
    {
        $this->actor->amGoingTo($argumentation);
    }

    public function expects($prediction)
    {
        $this->actor->expect($prediction);
    }

    public function expectsTo($prediction)
    {
        $this->actor->expectTo($prediction);
    }

    public function leave()
    {
        foreach ($this->multiSessionModules as $module) {
            if (isset($this->data[$module->_getName()])) {
                $module->_closeSession($this->data[$module->_getName()]);
            }
        }
    }
}
<?php
namespace Codeception\Lib\Generator;

use Codeception\Codecept;
use Codeception\Configuration;
use Codeception\Lib\Di;
use Codeception\Lib\ModuleContainer;
use Codeception\Util\ReflectionHelper;
use Codeception\Util\Template;

class Actions
{

    protected $template = <<<EOF
<?php  //[STAMP] {{hash}}
namespace {{namespace}}_generated;

// This class was automatically generated by build task
// You should not change it manually as it will be overwritten on next build
// @codingStandardsIgnoreFile

trait {{name}}Actions
{
    /**
     * @return \Codeception\Scenario
     */
    abstract protected function getScenario();

    {{methods}}
}

EOF;

    protected $methodTemplate = <<<EOF

    /**
     * [!] Method is generated. Documentation taken from corresponding module.
     *
     {{doc}}
     * @see \{{module}}::{{method}}()
     */
    public function {{action}}({{params}}){{return_type}} {
        {{return}}\$this->getScenario()->runStep(new \Codeception\Step\{{step}}('{{method}}', func_get_args()));
    }
EOF;

    protected $name;
    protected $settings;
    protected $modules = [];
    protected $actions;
    protected $numMethods = 0;

    /**
     * @var array GeneratedStep[]
     */
    protected $generatedSteps = [];

    public function __construct($settings)
    {
        $this->name = $settings['actor'];
        $this->settings = $settings;
        $this->di = new Di();
        $modules = Configuration::modules($this->settings);
        $this->moduleContainer = new ModuleContainer($this->di, $settings);
        foreach ($modules as $moduleName) {
            $this->moduleContainer->create($moduleName);
        }
        $this->modules = $this->moduleContainer->all();
        $this->actions = $this->moduleContainer->getActions();

        $this->generatedSteps = (array) $settings['step_decorators'];
    }


    public function produce()
    {
        $namespace = rtrim($this->settings['namespace'], '\\');

        $methods = [];
        $code = [];
        foreach ($this->actions as $action => $moduleName) {
            if (in_array($action, $methods)) {
                continue;
            }
            $class = new \ReflectionClass($this->modules[$moduleName]);
            $method = $class->getMethod($action);
            $code[] = $this->addMethod($method);
            $methods[] = $action;
            $this->numMethods++;
        }

        return (new Template($this->template))
            ->place('namespace', $namespace ? $namespace . '\\' : '')
            ->place('hash', self::genHash($this->modules, $this->settings))
            ->place('name', $this->name)
            ->place('methods', implode("\n\n ", $code))
            ->produce();
    }

    protected function addMethod(\ReflectionMethod $refMethod)
    {
        $class = $refMethod->getDeclaringClass();
        $params = $this->getParamsString($refMethod);
        $module = $class->getName();

        $body = '';
        $doc = $this->addDoc($class, $refMethod);
        $doc = str_replace('/**', '', $doc);
        $doc = trim(str_replace('*/', '', $doc));
        if (!$doc) {
            $doc = "*";
        }
        $returnType = $this->createReturnTypeHint($refMethod);

        $methodTemplate = (new Template($this->methodTemplate))
            ->place('module', $module)
            ->place('method', $refMethod->name)
            ->place('return_type', $returnType)
            ->place('return', $returnType === ': void' ? '' : 'return ')
            ->place('params', $params);

        if (0 === strpos($refMethod->name, 'see')) {
            $type = 'Assertion';
        } elseif (0 === strpos($refMethod->name, 'am')) {
            $type = 'Condition';
        } else {
            $type = 'Action';
        }

        $body .= $methodTemplate
            ->place('doc', $doc)
            ->place('action', $refMethod->name)
            ->place('step', $type)
            ->produce();

        // add auto generated steps
        foreach (array_unique($this->generatedSteps) as $generator) {
            if (!is_callable([$generator, 'getTemplate'])) {
                throw new \Exception("Wrong configuration for generated steps. $generator doesn't implement \Codeception\Step\GeneratedStep interface");
            }
            $template = call_user_func([$generator, 'getTemplate'], clone $methodTemplate);
            if ($template) {
                $body .= $template->produce();
            }
        }

        return $body;
    }

    /**
     * @param \ReflectionMethod $refMethod
     * @return array
     */
    protected function getParamsString(\ReflectionMethod $refMethod)
    {
        $params = [];
        foreach ($refMethod->getParameters() as $param) {
            $type = '';
            if (PHP_VERSION_ID >= 70000) {
                $reflectionType = $param->getType();
                if ($reflectionType !== null) {
                    $type = $this->stringifyType($reflectionType) . ' ';
                }
            }
            if ($param->isOptional()) {
                $params[] = $type . '$' . $param->name . ' = ' . ReflectionHelper::getDefaultValue($param);
            } else {
                $params[] = $type . '$' . $param->name;
            }
        }
        return implode(', ', $params);
    }

    /**
     * @param \ReflectionClass $class
     * @param \ReflectionMethod $refMethod
     * @return string
     */
    protected function addDoc(\ReflectionClass $class, \ReflectionMethod $refMethod)
    {
        $doc = $refMethod->getDocComment();

        if (!$doc) {
            $interfaces = $class->getInterfaces();
            foreach ($interfaces as $interface) {
                $i = new \ReflectionClass($interface->name);
                if ($i->hasMethod($refMethod->name)) {
                    $doc = $i->getMethod($refMethod->name)->getDocComment();
                    break;
                }
            }
        }

        if (!$doc and $class->getParentClass()) {
            $parent = new \ReflectionClass($class->getParentClass()->name);
            if ($parent->hasMethod($refMethod->name)) {
                $doc = $parent->getMethod($refMethod->name)->getDocComment();
                return $doc;
            }
            return $doc;
        }
        return $doc;
    }

    public static function genHash($modules, $settings)
    {
        $actions = [];
        foreach ($modules as $moduleName => $module) {
            $actions[$moduleName] = get_class_methods(get_class($module));
        }

        return md5(Codecept::VERSION . serialize($actions) . serialize($settings['modules']) . implode(',', (array) $settings['step_decorators']));
    }

    public function getNumMethods()
    {
        return $this->numMethods;
    }

    private function createReturnTypeHint(\ReflectionMethod $refMethod)
    {
        if (PHP_VERSION_ID < 70000) {
            return '';
        }

        $returnType = $refMethod->getReturnType();

        if ($returnType === null) {
            return '';
        }

        return ': ' . $this->stringifyType($returnType);
    }

    /**
     * @param \ReflectionType $type
     * @return string
     */
    private function stringifyType(\ReflectionType $type)
    {
        if ($type instanceof \ReflectionUnionType) {
            $types = $type->getTypes();
            return implode('|', $types);
        }

        if (PHP_VERSION_ID < 70100) {
            $returnTypeString = (string)$type;
        } else {
            $returnTypeString = $type->getName();
        }
        return sprintf(
            '%s%s%s',
            (PHP_VERSION_ID >= 70100 && $type->allowsNull()) ? '?' : '',
            $type->isBuiltin() ? '' : '\\',
            $returnTypeString
        );
    }
}
<?php
namespace Codeception\Lib\Generator;

use Codeception\Util\Template;

class Feature
{
    protected $template = <<<EOF
Feature: {{name}}
  In order to ...
  As a ...
  I need to ...

  Scenario: try {{name}}

EOF;

    protected $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function produce()
    {
        return (new Template($this->template))
            ->place('name', $this->name)
            ->produce();
    }
}
<?php
namespace Codeception\Lib\Generator;

use Codeception\Configuration;
use Codeception\Lib\Di;
use Codeception\Lib\ModuleContainer;
use Codeception\Util\ReflectionHelper;
use Codeception\Util\Template;

class Actor
{
    protected $template = <<<EOF
<?php
{{hasNamespace}}

/**
 * Inherited Methods
{{inheritedMethods}}
 *
 * @SuppressWarnings(PHPMD)
*/
class {{actor}} extends \Codeception\Actor
{
    use _generated\{{actor}}Actions;

    /**
     * Define custom actions here
     */
}

EOF;

    protected $inheritedMethodTemplate = ' * @method {{return}} {{method}}({{params}})';

    protected $settings;
    protected $modules;
    protected $actions;

    public function __construct($settings)
    {
        $this->settings = $settings;
        $this->di = new Di();
        $this->moduleContainer = new ModuleContainer($this->di, $settings);

        $modules = Configuration::modules($this->settings);
        foreach ($modules as $moduleName) {
            $this->moduleContainer->create($moduleName);
        }

        $this->modules = $this->moduleContainer->all();
        $this->actions = $this->moduleContainer->getActions();
    }

    public function produce()
    {
        $namespace = rtrim($this->settings['namespace'], '\\');

        if (!isset($this->settings['actor']) && isset($this->settings['class_name'])) {
            $this->settings['actor'] = $this->settings['class_name'];
        }

        return (new Template($this->template))
            ->place('hasNamespace', $namespace ? "namespace $namespace;" : '')
            ->place('actor', $this->settings['actor'])
            ->place('inheritedMethods', $this->prependAbstractActorDocBlocks())
            ->produce();
    }

    protected function prependAbstractActorDocBlocks()
    {
        $inherited = [];

        $class = new \ReflectionClass('\Codeception\\Actor');
        $methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC);

        foreach ($methods as $method) {
            if ($method->name == '__call') {
                continue;
            } // skipping magic
            if ($method->name == '__construct') {
                continue;
            } // skipping magic
            $returnType = 'void';
            if ($method->name == 'haveFriend') {
                $returnType = '\Codeception\Lib\Friend';
            }
            $params = $this->getParamsString($method);
            $inherited[] = (new Template($this->inheritedMethodTemplate))
                ->place('method', $method->name)
                ->place('params', $params)
                ->place('return', $returnType)
                ->produce();
        }

        return implode("\n", $inherited);
    }

    /**
     * @param \ReflectionMethod $refMethod
     * @return array
     */
    protected function getParamsString(\ReflectionMethod $refMethod)
    {
        $params = [];
        foreach ($refMethod->getParameters() as $param) {
            if ($param->isOptional()) {
                $params[] = '$' . $param->name . ' = ' . ReflectionHelper::getDefaultValue($param);
            } else {
                $params[] = '$' . $param->name;
            };
        }
        return implode(', ', $params);
    }

    public function getActorName()
    {
        return $this->settings['actor'];
    }

    public function getModules()
    {
        return array_keys($this->modules);
    }
}
<?php
namespace Codeception\Lib\Generator;

use Codeception\Exception\ConfigurationException;
use Codeception\Util\Shared\Namespaces;
use Codeception\Util\Template;

class StepObject
{
    use Namespaces;
    use Shared\Classname;

    protected $template = <<<EOF
<?php
namespace {{namespace}};

class {{name}} extends {{actorClass}}
{
{{actions}}
}
EOF;

    protected $actionTemplate = <<<EOF

    public function {{action}}()
    {
        \$I = \$this;
    }

EOF;

    protected $settings;
    protected $name;
    protected $actions = '';

    public function __construct($settings, $name)
    {
        $this->settings = $settings;
        $this->name = $this->getShortClassName($name);
        $this->namespace = $this->getNamespaceString($this->settings['namespace'] . '\\Step\\' . $name);
    }

    public function produce()
    {
        $actor = $this->settings['actor'];
        if (!$actor) {
            throw new ConfigurationException("Steps can't be created for suite without an actor");
        }
        $ns = $this->getNamespaceString($this->settings['namespace'] . '\\' . $actor . '\\' . $this->name);
        $ns = ltrim($ns, '\\');

        $extended = '\\' . ltrim('\\' . $this->settings['namespace'] . '\\' . $actor, '\\');

        return (new Template($this->template))
            ->place('namespace', $this->namespace)
            ->place('name', $this->name)
            ->place('actorClass', $extended)
            ->place('actions', $this->actions)
            ->produce();
    }

    public function createAction($action)
    {
        $this->actions .= (new Template($this->actionTemplate))
            ->place('action', $action)
            ->produce();
    }
}
<?php
namespace Codeception\Lib\Generator;

use Behat\Gherkin\Node\StepNode;
use Codeception\Test\Loader\Gherkin;
use Codeception\Util\Template;
use Symfony\Component\Finder\Finder;

class GherkinSnippets
{
    protected $template = <<<EOF
    /**
     * @{{type}} {{text}}
     */
     public function {{methodName}}({{params}})
     {
         throw new \PHPUnit\Framework\IncompleteTestError("Step `{{text}}` is not defined");
     }

EOF;

    protected $snippets = [];
    protected $processed = [];
    protected $features = [];

    public function __construct($settings, $test = null)
    {
        $loader = new Gherkin($settings);
        $pattern = $loader->getPattern();
        $path = $settings['path'];
        if (!empty($test)) {
            $path = $settings['path'].'/'.$test;
            if (preg_match($pattern, $test)) {
                $path = dirname($path);
                $pattern = basename($test);
            }
        }

        $finder = Finder::create()
            ->files()
            ->sortByName()
            ->in($path)
            ->followLinks()
            ->name($pattern);

        foreach ($finder as $file) {
            $pathname = str_replace("//", "/", $file->getPathname());
            $loader->loadTests($pathname);
        }
        $availableSteps = $loader->getSteps();
        $allSteps = [];
        foreach ($availableSteps as $stepGroup) {
            $allSteps = array_merge($allSteps, $stepGroup);
        }
        foreach ($loader->getTests() as $test) {
            /** @var $test \Codeception\Test\Gherkin  **/
            $steps = $test->getScenarioNode()->getSteps();
            if ($test->getFeatureNode()->hasBackground()) {
                $steps = array_merge($steps, $test->getFeatureNode()->getBackground()->getSteps());
            }
            foreach ($steps as $step) {
                $matched = false;
                $text = $step->getText();
                if (self::stepHasPyStringArgument($step)) {
                    // pretend it is inline argument
                    $text .= ' ""';
                }
                foreach (array_keys($allSteps) as $pattern) {
                    if (preg_match($pattern, $text)) {
                        $matched = true;
                        break;
                    }
                }
                if (!$matched) {
                    $this->addSnippet($step);
                    $file = str_ireplace($settings['path'], '', $test->getFeatureNode()->getFile());
                    if (!in_array($file, $this->features)) {
                        $this->features[] = $file;
                    }
                }
            }
        }
    }

    public function addSnippet(StepNode $step)
    {
        $args = [];
        $pattern = $step->getText();

        // match numbers (not in quotes)
        if (preg_match_all('~([\d\.])(?=([^"]*"[^"]*")*[^"]*$)~', $pattern, $matches)) {
            foreach ($matches[1] as $num => $param) {
                $num++;
                $args[] = '$num' . $num;
                $pattern = str_replace($param, ":num$num", $pattern);
            }
        }

        // match quoted string
        if (preg_match_all('~"(.*?)"~', $pattern, $matches)) {
            foreach ($matches[1] as $num => $param) {
                $num++;
                $args[] = '$arg' . $num;
                $pattern = str_replace('"'.$param.'"', ":arg$num", $pattern);
            }
        }
        // Has multiline argument at the end of step?
        if (self::stepHasPyStringArgument($step)) {
            $num = count($args) + 1;
            $pattern .= " :arg$num";
            $args[] = '$arg' . $num;
        }
        if (in_array($pattern, $this->processed)) {
            return;
        }

        $methodName = preg_replace('~(\s+?|\'|\"|\W)~', '', ucwords(preg_replace('~"(.*?)"|\d+~', '', $step->getText())));
        if (empty($methodName)) {
            $methodName = 'step_' . substr(sha1($pattern), 0, 9);
        }

        $this->snippets[] = (new Template($this->template))
            ->place('type', $step->getKeywordType())
            ->place('text', $pattern)
            ->place('methodName', lcfirst($methodName))
            ->place('params', implode(', ', $args))
            ->produce();

        $this->processed[] = $pattern;
    }

    public function getSnippets()
    {
        return $this->snippets;
    }

    public function getFeatures()
    {
        return $this->features;
    }

    public static function stepHasPyStringArgument(StepNode $step)
    {
        if ($step->hasArguments()) {
            $stepArgs = $step->getArguments();
            if ($stepArgs[count($stepArgs) - 1]->getNodeType() == "PyString") {
                return true;
            }
        }
        return false;
    }
}
<?php
namespace Codeception\Lib\Generator\Shared;

trait Classname
{
    protected function removeSuffix($classname, $suffix)
    {
        $classname = preg_replace('~\.php$~', '', $classname);
        return preg_replace("~$suffix$~", '', $classname);
    }
}
<?php
namespace Codeception\Lib\Generator;

use Codeception\Util\Shared\Namespaces;
use Codeception\Util\Template;

class PageObject
{
    use Namespaces;
    use Shared\Classname;

    protected $template = <<<EOF
<?php
namespace {{namespace}};

class {{class}}
{
    // include url of current page
    public static \$URL = '';

    /**
     * Declare UI map for this page here. CSS or XPath allowed.
     * public static \$usernameField = '#username';
     * public static \$formSubmitButton = "#mainForm input[type=submit]";
     */

    /**
     * Basic route example for your current URL
     * You can append any additional parameter to URL
     * and use it in tests like: Page\\Edit::route('/123-post');
     */
    public static function route(\$param)
    {
        return static::\$URL.\$param;
    }

{{actions}}
}

EOF;

    protected $actionsTemplate = <<<EOF
    /**
     * @var \\{{actorClass}};
     */
    protected \${{actor}};

    public function __construct(\\{{actorClass}} \$I)
    {
        \$this->{{actor}} = \$I;
    }

EOF;

    protected $actions = '';
    protected $settings;
    protected $name;
    protected $namespace;

    public function __construct($settings, $name)
    {
        $this->settings = $settings;
        $this->name = $this->getShortClassName($name);
        $this->namespace = $this->getNamespaceString($this->settings['namespace'] . '\\Page\\' . $name);
    }

    public function produce()
    {
        return (new Template($this->template))
            ->place('namespace', $this->namespace)
            ->place('actions', $this->produceActions())
            ->place('class', $this->name)
            ->produce();
    }

    protected function produceActions()
    {
        if (!isset($this->settings['actor'])) {
            return ''; // global pageobject
        }

        $actor = lcfirst($this->settings['actor']);
        $actorClass = $this->settings['actor'];
        if (!empty($this->settings['namespace'])) {
            $actorClass = rtrim($this->settings['namespace'], '\\') . '\\' . $actorClass;
        }

        return (new Template($this->actionsTemplate))
            ->place('actorClass', $actorClass)
            ->place('actor', $actor)
            ->place('pageObject', $this->name)
            ->produce();
    }
}
<?php
namespace Codeception\Lib\Generator;

use Codeception\Util\Shared\Namespaces;
use Codeception\Util\Template;

class Helper
{
    use Namespaces;

    protected $template = <<<EOF
<?php
{{namespace}}
// here you can define custom actions
// all public methods declared in helper class will be available in \$I

class {{name}} extends \\Codeception\\Module
{

}

EOF;

    protected $namespace;
    protected $name;

    public function __construct($name, $namespace = '')
    {
        $this->namespace = $namespace;
        $this->name = $name;
    }

    public function produce()
    {
        return (new Template($this->template))
            ->place('namespace', $this->getNamespaceHeader($this->namespace . '\\Helper\\' . $this->name))
            ->place('name', $this->getShortClassName($this->name))
            ->produce();
    }

    public function getHelperName()
    {
        return rtrim('\\' . $this->namespace, '\\') . '\\Helper\\' . $this->name;
    }
}
<?php
namespace Codeception\Lib\Generator;

use Codeception\Exception\ConfigurationException;
use Codeception\Util\Template;

class Cept
{

    protected $template = <<<EOF
<?php {{use}}
\$I = new {{actor}}(\$scenario);
\$I->wantTo('perform actions and see result');

EOF;

    protected $settings;

    public function __construct($settings)
    {
        $this->settings = $settings;
    }

    public function produce()
    {
        $actor = $this->settings['actor'];
        if (!$actor) {
            throw new ConfigurationException("Cept can't be created for suite without an actor. Add `actor: SomeTester` to suite config");
        }
        $use = '';
        if (! empty($this->settings['namespace'])) {
            $namespace = rtrim($this->settings['namespace'], '\\');
            $use = "use {$namespace}\\$actor;";
        }

        return (new Template($this->template))
            ->place('actor', $actor)
            ->place('use', $use)
            ->produce();
    }
}
<?php
namespace Codeception\Lib\Generator;

use Codeception\Configuration;
use Codeception\Util\Shared\Namespaces;
use Codeception\Util\Template;

class Test
{
    use Namespaces;
    use Shared\Classname;

    protected $template = <<<EOF
<?php
{{namespace}}
class {{name}}Test extends \Codeception\Test\Unit
{
{{tester}}
    protected function _before()
    {
    }

    protected function _after()
    {
    }

    // tests
    public function testSomeFeature()
    {

    }
}
EOF;

    protected $testerTemplate = <<<EOF
    /**
     * @var \{{actorClass}}
     */
    protected \${{actor}};
    
EOF;


    protected $settings;
    protected $name;

    public function __construct($settings, $name)
    {
        $this->settings = $settings;
        $this->name = $this->removeSuffix($name, 'Test');
    }

    public function produce()
    {
        $actor = $this->settings['actor'];
        if ($this->settings['namespace']) {
            $actor = $this->settings['namespace'] . '\\' . $actor;
        }

        $ns = $this->getNamespaceHeader($this->settings['namespace'] . '\\' . $this->name);

        $tester = '';
        if ($this->settings['actor']) {
            $tester = (new Template($this->testerTemplate))
            ->place('actorClass', $actor)
            ->place('actor', lcfirst(Configuration::config()['actor_suffix']))
            ->produce();
        }

        return (new Template($this->template))
            ->place('namespace', $ns)
            ->place('name', $this->getShortClassName($this->name))
            ->place('tester', $tester)
            ->produce();
    }
}
<?php
namespace Codeception\Lib\Generator;

use Codeception\Exception\ConfigurationException;
use Codeception\Util\Shared\Namespaces;
use Codeception\Util\Template;

class Cest
{
    use Shared\Classname;
    use Namespaces;

    protected $template = <<<EOF
<?php
{{namespace}}
class {{name}}Cest
{
    public function _before({{actor}} \$I)
    {
    }

    // tests
    public function tryToTest({{actor}} \$I)
    {
    }
}

EOF;

    protected $settings;
    protected $name;

    public function __construct($className, $settings)
    {
        $this->name = $this->removeSuffix($className, 'Cest');
        $this->settings = $settings;
    }

    public function produce()
    {
        $actor = $this->settings['actor'];
        if (!$actor) {
            throw new ConfigurationException("Cept can't be created for suite without an actor. Add `actor: SomeTester` to suite config");
        }

        if (array_key_exists('suite_namespace', $this->settings)) {
            $namespace = rtrim($this->settings['suite_namespace'], '\\');
        } else {
            $namespace = rtrim($this->settings['namespace'], '\\');
        }

        $ns = $this->getNamespaceHeader($namespace.'\\'.$this->name);

        if ($namespace) {
            $ns .= "use ".$this->settings['namespace'].'\\'.$actor.";";
        }

        return (new Template($this->template))
            ->place('name', $this->getShortClassName($this->name))
            ->place('namespace', $ns)
            ->place('actor', $actor)
            ->produce();
    }
}
<?php
namespace Codeception\Lib\Generator;

use Codeception\Util\Shared\Namespaces;
use Codeception\Util\Template;

class Group
{
    use Namespaces;
    use Shared\Classname;

    protected $template = <<<EOF
<?php
namespace {{namespace}};

use \Codeception\Event\TestEvent;
/**
 * Group class is Codeception Extension which is allowed to handle to all internal events.
 * This class itself can be used to listen events for test execution of one particular group.
 * It may be especially useful to create fixtures data, prepare server, etc.
 *
 * INSTALLATION:
 *
 * To use this group extension, include it to "extensions" option of global Codeception config.
 */

class {{class}} extends \Codeception\Platform\Group
{
    public static \$group = '{{groupName}}';

    public function _before(TestEvent \$e)
    {
    }

    public function _after(TestEvent \$e)
    {
    }
}

EOF;

    protected $name;
    protected $namespace;
    protected $settings;

    public function __construct($settings, $name)
    {
        $this->settings = $settings;
        $this->name = $name;
        $this->namespace = $this->getNamespaceString($this->settings['namespace'] . '\\Group\\' . $name);
    }

    public function produce()
    {
        $ns = $this->getNamespaceString($this->settings['namespace'] . '\\' . $this->name);
        return (new Template($this->template))
            ->place('class', ucfirst($this->name))
            ->place('name', $this->name)
            ->place('namespace', $this->namespace)
            ->place('groupName', strtolower($this->name))
            ->produce();
    }
}
<?php
namespace Codeception\Lib\Generator;

use Codeception\Util\Shared\Namespaces;
use Codeception\Util\Template;

class Snapshot
{
    use Namespaces;

    protected $template = <<<EOF
<?php
namespace {{namespace}};

class {{name}} extends \\Codeception\\Snapshot
{

{{actions}}

    protected function fetchData()
    {
        // TODO: return a value which will be used for snapshot 
    }
}
EOF;

    protected $actionsTemplate = <<<EOF
    /**
     * @var \\{{actorClass}};
     */
    protected \${{actor}};

    public function __construct(\\{{actorClass}} \$I)
    {
        \$this->{{actor}} = \$I;
    }
EOF;

    protected $namespace;
    protected $name;
    protected $settings;

    public function __construct($settings, $name)
    {
        $this->settings = $settings;
        $this->name = $this->getShortClassName($name);
        $this->namespace = $this->getNamespaceString($this->settings['namespace'] . '\\Snapshot\\' . $name);
    }

    public function produce()
    {
        return (new Template($this->template))
            ->place('namespace', $this->namespace)
            ->place('actions', $this->produceActions())
            ->place('name', $this->name)
            ->produce();
    }

    protected function produceActions()
    {
        if (!isset($this->settings['actor'])) {
            return ''; // no actor in suite
        }

        $actor = lcfirst($this->settings['actor']);
        $actorClass = $this->settings['actor'];
        if (!empty($this->settings['namespace'])) {
            $actorClass = rtrim($this->settings['namespace'], '\\') . '\\' . $actorClass;
        }

        return (new Template($this->actionsTemplate))
            ->place('actorClass', $actorClass)
            ->place('actor', $actor)
            ->produce();
    }
}
<?php
namespace Codeception\Lib\Actor\Shared;

trait Comment
{
    /**
     * @return \Codeception\Scenario
     */
    abstract protected function getScenario();

    public function expectTo($prediction)
    {
        return $this->comment('I expect to ' . $prediction);
    }

    public function expect($prediction)
    {
        return $this->comment('I expect ' . $prediction);
    }

    public function amGoingTo($argumentation)
    {
        return $this->comment('I am going to ' . $argumentation);
    }

    public function am($role)
    {
        $role = trim($role);

        if (stripos('aeiou', $role[0]) !== false) {
            return $this->comment('As an ' . $role);
        }

        return $this->comment('As a ' . $role);
    }

    public function lookForwardTo($achieveValue)
    {
        return $this->comment('So that I ' . $achieveValue);
    }

    public function comment($description)
    {
        $this->getScenario()->comment($description);
        return $this;
    }
}
<?php

namespace Codeception\Lib\Actor\Shared;

trait Retry
{
    protected $retryNum = 1;
    protected $retryInterval = 100;

    /**
     * Configure number of retries and initial interval.
     * Interval will be doubled on each unsuccessful execution.
     *
     * Use with \$I->retryXXX() methods;
     *
     * @param $num
     * @param int $interval
     */
    public function retry($num, $interval = 200)
    {
        $this->retryNum = $num;
        $this->retryInterval = $interval;
    }
}
<?php
namespace Codeception\Lib\Actor\Shared;

use Codeception\Lib\Friend as LibFriend;
use Codeception\Scenario;

trait Friend
{
    protected $friends = [];

    /**
     * @return Scenario
     */
    abstract protected function getScenario();

    /**
     * @param $name
     * @param $actorClass
     * @return \Codeception\Lib\Friend
     */
    public function haveFriend($name, $actorClass = null)
    {
        if (!isset($this->friends[$name])) {
            $actor = $actorClass === null ? $this : new $actorClass($this->getScenario());
            $this->friends[$name] = new LibFriend($name, $actor, $this->getScenario()->current('modules'));
        }
        return $this->friends[$name];
    }
}
<?php
namespace Codeception\Lib\Actor\Shared;

use Codeception\Lib\Console\ReplHistory;
use Symfony\Component\Console\Output\ConsoleOutput;

trait Pause
{
    public function pause()
    {
        if (!\Codeception\Util\Debug::isEnabled()) {
            return;
        }

        if (!class_exists('Hoa\Console\Readline\Readline')) {
            throw new \Exception('Hoa Console is not installed. Please add `hoa/console` to composer.json');
        }

        $autoStash = false;

        $I = $this;
        $output = new ConsoleOutput();
        $readline = new \Hoa\Console\Readline\Readline();

        $readline->setAutocompleter(
            new \Hoa\Console\Readline\Autocompleter\Word(get_class_methods($this))
        );

        $stashFn = function (\Hoa\Console\Readline\Readline $self, $isManual = true) {
            $lastCommand = $self->previousHistory();

            \Hoa\Console\Cursor::clear('↔');

            if (strlen($lastCommand) > 0) {
                ReplHistory::getInstance()->add("\$I->{$lastCommand};");
                codecept_debug("Command stashed: \$I->{$lastCommand};");
            } else {
                codecept_debug("Nothing to stash.");
            }

            if ($isManual) {
                \Hoa\Console\Console::getOutput()->writeAll($self->getPrefix() . $self->getLine());
            }

            $self->nextHistory();

            return \Hoa\Console\Readline\Readline::STATE_CONTINUE;
        };

        $clearStashFn = function (\Hoa\Console\Readline\Readline $self) {
            ReplHistory::getInstance()->clear();

            \Hoa\Console\Cursor::clear('↔');

            codecept_debug("Stash cleared.");

            \Hoa\Console\Console::getOutput()->writeAll($self->getPrefix() . $self->getLine());

            return \Hoa\Console\Readline\Readline::STATE_CONTINUE;
        };

        $viewStashedFn = function (\Hoa\Console\Readline\Readline $self) use ($output) {
            \Hoa\Console\Cursor::clear('↔');
            $stashedCommands = ReplHistory::getInstance()->getAll();

            if (!empty($stashedCommands)) {
                $output->writeln("\n<comment>Stashed commands:</comment>");
                codecept_debug(implode("\n", $stashedCommands) . "\n");
            } else {
                codecept_debug("No commands stashed.");
            }

            \Hoa\Console\Console::getOutput()->writeAll($self->getPrefix() . $self->getLine());

            return \Hoa\Console\Readline\Readline::STATE_CONTINUE;
        };

        $toggleAutoStashFn = function (\Hoa\Console\Readline\Readline $self) use (&$autoStash) {
            \Hoa\Console\Cursor::clear('↔');

            $autoStash = !$autoStash;

            codecept_debug("Autostash " . ($autoStash ? 'enabled' : 'disabled') . '.');

            \Hoa\Console\Console::getOutput()->writeAll($self->getPrefix() . $self->getLine());

            return \Hoa\Console\Readline\Readline::STATE_CONTINUE;
        };

        $tput = \Hoa\Console\Console::getTput();
        $readline->addMapping($tput->get('key_f5'), $stashFn);
        $readline->addMapping($tput->get('key_f6'), $toggleAutoStashFn);
        $readline->addMapping($tput->get('key_f8'), $viewStashedFn);
        $readline->addMapping($tput->get('key_f10'), $clearStashFn);

        $output->writeln("  <comment>Execution PAUSED, starting interactive shell...</comment>");
        $output->writeln("  Type in commands to try them:");
        $output->writeln("  - <info>ENTER</info> to continue");
        $output->writeln("  - <info>TAB</info> to auto-complete");
        $output->writeln("  - <info>F5</info> to stash a command");
        $output->writeln("  - <info>F6</info> to toggle auto-stashing of successful commands");
        $output->writeln("  - <info>F8</info> to view stashed commands");
        $output->writeln("  - <info>F10</info> to clear stashed commands");

        $result = '';

        do {
            $command = $readline->readLine('$I->'); // “> ” is the prefix of the line.

            if ($command == 'exit' || $command == '') {
                ReplHistory::getInstance()->save();
                return;
            }
            try {
                $value = eval("return \$I->$command;");
                if ($value) {
                    $result = $value;
                    if (!is_object($result)) {
                        codecept_debug($result);
                    }
                    codecept_debug('>> Result saved to $result variable, you can use it in next commands');
                }

                if ($autoStash) {
                    call_user_func($stashFn, $readline, false);
                }
            } catch (\PHPUnit\Framework\AssertionFailedError $fail) {
                $output->writeln("<error>fail</error> " . $fail->getMessage());
            } catch (\Exception $e) {
                $output->writeln("<error>error</error> " . $e->getMessage());
            } catch (\Throwable $e) {
                $output->writeln("<error>syntax error</error> " . $e->getMessage());
            }
        } while (true);
    }
}
<?php
namespace Codeception\Lib\Console;

use Symfony\Component\Console\Formatter\OutputFormatter;

class Colorizer
{
    /**
     * @param string $string
     * @return string
     */
    public function colorize($string = '')
    {
        $fp = fopen('php://memory', 'r+');
        fwrite($fp, $string);
        rewind($fp);

        $colorizedMessage = '';
        while ($line = fgets($fp)) {
            $char = $line[0];
            $line = OutputFormatter::escape(trim($line));

            switch ($char) {
                case '+':
                    $line = "<info>$line</info>";
                    break;
                case '-':
                    $line = "<comment>$line</comment>";
                    break;
            }

            $colorizedMessage .= $line . "\n";
        }

        return trim($colorizedMessage);
    }
}
<?php
namespace Codeception\Lib\Console;

use SebastianBergmann\Comparator\ComparisonFailure;
use SebastianBergmann\Diff\Differ;

/**
 * DiffFactory
 **/
class DiffFactory
{
    /**
     * @param ComparisonFailure $failure
     * @return string|null
     */
    public function createDiff(ComparisonFailure $failure)
    {
        $diff = $this->getDiff($failure->getExpectedAsString(), $failure->getActualAsString());
        if (!$diff) {
            return null;
        }

        return $diff;
    }

    /**
     * @param string $expected
     * @param string $actual
     * @return string
     */
    private function getDiff($expected = '', $actual = '')
    {
        if (!$actual && !$expected) {
            return '';
        }

        $differ = new Differ('');

        return $differ->diff($expected, $actual);
    }
}
<?php
namespace Codeception\Lib\Console;

use SebastianBergmann\Comparator\ComparisonFailure;

/**
 * MessageFactory
 **/
class MessageFactory
{
    /**
     * @var DiffFactory
     */
    protected $diffFactory;
    /**
     * @var Output
     */
    private $output;

    /**
     * @var Colorizer
     */
    protected $colorizer;

    /**
     * MessageFactory constructor.
     * @param Output $output
     */
    public function __construct(Output $output)
    {
        $this->output = $output;
        $this->diffFactory = new DiffFactory();
        $this->colorizer = new Colorizer();
    }

    /**
     * @param string $text
     * @return Message
     */
    public function message($text = '')
    {
        return new Message($text, $this->output);
    }

    /**
     * @param ComparisonFailure $failure
     * @return string
     */
    public function prepareComparisonFailureMessage(ComparisonFailure $failure)
    {
        $diff = $this->diffFactory->createDiff($failure);
        if (!$diff) {
            return '';
        }
        $diff = $this->colorizer->colorize($diff);

        return "\n<comment>- Expected</comment> | <info>+ Actual</info>\n$diff";
    }
}
<?php

namespace Codeception\Lib\Console;

class ReplHistory
{
    protected $outputFile;

    protected $stashedCommands = [];

    /**
     * @var ReplHistory
     */
    protected static $instance;

    private function __construct()
    {
        $this->outputFile = codecept_output_dir('stashed-commands');

        if (file_exists($this->outputFile)) {
            unlink($this->outputFile);
        }
    }

    /**
     * @return ReplHistory
     */
    public static function getInstance()
    {
        if (static::$instance == null) {
            static::$instance = new static();
        }

        return static::$instance;
    }

    public function add($command)
    {
        $this->stashedCommands[] = $command;
    }

    public function getAll()
    {
        return $this->stashedCommands;
    }

    public function clear()
    {
        $this->stashedCommands = [];
    }

    public function save()
    {
        if (empty($this->stashedCommands)) {
            return;
        }

        file_put_contents($this->outputFile, implode("\n", $this->stashedCommands) . "\n", FILE_APPEND);

        codecept_debug("Stashed commands have been saved to {$this->outputFile}");

        $this->clear();
    }
}
<?php
namespace Codeception\Lib\Console;

use Symfony\Component\Console\Output\OutputInterface;

class Message
{
    protected $output;
    protected $message;

    public function __construct($message, Output $output = null)
    {
        $this->message = $message;
        $this->output = $output;
    }

    public function with($param)
    {
        $args = array_merge([$this->message], func_get_args());
        $this->message = call_user_func_array('sprintf', $args);
        return $this;
    }

    public function style($name)
    {
        $this->message = sprintf('<%s>%s</%s>', $name, $this->message, $name);
        return $this;
    }

    public function width($length, $char = ' ')
    {
        $message_length = $this->getLength();

        if ($message_length < $length) {
            $this->message .= str_repeat($char, $length - $message_length);
        }
        return $this;
    }

    public function cut($length)
    {
        $this->message = mb_substr($this->message, 0, $length, 'utf-8');
        return $this;
    }

    public function write($verbose = OutputInterface::VERBOSITY_NORMAL)
    {
        if ($verbose > $this->output->getVerbosity()) {
            return;
        }
        $this->output->write($this->message);
    }

    public function writeln($verbose = OutputInterface::VERBOSITY_NORMAL)
    {
        if ($verbose > $this->output->getVerbosity()) {
            return;
        }
        $this->output->writeln($this->message);
    }

    public function prepend($string)
    {
        if ($string instanceof Message) {
            $string = $string->getMessage();
        }
        $this->message = $string . $this->message;
        return $this;
    }

    public function append($string)
    {
        if ($string instanceof Message) {
            $string = $string->getMessage();
        }
        $this->message .= $string;

        return $this;
    }

    public function apply($func)
    {
        $this->message = call_user_func($func, $this->message);
        return $this;
    }

    public function center($char)
    {
        $this->message = $char . $this->message . $char;
        return $this;
    }

    /**
     * @return mixed
     */
    public function getMessage()
    {
        return $this->message;
    }

    public function block($style)
    {
        $this->message = $this->output->formatHelper->formatBlock($this->message, $style, true);

        return $this;
    }

    public function getLength($includeTags = false)
    {
        return mb_strwidth($includeTags ? $this->message : strip_tags($this->message), 'utf-8');
    }

    public static function ucfirst($text)
    {
        return mb_strtoupper(mb_substr($text, 0, 1, 'utf-8'), 'utf-8') . mb_substr($text, 1, null, 'utf-8');
    }

    public function __toString()
    {
        return $this->message;
    }
}
<?php
namespace Codeception\Lib\Console;

use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Helper\FormatterHelper;
use Symfony\Component\Console\Output\ConsoleOutput;

class Output extends ConsoleOutput
{
    protected $config = [
        'colors'      => true,
        'verbosity'   => self::VERBOSITY_NORMAL,
        'interactive' => true
    ];

    /**
     * @var \Symfony\Component\Console\Helper\FormatterHelper
     */
    public $formatHelper;

    public $waitForDebugOutput = true;

    protected $isInteractive = false;

    public function __construct($config)
    {
        $this->config = array_merge($this->config, $config);

        // enable interactive output mode for CLI
        $this->isInteractive = $this->config['interactive']
            && isset($_SERVER['TERM'])
            && php_sapi_name() == 'cli'
            && $_SERVER['TERM'] != 'linux';

        $formatter = new OutputFormatter($this->config['colors']);
        $formatter->setStyle('default', new OutputFormatterStyle());
        $formatter->setStyle('bold', new OutputFormatterStyle(null, null, ['bold']));
        $formatter->setStyle('focus', new OutputFormatterStyle('magenta', null, ['bold']));
        $formatter->setStyle('ok', new OutputFormatterStyle('green', null, ['bold']));
        $formatter->setStyle('error', new OutputFormatterStyle('white', 'red', ['bold']));
        $formatter->setStyle('fail', new OutputFormatterStyle('red', null, ['bold']));
        $formatter->setStyle('pending', new OutputFormatterStyle('yellow', null, ['bold']));
        $formatter->setStyle('debug', new OutputFormatterStyle('cyan'));
        $formatter->setStyle('comment', new OutputFormatterStyle('yellow'));
        $formatter->setStyle('info', new OutputFormatterStyle('green'));

        $this->formatHelper = new FormatterHelper();


        parent::__construct($this->config['verbosity'], $this->config['colors'], $formatter);
    }

    public function isInteractive()
    {
        return $this->isInteractive;
    }

    protected function clean($message)
    {
        // clear json serialization
        $message = str_replace('\/', '/', $message);
        return $message;
    }

    public function debug($message)
    {
        $message = print_r($message, true);
        $message = str_replace("\n", "\n  ", $message);
        $message = $this->clean($message);
        $message = OutputFormatter::escape($message);

        if ($this->waitForDebugOutput) {
            $this->writeln('');
            $this->waitForDebugOutput = false;
        }
        $this->writeln("<debug>  $message</debug>");
    }

    public function message($message)
    {
        $message = call_user_func_array('sprintf', func_get_args());
        return new Message($message, $this);
    }

    public function exception(\Exception $e)
    {
        $class = get_class($e);

        $this->writeln("");
        $this->writeln("(![ $class ]!)");
        $this->writeln($e->getMessage());
        $this->writeln("");
    }

    public function notification($message)
    {
        $this->writeln("<comment>$message</comment>");
    }
}
<?php
namespace Codeception\Lib;

use Codeception\Exception\ConfigurationException;
use Symfony\Component\Yaml\Yaml;

class ParamsLoader
{
    protected $paramStorage;
    protected $paramsFile;

    public function load($paramStorage)
    {
        $this->paramsFile = null;
        $this->paramStorage = $paramStorage;

        if (is_array($paramStorage)) {
            return $this->loadArray();
        }

        if ($paramStorage === 'env' || $paramStorage === 'environment') {
            return $this->loadEnvironmentVars();
        }

        $this->paramsFile = codecept_absolute_path($paramStorage);
        if (!file_exists($this->paramsFile)) {
            throw new ConfigurationException("Params file {$this->paramsFile} not found");
        }

        try {
            if (preg_match('~\.ya?ml$~', $paramStorage)) {
                return $this->loadYamlFile();
            }

            if (preg_match('~\.ini$~', $paramStorage)) {
                return $this->loadIniFile();
            }

            if (preg_match('~\.php$~', $paramStorage)) {
                return $this->loadPhpFile();
            }

            if (preg_match('~(\.env(\.|$))~', $paramStorage)) {
                return $this->loadDotEnvFile();
            }

            if (preg_match('~\.xml$~', $paramStorage)) {
                return $this->loadXmlFile();
            }
        } catch (\Exception $e) {
            throw new ConfigurationException("Failed loading params from $paramStorage\n" . $e->getMessage());
        }

        throw new ConfigurationException("Params can't be loaded from `$paramStorage`.");
    }

    public function loadArray()
    {
        return $this->paramStorage;
    }

    protected function loadIniFile()
    {
        return parse_ini_file($this->paramsFile);
    }

    protected function loadPhpFile()
    {
        return require $this->paramsFile;
    }

    protected function loadYamlFile()
    {
        $params = Yaml::parse(file_get_contents($this->paramsFile));
        if (isset($params['parameters'])) { // Symfony style
            $params = $params['parameters'];
        }
        return $params;
    }

    protected function loadXmlFile()
    {
        $paramsToArray = function (\SimpleXMLElement $params) use (&$paramsToArray) {
            $a = [];
            foreach ($params as $param) {
                $key = isset($param['key']) ? (string) $param['key'] : $param->getName();
                $type = isset($param['type']) ? (string) $param['type'] : 'string';
                $value = (string) $param;
                switch ($type) {
                    case 'bool':
                    case 'boolean':
                    case 'int':
                    case 'integer':
                    case 'float':
                    case 'double':
                        $a[$key] = settype($value, $type);
                        break;
                    case 'constant':
                        $a[$key] = constant($value);
                        break;
                    case 'collection':
                        $a[$key] = $paramsToArray($param);
                        break;
                    default:
                        $a[$key] = (string) $param;
                }
            }

            return $a;
        };

        return $paramsToArray(simplexml_load_file($this->paramsFile));
    }

    protected function loadDotEnvFile()
    {
        if (class_exists('Dotenv\Dotenv')) {
            if (class_exists('Dotenv\Repository\RepositoryBuilder') && method_exists('Dotenv\Repository\RepositoryBuilder', 'createWithNoAdapters')) {
                //dotenv v5
                $repository = \Dotenv\Repository\RepositoryBuilder::createWithNoAdapters()
                    ->addAdapter(\Dotenv\Repository\Adapter\EnvConstAdapter::class)
                    ->addAdapter(\Dotenv\Repository\Adapter\ServerConstAdapter::class)
                    ->make();
                $dotEnv = \Dotenv\Dotenv::create($repository, codecept_root_dir(), $this->paramStorage);
            } elseif (class_exists('Dotenv\Repository\RepositoryBuilder')) {
                //dotenv v4
                $repository = \Dotenv\Repository\RepositoryBuilder::create()
                    ->withReaders([new \Dotenv\Repository\Adapter\ServerConstAdapter()])
                    ->immutable()
                    ->make();
                $dotEnv = \Dotenv\Dotenv::create($repository, codecept_root_dir(), $this->paramStorage);
            } elseif (method_exists('Dotenv\Dotenv', 'create')) {
                //dotenv v3
                $dotEnv = \Dotenv\Dotenv::create(codecept_root_dir(), $this->paramStorage);
            } else {
                //dotenv v2
                $dotEnv = new \Dotenv\Dotenv(codecept_root_dir(), $this->paramStorage);
            }
            $dotEnv->load();
            return $_SERVER;
        } elseif (class_exists('Symfony\Component\Dotenv\Dotenv')) {
            $dotEnv = new \Symfony\Component\Dotenv\Dotenv();
            $dotEnv->load(codecept_root_dir($this->paramStorage));
            return $_SERVER;
        }

        throw new ConfigurationException(
            "`vlucas/phpdotenv` library is required to parse .env files.\n" .
            "Please install it via composer: composer require vlucas/phpdotenv"
        );
    }

    protected function loadEnvironmentVars()
    {
        return $_SERVER;
    }
}
<?php
namespace Codeception\Lib;

use Codeception\Configuration;
use Codeception\Exception\ConfigurationException;
use Codeception\Test\Interfaces\Reported;
use Codeception\Test\Descriptor;
use Codeception\TestInterface;
use Codeception\Test\Gherkin;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;

/**
 * Loads information for groups from external sources (config, filesystem)
 */
class GroupManager
{
    protected $configuredGroups;
    protected $testsInGroups = [];

    protected $rootDir;


    public function __construct(array $groups)
    {
        $this->rootDir = Configuration::baseDir();
        $this->configuredGroups = $groups;
        $this->loadGroupsByPattern();
        $this->loadConfiguredGroupSettings();
    }

    /**
     * proceeds group names with asterisk:
     *
     * ```
     * "tests/_log/g_*" => [
     *      "tests/_log/group_1",
     *      "tests/_log/group_2",
     *      "tests/_log/group_3",
     * ]
     * ```
     */
    protected function loadGroupsByPattern()
    {
        foreach ($this->configuredGroups as $group => $pattern) {
            if (strpos($group, '*') === false) {
                continue;
            }
            $path = dirname($pattern);
            if (!\Codeception\Util\PathResolver::isPathAbsolute($pattern)) {
                $path = $this->rootDir . $path;
            }

            $files = Finder::create()->files()
                ->name(basename($pattern))
                ->sortByName()
                ->in($path);

            $i = 1;


            foreach ($files as $file) {
                /** @var SplFileInfo $file * */
                $this->configuredGroups[str_replace('*', $i, $group)] = dirname($pattern).DIRECTORY_SEPARATOR.$file->getRelativePathname();
                $i++;
            }
            unset($this->configuredGroups[$group]);
        }
    }

    protected function loadConfiguredGroupSettings()
    {
        foreach ($this->configuredGroups as $group => $tests) {
            $this->testsInGroups[$group] = [];
            if (is_array($tests)) {
                foreach ($tests as $test) {
                    $file = str_replace(['/', '\\'], [DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR], $test);
                    $this->testsInGroups[$group][] = $this->normalizeFilePath($file, $group);
                }
                continue;
            }

            $path = $tests;
            if (!codecept_is_path_absolute($tests)) {
                $path = $this->rootDir . $tests;
            }
            if (is_file($path)) {
                $handle = @fopen($path, "r");
                if ($handle) {
                    while (($test = fgets($handle, 4096)) !== false) {
                        // if the current line is blank then we need to move to the next line
                        // otherwise the current codeception directory becomes part of the group
                        // which causes every single test to run
                        if (trim($test) === '') {
                            continue;
                        }

                        $file = str_replace(['/', '\\'], [DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR], trim($test));
                        $this->testsInGroups[$group][] = $this->normalizeFilePath($file, $group);
                    }
                    fclose($handle);
                }
            }
        }
    }

    /**
     * @param string $file
     * @param string $group
     * @return false|string
     * @throws ConfigurationException
     */
    private function normalizeFilePath($file, $group)
    {
        $pathParts = explode(':', $file);


        if (codecept_is_path_absolute($file)) {
            if ($file[0] === '/' && count($pathParts) > 1) {
                //take segment before first :
                $this->checkIfFileExists($pathParts[0], $group);
                return sprintf('%s:%s', realpath($pathParts[0]), $pathParts[1]);
            } else if (count($pathParts) > 2) {
                //on Windows take segment before second :
                $fullPath = $pathParts[0] . ':' . $pathParts[1];
                $this->checkIfFileExists($fullPath, $group);
                return sprintf('%s:%s', realpath($fullPath), $pathParts[2]);
            }

            $this->checkIfFileExists($file, $group);
            return realpath($file);
        } elseif (strpos($file, ':') === false) {
            $dirtyPath = $this->rootDir . $file;
            $this->checkIfFileExists($dirtyPath, $group);
            return realpath($dirtyPath);
        }

        $dirtyPath = $this->rootDir . $pathParts[0];
        $this->checkIfFileExists($dirtyPath, $group);
        return sprintf('%s:%s', realpath($dirtyPath), $pathParts[1]);
    }

    /**
     * @param string $path
     * @param string $group
     * @throws ConfigurationException
     */
    private function checkIfFileExists($path, $group)
    {
        if (!file_exists($path)) {
            throw new ConfigurationException('GroupManager: File or directory ' . $path . ' set in ' . $group. ' group does not exist');
        }
    }

    public function groupsForTest(\PHPUnit\Framework\Test $test)
    {
        $groups = [];
        $filename = Descriptor::getTestFileName($test);
        if ($test instanceof TestInterface) {
            $groups = $test->getMetadata()->getGroups();
        }
        if ($test instanceof Reported) {
            $info = $test->getReportFields();
            if (isset($info['class'])) {
                $groups = array_merge($groups, \PHPUnit\Util\Test::getGroups($info['class'], $info['name']));
            }
            $filename = str_replace(['\\\\', '//', '/./'], ['\\', '/', '/'], $info['file']);
        }
        if ($test instanceof \PHPUnit\Framework\TestCase) {
            $groups = array_merge($groups, \PHPUnit\Util\Test::getGroups(get_class($test), $test->getName(false)));
        }

        foreach ($this->testsInGroups as $group => $tests) {
            foreach ($tests as $testPattern) {
                if ($filename == $testPattern) {
                    $groups[] = $group;
                }
                if (strpos($filename . ':' . $test->getName(false), $testPattern) === 0) {
                    $groups[] = $group;
                }
                if ($test instanceof Gherkin
                    && mb_strtolower($filename . ':' . $test->getMetadata()->getFeature()) === mb_strtolower($testPattern)) {
                    $groups[] = $group;
                }
            }
        }
        return array_unique($groups);
    }
}
<?php
namespace Codeception\Lib\Connector\Shared;

/**
 * Converts BrowserKit\Request's request parameters and files into PHP-compatible structure
 *
 * @see https://bugs.php.net/bug.php?id=25589
 * @see https://bugs.php.net/bug.php?id=25589
 *
 * @package Codeception\Lib\Connector
 */
trait PhpSuperGlobalsConverter
{
    /**
     * Rearrange files array to be compatible with PHP $_FILES superglobal structure
     * @see https://bugs.php.net/bug.php?id=25589
     *
     * @param array $requestFiles
     *
     * @return array
     */
    protected function remapFiles(array $requestFiles)
    {
        $files = $this->rearrangeFiles($requestFiles);

        return $this->replaceSpaces($files);
    }

    /**
     * Escape high-level variable name with dots, underscores and other "special" chars
     * to be compatible with PHP "bug"
     * @see https://bugs.php.net/bug.php?id=40000
     *
     * @param array $parameters
     *
     * @return array
     */
    protected function remapRequestParameters(array $parameters)
    {
        return $this->replaceSpaces($parameters);
    }

    private function rearrangeFiles($requestFiles)
    {
        $files = [];
        foreach ($requestFiles as $name => $info) {
            if (!is_array($info)) {
                continue;
            }

            /**
             * If we have a form with fields like
             * ```
             * <input type="file" name="foo" />
             * <input type="file" name="foo[bar]" />
             * ```
             * then only array variable will be used while simple variable will be ignored in php $_FILES
             * (eg $_FILES = [
             *                 foo => [
             *                     tmp_name => [
             *                         'bar' => 'asdf'
             *                     ],
             *                     //...
             *                ]
             *              ]
             * )
             * (notice there is no entry for file "foo", only for file "foo[bar]"
             * this will check if current element contains inner arrays within it's keys
             * so we can ignore element itself and only process inner files
             */
            $hasInnerArrays = count(array_filter($info, 'is_array'));

            if ($hasInnerArrays || !isset($info['tmp_name'])) {
                $inner = $this->remapFiles($info);
                foreach ($inner as $innerName => $innerInfo) {
                    /**
                     * Convert from ['a' => ['tmp_name' => '/tmp/test.txt'] ]
                     * to ['tmp_name' => ['a' => '/tmp/test.txt'] ]
                     */
                    $innerInfo = array_map(
                        function ($v) use ($innerName) {
                            return [$innerName => $v];
                        },
                        $innerInfo
                    );

                    if (empty($files[$name])) {
                        $files[$name] = [];
                    }

                    $files[$name] = array_replace_recursive($files[$name], $innerInfo);
                }
            } else {
                $files[$name] = $info;
            }
        }

        return $files;
    }

    /**
     * Replace spaces and dots and other chars in high-level query parameters for
     * compatibility with PHP bug (or not a bug)
     * @see https://bugs.php.net/bug.php?id=40000
     *
     * @param array $parameters Array of request parameters to be converted
     *
     * @return array
     */
    private function replaceSpaces($parameters)
    {
        $qs = http_build_query($parameters, '', '&');
        parse_str($qs, $output);

        return $output;
    }
}
<?php
namespace Codeception\Lib;

class Notification
{
    protected static $messages = [];

    public static function warning($message, $location)
    {
        self::$messages[] = 'WARNING: ' . self::formatMessage($message, $location);
    }

    public static function deprecate($message, $location = '')
    {
        self::$messages[] = 'DEPRECATION: ' . self::formatMessage($message, $location);
    }

    private static function formatMessage($message, $location = '')
    {
        if ($location) {
            return "<bold>$message</bold> <info>$location</info>";
        }
        return $message;
    }

    public static function all()
    {
        $messages = self::$messages;
        self::$messages = [];
        return $messages;
    }
}
<?php
namespace Codeception\Lib;

use Codeception\Configuration;
use Codeception\Exception\TestParseException;
use Codeception\Scenario;
use Codeception\Step;
use Codeception\Test\Metadata;

class Parser
{
    /**
     * @var Scenario
     */
    protected $scenario;
    /**
     * @var Metadata
     */
    protected $metadata;
    protected $code;

    public function __construct(Scenario $scenario, Metadata $metadata)
    {
        $this->scenario = $scenario;
        $this->metadata = $metadata;
    }

    public function prepareToRun($code)
    {
        $this->parseFeature($code);
        $this->parseScenarioOptions($code);
    }

    public function parseFeature($code)
    {
        $matches = [];
        $code = $this->stripComments($code);
        $res = preg_match("~\\\$I->wantTo\\(\s*?['\"](.*?)['\"]\s*?\\);~", $code, $matches);
        if ($res) {
            $this->scenario->setFeature($matches[1]);
            return;
        }
        $res = preg_match("~\\\$I->wantToTest\\(['\"](.*?)['\"]\\);~", $code, $matches);
        if ($res) {
            $this->scenario->setFeature("test " . $matches[1]);
            return;
        }
    }

    public function parseScenarioOptions($code)
    {
        $this->metadata->setParamsFromAnnotations($this->matchComments($code));
    }

    public function parseSteps($code)
    {
        // parse per line
        $friends = [];
        $lines = explode("\n", $code);
        $isFriend = false;
        foreach ($lines as $line) {
            // friends
            if (preg_match("~\\\$I->haveFriend\((.*?)\);~", $line, $matches)) {
                $friends[] = trim($matches[1], '\'"');
            }
            // friend's section start
            if (preg_match("~\\\$(.*?)->does\(~", $line, $matches)) {
                $friend = $matches[1];
                if (!in_array($friend, $friends)) {
                    continue;
                }
                $isFriend = true;
                $this->addCommentStep("\n----- $friend does -----");
                continue;
            }

            // actions
            if (preg_match("~\\\$I->(.*)\((.*?)\);~", $line, $matches)) {
                $this->addStep($matches);
            }

            // friend's section ends
            if ($isFriend && strpos($line, '}') !== false) {
                $this->addCommentStep("-------- back to me\n");
                $isFriend = false;
            }
        }
    }

    protected function addStep($matches)
    {
        list($m, $action, $params) = $matches;
        if (in_array($action, ['wantTo', 'wantToTest'])) {
            return;
        }
        $this->scenario->addStep(new Step\Action($action, explode(',', $params)));
    }

    protected function addCommentStep($comment)
    {
        $this->scenario->addStep(new \Codeception\Step\Comment($comment, []));
    }

    public static function validate($file)
    {
        $config = Configuration::config();
        if (empty($config['settings']['lint'])) { // lint disabled in config
            return;
        }
        if (!function_exists('exec')) {
            //exec function is disabled #3324
            return;
        }
        exec("php -l " . escapeshellarg($file) . " 2>&1", $output, $code);
        if ($code !== 0) {
            throw new TestParseException($file, implode("\n", $output));
        }
    }

    public static function load($file)
    {
        if (PHP_MAJOR_VERSION < 7) {
            self::validate($file);
        }
        try {
            self::includeFile($file);
        } catch (\ParseError $e) {
            throw new TestParseException($file, $e->getMessage(), $e->getLine());
        } catch (\Exception $e) {
            // file is valid otherwise
        }
    }

    public static function getClassesFromFile($file)
    {
        $sourceCode = file_get_contents($file);
        $classes = [];
        $tokens = token_get_all($sourceCode);
        $tokenCount = count($tokens);
        $namespace = '';

        for ($i = 0; $i < $tokenCount; $i++) {
            if ($tokens[$i][0] === T_NAMESPACE) {
                $namespace = '';
                for ($j = $i + 1; $j < $tokenCount; $j++) {
                    if ($tokens[$j] === '{' || $tokens[$j] === ';') {
                        break;
                    }
                    if ($tokens[$j][0] === T_STRING || (PHP_MAJOR_VERSION >= 8 && $tokens[$j][0] === T_NAME_QUALIFIED)) {
                        $namespace .= $tokens[$j][1] . '\\';
                    }
                }
            }

            if ($tokens[$i][0] === T_CLASS) {
                if (!isset($tokens[$i - 2])) {
                    $classes[] = $namespace . $tokens[$i + 2][1];
                    continue;
                }
                if ($tokens[$i - 2][0] === T_NEW) {
                    continue;
                }
                if ($tokens[$i - 1][0] === T_WHITESPACE and $tokens[$i - 2][0] === T_DOUBLE_COLON) {
                    continue;
                }
                if ($tokens[$i - 1][0] === T_DOUBLE_COLON) {
                    continue;
                }
                $classes[] = $namespace . $tokens[$i + 2][1];
            }
        }

        if (PHP_MAJOR_VERSION > 5) {
            $tokens = null;
            gc_mem_caches();
        }

        return $classes;
    }

    /*
     * Include in different scope to prevent included file from affecting $file variable
     */
    private static function includeFile($file)
    {
        include_once $file;
    }

    /**
     * @param $code
     * @return mixed
     */
    protected function stripComments($code)
    {
        $code = preg_replace('~\/\/.*?$~m', '', $code); // remove inline comments
        $code = preg_replace('~\/*\*.*?\*\/~ms', '', $code);
        return $code; // remove block comment
    }

    protected function matchComments($code)
    {
        $matches = [];
        $comments = '';
        $hasLineComment = preg_match_all('~\/\/(.*?)$~m', $code, $matches);
        if ($hasLineComment) {
            foreach ($matches[1] as $line) {
                $comments .= $line."\n";
            }
        }
        $hasBlockComment = preg_match('~\/*\*(.*?)\*\/~ms', $code, $matches);
        if ($hasBlockComment) {
            $comments .= $matches[1]."\n";
        }
        return $comments;
    }
}
<?php
namespace Codeception\Event;

use Symfony\Component\EventDispatcher\Event;

class PrintResultEvent extends Event
{
    /**
     * @var \PHPUnit\Framework\TestResult
     */
    protected $result;

    /**
     * @var \PHPUnit\Util\Printer
     */
    protected $printer;

    public function __construct(\PHPUnit\Framework\TestResult $result, \PHPUnit\Util\Printer $printer)
    {
        $this->result = $result;
        $this->printer = $printer;
    }

    /**
     * @return \PHPUnit\Util\Printer
     */
    public function getPrinter()
    {
        return $this->printer;
    }

    /**
     * @return \PHPUnit\Framework\TestResult
     */
    public function getResult()
    {
        return $this->result;
    }
}
<?php

namespace Codeception\Event;

use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface;

trait DispatcherWrapper
{
    /**
     * Compatibility wrapper for dispatcher change between Symfony 4 and 5
     * @param EventDispatcher $dispatcher
     * @param string $eventType
     * @param Event $eventObject
     */
    protected function dispatch(EventDispatcher $dispatcher, $eventType, Event $eventObject)
    {
        // The `EventDispatcherInterface` of `Symfony\Contracts` is only implemented in Symfony 4.3 or higher
        if ($dispatcher instanceof ContractsEventDispatcherInterface) {
            //Symfony 4.3 or higher
            $dispatcher->dispatch($eventObject, $eventType);
        } else {
            //Symfony 4.2 or lower
            $dispatcher->dispatch($eventType, $eventObject);
        }
    }
}
<?php
namespace Codeception\Event;

use Codeception\Step;
use Codeception\TestInterface;
use Symfony\Component\EventDispatcher\Event;

class StepEvent extends Event
{
    /**
     * @var Step
     */
    protected $step;

    /**
     * @var TestInterface
     */
    protected $test;

    public function __construct(TestInterface $test, Step $step)
    {
        $this->test = $test;
        $this->step = $step;
    }

    public function getStep()
    {
        return $this->step;
    }

    /**
     * @return TestInterface
     */
    public function getTest()
    {
        return $this->test;
    }
}
<?php
namespace Codeception\Event;

class FailEvent extends TestEvent
{
    /**
     * @var \Exception
     */
    protected $fail;

    /**
     * @var int
     */
    protected $count;

    public function __construct(\PHPUnit\Framework\Test $test, $time, $e, $count = 0)
    {
        parent::__construct($test, $time);
        $this->fail = $e;
        $this->count = $count;
    }

    public function getCount()
    {
        return $this->count;
    }

    public function getFail()
    {
        return $this->fail;
    }
}
<?php
namespace Codeception\Event;

use Symfony\Component\EventDispatcher\Event;

class TestEvent extends Event
{
    /**
     * @var \PHPUnit\Framework\Test
     */
    protected $test;

    /**
     * @var float Time taken
     */
    protected $time;

    public function __construct(\PHPUnit\Framework\Test $test, $time = 0)
    {
        $this->test = $test;
        $this->time = $time;
    }

    /**
     * @return float
     */
    public function getTime()
    {
        return $this->time;
    }

    /**
     * @return \Codeception\TestInterface
     */
    public function getTest()
    {
        return $this->test;
    }
}
<?php
namespace Codeception\Event;

use Codeception\Suite;
use Symfony\Component\EventDispatcher\Event;

class SuiteEvent extends Event
{
    /**
     * @var \PHPUnit\Framework\TestSuite
     */
    protected $suite;

    /**
     * @var \PHPUnit\Framework\TestResult
     */
    protected $result;

    /**
     * @var array
     */
    protected $settings;

    public function __construct(
        \PHPUnit\Framework\TestSuite $suite,
        \PHPUnit\Framework\TestResult $result = null,
        $settings = []
    ) {
        $this->suite = $suite;
        $this->result = $result;
        $this->settings = $settings;
    }

    /**
     * @return Suite
     */
    public function getSuite()
    {
        return $this->suite;
    }

    /**
     * @return \PHPUnit\Framework\TestResult
     */
    public function getResult()
    {
        return $this->result;
    }

    public function getSettings()
    {
        return $this->settings;
    }
}
<?php
namespace Codeception;

use Codeception\Lib\Actor\Shared\Comment;
use Codeception\Step\Executor;
use Codeception\Lib\Actor\Shared\Pause;

abstract class Actor
{
    use Comment;
    use Pause;

    /**
     * @var \Codeception\Scenario
     */
    protected $scenario;

    public function __construct(Scenario $scenario)
    {
        $this->scenario = $scenario;
    }

    /**
     * @return \Codeception\Scenario
     */
    protected function getScenario()
    {
        return $this->scenario;
    }

    public function wantToTest($text)
    {
        $this->wantTo('test ' . $text);
    }

    public function wantTo($text)
    {
        $this->scenario->setFeature($text);
    }

    public function __call($method, $arguments)
    {
        $class = get_class($this);
        throw new \RuntimeException("Call to undefined method $class::$method");
    }
    
    /**
     * Lazy-execution given anonymous function
     * @param $callable \Closure
     * @return $this
     */
    public function execute($callable)
    {
        $this->scenario->addStep(new Executor($callable, []));
        $callable();
        return $this;
    }
}
<?php
namespace Codeception\Test\Interfaces;

interface Dependent
{
    public function fetchDependencies();
}
<?php
namespace Codeception\Test\Interfaces;

interface Descriptive extends \PHPUnit\Framework\SelfDescribing
{
    public function getFileName();

    public function getSignature();
}
<?php
namespace Codeception\Test\Interfaces;

/**
 * TestCases that do not follow OOP
 */
interface Plain
{
}
<?php
namespace Codeception\Test\Interfaces;

interface Reported
{
    /**
     * Field values for XML/JSON/TAP reports
     *
     * @return array
     */
    public function getReportFields();
}
<?php

namespace Codeception\Test\Interfaces;

interface StrictCoverage
{
    public function getLinesToBeCovered();

    public function getLinesToBeUsed();
}
<?php
namespace Codeception\Test\Interfaces;

interface ScenarioDriven
{
    public function getFeature();

    /**
     * @return \Codeception\Scenario
     */
    public function getScenario();

    public function getScenarioText($format = 'text');

    public function preload();

    public function getSourceCode();
}
<?php
namespace Codeception\Test;

use Codeception\Exception\InjectionException;
use Codeception\Util\Annotation;

class Metadata
{
    protected $name;
    protected $filename;
    protected $feature;
    protected $index;

    protected $params = [
        'env' => [],
        'group' => [],
        'depends' => [],
        'skip' => null,
        'incomplete' => null
    ];

    protected $current = [];
    protected $services = [];
    protected $reports = [];

    /**
     * @return mixed
     */
    public function getEnv()
    {
        return $this->params['env'];
    }

    /**
     * @return array
     */
    public function getGroups()
    {
        return array_unique($this->params['group']);
    }

    /**
     * @param mixed $groups
     */
    public function setGroups($groups)
    {
        $this->params['group'] = array_merge($this->params['group'], $groups);
    }

    /**
     * @return mixed
     */
    public function getSkip()
    {
        return $this->params['skip'];
    }

    /**
     * @param mixed $skip
     */
    public function setSkip($skip)
    {
        $this->params['skip'] = $skip;
    }

    /**
     * @return mixed
     */
    public function getIncomplete()
    {
        return $this->params['incomplete'];
    }

    /**
     * @param mixed $incomplete
     */
    public function setIncomplete($incomplete)
    {
        $this->params['incomplete'] = $incomplete;
    }

    /**
     * @param string|null $key
     * @return mixed
     */
    public function getCurrent($key = null)
    {
        if ($key) {
            if (isset($this->current[$key])) {
                return $this->current[$key];
            }
            if ($key === 'name') {
                return $this->getName();
            }
            return null;
        }

        return $this->current;
    }

    public function setCurrent(array $currents)
    {
        $this->current = array_merge($this->current, $currents);
    }

    /**
     * @return mixed
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param mixed $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * @return mixed
     */
    public function getFilename()
    {
        return $this->filename;
    }

    /**
     * @param mixed $index
     */
    public function setIndex($index)
    {
        $this->index = $index;
    }

    /**
     * @return mixed
     */
    public function getIndex()
    {
        return $this->index;
    }

    /**
     * @param mixed $filename
     */
    public function setFilename($filename)
    {
        $this->filename = $filename;
    }

    /**
     * @return array
     */
    public function getDependencies()
    {
        return $this->params['depends'];
    }

    public function isBlocked()
    {
        return $this->getSkip() !== null || $this->getIncomplete() !== null;
    }

    /**
     * @return mixed
     */
    public function getFeature()
    {
        return $this->feature;
    }

    /**
     * @param mixed $feature
     */
    public function setFeature($feature)
    {
        $this->feature = $feature;
    }

    /**
     * @param $service
     * @return array
     * @throws InjectionException
     */
    public function getService($service)
    {
        if (!isset($this->services[$service])) {
            throw new InjectionException("Service $service is not defined and can't be accessed from a test");
        }
        return $this->services[$service];
    }

    /**
     * @param array $services
     */
    public function setServices($services)
    {
        $this->services = $services;
    }

    /**
     * Returns all test reports
     * @return array
     */
    public function getReports()
    {
        return $this->reports;
    }

    /**
     * @param $type
     * @param $report
     */
    public function addReport($type, $report)
    {
        $this->reports[$type] = $report;
    }

    /**
     * Returns test params like: env, group, skip, incomplete, etc
     * Can return by annotation or return all if no key passed
     *
     * @param null $key
     * @return array|mixed|null
     */
    public function getParam($key = null)
    {
        if ($key) {
            if (isset($this->params[$key])) {
                return $this->params[$key];
            }
            return null;
        }

        return $this->params;
    }

    /**
     * @param mixed $annotations
     */
    public function setParamsFromAnnotations($annotations)
    {
        $params = Annotation::fetchAllAnnotationsFromDocblock($annotations);
        $this->params = array_merge_recursive($this->params, $params);

        // set singular value for some params
        foreach (['skip', 'incomplete'] as $single) {
            $this->params[$single] = empty($this->params[$single]) ? null : (string) $this->params[$single][0];
        }
    }

    /**
     * @param $params
     */
    public function setParams($params)
    {
        $this->params = array_merge_recursive($this->params, $params);
    }
}
<?php
namespace Codeception\Test;

use Codeception\Test\Loader\Cept as CeptLoader;
use Codeception\Test\Loader\Cest as CestLoader;
use Codeception\Test\Loader\Unit as UnitLoader;
use Codeception\Test\Loader\Gherkin as GherkinLoader;
use Symfony\Component\Finder\Finder;

/**
 * Loads all Codeception supported test formats from a directory.
 *
 * ``` php
 * <?php
 * $testLoader = new \Codeception\TestLoader('tests/unit');
 * $testLoader->loadTests();
 * $tests = $testLoader->getTests();
 * ?>
 * ```
 * You can load specific file
 *
 * ``` php
 * <?php
 * $testLoader = new \Codeception\TestLoader('tests/unit');
 * $testLoader->loadTest('UserTest.php');
 * $testLoader->loadTest('PostTest.php');
 * $tests = $testLoader->getTests();
 * ?>
 * ```
 * or a subdirectory
 *
 * ``` php
 * <?php
 * $testLoader = new \Codeception\TestLoader('tests/unit');
 * $testLoader->loadTest('models'); // all tests from tests/unit/models
 * $tests = $testLoader->getTests();
 * ?>
 * ```
 *
 */
class Loader
{
    protected $formats = [];
    protected $tests = [];
    protected $path;

    public function __construct(array $suiteSettings)
    {
        $this->path = $suiteSettings['path'];
        $this->formats = [
            new CeptLoader(),
            new CestLoader(),
            new UnitLoader(),
            new GherkinLoader($suiteSettings)
        ];
        if (isset($suiteSettings['formats'])) {
            foreach ($suiteSettings['formats'] as $format) {
                $this->formats[] = new $format($suiteSettings);
            }
        }
    }

    public function getTests()
    {
        return $this->tests;
    }

    protected function relativeName($file)
    {
        return str_replace([$this->path, '\\'], ['', '/'], $file);
    }

    protected function findPath($path)
    {
        if (!file_exists($path)
            && substr($path, -strlen('.php')) !== '.php'
            && file_exists($newPath = $path . '.php')
        ) {
            return $newPath;
        }

        return $path;
    }

    protected function makePath($originalPath)
    {
        $path = $this->path . $this->relativeName($originalPath);

        if (file_exists($newPath = $this->findPath($path))
            || file_exists($newPath = $this->findPath(getcwd() . "/{$originalPath}"))
        ) {
            $path = $newPath;
        }

        if (!file_exists($path)) {
            throw new \Exception("File or path $originalPath not found");
        }

        return $path;
    }

    public function loadTest($path)
    {
        $path = $this->makePath($path);

        foreach ($this->formats as $format) {
            /** @var $format Loader  **/
            if (preg_match($format->getPattern(), $path)) {
                $format->loadTests($path);
                $this->tests = $format->getTests();
                return;
            }
        }

        if (is_dir($path)) {
            $currentPath = $this->path;
            $this->path = $path;
            $this->loadTests();
            $this->path = $currentPath;
            return;
        }
        throw new \Exception('Test format not supported. Please, check you use the right suffix. Available filetypes: Cept, Cest, Test');
    }

    public function loadTests($fileName = null)
    {
        if ($fileName) {
            return $this->loadTest($fileName);
        }

        $finder = Finder::create()->files()->sortByName()->in($this->path)->followLinks();

        foreach ($this->formats as $format) {
            /** @var $format Loader  **/
            $formatFinder = clone($finder);
            $testFiles = $formatFinder->name($format->getPattern());
            foreach ($testFiles as $test) {
                $pathname = str_replace(["//", "\\\\"], ["/", "\\"], $test->getPathname());
                $format->loadTests($pathname);
            }
            $this->tests = array_merge($this->tests, $format->getTests());
        }
    }
}
<?php
namespace Codeception\Test;

use Codeception\Test\Interfaces\Descriptive;
use Codeception\Test\Interfaces\Plain;
use Codeception\Util\ReflectionHelper;

class Descriptor
{
    /**
     * Provides a test name which can be located by
     *
     * @param \PHPUnit\Framework\SelfDescribing $testCase
     * @return string
     */
    public static function getTestSignature(\PHPUnit\Framework\SelfDescribing $testCase)
    {
        if ($testCase instanceof Descriptive) {
            return $testCase->getSignature();
        }
        if ($testCase instanceof \PHPUnit\Framework\TestCase) {
            return get_class($testCase) . ':' . $testCase->getName(false);
        }
        return $testCase->toString();
    }

    /**
     * Provides a test name which is unique for individual iterations of tests using examples
     *
     * @param \PHPUnit\Framework\SelfDescribing $testCase
     * @return string
     */
    public static function getTestSignatureUnique(\PHPUnit\Framework\SelfDescribing $testCase)
    {
        $env     = '';
        $example = '';

        if (method_exists($testCase, 'getScenario')
            && !empty($testCase->getScenario()->current('env'))
        ) {
            $env = ':' . $testCase->getScenario()->current('env');
        }

        if (method_exists($testCase, 'getMetaData')
            && !empty($testCase->getMetadata()->getCurrent('example'))
        ) {
            $example = ':' . substr(sha1(json_encode($testCase->getMetadata()->getCurrent('example'))), 0, 7);
        }

        return self::getTestSignature($testCase) . $env . $example;
    }

    public static function getTestAsString(\PHPUnit\Framework\SelfDescribing $testCase)
    {
        if ($testCase instanceof \PHPUnit\Framework\TestCase) {
            $text = self::getTestCaseNameAsString($testCase->getName());
            return ReflectionHelper::getClassShortName($testCase) . ': ' . $text;
        }

        return $testCase->toString();
    }

  /**
   * @param string $testCaseName
   * @return string
   */
    public static function getTestCaseNameAsString($testCaseName)
    {
        $text = $testCaseName;
        $text = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\\1 \\2', $text);
        $text = preg_replace('/([a-z\d])([A-Z])/', '\\1 \\2', $text);
        $text = preg_replace('/^test /', '', $text);
        $text = ucfirst(strtolower($text));
        $text = str_replace(['::', 'with data set'], [':', '|'], $text);
        return $text;
    }

    /**
     * Provides a test file name relative to Codeception root
     *
     * @param \PHPUnit\Framework\SelfDescribing $testCase
     * @return mixed
     */
    public static function getTestFileName(\PHPUnit\Framework\SelfDescribing $testCase)
    {
        if ($testCase instanceof Descriptive) {
            return codecept_relative_path(realpath($testCase->getFileName()));
        }
        return (new \ReflectionClass($testCase))->getFileName();
    }

    /**
     * @param \PHPUnit\Framework\SelfDescribing $testCase
     * @return mixed|string
     */
    public static function getTestFullName(\PHPUnit\Framework\SelfDescribing $testCase)
    {
        if ($testCase instanceof Plain) {
            return self::getTestFileName($testCase);
        }
        if ($testCase instanceof Descriptive) {
            $signature = $testCase->getSignature(); // cut everything before ":" from signature
            return self::getTestFileName($testCase) . ':' . preg_replace('~^(.*?):~', '', $signature);
        }
        if ($testCase instanceof \PHPUnit\Framework\TestCase) {
            return self::getTestFileName($testCase) . ':' . $testCase->getName(false);
        }
        return self::getTestFileName($testCase) . ':' . $testCase->toString();
    }

    /**
     * Provides a test data set index
     *
     * @param \PHPUnit\Framework\SelfDescribing $testCase
     * @return int|null
     */
    public static function getTestDataSetIndex(\PHPUnit\Framework\SelfDescribing $testCase)
    {
        if ($testCase instanceof Descriptive) {
            return $testCase->getMetadata()->getIndex();
        }
        return null;
    }
}
<?php
namespace Codeception\Test\Loader;

interface LoaderInterface
{
    public function loadTests($filename);

    public function getTests();

    public function getPattern();
}
<?php
namespace Codeception\Test\Loader;

use Behat\Gherkin\Filter\RoleFilter;
use Behat\Gherkin\Keywords\ArrayKeywords as GherkinKeywords;
use Behat\Gherkin\Lexer as GherkinLexer;
use Behat\Gherkin\Node\ExampleNode;
use Behat\Gherkin\Node\OutlineNode;
use Behat\Gherkin\Node\ScenarioInterface;
use Behat\Gherkin\Node\ScenarioNode;
use Behat\Gherkin\Parser as GherkinParser;
use Codeception\Configuration;
use Codeception\Exception\ParseException;
use Codeception\Exception\TestParseException;
use Codeception\Test\Gherkin as GherkinFormat;
use Codeception\Util\Annotation;

class Gherkin implements LoaderInterface
{
    protected static $defaultSettings = [
        'namespace' => '',
        'actor' => '',
        'gherkin' => [
            'contexts' => [
                'default' => [],
                'tag' => [],
                'role' => []
            ]
        ]
    ];

    protected $tests = [];

    /**
     * @var GherkinParser
     */
    protected $parser;

    protected $settings = [];

    protected $steps = [];

    public function __construct($settings = [])
    {
        $this->settings = Configuration::mergeConfigs(self::$defaultSettings, $settings);
        if (!class_exists('Behat\Gherkin\Keywords\ArrayKeywords')) {
            throw new TestParseException('Feature file can only be parsed with Behat\Gherkin library. Please install `behat/gherkin` with Composer');
        }
        $gherkin = new \ReflectionClass('Behat\Gherkin\Gherkin');
        $gherkinClassPath = dirname($gherkin->getFileName());
        $i18n = require $gherkinClassPath . '/../../../i18n.php';
        $keywords = new GherkinKeywords($i18n);
        $lexer = new GherkinLexer($keywords);
        $this->parser = new GherkinParser($lexer);
        $this->fetchGherkinSteps();
    }

    protected function fetchGherkinSteps()
    {
        $contexts = $this->settings['gherkin']['contexts'];

        foreach ($contexts['tag'] as $tag => $tagContexts) {
            $this->addSteps($tagContexts, "tag:$tag");
        }
        foreach ($contexts['role'] as $role => $roleContexts) {
            $this->addSteps($roleContexts, "role:$role");
        }

        if (empty($this->steps) && empty($contexts['default']) && $this->settings['actor']) { // if no context is set, actor to be a context
            $actorContext = $this->settings['namespace']
                ? rtrim($this->settings['namespace'], '\\') . '\\' . rtrim($this->settings['actor'], '\\')
                : $this->settings['actor'];
            if ($actorContext) {
                $contexts['default'][] = $actorContext;
            }
        }

        if (isset($this->settings['gherkin']['contexts']['path']) &&
            isset($this->settings['gherkin']['contexts']['namespace_prefix'])) {
            $files = glob($this->settings['gherkin']['contexts']['path'] . '/*/*.php');

            // Strip off include path
            $files = str_replace([$this->settings['gherkin']['contexts']['path'], '.php', '/'], ['', '', '\\'], $files);

            // Add namespace prefix
            $namespace = $this->settings['gherkin']['contexts']['namespace_prefix'];
            $dynamicContexts = array_map(function ($path) use ($namespace) {
                return $namespace . $path;
            }, $files);

            $this->addSteps($dynamicContexts, 'default');
        }

        $this->addSteps($contexts['default']);
    }

    protected function addSteps(array $contexts, $group = 'default')
    {
        if (!isset($this->steps[$group])) {
            $this->steps[$group] = [];
        }

        foreach ($contexts as $context) {
            $methods = get_class_methods($context);
            if (!$methods) {
                continue;
            }
            foreach ($methods as $method) {
                $annotation = Annotation::forMethod($context, $method);
                foreach (['Given', 'When', 'Then'] as $type) {
                    $patterns = $annotation->fetchAll($type);
                    foreach ($patterns as $pattern) {
                        if (!$pattern) {
                            continue;
                        }
                        $this->validatePattern($pattern);
                        $pattern = $this->makePlaceholderPattern($pattern);
                        $this->steps[$group][$pattern] = [$context, $method];
                    }
                }
            }
        }
    }

    public function makePlaceholderPattern($pattern)
    {
        if (isset($this->settings['describe_steps'])) {
            return $pattern;
        }
        if (strpos($pattern, '/') !== 0) {
            $pattern = preg_quote($pattern);

            $pattern = preg_replace('~(\w+)\/(\w+)~', '(?:$1|$2)', $pattern); // or
            $pattern = preg_replace('~\\\\\((\w)\\\\\)~', '$1?', $pattern); // (s)

            $replacePattern = sprintf(
                '(?|\"%s\"|%s)',
                "((?|[^\"\\\\\\]|\\\\\\.)*?)", // matching escaped string in ""
                '[\D]{0,1}([\d\,\.]+)[\D]{0,1}'
            ); // or matching numbers with optional $ or € chars

            // params converting from :param to match 11 and "aaa" and "aaa\"aaa"
            $pattern = preg_replace('~"?\\\:(\w+)"?~', $replacePattern, $pattern);
            $pattern = "/^$pattern$/u";
            // validating this pattern is slow, so we skip it now
        }
        return $pattern;
    }

    private function validatePattern($pattern)
    {
        if (strpos($pattern, '/') !== 0) {
            return; // not a user-regex but a string with placeholder
        }
        if (@preg_match($pattern, ' ') === false) {
            throw new ParseException("Loading Gherkin step with regex\n \n$pattern\n \nfailed. This regular expression is invalid.");
        }
    }

    public function loadTests($filename)
    {
        $featureNode = $this->parser->parse(file_get_contents($filename), $filename);

        if (!$featureNode) {
            return;
        }

        foreach ($featureNode->getScenarios() as $scenarioNode) {
            /** @var $scenarioNode ScenarioInterface * */
            $steps = $this->steps['default']; // load default context

            foreach (array_merge($scenarioNode->getTags(), $featureNode->getTags()) as $tag) { // load tag contexts
                if (isset($this->steps["tag:$tag"])) {
                    $steps = array_merge($steps, $this->steps["tag:$tag"]);
                }
            }

            $roles = $this->settings['gherkin']['contexts']['role']; // load role contexts
            foreach ($roles as $role => $context) {
                $filter = new RoleFilter($role);
                if ($filter->isFeatureMatch($featureNode)) {
                    $steps = array_merge($steps, $this->steps["role:$role"]);
                    break;
                }
            }

            if ($scenarioNode instanceof OutlineNode) {
                foreach ($scenarioNode->getExamples() as $example) {
                    /** @var $example ExampleNode  **/
                    $params = implode(', ', $example->getTokens());
                    $exampleNode = new ScenarioNode($scenarioNode->getTitle() . " | $params", $scenarioNode->getTags(), $example->getSteps(), $example->getKeyword(), $example->getLine());
                    $this->tests[] = new GherkinFormat($featureNode, $exampleNode, $steps);
                }
                continue;
            }
            $this->tests[] = new GherkinFormat($featureNode, $scenarioNode, $steps);
        }
    }

    public function getTests()
    {
        return $this->tests;
    }

    public function getPattern()
    {
        return '~\.feature$~';
    }

    /**
     * @return array
     */
    public function getSteps()
    {
        return $this->steps;
    }
}
<?php
namespace Codeception\Test\Loader;

use Codeception\Lib\Parser;
use Codeception\Test\Cept as CeptFormat;

class Cept implements LoaderInterface
{
    protected $tests = [];

    public function getPattern()
    {
        return '~Cept\.php$~';
    }

    function loadTests($file)
    {
        Parser::validate($file);
        $name = basename($file, 'Cept.php');

        $cept = new CeptFormat($name, $file);
        $this->tests[] = $cept;
    }

    public function getTests()
    {
        return $this->tests;
    }
}
<?php
namespace Codeception\Test\Loader;

use Codeception\Lib\Parser;
use Codeception\Test\Descriptor;
use Codeception\Test\Unit as UnitFormat;
use Codeception\Util\Annotation;

class Unit implements LoaderInterface
{
    protected $tests = [];

    public function getPattern()
    {
        return '~Test\.php$~';
    }

    public function loadTests($path)
    {
        Parser::load($path);
        $testClasses = Parser::getClassesFromFile($path);

        foreach ($testClasses as $testClass) {
            $reflected = new \ReflectionClass($testClass);
            if (!$reflected->isInstantiable()) {
                continue;
            }

            foreach ($reflected->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
                $test = $this->createTestFromPhpUnitMethod($reflected, $method);
                if (!$test) {
                    continue;
                }
                $this->tests[] = $test;
            }
        }
    }

    public function getTests()
    {
        return $this->tests;
    }

    protected function createTestFromPhpUnitMethod(\ReflectionClass $class, \ReflectionMethod $method)
    {
        if (method_exists(\PHPUnit\Framework\TestSuite::class, 'isTestMethod')) {
            //PHPUnit <8.2
            if (!\PHPUnit\Framework\TestSuite::isTestMethod($method)) {
                return;
            }
            $test = \PHPUnit\Framework\TestSuite::createTest($class, $method->name);
        } elseif (method_exists(\PHPUnit\Util\Test::class, 'isTestMethod')) {
            //PHPUnit >=8.2
            if (!\PHPUnit\Util\Test::isTestMethod($method)) {
                return;
            }
            $test = (new \PHPUnit\Framework\TestBuilder)->build($class, $method->name);
        } else {
            throw new \Exception('Unsupported version of PHPUnit, where is isTestMethod method?');
        }


        if ($test instanceof \PHPUnit\Framework\DataProviderTestSuite) {
            foreach ($test->tests() as $t) {
                $this->enhancePhpunitTest($t);
            }
            return $test;
        }

        $this->enhancePhpunitTest($test);
        return $test;
    }

    protected function enhancePhpunitTest(\PHPUnit\Framework\Test $test)
    {
        $className = get_class($test);
        $methodName = $test->getName(false);
        $dependencies = \PHPUnit\Util\Test::getDependencies($className, $methodName);
        $test->setDependencies($dependencies);
        if ($test instanceof UnitFormat) {
            $test->getMetadata()->setParamsFromAnnotations(Annotation::forMethod($test, $methodName)->raw());
            $test->getMetadata()->setFilename(Descriptor::getTestFileName($test));
        }
    }
}
<?php
namespace Codeception\Test\Loader;

use Codeception\Exception\TestParseException;
use Codeception\Lib\Parser;
use Codeception\Test\Cest as CestFormat;
use Codeception\Util\Annotation;
use Codeception\Util\ReflectionHelper;

class Cest implements LoaderInterface
{
    protected $tests = [];

    public function getTests()
    {
        return $this->tests;
    }

    public function getPattern()
    {
        return '~Cest\.php$~';
    }

    public function loadTests($file)
    {
        Parser::load($file);
        $testClasses = Parser::getClassesFromFile($file);

        foreach ($testClasses as $testClass) {
            if (substr($testClass, -strlen('Cest')) !== 'Cest') {
                continue;
            }
            if (!(new \ReflectionClass($testClass))->isInstantiable()) {
                continue;
            }
            $unit = new $testClass;

            $methods = get_class_methods($testClass);
            foreach ($methods as $method) {
                if (strpos($method, '_') === 0) {
                    continue;
                }
                $examples = [];

                // example Annotation
                $rawExamples = Annotation::forMethod($unit, $method)->fetchAll('example');
                if (count($rawExamples)) {
                    $examples = array_map(
                        function ($v) {
                            return Annotation::arrayValue($v);
                        },
                        $rawExamples
                    );
                }

                // dataProvider Annotation
                $dataMethod = Annotation::forMethod($testClass, $method)->fetch('dataProvider');
                // lowercase for back compatible
                if (empty($dataMethod)) {
                    $dataMethod = Annotation::forMethod($testClass, $method)->fetch('dataprovider');
                }

                if (!empty($dataMethod)) {
                    try {
                        $data = ReflectionHelper::invokePrivateMethod($unit, $dataMethod);
                        foreach ($data as $example) {
                            $examples[] = $example;
                        }
                    } catch (\ReflectionException $e) {
                        throw new TestParseException(
                            $file,
                            "DataProvider '$dataMethod' for $testClass->$method is invalid or not callable.\n" .
                            "Make sure that the dataprovider exist within the test class."
                        );
                    }
                }

                if (count($examples)) {
                    $dataProvider = new \PHPUnit\Framework\DataProviderTestSuite();
                    $index = 0;
                    foreach ($examples as $k => $example) {
                        if ($example === null) {
                            throw new TestParseException(
                                $file,
                                "Example for $testClass->$method contains invalid data:\n" .
                                $rawExamples[$k] . "\n" .
                                "Make sure this is a valid JSON (Hint: \"-char for strings) or a single-line annotation in Doctrine-style"
                            );
                        }
                        $test = new CestFormat($unit, $method, $file);
                        $test->getMetadata()->setCurrent(['example' => $example]);
                        $test->getMetadata()->setIndex($index);
                        $dataProvider->addTest($test);
                        $index++;
                    }
                    $this->tests[] = $dataProvider;
                    continue;
                }
                $this->tests[] = new CestFormat($unit, $method, $file);
            }
        }
    }
}
<?php
namespace Codeception\Test;

use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\ScenarioNode;
use Behat\Gherkin\Node\ScenarioInterface;
use Behat\Gherkin\Node\StepNode;
use Behat\Gherkin\Node\TableNode;
use Codeception\Lib\Di;
use Codeception\Lib\Generator\GherkinSnippets;
use Codeception\Scenario;
use Codeception\Step\Comment;
use Codeception\Step\Meta;
use Codeception\Test\Interfaces\Reported;
use Codeception\Test\Interfaces\ScenarioDriven;

class Gherkin extends Test implements ScenarioDriven, Reported
{
    protected $steps = [];

    /**
     * @var FeatureNode
     */
    protected $featureNode;

    /**
     * @var ScenarioNode
     */
    protected $scenarioNode;

    /**
     * @var Scenario
     */
    protected $scenario;

    public function __construct(FeatureNode $featureNode, ScenarioInterface $scenarioNode, $steps = [])
    {
        $this->featureNode = $featureNode;
        $this->scenarioNode = $scenarioNode;
        $this->steps = $steps;
        $this->setMetadata(new Metadata());
        $this->scenario = new Scenario($this);
        $this->getMetadata()->setName($scenarioNode->getTitle());
        $this->getMetadata()->setFeature($featureNode->getTitle());
        $this->getMetadata()->setFilename($featureNode->getFile());
    }

    public function preload()
    {
        $this->getMetadata()->setGroups($this->featureNode->getTags());
        $this->getMetadata()->setGroups($this->scenarioNode->getTags());
        $this->scenario->setMetaStep(null);

        if ($background = $this->featureNode->getBackground()) {
            foreach ($background->getSteps() as $step) {
                $this->validateStep($step);
            }
        }

        foreach ($this->scenarioNode->getSteps() as $step) {
            $this->validateStep($step);
        }
        if ($this->getMetadata()->getIncomplete()) {
            $this->getMetadata()->setIncomplete($this->getMetadata()->getIncomplete() . "\nRun gherkin:snippets to define missing steps");
        }
    }

    public function getSignature()
    {
        return basename($this->getFileName(), '.feature') . ':' . $this->getScenarioTitle();
    }

    public function test()
    {
        $this->makeContexts();
        $description = explode("\n", $this->featureNode->getDescription());
        foreach ($description as $line) {
            $this->getScenario()->runStep(new Comment($line));
        }

        if ($background = $this->featureNode->getBackground()) {
            foreach ($background->getSteps() as $step) {
                $this->runStep($step);
            }
        }

        foreach ($this->scenarioNode->getSteps() as $step) {
            $this->runStep($step);
        }
    }

    protected function validateStep(StepNode $stepNode)
    {
        $stepText = $stepNode->getText();
        if (GherkinSnippets::stepHasPyStringArgument($stepNode)) {
            $stepText .= ' ""';
        }
        $matches = [];
        foreach ($this->steps as $pattern => $context) {
            $res = preg_match($pattern, $stepText);
            if (!$res) {
                continue;
            }
            $matches[$pattern] = $context;
        }
        if (count($matches) === 0) {
            // There were no matches, meaning that the user should first add a step definition for this step
            $incomplete = $this->getMetadata()->getIncomplete();
            $this->getMetadata()->setIncomplete("$incomplete\nStep definition for `$stepText` not found in contexts");
        }
        if (count($matches) > 1) {
            // There were more than one match, meaning that we don't know which step definition to execute for this step
            $incomplete = $this->getMetadata()->getIncomplete();
            $matchingDefinitions = [];
            foreach ($matches as $pattern => $context) {
                $matchingDefinitions[] = '- ' . $pattern . ' (' . self::contextAsString($context) . ')';
            }
            $this->getMetadata()->setIncomplete(
                "$incomplete\nAmbiguous step: `$stepText` matches multiple definitions:\n"
                . implode("\n", $matchingDefinitions)
            );
        }
    }

    private function contextAsString($context)
    {
        if (is_array($context) && count($context) === 2) {
            list($class, $method) = $context;

            if (is_string($class) && is_string($method)) {
                return $class . ':' . $method;
            }
        }

        return var_export($context, true);
    }

    protected function runStep(StepNode $stepNode)
    {
        $params = [];
        if ($stepNode->hasArguments()) {
            $args = $stepNode->getArguments();
            $table = $args[0];
            if ($table instanceof TableNode) {
                $params = [$table->getTableAsString()];
            }
        }
        $meta = new Meta($stepNode->getText(), $params);
        $meta->setPrefix($stepNode->getKeyword());
        $this->scenario->setMetaStep($meta); // enable metastep
        $stepText = $stepNode->getText();
        $hasPyStringArg = GherkinSnippets::stepHasPyStringArgument($stepNode);
        if ($hasPyStringArg) {
            // pretend it is inline argument
            $stepText .= ' ""';
        }
        $this->getScenario()->comment(null); // make metastep to be printed even if no steps in it
        foreach ($this->steps as $pattern => $context) {
            $matches = [];
            if (!preg_match($pattern, $stepText, $matches)) {
                continue;
            }
            array_shift($matches);
            if ($hasPyStringArg) {
                // get rid off last fake argument
                array_pop($matches);
            }
            if ($stepNode->hasArguments()) {
                $matches = array_merge($matches, $stepNode->getArguments());
            }
            call_user_func_array($context, $matches); // execute the step
            break;
        }
        $this->scenario->setMetaStep(null); // disable metastep
    }

    protected function makeContexts()
    {
        /** @var $di Di  **/
        $di = $this->getMetadata()->getService('di');
        $di->set($this->getScenario());

        $actorClass = $this->getMetadata()->getCurrent('actor');
        if ($actorClass) {
            $di->set(new $actorClass($this->getScenario()));
        }

        foreach ($this->steps as $pattern => $step) {
            $di->instantiate($step[0]);
            $this->steps[$pattern][0] = $di->get($step[0]);
        }
    }

    public function toString()
    {
        return $this->getFeature() . ': ' . $this->getScenarioTitle();
    }

    public function getFeature()
    {
        return $this->getMetadata()->getFeature();
    }

    public function getScenarioTitle()
    {
        return $this->getMetadata()->getName();
    }

    /**
     * @return \Codeception\Scenario
     */
    public function getScenario()
    {
        return $this->scenario;
    }

    public function getScenarioText($format = 'text')
    {
        return file_get_contents($this->getFileName());
    }

    public function getSourceCode()
    {
    }

    /**
     * @return ScenarioNode
     */
    public function getScenarioNode()
    {
        return $this->scenarioNode;
    }

    /**
     * @return FeatureNode
     */
    public function getFeatureNode()
    {
        return $this->featureNode;
    }

    /**
     * Field values for XML/JSON/TAP reports
     *
     * @return array
     */
    public function getReportFields()
    {
        return [
            'file'    => $this->getFileName(),
            'name'    => $this->toString(),
            'feature' => $this->getFeature()
        ];
    }
}
<?php
namespace Codeception\Test;

use Codeception\Exception\TestParseException;
use Codeception\Lib\Parser;
use Codeception\Lib\Console\Message;

/**
 * Executes tests delivered in Cept format.
 * Prepares metadata, parses test body on preload, and executes a test in `test` method.
 */
class Cept extends Test implements Interfaces\Plain, Interfaces\ScenarioDriven, Interfaces\Reported, Interfaces\Dependent
{
    use Feature\ScenarioLoader;

    /**
     * @var Parser
     */
    protected $parser;

    public function __construct($name, $file)
    {
        $metadata = new Metadata();
        $metadata->setName($name);
        $metadata->setFilename($file);
        $this->setMetadata($metadata);
        $this->createScenario();
        $this->parser = new Parser($this->getScenario(), $this->getMetadata());
    }

    public function preload()
    {
        $this->getParser()->prepareToRun($this->getSourceCode());
    }

    public function test()
    {
        $scenario = $this->getScenario();
        $testFile = $this->getMetadata()->getFilename();
        /** @noinspection PhpIncludeInspection */
        try {
            require $testFile;
        } catch (\ParseError $e) {
            throw new TestParseException($testFile, $e->getMessage(), $e->getLine());
        }
    }

    public function getSignature()
    {
        return $this->getMetadata()->getName() . 'Cept';
    }

    public function toString()
    {
        return $this->getSignature() . ': ' . Message::ucfirst($this->getFeature());
    }

    public function getSourceCode()
    {
        return file_get_contents($this->getFileName());
    }

    public function getReportFields()
    {
        return [
            'name' => basename($this->getFileName(), 'Cept.php'),
            'file' => $this->getFileName(),
            'feature' => $this->getFeature()
        ];
    }

    /**
     * @return Parser
     */
    protected function getParser()
    {
        return $this->parser;
    }

    public function fetchDependencies()
    {
        return $this->getMetadata()->getDependencies();
    }
}
<?php
namespace Codeception\Test\Feature;

use Codeception\Lib\Parser;
use Codeception\Scenario;
use Codeception\Test\Metadata;

trait ScenarioLoader
{
    /**
     * @var Scenario
     */
    private $scenario;

    /**
     * @return Metadata
     */
    abstract public function getMetadata();

    protected function createScenario()
    {
        $this->scenario = new Scenario($this);
    }

    /**
     * @return Scenario
     */
    public function getScenario()
    {
        return $this->scenario;
    }

    public function getFeature()
    {
        return $this->getScenario()->getFeature();
    }

    public function getScenarioText($format = 'text')
    {
        $code = $this->getSourceCode();
        $this->getParser()->parseFeature($code);
        $this->getParser()->parseSteps($code);
        if ($format == 'html') {
            return $this->getScenario()->getHtml();
        }
        return $this->getScenario()->getText();
    }

    /**
     * @return Parser
     */
    abstract protected function getParser();
    abstract public function getSourceCode();
}
<?php
namespace Codeception\Test\Feature;

trait AssertionCounter
{
    protected $numAssertions = 0;

    public function getNumAssertions()
    {
        return $this->numAssertions;
    }
    /**
     * This method is not covered by the backward compatibility promise
     * for PHPUnit, but is nice to have for extensions.
     */
    public function addToAssertionCount($count)
    {
        $this->numAssertions += $count;
    }

    protected function assertionCounterStart()
    {
        \PHPUnit\Framework\Assert::resetCount();
    }

    protected function assertionCounterEnd()
    {
        $this->numAssertions = \PHPUnit\Framework\Assert::getCount();
    }
}
<?php
namespace Codeception\Test\Feature;

use Codeception\Test\Metadata;

trait MetadataCollector
{
    /**
     * @var Metadata
     */
    private $metadata;

    protected function setMetadata(Metadata $metadata)
    {
        $this->metadata = $metadata;
    }

    public function getMetadata()
    {
        return $this->metadata;
    }

    public function getName()
    {
        return $this->getMetadata()->getName();
    }

    public function getFileName()
    {
        return $this->getMetadata()->getFilename();
    }
}
<?php
namespace Codeception\Test\Feature;

use Codeception\Test\Test as CodeceptionTest;

trait ErrorLogger
{
    /**
     * @return \PHPUnit\Framework\TestResult
     */
    abstract public function getTestResultObject();

    public function errorLoggerEnd($status, $time, $exception = null)
    {
        if (!$exception) {
            return;
        }

        if ($status === CodeceptionTest::STATUS_ERROR) {
             $this->getTestResultObject()->addError($this, $exception, $time);
        }
        if ($status === CodeceptionTest::STATUS_FAIL) {
            $this->getTestResultObject()->addFailure($this, $exception, $time);
        }
    }
}
<?php
namespace Codeception\Test\Feature;

use Codeception\Test\Descriptor;
use Codeception\Test\Interfaces\StrictCoverage;

trait CodeCoverage
{
    /**
     * @return \PHPUnit\Framework\TestResult
     */
    abstract public function getTestResultObject();

    public function codeCoverageStart()
    {
        $codeCoverage = $this->getTestResultObject()->getCodeCoverage();
        if (!$codeCoverage) {
            return;
        }
        $codeCoverage->start(Descriptor::getTestSignature($this));
    }

    public function codeCoverageEnd($status, $time)
    {
        $codeCoverage = $this->getTestResultObject()->getCodeCoverage();
        if (!$codeCoverage) {
            return;
        }

        if ($this instanceof StrictCoverage) {
            $linesToBeCovered = $this->getLinesToBeCovered();
            $linesToBeUsed = $this->getLinesToBeUsed();
        } else {
            $linesToBeCovered = [];
            $linesToBeUsed = [];
        }

        try {
            $codeCoverage->stop(true, $linesToBeCovered, $linesToBeUsed);
        } catch (\PHP_CodeCoverage_Exception $cce) {
            if ($status === \Codeception\Test\Test::STATUS_OK) {
                $this->getTestResultObject()->addError($this, $cce, $time);
            }
        }
    }
}
<?php
namespace Codeception\Test\Feature;

use Codeception\Test\Metadata;

trait IgnoreIfMetadataBlocked
{
    /**
     * @return Metadata
     */
    abstract protected function getMetadata();

    abstract protected function ignore($ignored);

    /**
     * @return \PHPUnit\Framework\TestResult
     */
    abstract protected function getTestResultObject();

    protected function ignoreIfMetadataBlockedStart()
    {
        if (!$this->getMetadata()->isBlocked()) {
            return;
        }

        $this->ignore(true);

        if ($this->getMetadata()->getSkip() !== null) {
            $this->getTestResultObject()->addFailure($this, new \PHPUnit\Framework\SkippedTestError((string)$this->getMetadata()->getSkip()), 0);
            return;
        }
        if ($this->getMetadata()->getIncomplete() !== null) {
            $this->getTestResultObject()->addFailure($this, new \PHPUnit\Framework\IncompleteTestError((string)$this->getMetadata()->getIncomplete()), 0);
            return;
        }
    }
}
<?php
namespace Codeception\Test;

use Codeception\TestInterface;
use Codeception\Util\ReflectionHelper;
use SebastianBergmann\Timer\Duration;
use SebastianBergmann\Timer\Timer;

/**
 * The most simple testcase (with only one test in it) which can be executed by PHPUnit/Codeception.
 * It can be extended with included traits. Turning on/off a trait should not break class functionality.
 *
 * Class has exactly one method to be executed for testing, wrapped with before/after callbacks delivered from included traits.
 * A trait providing before/after callback should contain corresponding protected methods: `{traitName}Start` and `{traitName}End`,
 * then this trait should be enabled in `hooks` property.
 *
 * Inherited class must implement `test` method.
 */
abstract class Test implements TestInterface, Interfaces\Descriptive
{
    use Feature\AssertionCounter;
    use Feature\CodeCoverage;
    use Feature\ErrorLogger;
    use Feature\MetadataCollector;
    use Feature\IgnoreIfMetadataBlocked;

    private $testResult;
    private $ignored = false;

    /**
     * Enabled traits with methods to be called before and after the test.
     *
     * @var array
     */
    protected $hooks = [
      'ignoreIfMetadataBlocked',
      'codeCoverage',
      'assertionCounter',
      'errorLogger'
    ];

    const STATUS_FAIL = 'fail';
    const STATUS_ERROR = 'error';
    const STATUS_OK = 'ok';
    const STATUS_PENDING = 'pending';

    /**
     * Everything inside this method is treated as a test.
     *
     * @return mixed
     */
    abstract public function test();

    /**
     * Test representation
     *
     * @return mixed
     */
    abstract public function toString();

    /**
     * Runs a test and collects its result in a TestResult instance.
     * Executes before/after hooks coming from traits.
     *
     * @param  \PHPUnit\Framework\TestResult $result
     * @return \PHPUnit\Framework\TestResult
     */
    final public function run(\PHPUnit\Framework\TestResult $result = null)
    {
        $this->testResult = $result;

        $status = self::STATUS_PENDING;
        $time = 0;
        $e = null;
        $timer = null;
        if (class_exists(Duration::class)) {
            $timer = new Timer();
        }

        $result->startTest($this);

        foreach ($this->hooks as $hook) {
            if (method_exists($this, $hook.'Start')) {
                $this->{$hook.'Start'}();
            }
        }

        $failedToStart = ReflectionHelper::readPrivateProperty($result, 'lastTestFailed');

        if (!$this->ignored && !$failedToStart) {
            if (null !== $timer) {
                $timer->start();
            } else {
                Timer::start();
            }

            try {
                $this->test();
                $status = self::STATUS_OK;
            } catch (\PHPUnit\Framework\AssertionFailedError $e) {
                $status = self::STATUS_FAIL;
            } catch (\PHPUnit\Framework\Exception $e) {
                $status = self::STATUS_ERROR;
            } catch (\Throwable $e) {
                $e     = new \PHPUnit\Framework\ExceptionWrapper($e);
                $status = self::STATUS_ERROR;
            } catch (\Exception $e) {
                $e     = new \PHPUnit\Framework\ExceptionWrapper($e);
                $status = self::STATUS_ERROR;
            }

            if (null !== $timer) {
                $time = $timer->stop()->asSeconds();
            } else {
                $time = Timer::stop();
            }
        }

        foreach (array_reverse($this->hooks) as $hook) {
            if (method_exists($this, $hook.'End')) {
                $this->{$hook.'End'}($status, $time, $e);
            }
        }

        $result->endTest($this, $time);
        return $result;
    }

    public function getTestResultObject()
    {
        return $this->testResult;
    }

    #[\ReturnTypeWillChange]
    /**
     * This class represents exactly one test
     * @return int
     */
    public function count()
    {
        return 1;
    }

    /**
     * Should a test be skipped (can be set from hooks)
     *
     * @param boolean $ignored
     */
    protected function ignore($ignored)
    {
        $this->ignored = $ignored;
    }
}
<?php
namespace Codeception\Test;

use Codeception\Configuration;
use Codeception\Exception\ModuleException;
use Codeception\Lib\Di;
use Codeception\Lib\Notification;
use Codeception\Scenario;
use Codeception\TestInterface;

/**
 * Represents tests from PHPUnit compatible format.
 */
class Unit extends \Codeception\PHPUnit\TestCase implements
    Interfaces\Reported,
    Interfaces\Dependent,
    TestInterface
{
    use \Codeception\Test\Feature\Stub;

    /**
     * @var Metadata
     */
    private $metadata;

    public function getMetadata()
    {
        if (!$this->metadata) {
            $this->metadata = new Metadata();
        }
        return $this->metadata;
    }

    protected function _setUp()
    {
        if ($this->getMetadata()->isBlocked()) {
            if ($this->getMetadata()->getSkip() !== null) {
                $this->markTestSkipped($this->getMetadata()->getSkip());
            }
            if ($this->getMetadata()->getIncomplete() !== null) {
                $this->markTestIncomplete($this->getMetadata()->getIncomplete());
            }
            return;
        }

        /** @var $di Di  **/
        $di = $this->getMetadata()->getService('di');
        $di->set(new Scenario($this));

        // auto-inject $tester property
        if (($this->getMetadata()->getCurrent('actor')) && ($property = lcfirst(Configuration::config()['actor_suffix']))) {
            $this->$property = $di->instantiate($this->getMetadata()->getCurrent('actor'));
        }

        // Auto inject into the _inject method
        $di->injectDependencies($this); // injecting dependencies
        $this->_before();
    }

    /**
     * @Override
     */
    protected function _before()
    {
    }

    protected function _tearDown()
    {
        $this->_after();
    }

    /**
     * @Override
     */
    protected function _after()
    {
    }

    /**
     * @param $module
     * @return \Codeception\Module
     * @throws ModuleException
     */
    public function getModule($module)
    {
        $modules = $this->getMetadata()->getCurrent('modules');
        if (!isset($modules[$module])) {
            throw new ModuleException($module, "Module can't be accessed");
        }
        return $modules[$module];
    }

    /**
     * Returns current values
     */
    public function getCurrent($current)
    {
        return $this->getMetadata()->getCurrent($current);
    }

    /**
     * @return array
     */
    public function getReportFields()
    {
        return [
            'name'    => $this->getName(),
            'class'   => get_class($this),
            'file'    => $this->getMetadata()->getFilename()
        ];
    }

    public function fetchDependencies()
    {
        $names = [];
        foreach ($this->getMetadata()->getDependencies() as $required) {
            if ((strpos($required, ':') === false) and method_exists($this, $required)) {
                $required = get_class($this) . ":$required";
            }
            $names[] = $required;
        }
        return $names;
    }

    /**
     * Reset PHPUnit's dependencies
     * @return bool
     */
    public function handleDependencies()
    {
        $dependencies = $this->fetchDependencies();
        if (empty($dependencies)) {
            return true;
        }
        $passed = $this->getTestResultObject()->passed();
        $dependencyInput = [];

        foreach ($dependencies as $dependency) {
            $dependency = str_replace(':', '::', $dependency); // Codeception => PHPUnit format
            if (strpos($dependency, '::') === false) {         // check it is method of same class
                $dependency = get_class($this) . '::' . $dependency;
            }
            if (isset($passed[$dependency])) {
                $dependencyInput[] = $passed[$dependency]['result'];
            } else {
                $dependencyInput[] = null;
            }
        }
        $this->setDependencyInput($dependencyInput);
        return true;
    }
}
<?php
namespace Codeception\Test;

use Codeception\Example;
use Codeception\Lib\Console\Message;
use Codeception\Lib\Parser;
use Codeception\Step\Comment;
use Codeception\Util\Annotation;
use Codeception\Util\ReflectionHelper;

/**
 * Executes tests delivered in Cest format.
 *
 * Handles loading of Cest cases, executing specific methods, following the order from `@before` and `@after` annotations.
 */
class Cest extends Test implements
    Interfaces\ScenarioDriven,
    Interfaces\Reported,
    Interfaces\Dependent,
    Interfaces\StrictCoverage
{
    use Feature\ScenarioLoader;
    /**
     * @var Parser
     */
    protected $parser;
    protected $testClassInstance;
    protected $testMethod;

    public function __construct($testClass, $methodName, $fileName)
    {
        $metadata = new Metadata();
        $metadata->setName($methodName);
        $metadata->setFilename($fileName);
        $this->setMetadata($metadata);
        $this->testClassInstance = $testClass;
        $this->testMethod = $methodName;
        $this->createScenario();
        $this->parser = new Parser($this->getScenario(), $this->getMetadata());
    }

    public function preload()
    {
        $this->scenario->setFeature($this->getSpecFromMethod());
        $code = $this->getSourceCode();
        $this->parser->parseFeature($code);
        $this->getMetadata()->setParamsFromAnnotations(Annotation::forMethod($this->testClassInstance, $this->testMethod)->raw());
        $this->getMetadata()->getService('di')->injectDependencies($this->testClassInstance);

        // add example params to feature
        if ($this->getMetadata()->getCurrent('example')) {
            $step = new Comment('', $this->getMetadata()->getCurrent('example'));
            $this->getScenario()->setFeature($this->getScenario()->getFeature() . ' | '. $step->getArgumentsAsString(100));
        }
    }

    public function getSourceCode()
    {
        $method = new \ReflectionMethod($this->testClassInstance, $this->testMethod);
        $start_line = $method->getStartLine() - 1; // it's actually - 1, otherwise you wont get the function() block
        $end_line = $method->getEndLine();
        $source = file($method->getFileName());
        return implode("", array_slice($source, $start_line, $end_line - $start_line));
    }

    public function getSpecFromMethod()
    {
        $text = $this->testMethod;
        $text = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\\1 \\2', $text);
        $text = preg_replace('/([a-z\d])([A-Z])/', '\\1 \\2', $text);
        $text = strtolower($text);
        return $text;
    }

    public function test()
    {
        $actorClass = $this->getMetadata()->getCurrent('actor');
        $I = new $actorClass($this->getScenario());
        try {
            $this->executeHook($I, 'before');
            $this->executeBeforeMethods($this->testMethod, $I);
            $this->executeTestMethod($I);
            $this->executeAfterMethods($this->testMethod, $I);
            $this->executeHook($I, 'passed');
        } catch (\Exception $e) {
            $this->executeHook($I, 'failed');
            // fails and errors are now handled by Codeception\PHPUnit\Listener
            throw $e;
        } finally {
            $this->executeHook($I, 'after');
        }
    }

    protected function executeHook($I, $hook)
    {
        if (is_callable([$this->testClassInstance, "_$hook"])) {
            $this->invoke("_$hook", [$I, $this->scenario]);
        }
    }

    protected function executeBeforeMethods($testMethod, $I)
    {
        $annotations = \PHPUnit\Util\Test::parseTestMethodAnnotations(get_class($this->testClassInstance), $testMethod);
        if (!empty($annotations['method']['before'])) {
            foreach ($annotations['method']['before'] as $m) {
                $this->executeContextMethod(trim($m), $I);
            }
        }
    }
    protected function executeAfterMethods($testMethod, $I)
    {
        $annotations = \PHPUnit\Util\Test::parseTestMethodAnnotations(get_class($this->testClassInstance), $testMethod);
        if (!empty($annotations['method']['after'])) {
            foreach ($annotations['method']['after'] as $m) {
                $this->executeContextMethod(trim($m), $I);
            }
        }
    }

    protected function executeContextMethod($context, $I)
    {
        if (method_exists($this->testClassInstance, $context)) {
            $this->executeBeforeMethods($context, $I);
            $this->invoke($context, [$I, $this->scenario]);
            $this->executeAfterMethods($context, $I);
            return;
        }
        throw new \LogicException(
            "Method $context defined in annotation but does not exist in " . get_class($this->testClassInstance)
        );
    }

    protected function invoke($methodName, array $context)
    {
        foreach ($context as $class) {
            $this->getMetadata()->getService('di')->set($class);
        }
        $this->getMetadata()->getService('di')->injectDependencies($this->testClassInstance, $methodName, $context);
    }
    protected function executeTestMethod($I)
    {
        if (!method_exists($this->testClassInstance, $this->testMethod)) {
            throw new \Exception("Method {$this->testMethod} can't be found in tested class");
        }

        if ($this->getMetadata()->getCurrent('example')) {
            $this->invoke($this->testMethod, [$I, $this->scenario, new Example($this->getMetadata()->getCurrent('example'))]);
            return;
        }
        $this->invoke($this->testMethod, [$I, $this->scenario]);
    }

    public function toString()
    {
        return sprintf('%s: %s', ReflectionHelper::getClassShortName($this->getTestClass()), Message::ucfirst($this->getFeature()));
    }

    public function getSignature()
    {
        return get_class($this->getTestClass()) . ":" . $this->getTestMethod();
    }

    public function getTestClass()
    {
        return $this->testClassInstance;
    }

    public function getTestMethod()
    {
        return $this->testMethod;
    }

    /**
     * @return array
     */
    public function getReportFields()
    {
        return [
            'file'    => $this->getFileName(),
            'name'    => $this->getTestMethod(),
            'class'   => get_class($this->getTestClass()),
            'feature' => $this->getFeature()
        ];
    }

    protected function getParser()
    {
        return $this->parser;
    }

    public function fetchDependencies()
    {
        $names = [];
        foreach ($this->getMetadata()->getDependencies() as $required) {
            if ((strpos($required, ':') === false) and method_exists($this->getTestClass(), $required)) {
                $required = get_class($this->getTestClass()) . ":$required";
            }
            $names[] = $required;
        }
        return $names;
    }

    public function getLinesToBeCovered()
    {
        $class  = get_class($this->getTestClass());
        $method = $this->getTestMethod();

        return \PHPUnit\Util\Test::getLinesToBeCovered($class, $method);
    }

    public function getLinesToBeUsed()
    {
        $class  = get_class($this->getTestClass());
        $method = $this->getTestMethod();

        return \PHPUnit\Util\Test::getLinesToBeUsed($class, $method);
    }
}
<?php
namespace Codeception;

/**
 * Contains all events dispatched by Codeception.
 *
 * @author tiger-seo <tiger.seo@gmail.com>
 */
final class Events
{
    /**
     * Private constructor. This class cannot be instantiated.
     */
    private function __construct()
    {
    }

    /**
     * The <b>MODULE_INIT</b> event occurs before modules are initialized.
     *
     * The event listener method receives a {@link Codeception\Event\SuiteEvent} instance.
     */
    const MODULE_INIT = 'module.init';

    /**
     * The <b>SUITE_INIT</b> event occurs when suite is initialized.
     * Modules are created and initialized, but Actor class is not loaded.
     *
     * The event listener method receives a {@link Codeception\Event\SuiteEvent} instance.
     */
    const SUITE_INIT = 'suite.init';

    /**
     * The <b>SUITE_BEFORE</b> event occurs before suite is executed.
     *
     * The event listener method receives a {@link Codeception\Event\SuiteEvent} instance.
     */
    const SUITE_BEFORE = 'suite.before';

    /**
     * The <b>SUITE_AFTER</b> event occurs after suite has been executed.
     *
     * The event listener method receives a {@link Codeception\Event\SuiteEvent} instance.
     */
    const SUITE_AFTER = 'suite.after';

    /**
     * The event listener method receives a {@link Codeception\Event\TestEvent} instance.
     */
    const TEST_START = 'test.start';

    /**
     * The event listener method receives a {@link Codeception\Event\TestEvent} instance.
     */
    const TEST_BEFORE = 'test.before';

    /**
     * The event listener method receives a {@link Codeception\Event\StepEvent} instance.
     */
    const STEP_BEFORE = 'step.before';

    /**
     * The event listener method receives a {@link Codeception\Event\StepEvent} instance.
     */
    const STEP_AFTER = 'step.after';

    /**
     * The <b>TEST_FAIL</b> event occurs whenever test has failed.
     *
     * The event listener method receives a {@link Codeception\Event\FailEvent} instance.
     */
    const TEST_FAIL = 'test.fail';

    /**
     * The <b>TEST_ERROR</b> event occurs whenever test got an error while being executed.
     *
     * The event listener method receives a {@link Codeception\Event\FailEvent} instance.
     */
    const TEST_ERROR = 'test.error';

    /**
     * The event listener method receives a {@link Codeception\Event\TestEvent} instance.
     */
    const TEST_PARSED = 'test.parsed';

    /**
     * The event listener method receives a {@link Codeception\Event\FailEvent} instance.
     */
    const TEST_INCOMPLETE = 'test.incomplete';

    /**
     * The event listener method receives a {@link Codeception\Event\FailEvent} instance.
     */
    const TEST_SKIPPED = 'test.skipped';


    /**
     * The event listener method receives a {@link Codeception\Event\FailEvent} instance.
     */
    const TEST_WARNING = 'test.warning';


    /**
     * The event listener method receives a {@link Codeception\Event\TestEvent} instance.
     */
    const TEST_SUCCESS = 'test.success';

    /**
     * The event listener method receives a {@link Codeception\Event\TestEvent} instance.
     */
    const TEST_AFTER = 'test.after';

    /**
     * The event listener method receives a {@link Codeception\Event\TestEvent} instance.
     */
    const TEST_END = 'test.end';

    /**
     * The event listener method receives a {@link Codeception\Event\FailEvent} instance.
     */
    const TEST_FAIL_PRINT = 'test.fail.print';

    /**
     * The event listener method receives a {@link Codeception\Event\PrintResultEvent} instance.
     */
    const RESULT_PRINT_AFTER = 'result.print.after';
}
<?php
namespace Codeception;

use Codeception\Event\TestEvent;

abstract class GroupObject extends Extension
{
    public static $group;

    public function _before(TestEvent $e)
    {
    }

    public function _after(TestEvent $e)
    {
    }

    public static function getSubscribedEvents()
    {
        $inheritedEvents = parent::getSubscribedEvents();
        $events = [];
        if (static::$group) {
            $events = [
                Events::TEST_BEFORE . '.' . static::$group => '_before',
                Events::TEST_AFTER . '.' . static::$group  => '_after',
            ];
        }
        return array_merge($events, $inheritedEvents);
    }
}
<?php
namespace Codeception;

use Codeception\Event\DispatcherWrapper;
use Codeception\Exception\ConfigurationException;
use Codeception\Subscriber\ExtensionLoader;
use Symfony\Component\EventDispatcher\EventDispatcher;

class Codecept
{
    use DispatcherWrapper;

    const VERSION = '4.1.23';

    /**
     * @var \Codeception\PHPUnit\Runner
     */
    protected $runner;
    /**
     * @var \PHPUnit\Framework\TestResult
     */
    protected $result;

    /**
     * @var \Codeception\CodeCoverage
     */
    protected $coverage;

    /**
     * @var \Symfony\Component\EventDispatcher\EventDispatcher
     */
    protected $dispatcher;

    /**
     * @var ExtensionLoader
     */
    protected $extensionLoader;

    /**
     * @var array
     */
    protected $options = [
        'silent'          => false,
        'debug'           => false,
        'steps'           => false,
        'html'            => false,
        'xml'             => false,
        'phpunit-xml'     => false,
        'no-redirect'     => true,
        'json'            => false,
        'tap'             => false,
        'report'          => false,
        'colors'          => false,
        'coverage'        => false,
        'coverage-xml'    => false,
        'coverage-html'   => false,
        'coverage-text'   => false,
        'coverage-crap4j' => false,
        'coverage-cobertura' => false,
        'coverage-phpunit'=> false,
        'groups'          => null,
        'excludeGroups'   => null,
        'filter'          => null,
        'env'             => null,
        'fail-fast'       => false,
        'ansi'            => true,
        'verbosity'       => 1,
        'interactive'     => true,
        'no-rebuild'      => false,
        'quiet'           => false,
    ];

    protected $config = [];

    /**
     * @var array
     */
    protected $extensions = [];

    public function __construct($options = [])
    {
        $this->result = new \PHPUnit\Framework\TestResult;
        $this->dispatcher = new EventDispatcher();
        $this->extensionLoader = new ExtensionLoader($this->dispatcher);

        $baseOptions = $this->mergeOptions($options);
        $this->extensionLoader->bootGlobalExtensions($baseOptions); // extensions may override config

        $this->config = Configuration::config();
        $this->options = $this->mergeOptions($options); // options updated from config

        $this->registerSubscribers();
        $this->registerPHPUnitListeners();
        $this->registerPrinter();
    }

    /**
     * Merges given options with default values and current configuration
     *
     * @param array $options options
     * @return array
     * @throws ConfigurationException
     */
    protected function mergeOptions($options)
    {
        $config = Configuration::config();
        $baseOptions = array_merge($this->options, $config['settings']);
        return array_merge($baseOptions, $options);
    }

    protected function registerPHPUnitListeners()
    {
        $listener = new PHPUnit\Listener($this->dispatcher);
        $this->result->addListener($listener);
    }

    public function registerSubscribers()
    {
        // required
        $this->dispatcher->addSubscriber(new Subscriber\GracefulTermination());
        $this->dispatcher->addSubscriber(new Subscriber\ErrorHandler());
        $this->dispatcher->addSubscriber(new Subscriber\Dependencies());
        $this->dispatcher->addSubscriber(new Subscriber\Bootstrap());
        $this->dispatcher->addSubscriber(new Subscriber\PrepareTest());
        $this->dispatcher->addSubscriber(new Subscriber\Module());
        $this->dispatcher->addSubscriber(new Subscriber\BeforeAfterTest());

        // optional
        if (!$this->options['no-rebuild']) {
            $this->dispatcher->addSubscriber(new Subscriber\AutoRebuild());
        }
        if (!$this->options['silent']) {
            $this->dispatcher->addSubscriber(new Subscriber\Console($this->options));
        }
        if ($this->options['fail-fast']) {
            $this->dispatcher->addSubscriber(new Subscriber\FailFast($this->options['fail-fast']));
        }

        if ($this->options['coverage']) {
            $this->dispatcher->addSubscriber(new Coverage\Subscriber\Local($this->options));
            $this->dispatcher->addSubscriber(new Coverage\Subscriber\LocalServer($this->options));
            $this->dispatcher->addSubscriber(new Coverage\Subscriber\RemoteServer($this->options));
            $this->dispatcher->addSubscriber(new Coverage\Subscriber\Printer($this->options));
        }
        $this->dispatcher->addSubscriber($this->extensionLoader);
        $this->extensionLoader->registerGlobalExtensions();
    }

    public function run($suite, $test = null, array $config = null)
    {
        ini_set(
            'memory_limit',
            isset($this->config['settings']['memory_limit']) ? $this->config['settings']['memory_limit'] : '1024M'
        );

        $config = $config ?: Configuration::config();
        $config = Configuration::suiteSettings($suite, $config);

        $selectedEnvironments = $this->options['env'];

        if (!$selectedEnvironments || empty($config['env'])) {
            $this->runSuite($config, $suite, $test);
            return;
        }

        // Iterate over all unique environment sets and runs the given suite with each of the merged configurations.
        foreach (array_unique($selectedEnvironments) as $envList) {
            $envSet = explode(',', $envList);
            $suiteEnvConfig = $config;

            // contains a list of the environments used in this suite configuration env set.
            $envConfigs = [];
            foreach ($envSet as $currentEnv) {
                if (isset($config['env'])) {
                    // The $settings['env'] actually contains all parsed configuration files as a
                    // filename => filecontents key-value array. If there is no configuration file for the
                    // $currentEnv the merge will be skipped.
                    if (!array_key_exists($currentEnv, $config['env'])) {
                        return;
                    }

                    // Merge configuration consecutively with already build configuration
                    $suiteEnvConfig = Configuration::mergeConfigs($suiteEnvConfig, $config['env'][$currentEnv]);
                    $envConfigs[] = $currentEnv;
                }
            }

            $suiteEnvConfig['current_environment'] = implode(',', $envConfigs);

            if (empty($suiteEnvConfig)) {
                continue;
            }
            $suiteToRun = $suite;
            if (!empty($envList)) {
                $suiteToRun .= ' (' . implode(', ', $envSet) . ')';
            }
            $this->runSuite($suiteEnvConfig, $suiteToRun, $test);
        }
    }

    public function runSuite($settings, $suite, $test = null)
    {
        $suiteManager = new SuiteManager($this->dispatcher, $suite, $settings);
        $suiteManager->initialize();
        srand($this->options['seed']);
        $suiteManager->loadTests($test);
        srand();
        $suiteManager->run($this->runner, $this->result, $this->options);
        return $this->result;
    }

    public static function versionString()
    {
        return 'Codeception PHP Testing Framework v' . self::VERSION;
    }

    public function printResult()
    {
        $result = $this->getResult();
        $result->flushListeners();

        $printer = $this->runner->getPrinter();
        $printer->printResult($result);

        $this->dispatch($this->dispatcher, Events::RESULT_PRINT_AFTER, new Event\PrintResultEvent($result, $printer));
    }

    /**
     * @return \PHPUnit\Framework\TestResult
     */
    public function getResult()
    {
        return $this->result;
    }

    public function getOptions()
    {
        return $this->options;
    }

    /**
     * @return EventDispatcher
     */
    public function getDispatcher()
    {
        return $this->dispatcher;
    }

    protected function registerPrinter()
    {
        $printer = new PHPUnit\ResultPrinter\UI($this->dispatcher, $this->options);
        $this->runner = new PHPUnit\Runner();
        $this->runner->setPrinter($printer);
    }
}
<?php

namespace Codeception;

use Codeception\Exception\ConfigurationException;
use Codeception\Lib\Notification;
use Codeception\Lib\ParamsLoader;
use Codeception\Util\Autoload;
use Codeception\Util\Template;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;

class Configuration
{
    protected static $suites = [];

    /**
     * @var array Current configuration
     */
    protected static $config = null;

    /**
     * @var array environmental files configuration cache
     */
    protected static $envConfig = [];

    /**
     * @var string Directory containing main configuration file.
     * @see self::projectDir()
     */
    protected static $dir = null;

    /**
     * @var string Directory of a base configuration file for the project with includes.
     * @see self::projectDir()
     */
    protected static $baseDir = null;

    /**
     * @var string Current project output directory.
     */
    protected static $outputDir = null;

    /**
     * @var string Current project data directory. This directory is used to hold
     * sql dumps and other things needed for current project tests.
     */
    protected static $dataDir = null;

    /**
     * @var string Directory with test support files like Actors, Helpers, PageObjects, etc
     */
    protected static $supportDir = null;

    /**
     * @var string Directory containing environment configuration files.
     */
    protected static $envsDir = null;

    /**
     * @var string Directory containing tests and suites of the current project.
     */
    protected static $testsDir = null;

    public static $lock = false;

    protected static $di;

    /**
     * @var array Default config
     */
    public static $defaultConfig = [
        'actor_suffix'=> 'Tester',
        'namespace'  => '',
        'include'    => [],
        'paths'      => [],
        'extends'    => null,
        'suites'     => [],
        'modules'    => [],
        'extensions' => [
            'enabled'  => [],
            'config'   => [],
            'commands' => [],
        ],
        'reporters'  => [
            'xml'         => 'Codeception\PHPUnit\Log\JUnit',
            'html'        => 'Codeception\PHPUnit\ResultPrinter\HTML',
            'report'      => 'Codeception\PHPUnit\ResultPrinter\Report',
            'tap'         => 'PHPUnit\Util\Log\TAP',
            'json'        => 'PHPUnit\Util\Log\JSON',
            'phpunit-xml' => 'Codeception\PHPUnit\Log\PhpUnit',
        ],
        'groups'     => [],
        'bootstrap'  => false,
        'settings'   => [
            'colors'                    => true,
            'bootstrap'                 => false,
            'strict_xml'                => false,
            'lint'                      => true,
            'backup_globals'            => true,
            'log_incomplete_skipped'    => false,
            'report_useless_tests'      => false,
            'disallow_test_output'      => false,
            'be_strict_about_changes_to_global_state' => false,
            'shuffle'     => false,
        ],
        'coverage'   => [],
        'params'     => [],
        'gherkin'    => []
    ];

    public static $defaultSuiteSettings = [
        'actor'       => null,
        'class_name'  => null, // Codeception <2.3 compatibility
        'modules'     => [
            'enabled' => [],
            'config'  => [],
            'depends' => []
        ],
        'step_decorators' => 'Codeception\Step\ConditionalAssertion',
        'path'        => null,
        'extends'     => null,
        'namespace'   => null,
        'groups'      => [],
        'formats'     => [],
        'shuffle'     => false,
        'extensions'  => [ // suite extensions
            'enabled' => [],
            'config' => [],
        ],
        'error_level' => 'E_ALL & ~E_STRICT & ~E_DEPRECATED',
    ];

    protected static $params;

    /**
     * Loads global config file which is `codeception.yml` by default.
     * When config is already loaded - returns it.
     *
     * @param null $configFile
     * @return array
     * @throws Exception\ConfigurationException
     */
    public static function config($configFile = null)
    {
        if (!$configFile && self::$config) {
            return self::$config;
        }

        if (self::$config && self::$lock) {
            return self::$config;
        }

        if ($configFile === null) {
            $configFile = getcwd() . DIRECTORY_SEPARATOR . 'codeception.yml';
        }

        if (is_dir($configFile)) {
            $configFile = $configFile . DIRECTORY_SEPARATOR . 'codeception.yml';
        }

        $dir = realpath(dirname($configFile));
        self::$dir = $dir;

        // set the one default base directory for included setup
        if (!self::$baseDir) {
            self::$baseDir = $dir;
        }

        $configDistFile = $dir . DIRECTORY_SEPARATOR . 'codeception.dist.yml';

        if (!(file_exists($configDistFile) || file_exists($configFile))) {
            throw new ConfigurationException("Configuration file could not be found.\nRun `bootstrap` to initialize Codeception.", 404);
        }

        // Preload config to retrieve params such that they are applied to codeception config file below
        $tempConfig = self::$defaultConfig;

        $distConfigContents = "";
        if (file_exists($configDistFile)) {
            $distConfigContents = file_get_contents($configDistFile);
            $tempConfig = self::mergeConfigs($tempConfig, self::getConfFromContents($distConfigContents, $configDistFile));
        }

        $configContents = "";
        if (file_exists($configFile)) {
            $configContents = file_get_contents($configFile);
            $tempConfig = self::mergeConfigs($tempConfig, self::getConfFromContents($configContents, $configFile));
        }
        self::prepareParams($tempConfig);

        // load config using params
        $config = self::mergeConfigs(self::$defaultConfig, self::getConfFromContents($distConfigContents, $configDistFile));
        $config = self::mergeConfigs($config, self::getConfFromContents($configContents, $configFile));

        if ($config == self::$defaultConfig) {
            throw new ConfigurationException("Configuration file is invalid");
        }

        // we check for the "extends" key in the yml file
        if (isset($config['extends'])) {
            // and now we search for the file
            $presetFilePath = codecept_absolute_path($config['extends']);
            if (file_exists($presetFilePath)) {
                // and merge it with our configuration file
                $config = self::mergeConfigs(self::getConfFromFile($presetFilePath), $config);
            }
        }

        self::$config = $config;

        // compatibility with suites created by Codeception < 2.3.0
        if (!isset($config['paths']['output']) and isset($config['paths']['log'])) {
            $config['paths']['output'] = $config['paths']['log'];
        }

        if (isset(self::$config['actor'])) {
            self::$config['actor_suffix'] = self::$config['actor']; // old compatibility
        }

        if (!isset($config['paths']['support']) and isset($config['paths']['helpers'])) {
            $config['paths']['support'] = $config['paths']['helpers'];
        }

        if (!isset($config['paths']['output'])) {
            throw new ConfigurationException('Output path is not defined by key "paths: output"');
        }

        self::$outputDir = $config['paths']['output'];

        // fill up includes with wildcard expansions
        $config['include'] = self::expandWildcardedIncludes($config['include']);

        // config without tests, for inclusion of other configs
        if (count($config['include'])) {
            self::$config = $config;
            if (!isset($config['paths']['tests'])) {
                 return $config;
            }
        }

        if (!isset($config['paths']['tests'])) {
            throw new ConfigurationException(
                'Tests directory is not defined in Codeception config by key "paths: tests:"'
            );
        }

        if (!isset($config['paths']['data'])) {
            throw new ConfigurationException('Data path is not defined Codeception config by key "paths: data"');
        }

        if (!isset($config['paths']['support'])) {
            throw new ConfigurationException('Helpers path is not defined by key "paths: support"');
        }

        self::$dataDir = $config['paths']['data'];
        self::$supportDir = $config['paths']['support'];
        self::$testsDir = $config['paths']['tests'];

        if (isset($config['paths']['envs'])) {
            self::$envsDir = $config['paths']['envs'];
        }

        Autoload::addNamespace(self::$config['namespace'], self::supportDir());

        if ($config['settings']['bootstrap']) {
            $bootstrap = self::$config['settings']['bootstrap'];
            Notification::deprecate("'settings: bootstrap: $bootstrap' option is deprecated! Replace it with: 'bootstrap: $bootstrap' (not under settings section). See: https://codeception.com/docs/reference/Configuration");
            try {
                self::loadBootstrap($bootstrap, self::testsDir());
            } catch (ConfigurationException $exception) {
                Notification::deprecate("Bootstrap file ($bootstrap) is defined in configuration but can't be loaded. Disable 'settings: bootstrap:' configuration to remove this message");
            }
        }
        self::loadBootstrap($config['bootstrap'], self::testsDir());
        self::loadSuites();

        return $config;
    }

    public static function loadBootstrap($bootstrap, $path)
    {
        if (!$bootstrap) {
            return;
        }

        $bootstrap = \Codeception\Util\PathResolver::isPathAbsolute($bootstrap)
            ? $bootstrap
            : rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $bootstrap;


        if (!file_exists($bootstrap)) {
            throw new ConfigurationException("Bootstrap file $bootstrap can't be loaded");
        }
        require_once $bootstrap;
    }

    protected static function loadSuites()
    {
        $suites = Finder::create()
            ->files()
            ->name('*.{suite,suite.dist}.yml')
            ->in(self::$dir . DIRECTORY_SEPARATOR . self::$testsDir)
            ->depth('< 1')
            ->sortByName();

        self::$suites = [];

        foreach (array_keys(self::$config['suites']) as $suite) {
            self::$suites[$suite] = $suite;
        }

        /** @var SplFileInfo $suite */
        foreach ($suites as $suite) {
            preg_match('~(.*?)(\.suite|\.suite\.dist)\.yml~', $suite->getFilename(), $matches);
            self::$suites[$matches[1]] = $matches[1];
        }
    }

    /**
     * Returns suite configuration. Requires suite name and global config used (Configuration::config)
     *
     * @param string $suite
     * @param array $config
     * @return array
     * @throws \Exception
     */
    public static function suiteSettings($suite, $config)
    {
        // cut namespace name from suite name
        if ($suite != $config['namespace'] && substr($suite, 0, strlen($config['namespace'])) == $config['namespace']) {
            $suite = substr($suite, strlen($config['namespace']));
        }

        if (!in_array($suite, self::$suites)) {
            throw new ConfigurationException("Suite $suite was not loaded");
        }

        // load global config
        $globalConf = $config['settings'];
        foreach (['modules', 'coverage', 'namespace', 'groups', 'env', 'gherkin', 'extensions'] as $key) {
            if (isset($config[$key])) {
                $globalConf[$key] = $config[$key];
            }
        }
        $settings = self::mergeConfigs(self::$defaultSuiteSettings, $globalConf);

        // load suite config
        $settings = self::loadSuiteConfig($suite, $config['paths']['tests'], $settings);
        // load from environment configs
        if (isset($config['paths']['envs'])) {
            $envConf = self::loadEnvConfigs(self::$dir . DIRECTORY_SEPARATOR . $config['paths']['envs']);
            $settings = self::mergeConfigs($settings, $envConf);
        }

        if (!$settings['actor']) {
            // Codeception 2.2 compatibility
            $settings['actor'] = $settings['class_name'];
        }

        if (!$settings['path']) {
            // take a suite path from its name
            $settings['path'] = $suite;
        }

        $config['paths']['tests'] = str_replace('/', DIRECTORY_SEPARATOR, $config['paths']['tests']);

        $settings['path'] = self::$dir . DIRECTORY_SEPARATOR . $config['paths']['tests']
            . DIRECTORY_SEPARATOR . $settings['path'] . DIRECTORY_SEPARATOR;



        return $settings;
    }

    /**
     * Loads environments configuration from set directory
     *
     * @param string $path path to the directory
     * @return array
     */
    protected static function loadEnvConfigs($path)
    {
        if (isset(self::$envConfig[$path])) {
            return self::$envConfig[$path];
        }
        if (!is_dir($path)) {
            self::$envConfig[$path] = [];
            return self::$envConfig[$path];
        }

        $envFiles = Finder::create()
            ->files()
            ->name('*.yml')
            ->in($path)
            ->depth('< 2');

        $envConfig = [];
        /** @var SplFileInfo $envFile */
        foreach ($envFiles as $envFile) {
            $env = str_replace(['.dist.yml', '.yml'], '', $envFile->getFilename());
            $envConfig[$env] = [];
            $envPath = $path;
            if ($envFile->getRelativePath()) {
                $envPath .= DIRECTORY_SEPARATOR . $envFile->getRelativePath();
            }
            foreach (['.dist.yml', '.yml'] as $suffix) {
                $envConf = self::getConfFromFile($envPath . DIRECTORY_SEPARATOR . $env . $suffix, null);
                if ($envConf === null) {
                    continue;
                }
                $envConfig[$env] = self::mergeConfigs($envConfig[$env], $envConf);
            }
        }

        self::$envConfig[$path] = ['env' => $envConfig];
        return self::$envConfig[$path];
    }

    /**
     * Loads configuration from Yaml data
     *
     * @param string $contents Yaml config file contents
     * @param string $filename which is supposed to be loaded
     * @return array
     * @throws ConfigurationException
     */
    protected static function getConfFromContents($contents, $filename = '(.yml)')
    {
        if (self::$params) {
            $template = new Template($contents, '%', '%');
            $template->setVars(self::$params);
            $contents = $template->produce();
        }

        try {
            return Yaml::parse($contents);
        } catch (ParseException $exception) {
            throw new ConfigurationException(
                sprintf(
                    "Error loading Yaml config from `%s`\n \n%s\nRead more about Yaml format https://goo.gl/9UPuEC",
                    $filename,
                    $exception->getMessage()
                )
            );
        }
    }

    /**
     * Loads configuration from Yaml file or returns given value if the file doesn't exist
     *
     * @param string $filename filename
     * @param mixed $nonExistentValue value used if filename is not found
     * @return array
     * @throws ConfigurationException
     */
    protected static function getConfFromFile($filename, $nonExistentValue = [])
    {
        if (file_exists($filename)) {
            $yaml = file_get_contents($filename);
            return self::getConfFromContents($yaml, $filename);
        }
        return $nonExistentValue;
    }

    public static function suites()
    {
        return self::$suites;
    }

    /**
     * Return list of enabled modules according suite config.
     *
     * @param array $settings suite settings
     * @return array
     */
    public static function modules($settings)
    {
        return array_filter(
            array_map(
                function ($m) {
                    return is_array($m) ? key($m) : $m;
                },
                $settings['modules']['enabled'],
                array_keys($settings['modules']['enabled'])
            ),
            function ($m) use ($settings) {
                if (!isset($settings['modules']['disabled'])) {
                    return true;
                }
                return !in_array($m, $settings['modules']['disabled']);
            }
        );
    }

    public static function isExtensionEnabled($extensionName)
    {
        return isset(self::$config['extensions']['enabled'])
        && in_array($extensionName, self::$config['extensions']['enabled']);
    }

    /**
     * Returns current path to `_data` dir.
     * Use it to store database fixtures, sql dumps, or other files required by your tests.
     *
     * @return string
     */
    public static function dataDir()
    {
        return self::$dir . DIRECTORY_SEPARATOR . self::$dataDir . DIRECTORY_SEPARATOR;
    }

    /**
     * Return current path to `_helpers` dir.
     * Helpers are custom modules.
     *
     * @return string
     */
    public static function supportDir()
    {
        return self::$dir . DIRECTORY_SEPARATOR . self::$supportDir . DIRECTORY_SEPARATOR;
    }

    /**
     * Returns actual path to current `_output` dir.
     * Use it in Helpers or Groups to save result or temporary files.
     *
     * @return string
     * @throws Exception\ConfigurationException
     */
    public static function outputDir()
    {
        if (!self::$outputDir) {
            throw new ConfigurationException("Path for output not specified. Please, set output path in global config");
        }

        $dir = self::$outputDir . DIRECTORY_SEPARATOR;
        if (!codecept_is_path_absolute($dir)) {
            $dir = self::$dir . DIRECTORY_SEPARATOR . $dir;
        }

        if (!file_exists($dir)) {
            @mkdir($dir, 0777, true);
        }

        if (!is_writable($dir)) {
            @chmod($dir, 0777);
        }

        if (!is_writable($dir)) {
            throw new ConfigurationException(
                "Path for output is not writable. Please, set appropriate access mode for output path: {$dir}"
            );
        }

        return $dir;
    }

    /**
     * Compatibility alias to `Configuration::logDir()`
     * @return string
     * @throws ConfigurationException
     */
    public static function logDir()
    {
        return self::outputDir();
    }

    /**
     * Returns path to the root of your project.
     * Basically returns path to current `codeception.yml` loaded.
     * Use this method instead of `__DIR__`, `getcwd()` or anything else.
     * @return string
     */
    public static function projectDir()
    {
        return self::$dir . DIRECTORY_SEPARATOR;
    }

    /**
     * Returns path to the base dir for config which consists with included setup
     * Returns path to `codeception.yml` which was executed.
     * If config doesn't have "include" section the result is the same as `projectDir()`
     * @return string
     */
    public static function baseDir()
    {
        return self::$baseDir . DIRECTORY_SEPARATOR;
    }


    /**
     * Returns path to tests directory
     *
     * @return string
     */
    public static function testsDir()
    {
        return self::$dir . DIRECTORY_SEPARATOR . self::$testsDir . DIRECTORY_SEPARATOR;
    }

    /**
     * Return current path to `_envs` dir.
     * Use it to store environment specific configuration.
     *
     * @return string
     */
    public static function envsDir()
    {
        if (!self::$envsDir) {
            return null;
        }
        return self::$dir . DIRECTORY_SEPARATOR . self::$envsDir . DIRECTORY_SEPARATOR;
    }

    /**
     * Is this a meta-configuration file that just points to other `codeception.yml`?
     * If so, it may have no tests by itself.
     *
     * @return bool
     */
    public static function isEmpty()
    {
        return !(bool)self::$testsDir;
    }

    /**
     * Adds parameters to config
     *
     * @param array $config
     * @return array
     */
    public static function append(array $config = [])
    {
        self::$config = self::mergeConfigs(self::$config, $config);

        if (isset(self::$config['paths']['output'])) {
            self::$outputDir = self::$config['paths']['output'];
        }
        if (isset(self::$config['paths']['data'])) {
            self::$dataDir = self::$config['paths']['data'];
        }
        if (isset(self::$config['paths']['support'])) {
            self::$supportDir = self::$config['paths']['support'];
        }
        if (isset(self::$config['paths']['tests'])) {
            self::$testsDir = self::$config['paths']['tests'];
        }

        return self::$config;
    }

    public static function mergeConfigs($a1, $a2)
    {
        if (!is_array($a1)) {
            return $a2;
        }

        if (!is_array($a2)) {
            return $a1;
        }

        $res = [];

        // for sequential arrays
        if (isset($a1[0], $a2[0])) {
            return array_values(array_unique(array_merge_recursive($a2, $a1), SORT_REGULAR));
        }

        // for associative arrays
        foreach ($a2 as $k2 => $v2) {
            if (!isset($a1[$k2])) { // if no such key
                $res[$k2] = $v2;
                unset($a1[$k2]);
                continue;
            }

            $res[$k2] = self::mergeConfigs($a1[$k2], $v2);
            unset($a1[$k2]);
        }

        foreach ($a1 as $k1 => $v1) { // only single elements here left
            $res[$k1] = $v1;
        }

        return $res;
    }

    /**
     * Loads config from *.dist.suite.yml and *.suite.yml
     *
     * @param $suite
     * @param $path
     * @param $settings
     * @return array
     * @throws ConfigurationException
     */
    protected static function loadSuiteConfig($suite, $path, $settings)
    {
        if (isset(self::$config['suites'][$suite])) {
            // bundled config
            return self::mergeConfigs($settings, self::$config['suites'][$suite]);
        }

        $suiteDir = self::$dir . DIRECTORY_SEPARATOR . $path;

        $suiteDistConf = self::getConfFromFile($suiteDir . DIRECTORY_SEPARATOR . "$suite.suite.dist.yml");
        $suiteConf = self::getConfFromFile($suiteDir . DIRECTORY_SEPARATOR . "$suite.suite.yml");

        // now we check the suite config file, if a extends key is defined
        if (isset($suiteConf['extends'])) {
            $presetFilePath = codecept_is_path_absolute($suiteConf['extends'])
                ? $suiteConf['extends'] // If path is absolute – use it
                : realpath($suiteDir . DIRECTORY_SEPARATOR . $suiteConf['extends']); // Otherwise try to locate it in the suite dir

            if (file_exists($presetFilePath)) {
                $settings = self::mergeConfigs(self::getConfFromFile($presetFilePath), $settings);
            }
        }

        $settings = self::mergeConfigs($settings, $suiteDistConf);
        $settings = self::mergeConfigs($settings, $suiteConf);

        return $settings;
    }

    /**
     * Replaces wildcarded items in include array with real paths.
     *
     * @param $includes
     * @return array
     * @throws ConfigurationException
     */
    protected static function expandWildcardedIncludes(array $includes)
    {
        if (empty($includes)) {
            return $includes;
        }
        $expandedIncludes = [];
        foreach ($includes as $include) {
            $expandedIncludes = array_merge($expandedIncludes, self::expandWildcardsFor($include));
        }
        return $expandedIncludes;
    }

    /**
     * Finds config files in given wildcarded include path.
     * Returns the expanded paths or the original if not a wildcard.
     *
     * @param $include
     * @return array
     * @throws ConfigurationException
     */
    protected static function expandWildcardsFor($include)
    {
        if (1 !== preg_match('/[\?\.\*]/', $include)) {
            return [$include,];
        }

        try {
            $configFiles = Finder::create()->files()
                ->name('/codeception(\.dist\.yml|\.yml)/')
                ->in(self::$dir . DIRECTORY_SEPARATOR . $include);
        } catch (\InvalidArgumentException $e) {
            throw new ConfigurationException(
                "Configuration file(s) could not be found in \"$include\"."
            );
        }

        $paths = [];
        foreach ($configFiles as $file) {
            $paths[] = codecept_relative_path($file->getPath());
        }

        return $paths;
    }

    private static function prepareParams($settings)
    {
        self::$params = [];
        $paramsLoader = new ParamsLoader();

        foreach ($settings['params'] as $paramStorage) {
            static::$params = array_merge(self::$params, $paramsLoader->load($paramStorage));
        }
    }
}
<?php
namespace Codeception\Util;

class ArrayContainsComparator
{
    /**
     * @var array
     */
    protected $haystack = [];

    public function __construct($haystack)
    {
        $this->haystack = $haystack;
    }

    /**
     * @return array
     */
    public function getHaystack()
    {
        return $this->haystack;
    }

    public function containsArray(array $needle)
    {
        return $needle == $this->arrayIntersectRecursive($needle, $this->haystack);
    }

    /**
     * @author nleippe@integr8ted.com
     * @author tiger.seo@gmail.com
     * @link http://www.php.net/manual/en/function.array-intersect-assoc.php#39822
     *
     * @param mixed $arr1
     * @param mixed $arr2
     *
     * @return array|bool
     */
    private function arrayIntersectRecursive($arr1, $arr2)
    {
        if (!is_array($arr1) || !is_array($arr2)) {
            return false;
        }
        // if it is not an associative array we do not compare keys
        if ($this->arrayIsSequential($arr1) && $this->arrayIsSequential($arr2)) {
            return $this->sequentialArrayIntersect($arr1, $arr2);
        }
        return $this->associativeArrayIntersect($arr1, $arr2);
    }

    /**
     * This array has sequential keys?
     *
     * @param array $array
     *
     * @return bool
     */
    private function arrayIsSequential(array $array)
    {
        return array_keys($array) === range(0, count($array) - 1);
    }

    /**
     * @param array $arr1
     * @param array $arr2
     * @return array
     */
    private function sequentialArrayIntersect(array $arr1, array $arr2)
    {
        $ret = [];

        // Do not match the same item of $arr2 against multiple items of $arr1
        $matchedKeys = [];
        foreach ($arr1 as $key1 => $value1) {
            foreach ($arr2 as $key2 => $value2) {
                if (isset($matchedKeys[$key2])) {
                    continue;
                }

                $return = $this->arrayIntersectRecursive($value1, $value2);
                if ($return !== false && $return == $value1) {
                    $ret[$key1] = $return;
                    $matchedKeys[$key2] = true;
                    break;
                }

                if ($this->isEqualValue($value1, $value2)) {
                    $ret[$key1] = $value1;
                    $matchedKeys[$key2] = true;
                    break;
                }
            }
        }

        return $ret;
    }

    /**
     * @param array $arr1
     * @param array $arr2
     *
     * @return array|bool|null
     */
    private function associativeArrayIntersect(array $arr1, array $arr2)
    {
        $commonKeys = array_intersect(array_keys($arr1), array_keys($arr2));

        $ret = [];
        foreach ($commonKeys as $key) {
            $return = $this->arrayIntersectRecursive($arr1[$key], $arr2[$key]);
            if ($return !== false) {
                $ret[$key] = $return;
                continue;
            }
            if ($this->isEqualValue($arr1[$key], $arr2[$key])) {
                $ret[$key] = $arr1[$key];
            }
        }

        if (empty($commonKeys)) {
            foreach ($arr2 as $arr) {
                $return = $this->arrayIntersectRecursive($arr1, $arr);
                if ($return && $return == $arr1) {
                    return $return;
                }
            }
        }

        if (count($ret) < min(count($arr1), count($arr2))) {
            return null;
        }

        return $ret;
    }

    private function isEqualValue($val1, $val2)
    {
        if (is_numeric($val1)) {
            $val1 = (string) $val1;
        }

        if (is_numeric($val2)) {
            $val2 = (string) $val2;
        }

        return $val1 === $val2;
    }
}
<?php

namespace Codeception\Util;

use Codeception\Exception\ConfigurationException;

class PathResolver
{
    /**
     * Returns path to a given directory relative to $projDir.
     * @param string $path
     * @param string $projDir
     * @param string $dirSep
     * @return string
     */
    public static function getRelativeDir($path, $projDir, $dirSep = DIRECTORY_SEPARATOR)
    {
        // ensure $projDir ends with a trailing $dirSep
        $projDir = preg_replace('/'.preg_quote($dirSep, '/').'*$/', $dirSep, $projDir);
        // if $path is a within $projDir
        if (self::fsCaseStrCmp(substr($path, 0, strlen($projDir)), $projDir, $dirSep) == 0) {
            // simply chop it off the front
            return substr($path, strlen($projDir));
        }
        // Identify any absoluteness prefix (like '/' in Unix or "C:\\" in Windows)
        $pathAbsPrefix = self::getPathAbsolutenessPrefix($path, $dirSep);
        $projDirAbsPrefix = self::getPathAbsolutenessPrefix($projDir, $dirSep);
        $sameAbsoluteness = (self::fsCaseStrCmp($pathAbsPrefix['wholePrefix'], $projDirAbsPrefix['wholePrefix'], $dirSep) == 0);
        if (!$sameAbsoluteness) {
            // if the $projDir and $path aren't relative to the same
            // thing, we can't make a relative path.

            // if we're relative to the same device ...
            if (strlen($pathAbsPrefix['devicePrefix']) &&
                (self::fsCaseStrCmp($pathAbsPrefix['devicePrefix'], $projDirAbsPrefix['devicePrefix'], $dirSep) == 0)
            ) {
                // ... shave that off
                return substr($path, strlen($pathAbsPrefix['devicePrefix']));
            }
            // Return the input unaltered
            return $path;
        }
        // peel off optional absoluteness prefixes and convert
        // $path and $projDir to an subdirectory path array
        $relPathParts = array_filter(explode($dirSep, substr($path, strlen($pathAbsPrefix['wholePrefix']))), 'strlen');
        $relProjDirParts = array_filter(explode($dirSep, substr($projDir, strlen($projDirAbsPrefix['wholePrefix']))), 'strlen');
        // While there are any, peel off any common parent directories
        // from the beginning of the $projDir and $path
        while ((count($relPathParts) > 0) && (count($relProjDirParts) > 0) &&
            (self::fsCaseStrCmp($relPathParts[0], $relProjDirParts[0], $dirSep) == 0)
        ) {
            array_shift($relPathParts);
            array_shift($relProjDirParts);
        }
        if (count($relProjDirParts) > 0) {
            // prefix $relPath with '..' for all remaining unmatched $projDir
            // subdirectories
            $relPathParts = array_merge(array_fill(0, count($relProjDirParts), '..'), $relPathParts);
        }
        // only append a trailing seperator if one is already present
        $trailingSep = preg_match('/'.preg_quote($dirSep, '/').'$/', $path) ? $dirSep : '';
        // convert array of dir paths back into a string path
        return implode($dirSep, $relPathParts).$trailingSep;
    }
    /**
     * FileSystem Case String Compare
     * compare two strings with the filesystem's case-sensitiveness
     *
     * @param string $str1
     * @param string $str2
     * @param string $dirSep
     * @return int -1 / 0 / 1 for < / = / > respectively
     */
    private static function fsCaseStrCmp($str1, $str2, $dirSep = DIRECTORY_SEPARATOR)
    {
        $cmpFn = self::isWindows($dirSep) ? 'strcasecmp' : 'strcmp';
        return $cmpFn($str1, $str2);
    }

    /**
     * What part of this path (leftmost 0-3 characters) what
     * it is absolute relative to:
     *
     * On Unix:
     *     This is simply '/' for an absolute path or
     *     '' for a relative path
     *
     * On Windows this is more complicated:
     *     If the first two characters are a letter followed
     *         by a ':', this indicates that the path is
     *         on a specific device.
     *     With or without a device specified, a path MAY
     *         start with a '\\' to indicate an absolute path
     *         on the device or '' to indicate a path relative
     *         to the device's CWD
     *
     * @param string $path
     * @param string $dirSep
     * @return string
     */
    private static function getPathAbsolutenessPrefix($path, $dirSep = DIRECTORY_SEPARATOR)
    {
        $devLetterPrefixPattern = '';
        if (self::isWindows($dirSep)) {
            $devLetterPrefixPattern = '([A-Za-z]:|)';
        }
        $matches = [];
        if (!preg_match('/^'.$devLetterPrefixPattern.preg_quote($dirSep, '/').'?/', $path, $matches)) {
            // This should match, even if it matches 0 characters
            throw new ConfigurationException("INTERNAL ERROR: This must be a regex problem.");
        }
        return [
            'wholePrefix'  => $matches[0], // The optional device letter followed by the optional $dirSep
            'devicePrefix' => self::isWindows($dirSep) ? $matches[1] : ''];
    }

    /**
     * Are we in a Windows style filesystem?
     *
     * @param string $dirSep
     * @return bool
     */
    private static function isWindows($dirSep = DIRECTORY_SEPARATOR)
    {
        return ($dirSep == '\\');
    }

    public static function isPathAbsolute($path)
    {
        if (DIRECTORY_SEPARATOR === '/') {
            return substr($path, 0, 1) === DIRECTORY_SEPARATOR;
        }

        return preg_match('#^[A-Z]:(?![^/\\\])#i', $path) === 1;
    }
}
<?php
namespace Codeception\Util;

/**
 * Really basic class to store data in global array and use it in Cests/Tests.
 *
 * ```php
 * <?php
 * Fixtures::add('user1', ['name' => 'davert']);
 * Fixtures::get('user1');
 * Fixtures::exists('user1');
 *
 * ?>
 * ```
 *
 */
class Fixtures
{
    protected static $fixtures = [];

    public static function add($name, $data)
    {
        self::$fixtures[$name] = $data;
    }

    public static function get($name)
    {
        if (!self::exists($name)) {
            throw new \RuntimeException("$name not found in fixtures");
        }

        return self::$fixtures[$name];
    }

    public static function cleanup($name = null)
    {
        if (self::exists($name)) {
            unset(self::$fixtures[$name]);
            return;
        }

        self::$fixtures = [];
    }

    public static function exists($name)
    {
        return isset(self::$fixtures[$name]);
    }
}
<?php
namespace Codeception\Util;

use Codeception\Lib\Console\Output;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;

/**
 * This class is used only when Codeception is executed in `--debug` mode.
 * In other cases method of this class won't be seen.
 */
class Debug
{
    /**
     * @var Output null
     */
    protected static $output = null;

    public static function setOutput(Output $output)
    {
        self::$output = $output;
    }

    /**
     * Prints data to screen. Message can be any time of data
     *
     * @param $message
     */
    public static function debug($message)
    {
        if (!self::$output) {
            return;
        }
        self::$output->debug($message);
    }

    public static function isEnabled()
    {
        return (bool) self::$output;
    }

    public static function confirm($question)
    {
        if (!self::$output) {
            return;
        }

        $questionHelper = new QuestionHelper();
        return $questionHelper->ask(new ArgvInput(), self::$output, new ConfirmationQuestion($question));
    }
}
<?php
namespace Codeception\Util;

/**
 * Set of functions to work with Filesystem
 *
 */
class FileSystem
{
    /**
     * @param $path
     */
    public static function doEmptyDir($path)
    {
        /** @var $iterator \RecursiveIteratorIterator|\SplFileObject[] */
        $iterator = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($path),
            \RecursiveIteratorIterator::CHILD_FIRST
        );

        foreach ($iterator as $path) {
            $basename = basename((string)$path);
            if ($basename === '.' || $basename === '..' || $basename === '.gitignore' || $basename === '.gitkeep') {
                continue;
            }

            if ($path->isDir()) {
                rmdir((string)$path);
            } else {
                unlink((string)$path);
            }
        }
    }

    /**
     * @param $dir
     * @return bool
     */
    public static function deleteDir($dir)
    {
        if (!file_exists($dir)) {
            return true;
        }

        if (!is_dir($dir) || is_link($dir)) {
            return @unlink($dir);
        }

        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
            $dir = str_replace('/', '\\', $dir);
            exec('rd /s /q "'.$dir.'"');
            return true;
        }

        foreach (scandir($dir) as $item) {
            if ($item === '.' || $item === '..') {
                continue;
            }

            if (!self::deleteDir($dir . DIRECTORY_SEPARATOR . $item)) {
                chmod($dir . DIRECTORY_SEPARATOR . $item, 0777);
                if (!self::deleteDir($dir . DIRECTORY_SEPARATOR . $item)) {
                    return false;
                }
            }
        }

        return @rmdir($dir);
    }

    /**
     * @param $src
     * @param $dst
     */
    public static function copyDir($src, $dst)
    {
        $dir = opendir($src);
        @mkdir($dst);
        while (false !== ($file = readdir($dir))) {
            if (($file != '.') && ($file != '..')) {
                if (is_dir($src . DIRECTORY_SEPARATOR . $file)) {
                    self::copyDir($src . DIRECTORY_SEPARATOR . $file, $dst . DIRECTORY_SEPARATOR . $file);
                } else {
                    copy($src . DIRECTORY_SEPARATOR . $file, $dst . DIRECTORY_SEPARATOR . $file);
                }
            }
        }
        closedir($dir);
    }
}
<?php
namespace Codeception\Util;

/**
 * Autoloader, which is fully compatible with PSR-4,
 * and can be used to autoload your `Helper`, `Page`, and `Step` classes.
 */
class Autoload
{
    protected static $registered = false;
    /**
     * An associative array where the key is a namespace prefix and the value
     * is an array of base directories for classes in that namespace.
     * @var array
     */
    protected static $map = [];

    private function __construct()
    {
    }

    /**
     * Adds a base directory for a namespace prefix.
     *
     * Example:
     *
     * ```php
     * <?php
     * // app\Codeception\UserHelper will be loaded from '/path/to/helpers/UserHelper.php'
     * Autoload::addNamespace('app\Codeception', '/path/to/helpers');
     *
     * // LoginPage will be loaded from '/path/to/pageobjects/LoginPage.php'
     * Autoload::addNamespace('', '/path/to/pageobjects');
     *
     * Autoload::addNamespace('app\Codeception', '/path/to/controllers');
     * ?>
     * ```
     *
     * @param string $prefix The namespace prefix.
     * @param string $base_dir A base directory for class files in the namespace.
     * @param bool $prepend If true, prepend the base directory to the stack instead of appending it;
     *                      this causes it to be searched first rather than last.
     * @return void
     */
    public static function addNamespace($prefix, $base_dir, $prepend = false)
    {
        if (!self::$registered) {
            spl_autoload_register([__CLASS__, 'load']);
            self::$registered = true;
        }

        // normalize namespace prefix
        $prefix = trim($prefix, '\\') . '\\';

        // normalize the base directory with a trailing separator
        $base_dir = rtrim($base_dir, '/') . DIRECTORY_SEPARATOR;
        $base_dir = rtrim($base_dir, DIRECTORY_SEPARATOR) . '/';

        // initialize the namespace prefix array
        if (isset(self::$map[$prefix]) === false) {
            self::$map[$prefix] = [];
        }

        // retain the base directory for the namespace prefix
        if ($prepend) {
            array_unshift(self::$map[$prefix], $base_dir);
        } else {
            self::$map[$prefix][] = $base_dir;
        }
    }

    public static function load($class)
    {
        // the current namespace prefix
        $prefix = $class;

        // work backwards through the namespace names of the fully-qualified class name to find a mapped file name
        while (false !== ($pos = strrpos($prefix, '\\'))) {
            // retain the trailing namespace separator in the prefix
            $prefix = substr($class, 0, $pos + 1);

            // the rest is the relative class name
            $relative_class = substr($class, $pos + 1);

            // try to load a mapped file for the prefix and relative class
            $mapped_file = self::loadMappedFile($prefix, $relative_class);
            if ($mapped_file) {
                return $mapped_file;
            }

            // remove the trailing namespace separator for the next iteration of strrpos()
            $prefix = rtrim($prefix, '\\');
        }

        // fix for empty prefix
        if (isset(self::$map['\\']) && ($class[0] != '\\')) {
            return self::load('\\' . $class);
        }

        // backwards compatibility with old autoloader
        // :TODO: it should be removed
        if (strpos($class, '\\') !== false) {
            $relative_class = substr(strrchr($class, '\\'), 1); // Foo\Bar\ClassName -> ClassName
            $mapped_file = self::loadMappedFile('\\', $relative_class);
            if ($mapped_file) {
                return $mapped_file;
            }
        }

        return false;
    }

    /**
     * Load the mapped file for a namespace prefix and relative class.
     *
     * @param string $prefix The namespace prefix.
     * @param string $relative_class The relative class name.
     * @return mixed Boolean false if no mapped file can be loaded, or the name of the mapped file that was loaded.
     */
    protected static function loadMappedFile($prefix, $relative_class)
    {
        if (!isset(self::$map[$prefix])) {
            return false;
        }

        foreach (self::$map[$prefix] as $base_dir) {
            $file = $base_dir
                . str_replace('\\', '/', $relative_class)
                . '.php';

            // 'static' is for testing purposes
            if (static::requireFile($file)) {
                return $file;
            }
        }

        return false;
    }

    protected static function requireFile($file)
    {
        if (file_exists($file)) {
            require_once $file;
            return true;
        }
        return false;
    }
}
<?php
namespace Codeception\Util;

use GuzzleHttp\Psr7\Uri as Psr7Uri;

class Uri
{
    /**
     * Merges the passed $add argument onto $base.
     *
     * If a relative URL is passed as the 'path' part of the $add url
     * array, the relative URL is mapped using the base 'path' part as
     * its base.
     *
     * @param string $baseUri the base URL
     * @param string $uri the URL to merge
     * @return array the merged array
     */
    public static function mergeUrls($baseUri, $uri)
    {
        $base = new Psr7Uri($baseUri);
        $parts = parse_url($uri);

        //If the relative URL does not parse, attempt to parse the entire URL.
        //PHP Known bug ( https://bugs.php.net/bug.php?id=70942 )
        if ($parts === false) {
            $parts = parse_url($base.$uri);
        }
        
        if ($parts === false) {
            throw new \InvalidArgumentException("Invalid URI $uri");
        }

        if (isset($parts['host']) and isset($parts['scheme'])) {
            // if this is an absolute url, replace with it
            return $uri;
        }

        if (isset($parts['host'])) {
            $base = $base->withHost($parts['host']);
            $base = $base->withPath('');
            $base = $base->withQuery('');
            $base = $base->withFragment('');
        }
        if (isset($parts['path'])) {
            $path = $parts['path'];
            $basePath = $base->getPath();
            if ((strpos($path, '/') !== 0) && !empty($path)) {
                if ($basePath) {
                    // if it ends with a slash, relative paths are below it
                    if (preg_match('~/$~', $basePath)) {
                        $path = $basePath . $path;
                    } else {
                        // remove double slashes
                        $dir = rtrim(dirname($basePath), '\\/');
                        $path = $dir . '/' . $path;
                    }
                } else {
                    $path = '/' . ltrim($path, '/');
                }
            }
            $base = $base->withPath($path);
            $base = $base->withQuery('');
            $base = $base->withFragment('');
        }
        if (isset($parts['query'])) {
            $base = $base->withQuery($parts['query']);
            $base = $base->withFragment('');
        }
        if (isset($parts['fragment'])) {
            $base = $base->withFragment($parts['fragment']);
        }

        return (string) $base;
    }

    /**
     * Retrieve /path?query#fragment part of URL
     * @param $url
     * @return string
     */
    public static function retrieveUri($url)
    {
        $uri = new Psr7Uri($url);
        return (string)(new Psr7Uri())
            ->withPath($uri->getPath())
            ->withQuery($uri->getQuery())
            ->withFragment($uri->getFragment());
    }

    public static function retrieveHost($url)
    {
        $urlParts = parse_url($url);
        if (!isset($urlParts['host']) or !isset($urlParts['scheme'])) {
            throw new \InvalidArgumentException("Wrong URL passes, host and scheme not set");
        }
        $host = $urlParts['scheme'] . '://' . $urlParts['host'];
        if (isset($urlParts['port'])) {
            $host .= ':' . $urlParts['port'];
        }
        return $host;
    }

    public static function appendPath($url, $path)
    {
        $uri = new Psr7Uri($url);
        $cutUrl = (string)$uri->withQuery('')->withFragment('');

        if ($path === '' || $path[0] === '#') {
            return $cutUrl . $path;
        }

        return rtrim($cutUrl, '/') . '/'  . ltrim($path, '/');
    }
}
<?php
namespace Codeception\Util;

use Codeception\Exception\ElementNotFound;
use Codeception\Exception\MalformedLocatorException;
use Symfony\Component\CssSelector\CssSelectorConverter;
use Symfony\Component\CssSelector\Exception\ParseException;
use Codeception\Util\Soap as XmlUtils;

class XmlStructure
{
    /**
     * @var \DOMDocument|\DOMNode
     */
    protected $xml;
    
    public function __construct($xml)
    {
        $this->xml = XmlUtils::toXml($xml);
    }

    public function matchesXpath($xpath)
    {
        $path = new \DOMXPath($this->xml);
        $res = $path->query($xpath);
        if ($res === false) {
            throw new MalformedLocatorException($xpath);
        }
        return $res->length > 0;
    }

    /**
     * @param $cssOrXPath
     * @return \DOMElement
     */
    public function matchElement($cssOrXPath)
    {
        $xpath = new \DOMXpath($this->xml);
        try {
            $selector = (new CssSelectorConverter())->toXPath($cssOrXPath);
            $els = $xpath->query($selector);
            if ($els) {
                return $els->item(0);
            }
        } catch (ParseException $e) {
        }
        $els = $xpath->query($cssOrXPath);
        if ($els->length) {
            return $els->item(0);
        }
        throw new ElementNotFound($cssOrXPath);
    }
    /**

     * @param $xml
     * @return bool
     */
    public function matchXmlStructure($xml)
    {
        $xml = XmlUtils::toXml($xml);
        $root = $xml->firstChild;
        $els = $this->xml->getElementsByTagName($root->nodeName);
        if (empty($els)) {
            throw new ElementNotFound($root->nodeName, 'Element');
        }

        $matches = false;
        foreach ($els as $node) {
            $matches |= $this->matchForNode($root, $node);
        }
        return $matches;
    }

    protected function matchForNode($schema, $xml)
    {
        foreach ($schema->childNodes as $node1) {
            $matched = false;
            foreach ($xml->childNodes as $node2) {
                if ($node1->nodeName == $node2->nodeName) {
                    $matched = $this->matchForNode($node1, $node2);
                    if ($matched) {
                        break;
                    }
                }
            }
            if (!$matched) {
                return false;
            }
        }
        return true;
    }
}
<?php
namespace Codeception\Util\Shared;

trait Namespaces
{
    protected function breakParts($class)
    {
        // removing leading slashes and dots first
        $class = str_replace('/', '\\', ltrim($class, './\\'));
        return explode('\\', $class);
    }

    protected function getShortClassName($class)
    {
        $namespaces = $this->breakParts($class);
        return array_pop($namespaces);
    }

    protected function getNamespaceString($class)
    {
        $namespaces = $this->getNamespaces($class);
        return implode('\\', $namespaces);
    }

    protected function getNamespaceHeader($class)
    {
        $str = $this->getNamespaceString($class);
        if (!$str) {
            return "";
        }
        return "namespace $str;\n";
    }

    protected function getNamespaces($class)
    {
        $namespaces = $this->breakParts($class);
        array_pop($namespaces);
        $namespaces = array_filter($namespaces, 'strlen');
        return $namespaces;
    }
}
<?php
namespace Codeception\Util;

/**
 * Basic template engine used for generating initial Cept/Cest/Test files.
 */
class Template
{
    protected $template;
    protected $vars = [];
    protected $placeholderStart;
    protected $placeholderEnd;

    /**
     * Takes a template string
     *
     * @param $template
     */
    public function __construct($template, $placeholderStart = '{{', $placeholderEnd = '}}')
    {
        $this->template         = $template;
        $this->placeholderStart = $placeholderStart;
        $this->placeholderEnd   = $placeholderEnd;
    }

    /**
     * Replaces {{var}} string with provided value
     *
     * @param $var
     * @param $val
     * @return $this
     */
    public function place($var, $val)
    {
        $this->vars[$var] = $val;
        return $this;
    }

    /**
     * Sets all template vars
     *
     * @param array $vars
     */
    public function setVars(array $vars)
    {
        $this->vars = $vars;
    }

    public function getVar($name)
    {
        if (isset($this->vars[$name])) {
            return $this->vars[$name];
        }
    }

    /**
     * Fills up template string with placed variables.
     *
     * @return mixed
     */
    public function produce()
    {
        $result = $this->template;
        $regex = sprintf('~%s([\w\.]+)%s~m', $this->placeholderStart, $this->placeholderEnd);

        $matched = preg_match_all($regex, $result, $matches, PREG_SET_ORDER);
        if (!$matched) {
            return $result;
        }

        foreach ($matches as $match) { // fill in placeholders
            $placeholder = $match[1];
            $value = $this->vars;
            foreach (explode('.', $placeholder) as $segment) {
                if (is_array($value) && array_key_exists($segment, $value)) {
                    $value = $value[$segment];
                } else {
                    continue 2;
                }
            }

            $result = str_replace($this->placeholderStart . $placeholder . $this->placeholderEnd, $value, $result);
        }
        return $result;
    }
}
<?php
namespace Codeception\Util;

/**
 * Class to represent any type of content.
 * This class can act as an object, array, or string.
 * Method or property calls to this class won't cause any errors.
 *
 * Maybe was used in Codeception 1.x to represent data on parsing step.
 * Not widely used in 2.0 anymore, but left for compatibility.
 *
 * For instance, you may use `Codeception\Util\Maybe` as a test dummies.
 *
 * ```php
 * <?php
 * $user = new Maybe;
 * $user->posts->comments->count();
 * ?>
 * ```
 */
class Maybe implements \ArrayAccess, \Iterator, \JsonSerializable
{
    protected $position = 0;
    protected $val = null;
    protected $assocArray = null;

    public function __construct($val = null)
    {
        $this->val = $val;
        if (is_array($this->val)) {
            $this->assocArray = $this->isAssocArray($this->val);
        }
        $this->position = 0;
    }

    private function isAssocArray($arr)
    {
        return array_keys($arr) !== range(0, count($arr) - 1);
    }

    public function __toString()
    {
        if ($this->val === null) {
            return "?";
        }
        if (is_scalar($this->val)) {
            return (string)$this->val;
        }

        if (is_object($this->val) && method_exists($this->val, '__toString')) {
            return $this->val->__toString();
        }

        return $this->val;
    }

    public function __get($key)
    {
        if ($this->val === null) {
            return new Maybe();
        }

        if (is_object($this->val)) {
            if (isset($this->val->{$key}) || property_exists($this->val, $key)) {
                return $this->val->{$key};
            }
        }

        return $this->val->key;
    }

    public function __set($key, $val)
    {
        if ($this->val === null) {
            return;
        }

        if (is_object($this->val)) {
            $this->val->{$key} = $val;
            return;
        }

        $this->val->key = $val;
    }

    public function __call($method, $args)
    {
        if ($this->val === null) {
            return new Maybe();
        }
        return call_user_func_array([$this->val, $method], $args);
    }

    public function __clone()
    {
        if (is_object($this->val)) {
            $this->val = clone $this->val;
        }
    }

    public function __unset($key)
    {
        if (is_object($this->val)) {
            if (isset($this->val->{$key}) || property_exists($this->val, $key)) {
                unset($this->val->{$key});
                return;
            }
        }
    }

    public function offsetExists($offset)
    {
        if (is_array($this->val) || ($this->val instanceof \ArrayAccess)) {
            return isset($this->val[$offset]);
        }
        return false;
    }

    public function offsetGet($offset)
    {
        if (is_array($this->val) || ($this->val instanceof \ArrayAccess)) {
            return $this->val[$offset];
        }
        return new Maybe();
    }

    public function offsetSet($offset, $value)
    {
        if (is_array($this->val) || ($this->val instanceof \ArrayAccess)) {
            $this->val[$offset] = $value;
        }
    }

    public function offsetUnset($offset)
    {
        if (is_array($this->val) || ($this->val instanceof \ArrayAccess)) {
            unset($this->val[$offset]);
        }
    }

    public function __value()
    {
        $val = $this->val;
        if (is_array($val)) {
            foreach ($val as $k => $v) {
                if ($v instanceof self) {
                    $v = $v->__value();
                }
                $val[$k] = $v;
            }
        }
        return $val;
    }

    /**
     * (PHP 5 &gt;= 5.0.0)<br/>
     * Return the current element
     * @link http://php.net/manual/en/iterator.current.php
     * @return mixed Can return any type.
     */
    public function current()
    {
        if (!is_array($this->val)) {
            return null;
        }
        if ($this->assocArray) {
            $keys = array_keys($this->val);
            return $this->val[$keys[$this->position]];
        }

        return $this->val[$this->position];
    }

    /**
     * (PHP 5 &gt;= 5.0.0)<br/>
     * Move forward to next element
     * @link http://php.net/manual/en/iterator.next.php
     * @return void Any returned value is ignored.
     */
    public function next()
    {
        ++$this->position;
    }

    /**
     * (PHP 5 &gt;= 5.0.0)<br/>
     * Return the key of the current element
     * @link http://php.net/manual/en/iterator.key.php
     * @return mixed scalar on success, or null on failure.
     */
    public function key()
    {
        if ($this->assocArray) {
            $keys = array_keys($this->val);
            return $keys[$this->position];
        }

        return $this->position;
    }

    /**
     * (PHP 5 &gt;= 5.0.0)<br/>
     * Checks if current position is valid
     * @link http://php.net/manual/en/iterator.valid.php
     * @return boolean The return value will be casted to boolean and then evaluated.
     * Returns true on success or false on failure.
     */
    public function valid()
    {
        if (!is_array($this->val)) {
            return null;
        }
        if ($this->assocArray) {
            $keys = array_keys($this->val);
            return isset($keys[$this->position]);
        }

        return isset($this->val[$this->position]);
    }

    /**
     * (PHP 5 &gt;= 5.0.0)<br/>
     * Rewind the Iterator to the first element
     * @link http://php.net/manual/en/iterator.rewind.php
     * @return void Any returned value is ignored.
     */
    public function rewind()
    {
        if (is_array($this->val)) {
            $this->assocArray = $this->isAssocArray($this->val);
        }
        $this->position = 0;
    }

    /**
     * (PHP 5 >= 5.4.0)
     * Serializes the object to a value that can be serialized natively by json_encode().
     * @link http://docs.php.net/manual/en/jsonserializable.jsonserialize.php
     * @return mixed Returns data which can be serialized by json_encode(), which is a value of any type other than a resource.
     */
    public function jsonSerialize()
    {
        return $this->__value();
    }
}
<?php
namespace Codeception\Util;

/**
 * This class is left for BC compatibility.
 * Most of its contents moved to parent
 *
 * Class Soap
 * @package Codeception\Util
 */
class Soap extends Xml
{
    public static function request()
    {
        return new XmlBuilder();
    }

    public static function response()
    {
        return new XmlBuilder();
    }
}
<?php

namespace Codeception\Util;

use Codeception\Lib\Notification;
use Codeception\Stub\Expected;

class Stub extends \Codeception\Stub
{
    public static function never($params = null)
    {
        Notification::deprecate("Stub::never is deprecated in favor of \Codeception\Stub\Expected::never");
        return Expected::never($params);
    }

    public static function once($params = null)
    {
        Notification::deprecate("Stub::once is deprecated in favor of \Codeception\Stub\Expected::once");
        return Expected::once($params);
    }

    public static function atLeastOnce($params = null)
    {
        Notification::deprecate("Stub::atLeastOnce is deprecated in favor of \Codeception\Stub\Expected::atLeastOnce");
        return Expected::atLeastOnce($params);
    }

    public static function exactly($count, $params = null)
    {
        Notification::deprecate("Stub::exactly is deprecated in favor of \Codeception\Stub\Expected::exactly");
        return Expected::exactly($count, $params);
    }
}
<?php
namespace Codeception\Util;

use Codeception\Step\Action;

/**
 * Class for defining an array actions to be executed inside `performOn` of WebDriver
 *
 * ```php
 * <?php
 * (new ActionSequence)->click('do')->click('undo');
 * ActionSequence::build()->click('do')->click('undo');
 * ```
 *
 * @method $this see([optional])
 * @method $this dontSee([optional])
 * @method $this seeElement([optional])
 * @method $this dontSeeElement([optional])
 * @method $this click([optional])
 * @method $this wait([optional])
 * @method $this waitForElementChange([optional])
 * @method $this waitForElement([optional])
 * @method $this waitForElementVisible([optional])
 * @method $this waitForElementNotVisible([optional])
 * @method $this waitForText([optional])
 * @method $this submitForm([optional])
 * @method $this seeLink([optional])
 * @method $this dontSeeLink([optional])
 * @method $this seeCheckboxIsChecked([optional])
 * @method $this dontSeeCheckboxIsChecked([optional])
 * @method $this seeInField([optional])
 * @method $this dontSeeInField([optional])
 * @method $this seeInFormFields([optional])
 * @method $this dontSeeInFormFields([optional])
 * @method $this selectOption([optional])
 * @method $this checkOption([optional])
 * @method $this uncheckOption([optional])
 * @method $this fillField([optional])
 * @method $this attachFile([optional])
 * @method $this seeNumberOfElements([optional])
 * @method $this seeOptionIsSelected([optional])
 * @method $this dontSeeOptionIsSelected([optional])
 */
class ActionSequence
{
    protected $actions = [];

    /**
     * Creates an instance
     * @return ActionSequence
     */
    public static function build()
    {
        return new self;
    }

    public function __call($action, $arguments)
    {
        $this->addAction($action, $arguments);
        return $this;
    }

    protected function addAction($action, $arguments)
    {
        if (!is_array($arguments)) {
            $arguments = [$arguments];
        }
        $this->actions[] = new Action($action, $arguments);
    }

    /**
     * Creates action sequence from associative array,
     * where key is action, and value is action arguments
     *
     * @param array $actions
     * @return $this
     */
    public function fromArray(array $actions)
    {
        foreach ($actions as $action => $arguments) {
            $this->addAction($action, $arguments);
        }
        return $this;
    }

    /**
     * Returns a list of logged actions as associative array
     * @return array
     */
    public function toArray()
    {
        return $this->actions;
    }

    /**
     * Executes sequence of action as methods of passed object.
     *
     * @param $context
     */
    public function run($context)
    {
        foreach ($this->actions as $step) {
            /** @var $step Action  **/
            codecept_debug("- $step");
            try {
                call_user_func_array([$context, $step->getAction()], $step->getArguments());
            } catch (\Exception $e) {
                $class = get_class($e); // rethrow exception for a specific action
                throw new $class($e->getMessage() . "\nat $step");
            }
        }
    }

    public function __toString()
    {
        $actionsLog = [];

        foreach ($this->actions as $step) {
            $args = str_replace('"', "'", $step->getArgumentsAsString(20));
            $actionsLog[] = $step->getAction() . ": $args";
        }

        return implode(', ', $actionsLog);
    }
}
<?php
namespace Codeception\Util;

use ReflectionException;
use ReflectionParameter;
use ReflectionProperty;
use ReflectionMethod;

/**
 * This class contains helper methods to help with common Reflection tasks.
 */
class ReflectionHelper
{
    /**
     * Read a private property of an object.
     *
     * @param object $object
     * @param string $property
     * @param string|null $class
     * @return mixed
     * @throws ReflectionException
     */
    public static function readPrivateProperty($object, $property, $class = null)
    {
        if (is_null($class)) {
            $class = $object;
        }

        $property = new ReflectionProperty($class, $property);
        $property->setAccessible(true);

        return $property->getValue($object);
    }

    /**
     * Invoke a private method of an object.
     *
     * @param object $object
     * @param string $method
     * @param array $args
     * @param string|null $class
     * @return mixed
     * @throws ReflectionException
     */
    public static function invokePrivateMethod($object, $method, $args = [], $class = null)
    {
        if (is_null($class)) {
            $class = $object;
        }

        $method = new ReflectionMethod($class, $method);
        $method->setAccessible(true);

        return $method->invokeArgs($object, $args);
    }

    /**
     * Returns class name without namespace
     *
     * (does not use reflection actually)
     *
     * @param $object
     * @return mixed
     */
    public static function getClassShortName($object)
    {
        $path = explode('\\', get_class($object));
        return array_pop($path);
    }

    /**
     * Adapted from https://github.com/Behat/Behat/pull/1313
     *
     * @param ReflectionParameter $parameter
     * @return string|null
     */
    public static function getClassFromParameter(ReflectionParameter $parameter)
    {
        if (PHP_VERSION_ID < 70100) {
            $class = $parameter->getClass();
            if ($class !== null) {
                return $class->name;
            }
            return $class;
        }

        $type = $parameter->getType();
        if ($type === null || $type->isBuiltin()) {
            return null;
        }
        $typeString = $type->getName();

        if ($typeString === 'self') {
            return $parameter->getDeclaringClass()->getName();
        } elseif ($typeString === 'parent') {
            return $parameter->getDeclaringClass()->getParentClass()->getName();
        }

        return $typeString;
    }

    /**
     * Infer default parameter from the reflection object and format it as PHP (code) string
     *
     * @param ReflectionParameter $param
     *
     * @return string
     */
    public static function getDefaultValue(ReflectionParameter $param)
    {
        if ($param->isDefaultValueAvailable()) {
            if (method_exists($param, 'isDefaultValueConstant') && $param->isDefaultValueConstant()) {
                $constName = $param->getDefaultValueConstantName();
                if (false !== strpos($constName, '::')) {
                    list($class, $const) = explode('::', $constName);
                    if (in_array($class, ['self', 'static'])) {
                        $constName = '\\' . $param->getDeclaringClass()->getName() . '::' . $const;
                    } elseif (substr($class, 0, 1) !== '\\') {
                        $constName = '\\' . $constName;
                    }
                }

                return $constName;
            }

            return self::phpEncodeValue($param->getDefaultValue());
        }

        // Default to 'null' for PHP versions < 7.1.
        if (PHP_VERSION_ID < 70100) {
            return 'null';
        }

        $type = $param->getType();

        // Default to 'null' if explicitly allowed or there is no specific type hint.
        if (!$type || $type->allowsNull() || !$type->isBuiltin()) {
            return 'null';
        }

        // Default value should match the parameter type if 'null' is NOT allowed.
        switch ($type->getName()) {
            case 'string':
                return "''";
            case 'array':
                return '[]';
            case 'boolean':
                return 'false';
            case 'int':
            case 'integer':
            case 'float':
            case 'double':
            case 'number':
            case 'numeric':
                return '0';
            default:
                return 'null';
        }
    }

    /**
     * PHP encode value
     *
     * @param mixed $value
     *
     * @return string
     */
    public static function phpEncodeValue($value)
    {
        if (is_array($value)) {
            return self::phpEncodeArray($value);
        }

        if (is_string($value)) {
            return json_encode($value);
        }

        return var_export($value, true);
    }

    /**
     * Recursively PHP encode an array
     *
     * @param array $array
     *
     * @return string
     */
    public static function phpEncodeArray(array $array)
    {
        $isPlainArray = function (array $value) {
            return ((count($value) === 0)
                || (
                    (array_keys($value) === range(0, count($value) - 1))
                    && (0 === count(array_filter(array_keys($value), 'is_string'))))
            );
        };

        if ($isPlainArray($array)) {
            return '[' . implode(', ', array_map([self::class, 'phpEncodeValue'], $array)) . ']';
        }

        $values = array_map(
            function ($key) use ($array) {
                return self::phpEncodeValue($key) . ' => ' . self::phpEncodeValue($array[$key]);
            },
            array_keys($array)
        );

        return '[' . implode(', ', $values) . ']';
    }
}
<?php
namespace Codeception\Util;

class Xml
{
    /**
     * @static
     *
     * @param \DOMDocument $xml
     * @param \DOMNode $node
     * @param array $array
     *
     * @return \DOMDocument
     */
    public static function arrayToXml(\DOMDocument $xml, \DOMNode $node, $array = [])
    {
        foreach ($array as $el => $val) {
            if (is_array($val)) {
                self::arrayToXml($xml, $node->$el, $val);
            } else {
                $node->appendChild($xml->createElement($el, $val));
            }
        }
        return $xml;
    }

    /**
     * @static
     *
     * @param $xml
     *
     * @return \DOMDocument|\DOMNode
     */
    public static function toXml($xml)
    {
        if ($xml instanceof XmlBuilder) {
            return $xml->getDom();
        }
        if ($xml instanceof \DOMDocument) {
            return $xml;
        }
        $dom = new \DOMDocument();
        $dom->preserveWhiteSpace = false;
        if ($xml instanceof \DOMNode) {
            $xml = $dom->importNode($xml, true);
            $dom->appendChild($xml);
            return $dom;
        }

        if (is_array($xml)) {
            return self::arrayToXml($dom, $dom, $xml);
        }
        if (!empty($xml)) {
            $dom->loadXML($xml);
        }
        return $dom;
    }

    public static function build()
    {
        return new XmlBuilder();
    }
}
<?php

namespace Codeception\Util;

use InvalidArgumentException;
use ReflectionClass;
use ReflectionException;
use function get_class;
use function get_parent_class;
use function gettype;
use function is_object;

class ReflectionPropertyAccessor
{
    /**
     * @param object $obj
     * @param string $field
     * @return mixed
     * @throws ReflectionException
     */
    public function getProperty($obj, $field)
    {
        if (!$obj || !is_object($obj)) {
            throw new InvalidArgumentException('Cannot get property "' . $field . '" of "' . gettype($obj) . '", expecting object');
        }
        $class = get_class($obj);
        do {
            $reflectedEntity = new ReflectionClass($class);
            if ($reflectedEntity->hasProperty($field)) {
                $property = $reflectedEntity->getProperty($field);
                $property->setAccessible(true);
                return $property->getValue($obj);
            }
            $class = get_parent_class($class);
        } while ($class);
        throw new InvalidArgumentException('Property "' . $field . '" does not exists in class "' . get_class($obj) . '" and its parents');
    }

    /**
     * @param object|null $obj
     * @param string $class
     * @param array $data
     * @return object|null
     * @throws ReflectionException
     */
    private function setPropertiesForClass($obj, $class, array $data)
    {
        $reflectedEntity = new ReflectionClass($class);

        if (!$obj) {
            $constructorParameters = [];
            $constructor = $reflectedEntity->getConstructor();
            if (null !== $constructor) {
                foreach ($constructor->getParameters() as $parameter) {
                    if ($parameter->isOptional()) {
                        $constructorParameters[] = $parameter->getDefaultValue();
                    } elseif (array_key_exists($parameter->getName(), $data)) {
                        $constructorParameters[] = $data[$parameter->getName()];
                    } else {
                        throw new InvalidArgumentException(
                            'Constructor parameter "'.$parameter->getName().'" missing'
                        );
                    }
                }
            }

            $obj = $reflectedEntity->newInstance(...$constructorParameters);
        }

        foreach ($reflectedEntity->getProperties() as $property) {
            if (isset($data[$property->name])) {
                $property->setAccessible(true);
                $property->setValue($obj, $data[$property->name]);
            }
        }
        return $obj;
    }

    /**
     * @param object|null $obj
     * @param array $data
     * @throws ReflectionException
     */
    public function setProperties($obj, array $data)
    {
        if (!$obj || !is_object($obj)) {
            throw new InvalidArgumentException('Cannot set properties for "' . gettype($obj) . '", expecting object');
        }
        $class = get_class($obj);
        do {
            $obj = $this->setPropertiesForClass($obj, $class, $data);
            $class = get_parent_class($class);
        } while ($class);
    }

    /**
     * @param string $class
     * @param array $data
     * @return object
     * @throws ReflectionException
     */
    public function createWithProperties($class, array $data)
    {
        $obj = null;
        do {
            $obj = $this->setPropertiesForClass($obj, $class, $data);
            $class = get_parent_class($class);
        } while ($class);
        return $obj;
    }
}
<?php
namespace Codeception\Util;

/**
 * Simple annotation parser. Take only key-value annotations for methods or class.
 */
class Annotation
{
    protected static $reflectedClasses = [];
    protected static $regex = '/@%s(?:[ \t]*(.*?))?[ \t]*(?:\*\/)?\r?$/m';
    protected static $lastReflected = null;

    /**
     * @var \ReflectionClass
     */
    protected $reflectedClass;

    protected $currentReflectedItem;

    /**
     * Grabs annotation values.
     *
     * Usage example:
     *
     * ``` php
     * <?php
     * Annotation::forClass('MyTestCase')->fetch('guy');
     * Annotation::forClass('MyTestCase')->method('testData')->fetch('depends');
     * Annotation::forClass('MyTestCase')->method('testData')->fetchAll('depends');
     *
     * ?>
     * ```
     *
     * @param $class
     *
     * @return $this
     */
    public static function forClass($class)
    {
        if (is_object($class)) {
            $class = get_class($class);
        }

        if (!isset(static::$reflectedClasses[$class])) {
            static::$reflectedClasses[$class] = new \ReflectionClass($class);
        }

        return new static(static::$reflectedClasses[$class]);
    }

    /**
     * @param $class
     * @param $method
     *
     * @return $this
     */
    public static function forMethod($class, $method)
    {
        return self::forClass($class)->method($method);
    }

    /**
     * Parses raw comment for annotations
     *
     * @param $docblock
     * @param $annotation
     * @return array
     */
    public static function fetchAnnotationsFromDocblock($annotation, $docblock)
    {
        if (preg_match_all(sprintf(self::$regex, $annotation), $docblock, $matched)) {
            return $matched[1];
        }
        return [];
    }

    /**
     * Fetches all available annotations
     *
     * @param $docblock
     * @return array
     */
    public static function fetchAllAnnotationsFromDocblock($docblock)
    {
        $annotations = [];
        if (!preg_match_all(sprintf(self::$regex, '(\w+)'), $docblock, $matched)) {
            return $annotations;
        }
        foreach ($matched[1] as $k => $annotation) {
            if (!isset($annotations[$annotation])) {
                $annotations[$annotation] = [];
            }
            $annotations[$annotation][] = $matched[2][$k];
        };
        return $annotations;
    }


    public function __construct(\ReflectionClass $class)
    {
        $this->currentReflectedItem = $this->reflectedClass = $class;
    }

    /**
     * @param $method
     *
     * @return $this
     */
    public function method($method)
    {
        $this->currentReflectedItem = $this->reflectedClass->getMethod($method);
        return $this;
    }

    /**
     * @param $annotation
     * @return null
     */
    public function fetch($annotation)
    {
        $docBlock = $this->currentReflectedItem->getDocComment();
        if (preg_match(sprintf(self::$regex, $annotation), $docBlock, $matched)) {
            return $matched[1];
        }
        return null;
    }

    /**
     * @param $annotation
     * @return array
     */
    public function fetchAll($annotation)
    {
        $docBlock = $this->currentReflectedItem->getDocComment();
        if (preg_match_all(sprintf(self::$regex, $annotation), $docBlock, $matched)) {
            return $matched[1];
        }
        return [];
    }

    public function raw()
    {
        return $this->currentReflectedItem->getDocComment();
    }

    /**
     * Returns an associative array value of annotation
     * Either JSON or Doctrine-annotation style allowed
     * Returns null if not a valid array data
     *
     * @param $annotation
     * @return array|mixed|string
     */
    public static function arrayValue($annotation)
    {
        $annotation = trim($annotation);
        $openingBrace = substr($annotation, 0, 1);

        // json-style data format
        if (in_array($openingBrace, ['{', '['])) {
            return json_decode($annotation, true);
        }

        // doctrine-style data format
        if ($openingBrace === '(') {
            preg_match_all('~(\w+)\s*?=\s*?"(.*?)"\s*?[,)]~', $annotation, $matches, PREG_SET_ORDER);
            $data = [];
            foreach ($matches as $item) {
                $data[$item[1]] = $item[2];
            }
            return $data;
        }
        return null;
    }
}
<?php
namespace Codeception\Util;

use Facebook\WebDriver\WebDriverBy;
use Symfony\Component\CssSelector\CssSelectorConverter;
use Symfony\Component\CssSelector\Exception\ParseException;
use Symfony\Component\CssSelector\XPath\Translator;

/**
 * Set of useful functions for using CSS and XPath locators.
 * Please check them before writing complex functional or acceptance tests.
 *
 */
class Locator
{
    /**
     * Applies OR operator to any number of CSS or XPath selectors.
     * You can mix up CSS and XPath selectors here.
     *
     * ```php
     * <?php
     * use \Codeception\Util\Locator;
     *
     * $I->see('Title', Locator::combine('h1','h2','h3'));
     * ?>
     * ```
     *
     * This will search for `Title` text in either `h1`, `h2`, or `h3` tag.
     * You can also combine CSS selector with XPath locator:
     *
     * ```php
     * <?php
     * use \Codeception\Util\Locator;
     *
     * $I->fillField(Locator::combine('form input[type=text]','//form/textarea[2]'), 'qwerty');
     * ?>
     * ```
     *
     * As a result the Locator will produce a mixed XPath value that will be used in fillField action.
     *
     * @static
     *
     * @param $selector1
     * @param $selector2
     *
     * @throws \Exception
     *
     * @return string
     */
    public static function combine($selector1, $selector2)
    {
        $selectors = func_get_args();
        foreach ($selectors as $k => $v) {
            $selectors[$k] = self::toXPath($v);
            if (!$selectors[$k]) {
                throw new \Exception("$v is invalid CSS or XPath");
            }
        }
        return implode(' | ', $selectors);
    }

    /**
     * Matches the *a* element with given URL
     *
     * ```php
     * <?php
     * use \Codeception\Util\Locator;
     *
     * $I->see('Log In', Locator::href('/login.php'));
     * ?>
     * ```
     *
     * @static
     *
     * @param $url
     *
     * @return string
     */
    public static function href($url)
    {
        return sprintf('//a[@href=normalize-space(%s)]', Translator::getXpathLiteral($url));
    }

    /**
     * Matches the element with given tab index
     *
     * Do you often use the `TAB` key to navigate through the web page? How do your site respond to this navigation?
     * You could try to match elements by their tab position using `tabIndex` method of `Locator` class.
     * ```php
     * <?php
     * use \Codeception\Util\Locator;
     *
     * $I->fillField(Locator::tabIndex(1), 'davert');
     * $I->fillField(Locator::tabIndex(2) , 'qwerty');
     * $I->click('Login');
     * ?>
     * ```
     *
     * @static
     *
     * @param $index
     *
     * @return string
     */
    public static function tabIndex($index)
    {
        return sprintf('//*[@tabindex = normalize-space(%d)]', $index);
    }

    /**
     * Matches option by text:
     *
     * ```php
     * <?php
     * use Codeception\Util\Locator;
     *
     * $I->seeElement(Locator::option('Male'), '#select-gender');
     * ```
     *
     * @param $value
     *
     * @return string
     */
    public static function option($value)
    {
        return sprintf('//option[.=normalize-space("%s")]', $value);
    }

    protected static function toXPath($selector)
    {
        try {
            $xpath = (new CssSelectorConverter())->toXPath($selector);
            return $xpath;
        } catch (ParseException $e) {
            if (self::isXPath($selector)) {
                return $selector;
            }
        }
        return null;
    }

    /**
     * Finds element by it's attribute(s)
     *
     * ```php
     * <?php
     * use \Codeception\Util\Locator;
     *
     * $I->seeElement(Locator::find('img', ['title' => 'diagram']));
     * ```
     *
     * @static
     *
     * @param $element
     * @param $attributes
     *
     * @return string
     */
    public static function find($element, array $attributes)
    {
        $operands = [];
        foreach ($attributes as $attribute => $value) {
            if (is_int($attribute)) {
                $operands[] = '@' . $value;
            } else {
                $operands[] = '@' . $attribute . ' = ' . Translator::getXpathLiteral($value);
            }
        }
        return sprintf('//%s[%s]', $element, implode(' and ', $operands));
    }

    /**
     * Checks that provided string is CSS selector
     *
     * ```php
     * <?php
     * Locator::isCSS('#user .hello') => true
     * Locator::isCSS('body') => true
     * Locator::isCSS('//body/p/user') => false
     * ```
     *
     * @param $selector
     *
     * @return bool
     */
    public static function isCSS($selector)
    {
        try {
            (new CssSelectorConverter())->toXPath($selector);
        } catch (ParseException $e) {
            return false;
        }
        return true;
    }

    /**
     * Checks that locator is an XPath
     *
     * ```php
     * <?php
     * Locator::isXPath('#user .hello') => false
     * Locator::isXPath('body') => false
     * Locator::isXPath('//body/p/user') => true
     * ```
     *
     * @param $locator
     *
     * @return bool
     */
    public static function isXPath($locator)
    {
        $document = new \DOMDocument('1.0', 'UTF-8');
        $xpath = new \DOMXPath($document);
        return @$xpath->evaluate($locator, $document) !== false;
    }

    /**
     * @param $locator
     * @return bool
     */
    public static function isPrecise($locator)
    {
        if (is_array($locator)) {
            return true;
        }
        if ($locator instanceof WebDriverBy) {
            return true;
        }
        if (Locator::isID($locator)) {
            return true;
        }
        if (strpos($locator, '//') === 0) {
            return true; // simple xpath check
        }
        return false;
    }

    /**
     * Checks that a string is valid CSS ID
     *
     * ```php
     * <?php
     * Locator::isID('#user') => true
     * Locator::isID('body') => false
     * Locator::isID('//body/p/user') => false
     * ```
     *
     * @param $id
     *
     * @return bool
     */
    public static function isID($id)
    {
        return (bool)preg_match('~^#[\w\.\-\[\]\=\^\~\:]+$~', $id);
    }

    /**
     * Checks that a string is valid CSS class
     *
     * ```php
     * <?php
     * Locator::isClass('.hello') => true
     * Locator::isClass('body') => false
     * Locator::isClass('//body/p/user') => false
     * ```
     *
     * @param $class
     * @return bool
     */
    public static function isClass($class)
    {
        return (bool)preg_match('~^\.[\w\.\-\[\]\=\^\~\:]+$~', $class);
    }

    /**
     * Locates an element containing a text inside.
     * Either CSS or XPath locator can be passed, however they will be converted to XPath.
     *
     * ```php
     * <?php
     * use Codeception\Util\Locator;
     *
     * Locator::contains('label', 'Name'); // label containing name
     * Locator::contains('div[@contenteditable=true]', 'hello world');
     * ```
     *
     * @param $element
     * @param $text
     *
     * @return string
     */
    public static function contains($element, $text)
    {
        $text = Translator::getXpathLiteral($text);
        return sprintf('%s[%s]', self::toXPath($element), "contains(., $text)");
    }

    /**
     * Locates element at position.
     * Either CSS or XPath locator can be passed as locator,
     * position is an integer. If a negative value is provided, counting starts from the last element.
     * First element has index 1
     *
     * ```php
     * <?php
     * use Codeception\Util\Locator;
     *
     * Locator::elementAt('//table/tr', 2); // second row
     * Locator::elementAt('//table/tr', -1); // last row
     * Locator::elementAt('table#grind>tr', -2); // previous than last row
     * ```
     *
     * @param string $element CSS or XPath locator
     * @param int $position xpath index
     *
     * @return mixed
     */
    public static function elementAt($element, $position)
    {
        if (is_int($position) && $position < 0) {
            $position++; // -1 points to the last element
            $position = 'last()-'.abs($position);
        }
        if ($position === 0) {
            throw new \InvalidArgumentException(
                '0 is not valid element position. XPath expects first element to have index 1'
            );
        }
        return sprintf('(%s)[position()=%s]', self::toXPath($element), $position);
    }

    /**
     * Locates first element of group elements.
     * Either CSS or XPath locator can be passed as locator,
     * Equal to `Locator::elementAt($locator, 1)`
     *
     * ```php
     * <?php
     * use Codeception\Util\Locator;
     *
     * Locator::firstElement('//table/tr');
     * ```
     *
     * @param $element
     *
     * @return mixed
     */
    public static function firstElement($element)
    {
        return self::elementAt($element, 1);
    }

    /**
     * Locates last element of group elements.
     * Either CSS or XPath locator can be passed as locator,
     * Equal to `Locator::elementAt($locator, -1)`
     *
     * ```php
     * <?php
     * use Codeception\Util\Locator;
     *
     * Locator::lastElement('//table/tr');
     * ```
     *
     * @param $element
     *
     * @return mixed
     */
    public static function lastElement($element)
    {
        return self::elementAt($element, 'last()');
    }

    /**
     * Transforms strict locator, \Facebook\WebDriver\WebDriverBy into a string represenation
     *
     * @param $selector
     *
     * @return string
     */
    public static function humanReadableString($selector)
    {
        if (is_string($selector)) {
            return "'$selector'";
        }
        if (is_array($selector)) {
            $type = strtolower(key($selector));
            $locator = $selector[$type];
            return "$type '$locator'";
        }
        if (class_exists('\Facebook\WebDriver\WebDriverBy')) {
            if ($selector instanceof WebDriverBy) {
                $type = $selector->getMechanism();
                $locator = $selector->getValue();
                return "$type '$locator'";
            }
        }
        throw new \InvalidArgumentException("Unrecognized selector");
    }
}
<?php
namespace Codeception\Util;

/**
 * That's a pretty simple yet powerful class to build XML structures in jQuery-like style.
 * With no XML line actually written!
 * Uses DOM extension to manipulate XML data.
 *
 *
 * ```php
 * <?php
 * $xml = new \Codeception\Util\XmlBuilder();
 * $xml->users
 *    ->user
 *        ->val(1)
 *        ->email
 *            ->val('davert@mail.ua')
 *            ->attr('valid','true')
 *            ->parent()
 *        ->cart
 *            ->attr('empty','false')
 *            ->items
 *                ->item
 *                    ->val('useful item');
 *                ->parents('user')
 *        ->active
 *            ->val(1);
 * echo $xml;
 * ```
 *
 * This will produce this XML
 *
 * ```xml
 * <?xml version="1.0"?>
 * <users>
 *    <user>
 *        1
 *        <email valid="true">davert@mail.ua</email>
 *        <cart empty="false">
 *            <items>
 *                <item>useful item</item>
 *            </items>
 *        </cart>
 *        <active>1</active>
 *    </user>
 * </users>
 * ```
 *
 * ### Usage
 *
 * Builder uses chained calls. So each call to builder returns a builder object.
 * Except for `getDom` and `__toString` methods.
 *
 *  * `$xml->node` - create new xml node and go inside of it.
 *  * `$xml->node->val('value')` - sets the inner value of node
 *  * `$xml->attr('name','value')` - set the attribute of node
 *  * `$xml->parent()` - go back to parent node.
 *  * `$xml->parents('user')` - go back through all parents to `user` node.
 *
 * Export:
 *
 *  * `$xml->getDom` - get a DOMDocument object
 *  * `$xml->__toString` - get a string representation of XML.
 *
 * [Source code](https://github.com/Codeception/Codeception/blob/4.0/src/Codeception/Util/XmlBuilder.php)
 */
class XmlBuilder
{
    /**
     * @var \DOMDocument
     */
    protected $__dom__;

    /**
     * @var \DOMElement
     */
    protected $__currentNode__;


    public function __construct()
    {
        $this->__dom__ = new \DOMDocument();
        $this->__currentNode__ = $this->__dom__;
    }

    /**
     * Appends child node
     *
     * @param $tag
     *
     * @return XmlBuilder
     */
    public function __get($tag)
    {
        $node = $this->__dom__->createElement($tag);
        $this->__currentNode__->appendChild($node);
        $this->__currentNode__ = $node;
        return $this;
    }

    /**
     * @param $val
     *
     * @return XmlBuilder
     */
    public function val($val)
    {
        $this->__currentNode__->nodeValue = $val;
        return $this;
    }

    /**
     * Sets attribute for current node
     *
     * @param $attr
     * @param $val
     *
     * @return XmlBuilder
     */
    public function attr($attr, $val)
    {
        $this->__currentNode__->setAttribute($attr, $val);
        return $this;
    }

    /**
     * Traverses to parent
     *
     * @return XmlBuilder
     */
    public function parent()
    {
        $this->__currentNode__ = $this->__currentNode__->parentNode;
        return $this;
    }

    /**
     * Traverses to parent with $name
     *
     * @param $tag
     *
     * @return XmlBuilder
     * @throws \Exception
     */
    public function parents($tag)
    {
        $traverseNode = $this->__currentNode__;
        $elFound = false;
        while ($traverseNode->parentNode) {
            $traverseNode = $traverseNode->parentNode;
            if ($traverseNode->tagName == $tag) {
                $this->__currentNode__ = $traverseNode;
                $elFound = true;
                break;
            }
        }

        if (!$elFound) {
            throw new \Exception("Parent $tag not found in XML");
        }

        return $this;
    }

    public function __toString()
    {
        return $this->__dom__->saveXML();
    }

    /**
     * @return \DOMDocument
     */
    public function getDom()
    {
        return $this->__dom__;
    }
}
<?php
namespace Codeception\Step;

use Codeception\Lib\ModuleContainer;
use Codeception\Step as CodeceptionStep;

class Comment extends CodeceptionStep
{
    public function __toString()
    {
        return (string) $this->getAction();
    }

    public function toString($maxLength)
    {
        return mb_strcut($this->__toString(), 0, $maxLength, 'utf-8');
    }

    public function getHtml($highlightColor = '#732E81')
    {
        return '<strong>' . $this->getAction() . '</strong>';
    }

    public function getPhpCode($maxLength)
    {
        return '// ' . $this->getAction();
    }

    public function run(ModuleContainer $container = null)
    {
        // don't do anything, let's rest
    }

    public function getPrefix()
    {
        return '';
    }
}
<?php

namespace Codeception\Step;

use Codeception\Lib\ModuleContainer;
use Codeception\Util\Template;

class Retry extends Assertion implements GeneratedStep
{

    protected static $methodTemplate = <<<EOF
    
    /**
     * [!] Method is generated.
     * 
     * {{doc}}
     * 
     * Retry number and interval set by \$I->retry();
     *
     * @see \{{module}}::{{method}}()
     */
    public function {{action}}({{params}}) {
        \$retryNum = isset(\$this->retryNum) ? \$this->retryNum : 1;
        \$retryInterval = isset(\$this->retryInterval) ? \$this->retryInterval : 200;
        return \$this->getScenario()->runStep(new \Codeception\Step\Retry('{{method}}', func_get_args(), \$retryNum, \$retryInterval));
    }
EOF;

    private $retryNum;
    private $retryInterval;

    public function __construct($action, array $arguments, $retryNum, $retryInterval)
    {
        $this->action = $action;
        $this->arguments = $arguments;
        $this->retryNum = $retryNum;
        $this->retryInterval = $retryInterval;
    }

    public function run(ModuleContainer $container = null)
    {
        $retry = 0;
        $interval = $this->retryInterval;
        while (true) {
            try {
                $this->isTry = $retry < $this->retryNum;
                return parent::run($container);
            } catch (\Exception $e) {
                $retry++;
                if (!$this->isTry) {
                    throw $e;
                }
                codecept_debug("Retrying #$retry in ${interval}ms");
                usleep($interval * 1000);
                $interval *= 2;
            }
        }
    }

    public static function getTemplate(Template $template)
    {
        $action = $template->getVar('action');

        if ((strpos($action, 'have') === 0) || (strpos($action, 'am') === 0)) {
            return; // dont retry conditions
        }

        if (strpos($action, 'wait') === 0) {
            return; // dont retry waiters
        }

        $doc = "* Executes $action and retries on failure.";

        return (new Template(self::$methodTemplate))
            ->place('method', $template->getVar('method'))
            ->place('module', $template->getVar('module'))
            ->place('params', $template->getVar('params'))
            ->place('doc', $doc)
            ->place('action', 'retry'. ucfirst($action));
    }
}
<?php
namespace Codeception\Step;

use Codeception\Step;

class Action extends Step
{
}
<?php
namespace Codeception\Step;

use Codeception\Step as CodeceptionStep;
use Codeception\Lib\ModuleContainer;

class Skip extends CodeceptionStep
{
    public function run(ModuleContainer $container = null)
    {
        throw new \PHPUnit\Framework\SkippedTestError($this->getAction());
    }

    public function __toString()
    {
        return $this->getAction();
    }
}
<?php

namespace Codeception\Step;

use Codeception\Lib\ModuleContainer;
use Codeception\Util\Template;

class TryTo extends Assertion implements GeneratedStep
{
    public function run(ModuleContainer $container = null)
    {
        $this->isTry = true;
        try {
            parent::run($container);
        } catch (\Exception $e) {
            codecept_debug("Failed to perform: {$e->getMessage()}, skipping...");
            return false;
        }
        return true;
    }

    public static function getTemplate(Template $template)
    {
        $action = $template->getVar('action');

        if ((strpos($action, 'have') === 0) || (strpos($action, 'am') === 0)) {
            return; // dont try on conditions
        }

        if (strpos($action, 'wait') === 0) {
            return; // dont try on waiters
        }

        if (strpos($action, 'grab') === 0) {
            return; // dont on grabbers
        }

        $conditionalDoc = "* [!] Test won't be stopped on fail. Error won't be logged \n     " . $template->getVar('doc');

        return $template
            ->place('doc', $conditionalDoc)
            ->place('action', 'tryTo' . ucfirst($action))
            ->place('step', 'TryTo');
    }
}
<?php
namespace Codeception\Step;

use Codeception\Step as CodeceptionStep;

class Assertion extends CodeceptionStep
{
}
<?php
namespace Codeception\Step;

use Codeception\Step as CodeceptionStep;
use Codeception\Lib\ModuleContainer;

class Executor extends CodeceptionStep
{

    protected $callable = null;

    public function __construct(\Closure $callable, $arguments = [])
    {
        parent::__construct('execute callable function', []);

        $this->callable = $callable;
    }

    public function run(ModuleContainer $container = null)
    {
        $callable = $this->callable;

        return $callable();
    }
}
<?php
namespace Codeception\Step;

use Codeception\Step as CodeceptionStep;
use Codeception\Lib\ModuleContainer;

class Incomplete extends CodeceptionStep
{
    public function run(ModuleContainer $container = null)
    {
        throw new \PHPUnit\Framework\IncompleteTestError($this->getAction());
    }

    public function __toString()
    {
        return $this->getAction();
    }
}
<?php
namespace Codeception\Step;

use Codeception\Util\Template;

interface GeneratedStep
{
    public static function getTemplate(Template $template);
}
<?php

namespace Codeception\Step\Argument;

class PasswordArgument implements FormattedOutput
{
    /**
     * @var string
     */
    private $password;

    public function __construct($password)
    {
        $this->password = $password;
    }

    /**
     * {@inheritdoc}
     */
    public function getOutput()
    {
        return '******';
    }

    /**
     * {@inheritdoc}
     */
    public function __toString()
    {
        return $this->password;
    }
}
<?php

namespace Codeception\Step\Argument;

/**
 * Implemented in Step arguments where literal values need to be modified in test execution output (e.g. passwords).
 */
interface FormattedOutput
{
    /**
     * Returns the argument's value formatted for output.
     *
     * @return string
     */
    public function getOutput();

    /**
     * Returns the argument's literal value.
     *
     * @return string
     */
    public function __toString();
}
<?php
namespace Codeception\Step;

use Codeception\Step as CodeceptionStep;

class Condition extends CodeceptionStep
{
}
<?php
namespace Codeception\Step;

use Codeception\Exception\ConditionalAssertionFailed;
use Codeception\Lib\ModuleContainer;
use Codeception\Util\Template;

class ConditionalAssertion extends Assertion implements GeneratedStep
{
    public function run(ModuleContainer $container = null)
    {
        try {
            parent::run($container);
        } catch (\PHPUnit\Framework\AssertionFailedError $e) {
            throw new ConditionalAssertionFailed($e->getMessage(), $e->getCode(), $e);
        }
    }

    public function getAction()
    {
        $action = 'can' . ucfirst($this->action);
        $action = preg_replace('/^canDont/', 'cant', $action);
        return $action;
    }

    public function getHumanizedAction()
    {
        return $this->humanize($this->action . ' ' . $this->getHumanizedArguments());
    }

    public static function getTemplate(Template $template)
    {
        $action = $template->getVar('action');

        if ((0 !== strpos($action, 'see')) && (0 !== strpos($action, 'dontSee'))) {
            return '';
        }

        $conditionalDoc = "* [!] Conditional Assertion: Test won't be stopped on fail\n     " . $template->getVar('doc');

        $prefix = 'can';
        if (strpos($action, 'dontSee') === 0) {
            $prefix = 'cant';
            $action = str_replace('dont', '', $action);
        }

        return $template
            ->place('doc', $conditionalDoc)
            ->place('action', $prefix . ucfirst($action))
            ->place('step', 'ConditionalAssertion');
    }

    public function match($name)
    {
        return 0 === strpos($name, 'see') || 0 === strpos($name, 'dontSee');
    }
}
<?php
namespace Codeception\Step;

use Codeception\Lib\ModuleContainer;
use Codeception\Step as CodeceptionStep;

class Meta extends CodeceptionStep
{
    public function run(ModuleContainer $container = null)
    {
    }

    public function setTraceInfo($file, $line)
    {
        $this->file = $file;
        $this->line = $line;
    }

    public function setPrefix($actor)
    {
        $this->prefix = $actor;
    }

    public function getArgumentsAsString($maxLength = 200)
    {
        $argumentBackup = $this->arguments;
        $lastArgAsString = '';
        $lastArg = end($this->arguments);
        if (is_string($lastArg) && strpos($lastArg, "\n")  !== false) {
            $lastArgAsString = "\r\n   " . str_replace("\n", "\n   ", $lastArg);
            array_pop($this->arguments);
        }
        $result = parent::getArgumentsAsString($maxLength) . $lastArgAsString;
        $this->arguments = $argumentBackup;
        return $result;
    }

    public function setFailed($failed)
    {
        $this->failed = $failed;
    }
}
<?php

namespace Codeception;

use Codeception\Exception\ConfigurationException;
use Symfony\Component\Console\Application as BaseApplication;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\OutputInterface;

class Application extends BaseApplication
{

    /**
     * @var ArgvInput
     */
    protected $coreArguments = null;

    /**
     * Register commands from config file
     *
     *  extensions:
     *      commands:
     *          - Project\Command\MyCustomCommand
     *
     */
    public function registerCustomCommands()
    {
        try {
            $this->readCustomCommandsFromConfig();
        } catch (ConfigurationException $e) {
            if ($e->getCode() === 404) {
                return;
            }
            $this->renderExceptionWrapper($e, new ConsoleOutput());
            exit(1);
        } catch (\Exception $e) {
            $this->renderExceptionWrapper($e, new ConsoleOutput());
            exit(1);
        }
    }

    public function renderExceptionWrapper(\Exception $e, OutputInterface $output)
    {
        if (method_exists('Symfony\Component\Console\Application', 'renderException')) {
            //Symfony 5
            parent::renderException($e, $output);
        } else {
            parent::renderThrowable($e, $output);
        }
    }

    /**
     * Search custom commands and register them.
     *
     * @throws ConfigurationException
     */
    protected function readCustomCommandsFromConfig()
    {
        $this->getCoreArguments(); // Maybe load outside configfile

        $config = Configuration::config();

        if (empty($config['extensions']['commands'])) {
            return;
        }

        foreach ($config['extensions']['commands'] as $commandClass) {
            $commandName = $this->getCustomCommandName($commandClass);
            $this->add(new $commandClass($commandName));
        }
    }

    /**
     * Validate and get the name of the command
     *
     * @param CustomCommandInterface $commandClass
     *
     * @throws ConfigurationException
     *
     * @return string
     */
    protected function getCustomCommandName($commandClass)
    {
        if (!class_exists($commandClass)) {
            throw new ConfigurationException("Extension: Command class $commandClass not found");
        }

        $interfaces = class_implements($commandClass);

        if (!in_array('Codeception\CustomCommandInterface', $interfaces)) {
            throw new ConfigurationException("Extension: Command {$commandClass} must implement " .
                                             "the interface `Codeception\\CustomCommandInterface`");
        }

        return $commandClass::getCommandName();
    }

    /**
     * To cache Class ArgvInput
     *
     * @inheritDoc
     */
    public function run(InputInterface $input = null, OutputInterface $output = null)
    {
        if ($input === null) {
            $input = $this->getCoreArguments();
        }

        if (!ini_get('register_argc_argv')) {
            throw new ConfigurationException('register_argc_argv must be set to On for running Codeception');
        }

        return parent::run($input, $output);
    }

    /**
     * Add global a --config option.
     *
     * @return InputDefinition
     */
    protected function getDefaultInputDefinition()
    {
        $inputDefinition = parent::getDefaultInputDefinition();
        $inputDefinition->addOption(
            new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config')
        );
        return $inputDefinition;
    }

    /**
     * Search for --config Option and if found will be loaded
     *
     * example:
     * -c file.yml|dir
     * -cfile.yml|dir
     * --config file.yml|dir
     * --config=file.yml|dir
     *
     * @return ArgvInput
     */
    protected function getCoreArguments()
    {
        if ($this->coreArguments !== null) {
            return $this->coreArguments;
        }

        $argvWithoutConfig = [];
        if (isset($_SERVER['argv'])) {
            $argv = $_SERVER['argv'];

            for ($i = 0; $i < count($argv); $i++) {
                if (preg_match('/^(?:-([^c-]*)?c|--config(?:=|$))(.*)$/', $argv[$i], $match)) {
                    if (!empty($match[2])) { //same index
                        $this->preloadConfiguration($match[2]);
                    } elseif (isset($argv[$i + 1])) { //next index
                        $this->preloadConfiguration($argv[++$i]);
                    }
                    if (!empty($match[1])) {
                        $argvWithoutConfig[] = "-" . $match[1]; //rest commands
                    }
                    continue;
                }
                $argvWithoutConfig[] = $argv[$i];
            }
        }

        return $this->coreArguments = new ArgvInput($argvWithoutConfig);
    }

    /**
     * Pre load Configuration, the config option is use.
     *
     * @param string $configFile Path to Configuration
     *
     * @throws ConfigurationException
     */
    protected function preloadConfiguration($configFile)
    {
        try {
            Configuration::config($configFile);
        } catch (ConfigurationException $e) {
            if ($e->getCode() == 404) {
                throw new ConfigurationException("Your configuration file `{$configFile}` could not be found.", 405);
            }
            throw $e;
        }
    }
}
<?php

namespace Codeception;

use Codeception\Test\Metadata;

interface TestInterface extends \PHPUnit\Framework\Test
{
    /**
     * @return Metadata
     */
    public function getMetadata();
}
<?php
namespace Codeception;

use Codeception\Test\Descriptor;
use Codeception\Test\Interfaces\Dependent;

class Suite extends \PHPUnit\Framework\TestSuite
{
    protected $modules;
    protected $baseName;

    public function reorderDependencies()
    {
        $tests = [];
        foreach ($this->tests as $test) {
            $tests = array_merge($tests, $this->getDependencies($test));
        }

        $queue = [];
        $hashes = [];
        foreach ($tests as $test) {
            if (in_array(spl_object_hash($test), $hashes)) {
                continue;
            }
            $hashes[] = spl_object_hash($test);
            $queue[] = $test;
        }
        $this->tests = $queue;
    }

    protected function getDependencies($test)
    {
        if (!$test instanceof Dependent) {
            return [$test];
        }
        $tests = [];
        foreach ($test->fetchDependencies() as $requiredTestName) {
            $required = $this->findMatchedTest($requiredTestName);
            if (!$required) {
                continue;
            }
            $tests = array_merge($tests, $this->getDependencies($required));
        }
        $tests[] = $test;
        return $tests;
    }

    protected function findMatchedTest($testSignature)
    {
        foreach ($this->tests as $test) {
            $signature = Descriptor::getTestSignature($test);
            if ($signature === $testSignature) {
                return $test;
            }
        }
    }

    /**
     * @return mixed
     */
    public function getModules()
    {
        return $this->modules;
    }

    /**
     * @param mixed $modules
     */
    public function setModules($modules)
    {
        $this->modules = $modules;
    }

    /**
     * @return mixed
     */
    public function getBaseName()
    {
        return $this->baseName;
    }

    /**
     * @param mixed $baseName
     */
    public function setBaseName($baseName)
    {
        $this->baseName = $baseName;
    }
}
<?php
namespace Codeception\Coverage;

use Codeception\Configuration;
use Codeception\Coverage\Subscriber\Printer;
use Codeception\Lib\Interfaces\Remote;
use Codeception\Stub;
use Codeception\Subscriber\Shared\StaticEvents;
use PHPUnit\Framework\CodeCoverageException;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Filter as CodeCoverageFilter;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

abstract class SuiteSubscriber implements EventSubscriberInterface
{
    use StaticEvents;

    protected $defaultSettings = [
        'enabled'        => false,
        'remote'         => false,
        'local'          => false,
        'xdebug_session' => 'codeception',
        'remote_config'  => null,
        'show_uncovered' => false,
        'c3_url'         => null,
        'work_dir'       => null,
        'cookie_domain'  => null,
    ];

    protected $settings = [];
    protected $filters = [];
    protected $modules = [];

    protected $coverage;
    protected $logDir;
    protected $options;
    public static $events = [];

    abstract protected function isEnabled();

    public function __construct($options = [])
    {
        $this->options = $options;
        $this->logDir = Configuration::outputDir();
    }

    protected function applySettings($settings)
    {
        try {
            $this->coverage = PhpCodeCoverageFactory::build();
        } catch (CodeCoverageException $e) {
            throw new \Exception(
                'XDebug is required to collect CodeCoverage. Please install xdebug extension and enable it in php.ini'
            );
        }

        $this->filters = $settings;
        $this->settings = $this->defaultSettings;
        $keys = array_keys($this->defaultSettings);
        foreach ($keys as $key) {
            if (isset($settings['coverage'][$key])) {
                $this->settings[$key] = $settings['coverage'][$key];
            }
        }
        if (method_exists($this->coverage, 'setProcessUncoveredFilesFromWhitelist')) {
            //php-code-coverage 8 or older
            $this->coverage->setProcessUncoveredFilesFromWhitelist($this->settings['show_uncovered']);
        } else {
            //php-code-coverage 9+
            if ($this->settings['show_uncovered']) {
                $this->coverage->processUncoveredFiles();
            } else {
                $this->coverage->doNotProcessUncoveredFiles();
            }
        }
    }

    /**
     * @param array $modules
     * @return \Codeception\Lib\Interfaces\Remote|null
     */
    protected function getServerConnectionModule(array $modules)
    {
        foreach ($modules as $module) {
            if ($module instanceof Remote) {
                return $module;
            }
        }
        return null;
    }

    public function applyFilter(\PHPUnit\Framework\TestResult $result)
    {
        $driver = Stub::makeEmpty('SebastianBergmann\CodeCoverage\Driver\Driver');
        $result->setCodeCoverage(new CodeCoverage($driver, new CodeCoverageFilter()));

        Filter::setup($this->coverage)
            ->whiteList($this->filters)
            ->blackList($this->filters);

        $result->setCodeCoverage($this->coverage);
    }

    protected function mergeToPrint($coverage)
    {
        Printer::$coverage->merge($coverage);
    }
}
<?php
namespace Codeception\Coverage;

use Codeception\Configuration;
use Codeception\Exception\ConfigurationException;
use Codeception\Exception\ModuleException;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use Symfony\Component\Finder\Exception\DirectoryNotFoundException;
use Symfony\Component\Finder\Finder;

class Filter
{
    /**
     * @var CodeCoverage
     */
    protected $phpCodeCoverage = null;

    /**
     * @var Filter
     */
    protected static $c3;

    /**
     * @var \SebastianBergmann\CodeCoverage\Filter
     */
    protected $filter = null;

    public function __construct(CodeCoverage $phpCoverage)
    {
        $this->phpCodeCoverage = $phpCoverage;
        $this->filter = $this->phpCodeCoverage->filter();
    }

    /**
     * @param CodeCoverage $phpCoverage
     * @return Filter
     */
    public static function setup(CodeCoverage $phpCoverage)
    {
        self::$c3 = new self($phpCoverage);
        return self::$c3;
    }

    /**
     * @return null|CodeCoverage
     */
    public function getPhpCodeCoverage()
    {
        return $this->phpCodeCoverage;
    }

    /**
     * @param $config
     * @return Filter
     */
    public function whiteList($config)
    {
        $filter = $this->filter;
        if (!isset($config['coverage'])) {
            return $this;
        }
        $coverage = $config['coverage'];
        if (!isset($coverage['whitelist'])) {
            $coverage['whitelist'] = [];
            if (isset($coverage['include'])) {
                $coverage['whitelist']['include'] = $coverage['include'];
            }
            if (isset($coverage['exclude'])) {
                $coverage['whitelist']['exclude'] = $coverage['exclude'];
            }
        }

        if (isset($coverage['whitelist']['include'])) {
            if (!is_array($coverage['whitelist']['include'])) {
                throw new ConfigurationException('Error parsing yaml. Config `whitelist: include:` should be an array');
            }
            foreach ($coverage['whitelist']['include'] as $fileOrDir) {
                $finder = strpos($fileOrDir, '*') === false
                    ? [Configuration::projectDir() . DIRECTORY_SEPARATOR . $fileOrDir]
                    : $this->matchWildcardPattern($fileOrDir);

                foreach ($finder as $file) {
                    if (method_exists($filter, 'addFileToWhitelist')) {
                        //php-code-coverage 8 or older
                        $filter->addFileToWhitelist($file);
                    } else {
                        //php-code-coverage 9+
                        $filter->includeFile($file);
                    }
                }
            }
        }

        if (isset($coverage['whitelist']['exclude'])) {
            if (!is_array($coverage['whitelist']['exclude'])) {
                throw new ConfigurationException('Error parsing yaml. Config `whitelist: exclude:` should be an array');
            }
            foreach ($coverage['whitelist']['exclude'] as $fileOrDir) {
                try {
                    $finder = strpos($fileOrDir, '*') === false
                        ? [Configuration::projectDir() . DIRECTORY_SEPARATOR . $fileOrDir]
                        : $this->matchWildcardPattern($fileOrDir);

                    foreach ($finder as $file) {
                        if (method_exists($filter, 'removeFileFromWhitelist')) {
                            //php-code-coverage 8 or older
                            $filter->removeFileFromWhitelist($file);
                        } else {
                            //php-code-coverage 9+
                            $filter->excludeFile($file);
                        }
                    }
                } catch (DirectoryNotFoundException $e) {
                    continue;
                }
            }
        }
        return $this;
    }

    /**
     * @param $config
     * @return Filter
     */
    public function blackList($config)
    {
        $filter = $this->filter;
        if (!isset($config['coverage'])) {
            return $this;
        }
        $coverage = $config['coverage'];
        if (isset($coverage['blacklist'])) {
            if (!method_exists($filter, 'addFileToBlacklist')) {
                throw new ModuleException($this, 'The blacklist functionality has been removed from PHPUnit 5,'
                . ' please remove blacklist section from configuration.');
            }

            if (isset($coverage['blacklist']['include'])) {
                foreach ($coverage['blacklist']['include'] as $fileOrDir) {
                    $finder = strpos($fileOrDir, '*') === false
                        ? [Configuration::projectDir() . DIRECTORY_SEPARATOR . $fileOrDir]
                        : $this->matchWildcardPattern($fileOrDir);

                    foreach ($finder as $file) {
                        $filter->addFileToBlacklist($file);
                    }
                }
            }
            if (isset($coverage['blacklist']['exclude'])) {
                foreach ($coverage['blacklist']['exclude'] as $fileOrDir) {
                    $finder = strpos($fileOrDir, '*') === false
                        ? [Configuration::projectDir() . DIRECTORY_SEPARATOR . $fileOrDir]
                        : $this->matchWildcardPattern($fileOrDir);

                    foreach ($finder as $file) {
                        $filter->removeFileFromBlacklist($file);
                    }
                }
            }
        }
        return $this;
    }

    protected function matchWildcardPattern($pattern)
    {
        $finder = Finder::create();
        $fileOrDir = str_replace('\\', '/', $pattern);
        $parts = explode('/', $fileOrDir);
        $file = array_pop($parts);
        if ($file === '*') {
            $file = '*.php';
        }
        $finder->name($file);
        if (count($parts)) {
            $last_path = array_pop($parts);
            if ($last_path === '*') {
                $finder->in(Configuration::projectDir() . implode('/', $parts));
            } else {
                $finder->in(Configuration::projectDir() . implode('/', $parts) . '/' . $last_path);
            }
        }
        $finder->ignoreVCS(true)->files();
        return $finder;
    }

    /**
     * @return \SebastianBergmann\CodeCoverage\Filter
     */
    public function getFilter()
    {
        return $this->filter;
    }
}
<?php

namespace Codeception\Coverage;

use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Driver\Driver;
use SebastianBergmann\CodeCoverage\Filter as CodeCoverageFilter;

class PhpCodeCoverageFactory
{
    public static function build()
    {
        if (method_exists(Driver::class, 'forLineCoverage')) {
            //php-code-coverage 9+
            $filter = new CodeCoverageFilter();
            $driver = Driver::forLineCoverage($filter);
            return new CodeCoverage($driver, $filter);
        } else {
            //php-code-coverage 8 or older
            return new CodeCoverage();
        }
    }
}
<?php
namespace Codeception\Coverage\Subscriber;

use Codeception\Configuration;
use Codeception\Event\SuiteEvent;
use Codeception\Util\FileSystem;

/**
 * When collecting code coverage on remote server
 * data is retrieved over HTTP and not merged with the local code coverage results.
 *
 * Class RemoteServer
 * @package Codeception\Coverage\Subscriber
 */
class RemoteServer extends LocalServer
{
    public function isEnabled()
    {
        return $this->module and $this->settings['remote'] and $this->settings['enabled'];
    }

    public function afterSuite(SuiteEvent $e)
    {
        if (!$this->isEnabled()) {
            return;
        }

        $suite = strtr($e->getSuite()->getName(), ['\\' => '.']);
        if ($this->options['coverage-xml']) {
            $this->retrieveAndPrintXml($suite);
        }
        if ($this->options['coverage-html']) {
            $this->retrieveAndPrintHtml($suite);
        }
        if ($this->options['coverage-crap4j']) {
            $this->retrieveAndPrintCrap4j($suite);
        }
        if ($this->options['coverage-cobertura']) {
            $this->retrieveAndPrintCobertura($suite);
        }
        if ($this->options['coverage-phpunit']) {
            $this->retrieveAndPrintPHPUnit($suite);
        }
    }

    protected function retrieveAndPrintHtml($suite)
    {
        $tempFile = tempnam(sys_get_temp_dir(), 'C3') . '.tar';
        file_put_contents($tempFile, $this->c3Request('html'));

        $destDir = Configuration::outputDir() . $suite . '.remote.coverage';
        if (is_dir($destDir)) {
            FileSystem::doEmptyDir($destDir);
        } else {
            mkdir($destDir, 0777, true);
        }

        $phar = new \PharData($tempFile);
        $phar->extractTo($destDir);

        unlink($tempFile);
    }

    protected function retrieveAndPrintXml($suite)
    {
        $destFile = Configuration::outputDir() . $suite . '.remote.coverage.xml';
        file_put_contents($destFile, $this->c3Request('clover'));
    }

    protected function retrieveAndPrintCrap4j($suite)
    {
        $destFile = Configuration::outputDir() . $suite . '.remote.crap4j.xml';
        file_put_contents($destFile, $this->c3Request('crap4j'));
    }

    protected function retrieveAndPrintCobertura($suite)
    {
        $destFile = Configuration::outputDir() . $suite . '.remote.cobertura.xml';
        file_put_contents($destFile, $this->c3Request('cobertura'));
    }

    protected function retrieveAndPrintPHPUnit($suite)
    {
        $tempFile = tempnam(sys_get_temp_dir(), 'C3') . '.tar';
        file_put_contents($tempFile, $this->c3Request('phpunit'));

        $destDir = Configuration::outputDir() . $suite . '.remote.coverage-phpunit';
        if (is_dir($destDir)) {
            FileSystem::doEmptyDir($destDir);
        } else {
            mkdir($destDir, 0777, true);
        }

        $phar = new \PharData($tempFile);
        $phar->extractTo($destDir);

        unlink($tempFile);
    }
}
<?php
namespace Codeception\Coverage\Subscriber;

use Codeception\Coverage\SuiteSubscriber;
use Codeception\Event\SuiteEvent;
use Codeception\Events;
use Codeception\Lib\Interfaces\Remote;

/**
 * Collects code coverage from unit and functional tests.
 * Results from all suites are merged.
 */
class Local extends SuiteSubscriber
{
    public static $events = [
        Events::SUITE_BEFORE => 'beforeSuite',
        Events::SUITE_AFTER  => 'afterSuite',
    ];

    /**
     * @var Remote
     */
    protected $module;

    protected function isEnabled()
    {
        return $this->module === null and $this->settings['enabled'];
    }

    public function beforeSuite(SuiteEvent $e)
    {
        $this->applySettings($e->getSettings());
        $this->module = $this->getServerConnectionModule($e->getSuite()->getModules());
        if (!$this->isEnabled()) {
            return;
        }
        $this->applyFilter($e->getResult());
    }

    public function afterSuite(SuiteEvent $e)
    {
        if (!$this->isEnabled()) {
            return;
        }
        $this->mergeToPrint($e->getResult()->getCodeCoverage());
    }
}
<?php
namespace Codeception\Coverage\Subscriber;

use Codeception\Configuration;
use Codeception\Coverage\Filter;
use Codeception\Coverage\PhpCodeCoverageFactory;
use Codeception\Event\PrintResultEvent;
use Codeception\Events;
use Codeception\Exception\ConfigurationException;
use Codeception\Subscriber\Shared\StaticEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class Printer implements EventSubscriberInterface
{
    use StaticEvents;

    public static $events = [
        Events::RESULT_PRINT_AFTER => 'printResult'
    ];

    protected $settings = [
        'enabled'           => true,
        'low_limit'         => '35',
        'high_limit'        => '70',
        'show_uncovered'    => false,
        'show_only_summary' => false
    ];

    public static $coverage;
    protected $options;
    protected $logDir;
    protected $destination = [];

    public function __construct($options)
    {
        $this->options = $options;
        $this->logDir = Configuration::outputDir();
        $this->settings = array_merge($this->settings, Configuration::config()['coverage']);

        self::$coverage = PhpCodeCoverageFactory::build();

        // Apply filter
        $filter = new Filter(self::$coverage);
        $filter
            ->whiteList(Configuration::config())
            ->blackList(Configuration::config());
    }

    protected function absolutePath($path)
    {
        if ((strpos($path, '/') === 0) || (strpos($path, ':') === 1)) { // absolute path
            return $path;
        }
        return $this->logDir . $path;
    }

    public function printResult(PrintResultEvent $e)
    {
        $printer = $e->getPrinter();
        if (!$this->settings['enabled']) {
            $printer->write("\nCodeCoverage is disabled in `codeception.yml` config\n");
            return;
        }

        if (!$this->options['quiet']) {
            $this->printConsole($printer);
        }
        $printer->write("Remote CodeCoverage reports are not printed to console\n");
        $this->printPHP();
        $printer->write("\n");
        if ($this->options['coverage-html']) {
            $this->printHtml();
            $printer->write("HTML report generated in {$this->options['coverage-html']}\n");
        }
        if ($this->options['coverage-xml']) {
            $this->printXml();
            $printer->write("XML report generated in {$this->options['coverage-xml']}\n");
        }
        if ($this->options['coverage-text']) {
            $this->printText();
            $printer->write("Text report generated in {$this->options['coverage-text']}\n");
        }
        if ($this->options['coverage-crap4j']) {
            $this->printCrap4j();
            $printer->write("Crap4j report generated in {$this->options['coverage-crap4j']}\n");
        }
        if ($this->options['coverage-cobertura']) {
            $this->printCobertura();
            $printer->write("Cobertura report generated in {$this->options['coverage-cobertura']}\n");
        }
        if ($this->options['coverage-phpunit']) {
            $this->printPHPUnit();
            $printer->write("PHPUnit report generated in {$this->options['coverage-phpunit']}\n");
        }
    }

    protected function printConsole(\PHPUnit\Util\Printer $printer)
    {
        $writer = new \SebastianBergmann\CodeCoverage\Report\Text(
            $this->settings['low_limit'],
            $this->settings['high_limit'],
            $this->settings['show_uncovered'],
            $this->settings['show_only_summary']
        );
        $printer->write($writer->process(self::$coverage, $this->options['colors']));
    }

    protected function printHtml()
    {
        $writer = new \SebastianBergmann\CodeCoverage\Report\Html\Facade(
            $this->settings['low_limit'],
            $this->settings['high_limit'],
            sprintf(
                ', <a href="http://codeception.com">Codeception</a> and <a href="http://phpunit.de/">PHPUnit %s</a>',
                \PHPUnit\Runner\Version::id()
            )
        );

        $writer->process(self::$coverage, $this->absolutePath($this->options['coverage-html']));
    }

    protected function printXml()
    {
        $writer = new \SebastianBergmann\CodeCoverage\Report\Clover();
        $writer->process(self::$coverage, $this->absolutePath($this->options['coverage-xml']));
    }

    protected function printPHP()
    {
        $writer = new \SebastianBergmann\CodeCoverage\Report\PHP;
        $writer->process(self::$coverage, $this->absolutePath($this->options['coverage']));
    }

    protected function printText()
    {
        $writer = new \SebastianBergmann\CodeCoverage\Report\Text(
            $this->settings['low_limit'],
            $this->settings['high_limit'],
            $this->settings['show_uncovered'],
            $this->settings['show_only_summary']
        );
        file_put_contents(
            $this->absolutePath($this->options['coverage-text']),
            $writer->process(self::$coverage, false)
        );
    }

    protected function printCrap4j()
    {
        $writer = new \SebastianBergmann\CodeCoverage\Report\Crap4j;
        $writer->process(self::$coverage, $this->absolutePath($this->options['coverage-crap4j']));
    }

    protected function printCobertura()
    {
        if (!class_exists(\SebastianBergmann\CodeCoverage\Report\Cobertura::class)) {
            throw new ConfigurationException("Cobertura report requires php-code-coverage >= 9.2");
        }
        $writer = new \SebastianBergmann\CodeCoverage\Report\Cobertura;
        $writer->process(self::$coverage, $this->absolutePath($this->options['coverage-cobertura']));
    }

    protected function printPHPUnit()
    {
        $writer = new \SebastianBergmann\CodeCoverage\Report\Xml\Facade(\PHPUnit\Runner\Version::id());
        $writer->process(self::$coverage, $this->absolutePath($this->options['coverage-phpunit']));
    }
}
<?php
namespace Codeception\Coverage\Subscriber;

use Codeception\Configuration;
use Codeception\Coverage\SuiteSubscriber;
use Codeception\Event\StepEvent;
use Codeception\Event\SuiteEvent;
use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\Exception\ModuleException;
use Codeception\Exception\RemoteException;
use Facebook\WebDriver\Exception\NoSuchAlertException;

/**
 * When collecting code coverage data from local server HTTP requests are sent to c3.php file.
 * Coverage Collection is started by sending cookies/headers.
 * Result is taken from the local file and merged with local code coverage results.
 *
 * Class LocalServer
 * @package Codeception\Coverage\Subscriber
 */
class LocalServer extends SuiteSubscriber
{
    // headers
    const COVERAGE_HEADER = 'X-Codeception-CodeCoverage';
    const COVERAGE_HEADER_ERROR = 'X-Codeception-CodeCoverage-Error';
    const COVERAGE_HEADER_CONFIG = 'X-Codeception-CodeCoverage-Config';
    const COVERAGE_HEADER_SUITE = 'X-Codeception-CodeCoverage-Suite';

    // cookie names
    const COVERAGE_COOKIE = 'CODECEPTION_CODECOVERAGE';
    const COVERAGE_COOKIE_ERROR = 'CODECEPTION_CODECOVERAGE_ERROR';

    protected $suiteName;
    protected $c3Access = [
        'http' => [
            'method' => "GET",
            'header' => ''
        ]
    ];

    /**
     * @var \Codeception\Lib\Interfaces\Web
     */
    protected $module;

    public static $events = [
        Events::SUITE_BEFORE => 'beforeSuite',
        Events::TEST_BEFORE  => 'beforeTest',
        Events::STEP_AFTER   => 'afterStep',
        Events::SUITE_AFTER  => 'afterSuite',
    ];

    protected function isEnabled()
    {
        return $this->module && !$this->settings['remote'] && $this->settings['enabled'];
    }

    public function beforeSuite(SuiteEvent $e)
    {
        $this->module = $this->getServerConnectionModule($e->getSuite()->getModules());
        $this->applySettings($e->getSettings());
        if (!$this->isEnabled()) {
            return;
        }

        $this->suiteName = $e->getSuite()->getBaseName();

        if ($this->settings['remote_config']) {
            $this->addC3AccessHeader(self::COVERAGE_HEADER_CONFIG, $this->settings['remote_config']);
            $knock = $this->c3Request('clear');
            if ($knock === false) {
                throw new RemoteException(
                    '
                    CodeCoverage Error.
                    Check the file "c3.php" is included in your application.
                    We tried to access "/c3/report/clear" but this URI was not accessible.
                    You can review actual error messages in c3tmp dir.
                    '
                );
            }
        }
    }

    public function beforeTest(TestEvent $e)
    {
        if (!$this->isEnabled()) {
            return;
        }
        $this->startCoverageCollection($e->getTest()->getName());
    }

    public function afterStep(StepEvent $e)
    {
        if (!$this->isEnabled()) {
            return;
        }
        $this->fetchErrors();
    }

    public function afterSuite(SuiteEvent $e)
    {
        if (!$this->isEnabled()) {
            return;
        }
        $coverageFile = Configuration::outputDir() . 'c3tmp/codecoverage.serialized';

        $retries = 5;
        while (!file_exists($coverageFile) && --$retries >= 0) {
            usleep(0.5 * 1000000); // 0.5 sec
        }

        if (!file_exists($coverageFile)) {
            if (file_exists(Configuration::outputDir() . 'c3tmp/error.txt')) {
                throw new \RuntimeException(file_get_contents(Configuration::outputDir() . 'c3tmp/error.txt'));
            }
            return;
        }

        $contents = file_get_contents($coverageFile);
        $coverage = @unserialize($contents);
        if ($coverage === false) {
            return;
        }

        $this->preProcessCoverage($coverage)
             ->mergeToPrint($coverage);
    }

    /**
     * Allows Translating Remote Paths To Local (IE: When Using Docker)
     *
     * @param \SebastianBergmann\CodeCoverage\CodeCoverage $coverage
     * @return $this
     */
    protected function preProcessCoverage($coverage)
    {
        //Only Process If Work Directory Set
        if ($this->settings['work_dir'] === null) {
            return $this;
        }

        $workDir    = rtrim($this->settings['work_dir'], '/\\') . DIRECTORY_SEPARATOR;
        $projectDir = Configuration::projectDir();
        $data       = $coverage->getData(true); //We only want covered files, not all whitelisted ones.

        codecept_debug("Replacing all instances of {$workDir} with {$projectDir}");

        foreach ($data as $path => $datum) {
            unset($data[$path]);

            $path = str_replace($workDir, $projectDir, $path);

            $data[$path] = $datum;
        }

        $coverage->setData($data);

        return $this;
    }

    protected function c3Request($action)
    {
        $this->addC3AccessHeader(self::COVERAGE_HEADER, 'remote-access');
        $context = stream_context_create($this->c3Access);
        $c3Url = $this->settings['c3_url'] ? $this->settings['c3_url'] : $this->module->_getUrl();
        $contents = file_get_contents($c3Url . '/c3/report/' . $action, false, $context);

        $okHeaders = array_filter(
            $http_response_header,
            function ($h) {
                return preg_match('~^HTTP(.*?)\s200~', $h);
            }
        );
        if (empty($okHeaders)) {
            throw new RemoteException("Request was not successful. See response header: " . $http_response_header[0]);
        }
        if ($contents === false) {
            $this->getRemoteError($http_response_header);
        }
        return $contents;
    }

    protected function startCoverageCollection($testName)
    {
        $value = [
            'CodeCoverage'        => $testName,
            'CodeCoverage_Suite'  => $this->suiteName,
            'CodeCoverage_Config' => $this->settings['remote_config']
        ];
        $value = json_encode($value);

        if ($this->module instanceof \Codeception\Module\WebDriver) {
            $this->module->amOnPage('/');
        }

        $cookieDomain = isset($this->settings['cookie_domain']) ? $this->settings['cookie_domain'] : null;

        if (!$cookieDomain) {
            $c3Url = parse_url($this->settings['c3_url'] ? $this->settings['c3_url'] : $this->module->_getUrl());

            // we need to separate coverage cookies by host; we can't separate cookies by port.
            $cookieDomain = isset($c3Url['host']) ? $c3Url['host'] : 'localhost';
        }
        
        $cookieParams = [];
        if ($cookieDomain !== 'localhost') {
            $cookieParams['domain'] = $cookieDomain;
        }

        $this->module->setCookie(self::COVERAGE_COOKIE, $value, $cookieParams);

        // putting in configuration ensures the cookie is used for all sessions of a MultiSession test

        $cookies = $this->module->_getConfig('cookies');
        if (!$cookies || !is_array($cookies)) {
            $cookies = [];
        }

        $found = false;
        foreach ($cookies as &$cookie) {
            if (!is_array($cookie) || !array_key_exists('Name', $cookie) || !array_key_exists('Value', $cookie)) {
                // \Codeception\Lib\InnerBrowser will complain about this
                continue;
            }
            if ($cookie['Name'] === self::COVERAGE_COOKIE) {
                $found = true;
                $cookie['Value'] = $value;
                break;
            }
        }
        unset($cookie);

        if (!$found) {
            $cookies[] = [
                'Name' => self::COVERAGE_COOKIE,
                'Value' => $value
            ];
        }

        $this->module->_setConfig(['cookies' => $cookies]);
    }

    protected function fetchErrors()
    {
        // Calling grabCookie() while an alert is present dismisses the alert
        // @see https://github.com/Codeception/Codeception/issues/1485
        if ($this->module instanceof \Codeception\Module\WebDriver) {
            try {
                $alert = $this->module->webDriver->switchTo()->alert();
                $alert->getText();
                // If this succeeds an alert is present, abort
                return;
            } catch (NoSuchAlertException $e) {
                // No alert present, continue
            }
        }

        try {
            $error = $this->module->grabCookie(self::COVERAGE_COOKIE_ERROR);
        } catch (ModuleException $e) {
            // when a new session is started we can't get cookies because there is no
            // current page, but there can be no code coverage error either
            $error = null;
        }
        if (!empty($error)) {
            $this->module->resetCookie(self::COVERAGE_COOKIE_ERROR);
            throw new RemoteException($error);
        }
    }

    protected function getRemoteError($headers)
    {
        foreach ($headers as $header) {
            if (strpos($header, self::COVERAGE_HEADER_ERROR) === 0) {
                throw new RemoteException($header);
            }
        }
    }

    protected function addC3AccessHeader($header, $value)
    {
        $headerString = "$header: $value\r\n";
        if (strpos($this->c3Access['http']['header'], $headerString) === false) {
            $this->c3Access['http']['header'] .= $headerString;
        }
    }

    protected function applySettings($settings)
    {
        parent::applySettings($settings);
        if (isset($settings['coverage']['remote_context_options'])) {
            $this->c3Access = array_replace_recursive($this->c3Access, $settings['coverage']['remote_context_options']);
        }
    }
}
<?php
namespace Codeception;

use Codeception\Event\DispatcherWrapper;
use Codeception\Event\StepEvent;
use Codeception\Exception\ConditionalAssertionFailed;
use Codeception\Test\Metadata;

class Scenario
{
    use DispatcherWrapper;

    /**
     * @var TestInterface
     */
    protected $test;
    /**
     * @var Metadata
     */
    protected $metadata;

    /**
     * @var    array
     */
    protected $steps = [];

    /**
     * @var    string
     */
    protected $feature;

    protected $metaStep;

    /**
     * Constructor
     *
     * @param TestInterface $test
     */
    public function __construct(TestInterface $test)
    {
        $this->metadata = $test->getMetadata();
        $this->test = $test;
    }

    public function setFeature($feature)
    {
        $this->metadata->setFeature($feature);
    }

    public function getFeature()
    {
        return $this->metadata->getFeature();
    }

    public function getGroups()
    {
        return $this->metadata->getGroups();
    }

    public function current($key)
    {
        return $this->metadata->getCurrent($key);
    }

    public function runStep(Step $step)
    {
        $step->saveTrace();
        if ($this->metaStep instanceof Step\Meta) {
            $step->setMetaStep($this->metaStep);
        }
        $this->steps[] = $step;
        $result = null;
        $dispatcher = $this->metadata->getService('dispatcher');
        $this->dispatch($dispatcher, Events::STEP_BEFORE, new StepEvent($this->test, $step));
        try {
            $result = $step->run($this->metadata->getService('modules'));
        } catch (ConditionalAssertionFailed $f) {
            $result = $this->test->getTestResultObject();
            if (is_null($result)) {
                $this->dispatch($dispatcher, Events::STEP_AFTER, new StepEvent($this->test, $step));
                throw $f;
            } else {
                $result->addFailure(clone($this->test), $f, $result->time());
            }
        } catch (\Exception $e) {
            $this->dispatch($dispatcher, Events::STEP_AFTER, new StepEvent($this->test, $step));
            throw $e;
        }
        $this->dispatch($dispatcher, Events::STEP_AFTER, new StepEvent($this->test, $step));
        $step->executed = true;
        return $result;
    }

    public function addStep(Step $step)
    {
        $this->steps[] = $step;
    }

    /**
     * Returns the steps of this scenario.
     *
     * @return array
     */
    public function getSteps()
    {
        return $this->steps;
    }

    public function getHtml()
    {
        $text = '';
        foreach ($this->getSteps() as $step) {
            /** @var Step $step */
            if ($step->getName() !== 'Comment') {
                $text .= $step->getHtml() . '<br/>';
            } else {
                $text .= trim($step->getHumanizedArguments(), '"') . '<br/>';
            }
        }
        $text = str_replace(['"\'', '\'"'], ["'", "'"], $text);
        $text = "<h3>" . mb_strtoupper('I want to ' . $this->getFeature(), 'utf-8') . "</h3>" . $text;
        return $text;
    }

    public function getText()
    {
        $text = '';
        foreach ($this->getSteps() as $step) {
            $text .= $step->getPrefix() . "$step \r\n";
        }
        $text = trim(str_replace(['"\'', '\'"'], ["'", "'"], $text));
        $text = mb_strtoupper('I want to ' . $this->getFeature(), 'utf-8') . "\r\n\r\n" . $text . "\r\n\r\n";
        return $text;
    }

    public function comment($comment)
    {
        $this->runStep(new \Codeception\Step\Comment($comment, []));
    }

    public function skip($message = '')
    {
        throw new \PHPUnit\Framework\SkippedTestError($message);
    }

    public function incomplete($message = '')
    {
        throw new \PHPUnit\Framework\IncompleteTestError($message);
    }

    public function __call($method, $args)
    {
        // all methods were deprecated and removed from here
        trigger_error("Codeception: \$scenario->$method() has been deprecated and removed. Use annotations to pass scenario params", E_USER_DEPRECATED);
    }

    /**
     * @param Step\Meta $metaStep
     */
    public function setMetaStep($metaStep)
    {
        $this->metaStep = $metaStep;
    }

    /**
     * @return Step\Meta
     */
    public function getMetaStep()
    {
        return $this->metaStep;
    }
}
<?php
namespace Codeception;

use Codeception\Configuration as Config;
use Codeception\Event\SuiteEvent;
use Codeception\Exception\ModuleRequireException;
use Codeception\Lib\Console\Output;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * A base class for all Codeception Extensions and GroupObjects
 *
 * Available Properties:
 *
 * * config: current extension configuration
 * * options: passed running options
 *
 */
abstract class Extension implements EventSubscriberInterface
{
    protected $config = [];
    protected $options;
    protected $output;
    protected $globalConfig;
    private $modules = [];

    public function __construct($config, $options)
    {
        $this->config = array_merge($this->config, $config);
        $this->options = $options;
        $this->output = new Output($options);
        $this->_initialize();
    }


    public static function getSubscribedEvents()
    {
        if (!isset(static::$events)) {
            return [Events::SUITE_INIT => 'receiveModuleContainer'];
        }
        if (isset(static::$events[Events::SUITE_INIT])) {
            if (!is_array(static::$events[Events::SUITE_INIT])) {
                static::$events[Events::SUITE_INIT] = [[static::$events[Events::SUITE_INIT]]];
            }
            static::$events[Events::SUITE_INIT][] = ['receiveModuleContainer'];
        } else {
            static::$events[Events::SUITE_INIT] = 'receiveModuleContainer';
        }
        return static::$events;
    }

    public function receiveModuleContainer(SuiteEvent $e)
    {
        $this->modules = $e->getSuite()->getModules();
    }

    /**
     * Pass config variables that should be injected into global config.
     *
     * @param array $config
     */
    public function _reconfigure($config = [])
    {
        if (is_array($config)) {
            Config::append($config);
        }
    }

    /**
     * You can do all preparations here. No need to override constructor.
     * Also you can skip calling `_reconfigure` if you don't need to.
     */
    public function _initialize()
    {
        $this->_reconfigure(); // hook for BC only.
    }

    protected function write($message)
    {
        if (!$this->options['silent']) {
            $this->output->write($message);
        }
    }

    protected function writeln($message)
    {
        if (!$this->options['silent']) {
            $this->output->writeln($message);
        }
    }

    public function hasModule($name)
    {
        return isset($this->modules[$name]);
    }

    public function getCurrentModuleNames()
    {
        return array_keys($this->modules);
    }

    public function getModule($name)
    {
        if (!$this->hasModule($name)) {
            throw new ModuleRequireException($name, "module is not enabled");
        }
        return $this->modules[$name];
    }

    public function getTestsDir()
    {
        return Config::testsDir();
    }

    public function getLogDir()
    {
        return Config::outputDir();
    }

    public function getDataDir()
    {
        return Config::dataDir();
    }

    public function getRootDir()
    {
        return Config::projectDir();
    }

    public function getGlobalConfig()
    {
        return Config::config();
    }
}
<?php
namespace Codeception\Command;

use Codeception\Lib\Generator\Cept;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * @deprecated
 */
class GenerateCept extends Command
{
    use Shared\FileSystem;
    use Shared\Config;

    protected function configure()
    {
        $this->setDefinition([
            new InputArgument('suite', InputArgument::REQUIRED, 'suite to be tested'),
            new InputArgument('test', InputArgument::REQUIRED, 'test to be run'),
        ]);
    }

    public function getDescription()
    {
        return 'Generates empty Cept file in suite';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $suite = $input->getArgument('suite');
        $filename = $input->getArgument('test');

        $config = $this->getSuiteConfig($suite);
        $this->createDirectoryFor($config['path'], $filename);

        $filename = $this->completeSuffix($filename, 'Cept');
        $gen = new Cept($config);

        $full_path = rtrim($config['path'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $filename;
        $res = $this->createFile($full_path, $gen->produce());
        if (!$res) {
            $output->writeln("<error>Test $filename already exists</error>");
            return 1;
        }
        $output->writeln("<info>Test was created in $full_path</info>");
        return 0;
    }
}
<?php
namespace Codeception\Command;

use Codeception\Codecept;
use Codeception\Configuration;
use Codeception\Event\DispatcherWrapper;
use Codeception\Event\SuiteEvent;
use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\Exception\ConfigurationException;
use Codeception\Lib\Console\Output;
use Codeception\Scenario;
use Codeception\SuiteManager;
use Codeception\Test\Cept;
use Codeception\Util\Debug;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\Question;

/**
 * Try to execute test commands in run-time. You may try commands before writing the test.
 *
 * * `codecept console acceptance` - starts acceptance suite environment. If you use WebDriver you can manipulate browser with Codeception commands.
 */
class Console extends Command
{
    use DispatcherWrapper;

    protected $test;
    protected $codecept;
    protected $suite;
    protected $output;
    protected $actions = [];

    protected function configure()
    {
        $this->setDefinition([
            new InputArgument('suite', InputArgument::REQUIRED, 'suite to be executed'),
            new InputOption('colors', '', InputOption::VALUE_NONE, 'Use colors in output'),
        ]);

        parent::configure();
    }

    public function getDescription()
    {
        return 'Launches interactive test console';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $suiteName = $input->getArgument('suite');
        $this->output = $output;

        $config = Configuration::config();
        $settings = Configuration::suiteSettings($suiteName, $config);

        $options = $input->getOptions();
        $options['debug'] = true;
        $options['silent'] = true;
        $options['interactive'] = false;
        $options['colors'] = true;

        Debug::setOutput(new Output($options));

        $this->codecept = new Codecept($options);
        $dispatcher = $this->codecept->getDispatcher();

        $suiteManager = new SuiteManager($dispatcher, $suiteName, $settings);
        $suiteManager->initialize();
        $this->suite = $suiteManager->getSuite();
        $moduleContainer = $suiteManager->getModuleContainer();

        $this->actions = array_keys($moduleContainer->getActions());

        $this->test = new Cept(null, null);
        $this->test->getMetadata()->setServices([
           'dispatcher' => $dispatcher,
           'modules' =>  $moduleContainer
        ]);

        $scenario = new Scenario($this->test);
        if (!$settings['actor']) {
            throw new ConfigurationException("Interactive shell can't be started without an actor");
        }
        if (isset($config["namespace"])) {
            $settings['actor'] = $config["namespace"] .'\\' . $settings['actor'];
        }
        $actor = $settings['actor'];
        $I = new $actor($scenario);

        $this->listenToSignals();

        $output->writeln("<info>Interactive console started for suite $suiteName</info>");
        $output->writeln("<info>Try Codeception commands without writing a test</info>");

        $suiteEvent = new SuiteEvent($this->suite, $this->codecept->getResult(), $settings);
        $this->dispatch($dispatcher, Events::SUITE_BEFORE, $suiteEvent);

        $this->dispatch($dispatcher, Events::TEST_PARSED, new TestEvent($this->test));
        $this->dispatch($dispatcher, Events::TEST_BEFORE, new TestEvent($this->test));

        if (file_exists($settings['bootstrap'])) {
            require $settings['bootstrap'];
        }

        $I->pause();

        $this->dispatch($dispatcher, Events::TEST_AFTER, new TestEvent($this->test));
        $this->dispatch($dispatcher, Events::SUITE_AFTER, new SuiteEvent($this->suite));

        $output->writeln("<info>Bye-bye!</info>");
        return 0;
    }

    protected function listenToSignals()
    {
        if (function_exists('pcntl_signal')) {
            declare (ticks = 1);
            pcntl_signal(SIGINT, SIG_IGN);
            pcntl_signal(SIGTERM, SIG_IGN);
        }
    }
}
<?php
namespace Codeception\Command;

use Codeception\Configuration;
use Codeception\Lib\Generator\PageObject as PageObjectGenerator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Generates PageObject. Can be generated either globally, or just for one suite.
 * If PageObject is generated globally it will act as UIMap, without any logic in it.
 *
 * * `codecept g:page Login`
 * * `codecept g:page Registration`
 * * `codecept g:page acceptance Login`
 */
class GeneratePageObject extends Command
{
    use Shared\FileSystem;
    use Shared\Config;

    protected function configure()
    {
        $this->setDefinition([
            new InputArgument('suite', InputArgument::REQUIRED, 'Either suite name or page object name)'),
            new InputArgument('page', InputArgument::OPTIONAL, 'Page name of pageobject to represent'),
        ]);
        parent::configure();
    }

    public function getDescription()
    {
        return 'Generates empty PageObject class';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $suite = $input->getArgument('suite');
        $class = $input->getArgument('page');

        if (!$class) {
            $class = $suite;
            $suite = '';
        }

        $conf = $suite
            ? $this->getSuiteConfig($suite)
            : $this->getGlobalConfig();

        if ($suite) {
            $suite = DIRECTORY_SEPARATOR . ucfirst($suite);
        }

        $path = $this->createDirectoryFor(Configuration::supportDir() . 'Page' . $suite, $class);

        $filename = $path . $this->getShortClassName($class) . '.php';

        $output->writeln($filename);

        $gen = new PageObjectGenerator($conf, ucfirst($suite) . '\\' . $class);
        $res = $this->createFile($filename, $gen->produce());

        if (!$res) {
            $output->writeln("<error>PageObject $filename already exists</error>");
            return 1;
        }
        $output->writeln("<info>PageObject was created in $filename</info>");
        return 0;
    }

    protected function pathToPageObject($class, $suite)
    {
    }
}
<?php
namespace Codeception\Command;

use Codeception\Lib\Generator\GherkinSnippets as SnippetsGenerator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Generates code snippets for matched feature files in a suite.
 * Code snippets are expected to be implemented in Actor or PageObjects
 *
 * Usage:
 *
 * * `codecept gherkin:snippets acceptance` - snippets from all feature of acceptance tests
 * * `codecept gherkin:snippets acceptance/feature/users` - snippets from `feature/users` dir of acceptance tests
 * * `codecept gherkin:snippets acceptance user_account.feature` - snippets from a single feature file
 * * `codecept gherkin:snippets acceptance/feature/users/user_accout.feature` - snippets from feature file in a dir
 */
class GherkinSnippets extends Command
{
    use Shared\Config;
    use Shared\Style;

    protected function configure()
    {
        $this->setDefinition(
            [
                new InputArgument('suite', InputArgument::REQUIRED, 'suite to scan for feature files'),
                new InputArgument('test', InputArgument::OPTIONAL, 'test to be scanned'),
                new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
            ]
        );
        parent::configure();
    }

    public function getDescription()
    {
        return 'Fetches empty steps from feature files of suite and prints code snippets for them';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $this->addStyles($output);
        $suite = $input->getArgument('suite');
        $test = $input->getArgument('test');
        $config = $this->getSuiteConfig($suite);

        $generator = new SnippetsGenerator($config, $test);
        $snippets = $generator->getSnippets();
        $features = $generator->getFeatures();

        if (empty($snippets)) {
            $output->writeln("<notice> All Gherkin steps are defined. Exiting... </notice>");
            return 0;
        }
        $output->writeln("<comment> Snippets found in: </comment>");
        foreach ($features as $feature) {
            $output->writeln("<info>  - {$feature} </info>");
        }
        $output->writeln("<comment> Generated Snippets: </comment>");
        $output->writeln("<info> ----------------------------------------- </info>");
        foreach ($snippets as $snippet) {
            $output->writeln($snippet);
        }
        $output->writeln("<info> ----------------------------------------- </info>");
        $output->writeln(sprintf(' <bold>%d</bold> snippets proposed', count($snippets)));
        $output->writeln("<notice> Copy generated snippets to {$config['actor']} or a specific Gherkin context </notice>");
        return 0;
    }
}
<?php
namespace Codeception\Command;

use Codeception\Configuration;
use Codeception\Util\FileSystem;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Recursively cleans `output` directory and generated code.
 *
 * * `codecept clean`
 *
 */
class Clean extends Command
{
    use Shared\Config;

    public function getDescription()
    {
        return 'Recursively cleans log and generated code';
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $projectDir = Configuration::projectDir();
        $this->cleanProjectsRecursively($output, $projectDir);
        $output->writeln("Done");
        return 0;
    }

    private function cleanProjectsRecursively(OutputInterface $output, $projectDir)
    {
        $config = Configuration::config($projectDir);
        
        $logDir = Configuration::logDir();
        $output->writeln("<info>Cleaning up output " . $logDir . "...</info>");
        FileSystem::doEmptyDir($logDir);

        $subProjects = $config['include'];
        foreach ($subProjects as $subProject) {
            $subProjectDir = $projectDir . $subProject;
            $this->cleanProjectsRecursively($output, $subProjectDir);
        }
    }
}
<?php
namespace Codeception\Command;

use Codeception\Template\Bootstrap as BootstrapTemplate;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Creates default config, tests directory and sample suites for current project.
 * Use this command to start building a test suite.
 *
 * By default it will create 3 suites **acceptance**, **functional**, and **unit**.
 *
 * * `codecept bootstrap` - creates `tests` dir and `codeception.yml` in current dir.
 * * `codecept bootstrap --empty` - creates `tests` dir without suites
 * * `codecept bootstrap --namespace Frontend` - creates tests, and use `Frontend` namespace for actor classes and helpers.
 * * `codecept bootstrap --actor Wizard` - sets actor as Wizard, to have `TestWizard` actor in tests.
 * * `codecept bootstrap path/to/the/project` - provide different path to a project, where tests should be placed
 *
 */
class Bootstrap extends Command
{

    protected function configure()
    {
        $this->setDefinition(
            [
                new InputArgument('path', InputArgument::OPTIONAL, 'custom installation dir', null),
                new InputOption(
                    'namespace',
                    's',
                    InputOption::VALUE_OPTIONAL,
                    'Namespace to add for actor classes and helpers'
                ),
                new InputOption('actor', 'a', InputOption::VALUE_OPTIONAL, 'Custom actor instead of Tester'),
                new InputOption('empty', 'e', InputOption::VALUE_NONE, 'Don\'t create standard suites')
            ]
        );
    }

    public function getDescription()
    {
        return "Creates default test suites and generates all required files";
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $bootstrap = new BootstrapTemplate($input, $output);
        if ($input->getArgument('path')) {
            $bootstrap->initDir($input->getArgument('path'));
        }
        $bootstrap->setup();
        return 0;
    }
}
<?php
namespace Codeception\Command;

use Codeception\Configuration;
use Codeception\Event\DispatcherWrapper;
use Codeception\Event\SuiteEvent;
use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\Subscriber\Bootstrap as BootstrapLoader;
use Codeception\Subscriber\Console as ConsolePrinter;
use Codeception\SuiteManager;
use Codeception\Test\Interfaces\ScenarioDriven;
use Codeception\Test\Test;
use Codeception\Util\Maybe;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\EventDispatcher\EventDispatcher;

/**
 * Shows step by step execution process for scenario driven tests without actually running them.
 *
 * * `codecept dry-run acceptance`
 * * `codecept dry-run acceptance MyCest`
 * * `codecept dry-run acceptance checkout.feature`
 * * `codecept dry-run tests/acceptance/MyCest.php`
 *
 */
class DryRun extends Command
{
    use DispatcherWrapper;
    use Shared\Config;
    use Shared\Style;

    protected function configure()
    {
        $this->setDefinition(
            [
                new InputArgument('suite', InputArgument::REQUIRED, 'suite to scan for feature files'),
                new InputArgument('test', InputArgument::OPTIONAL, 'tests to be loaded'),
            ]
        );
        parent::configure();
    }

    public function getDescription()
    {
        return 'Prints step-by-step scenario-driven test or a feature';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $this->addStyles($output);
        $suite = $input->getArgument('suite');
        $test = $input->getArgument('test');

        $config = $this->getGlobalConfig();
        ini_set(
            'memory_limit',
            isset($config['settings']['memory_limit']) ? $config['settings']['memory_limit'] : '1024M'
        );
        if (! Configuration::isEmpty() && ! $test && strpos($suite, $config['paths']['tests']) === 0) {
            list(, $suite, $test) = $this->matchTestFromFilename($suite, $config['paths']['tests']);
        }
        $settings = $this->getSuiteConfig($suite);

        $dispatcher = new EventDispatcher();
        $dispatcher->addSubscriber(new ConsolePrinter([
            'colors'    => (!$input->hasParameterOption('--no-ansi') xor $input->hasParameterOption('ansi')),
            'steps'     => true,
            'verbosity' => OutputInterface::VERBOSITY_VERBOSE,
        ]));
        $dispatcher->addSubscriber(new BootstrapLoader());

        $suiteManager = new SuiteManager($dispatcher, $suite, $settings);
        $moduleContainer = $suiteManager->getModuleContainer();
        foreach (Configuration::modules($settings) as $module) {
            $moduleContainer->mock($module, new Maybe());
        }
        $suiteManager->loadTests($test);
        $tests = $suiteManager->getSuite()->tests();

        $this->dispatch($dispatcher, Events::SUITE_INIT, new SuiteEvent($suiteManager->getSuite(), null, $settings));
        $this->dispatch($dispatcher, Events::SUITE_BEFORE, new SuiteEvent($suiteManager->getSuite(), null, $settings));
        foreach ($tests as $test) {
            if ($test instanceof Test and $test instanceof ScenarioDriven) {
                $this->dryRunTest($output, $dispatcher, $test);
            }
        }
        $this->dispatch($dispatcher, Events::SUITE_AFTER, new SuiteEvent($suiteManager->getSuite()));
        return 0;
    }


    protected function matchTestFromFilename($filename, $tests_path)
    {
        $filename = str_replace(['//', '\/', '\\'], '/', $filename);
        $res = preg_match("~^$tests_path/(.*?)/(.*)$~", $filename, $matches);
        if (!$res) {
            throw new \InvalidArgumentException("Test file can't be matched");
        }

        return $matches;
    }

    /**
     * @param OutputInterface $output
     * @param $dispatcher
     * @param $test
     */
    protected function dryRunTest(OutputInterface $output, EventDispatcher $dispatcher, Test $test)
    {
        $this->dispatch($dispatcher, Events::TEST_START, new TestEvent($test));
        $this->dispatch($dispatcher, Events::TEST_BEFORE, new TestEvent($test));
        try {
            $test->test();
        } catch (\Exception $e) {
        }
        $this->dispatch($dispatcher, Events::TEST_AFTER, new TestEvent($test));
        $this->dispatch($dispatcher, Events::TEST_END, new TestEvent($test));
        if ($test->getMetadata()->isBlocked()) {
            $output->writeln('');
            if ($skip = $test->getMetadata()->getSkip()) {
                $output->writeln("<warning> SKIPPED </warning>" . $skip);
            }
            if ($incomplete = $test->getMetadata()->getIncomplete()) {
                $output->writeln("<warning> INCOMPLETE </warning>" . $incomplete);
            }
        }
        $output->writeln('');
    }
}
<?php
namespace Codeception\Command;

use Codeception\Configuration;
use Stecman\Component\Symfony\Console\BashCompletion\Completion as ConsoleCompletion;
use Stecman\Component\Symfony\Console\BashCompletion\CompletionCommand;
use Stecman\Component\Symfony\Console\BashCompletion\CompletionHandler;
use Stecman\Component\Symfony\Console\BashCompletion\Completion\ShellPathCompletion;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class CompletionFallback extends Command
{
    protected function configure()
    {
        $this
            ->setName('_completion')
            ->setDescription('BASH completion hook.')
            ->setHelp(<<<END
To enable BASH completion, install optional stecman/symfony-console-completion first:

    <comment>composer require stecman/symfony-console-completion</comment>

END
            );

        // Hide this command from listing if supported
        // Command::setHidden() was not available before Symfony 3.2.0
        if (method_exists($this, 'setHidden')) {
            $this->setHidden(true);
        }
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $output->writeln("Install optional <comment>stecman/symfony-console-completion</comment>");
        return 0;
    }
}
<?php
namespace Codeception\Command;

use Codeception\Codecept;
use Codeception\Configuration;
use Codeception\Lib\GroupManager;
use Codeception\Util\PathResolver;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Executes tests.
 *
 * Usage:
 *
 * * `codecept run acceptance`: run all acceptance tests
 * * `codecept run tests/acceptance/MyCest.php`: run only MyCest
 * * `codecept run acceptance MyCest`: same as above
 * * `codecept run acceptance MyCest:myTestInIt`: run one test from a Cest
 * * `codecept run acceptance checkout.feature`: run feature-file
 * * `codecept run acceptance -g slow`: run tests from *slow* group
 * * `codecept run unit,functional`: run only unit and functional suites
 *
 * Verbosity modes:
 *
 * * `codecept run -v`:
 * * `codecept run --steps`: print step-by-step execution
 * * `codecept run -vv`: print steps and debug information
 * * `codecept run --debug`: alias for `-vv`
 * * `codecept run -vvv`: print Codeception-internal debug information
 *
 * Load config:
 *
 * * `codecept run -c path/to/another/config`: from another dir
 * * `codecept run -c another_config.yml`: from another config file
 *
 * Override config values:
 *
 * * `codecept run -o "settings: shuffle: true"`: enable shuffle
 * * `codecept run -o "settings: lint: false"`: disable linting
 * * `codecept run -o "reporters: report: \Custom\Reporter" --report`: use custom reporter
 *
 * Run with specific extension
 *
 * * `codecept run --ext Recorder` run with Recorder extension enabled
 * * `codecept run --ext DotReporter` run with DotReporter printer
 * * `codecept run --ext "My\Custom\Extension"` run with an extension loaded by class name
 *
 * Full reference:
 * ```
 * Arguments:
 *  suite                 suite to be tested
 *  test                  test to be run
 *
 * Options:
 *  -o, --override=OVERRIDE Override config values (multiple values allowed)
 *  --config (-c)         Use custom path for config
 *  --report              Show output in compact style
 *  --html                Generate html with results (default: "report.html")
 *  --xml                 Generate JUnit XML Log (default: "report.xml")
 *  --phpunit-xml         Generate PhpUnit XML Log (default: "phpunit-report.xml")
 *  --no-redirect         Do not redirect to Composer-installed version in vendor/codeception
 *  --tap                 Generate Tap Log (default: "report.tap.log")
 *  --json                Generate Json Log (default: "report.json")
 *  --colors              Use colors in output
 *  --no-colors           Force no colors in output (useful to override config file)
 *  --silent              Only outputs suite names and final results. Almost the same as `--quiet`
 *  --steps               Show steps in output
 *  --debug (-d)          Alias for `-vv`
 *  --bootstrap           Execute bootstrap script before the test
 *  --coverage            Run with code coverage (default: "coverage.serialized")
 *  --coverage-html       Generate CodeCoverage HTML report in path (default: "coverage")
 *  --coverage-xml        Generate CodeCoverage XML report in file (default: "coverage.xml")
 *  --coverage-text       Generate CodeCoverage text report in file (default: "coverage.txt")
 *  --coverage-phpunit    Generate CodeCoverage PHPUnit report in file (default: "coverage-phpunit")
 *  --coverage-cobertura  Generate CodeCoverage Cobertura report in file (default: "coverage-cobertura")
 *  --no-exit             Don't finish with exit code
 *  --group (-g)          Groups of tests to be executed (multiple values allowed)
 *  --skip (-s)           Skip selected suites (multiple values allowed)
 *  --skip-group (-x)     Skip selected groups (multiple values allowed)
 *  --env                 Run tests in selected environments. (multiple values allowed, environments can be merged with ',')
 *  --fail-fast (-f)      Stop after nth failure (defaults to 1)
 *  --no-rebuild          Do not rebuild actor classes on start
 *  --help (-h)           Display this help message.
 *  --quiet (-q)          Do not output any message. Almost the same as `--silent`
 *  --verbose (-v|vv|vvv) Increase the verbosity of messages: `v` for normal output, `vv` for steps and debug, `vvv` for Codeception-internal debug
 *  --version (-V)        Display this application version.
 *  --ansi                Force ANSI output.
 *  --no-ansi             Disable ANSI output.
 *  --no-interaction (-n) Do not ask any interactive question.
 *  --seed                Use the given seed for shuffling tests
 * ```
 *
 */
class Run extends Command
{
    use Shared\Config;
    /**
     * @var Codecept
     */
    protected $codecept;

    /**
     * @var integer of executed suites
     */
    protected $executed = 0;

    /**
     * @var array of options (command run)
     */
    protected $options = [];

    /**
     * @var OutputInterface
     */
    protected $output;

    /**
     * Sets Run arguments
     * @throws \Symfony\Component\Console\Exception\InvalidArgumentException
     */
    protected function configure()
    {
        $this->setDefinition([
            new InputArgument('suite', InputArgument::OPTIONAL, 'suite to be tested'),
            new InputArgument('test', InputArgument::OPTIONAL, 'test to be run'),
            new InputOption('override', 'o', InputOption::VALUE_IS_ARRAY  | InputOption::VALUE_REQUIRED, 'Override config values'),
            new InputOption('ext', 'e', InputOption::VALUE_IS_ARRAY  | InputOption::VALUE_REQUIRED, 'Run with extension enabled'),
            new InputOption('report', '', InputOption::VALUE_NONE, 'Show output in compact style'),
            new InputOption('html', '', InputOption::VALUE_OPTIONAL, 'Generate html with results', 'report.html'),
            new InputOption('xml', '', InputOption::VALUE_OPTIONAL, 'Generate JUnit XML Log', 'report.xml'),
            new InputOption('phpunit-xml', '', InputOption::VALUE_OPTIONAL, 'Generate PhpUnit XML Log', 'phpunit-report.xml'),
            new InputOption('tap', '', InputOption::VALUE_OPTIONAL, 'Generate Tap Log', 'report.tap.log'),
            new InputOption('json', '', InputOption::VALUE_OPTIONAL, 'Generate Json Log', 'report.json'),
            new InputOption('colors', '', InputOption::VALUE_NONE, 'Use colors in output'),
            new InputOption(
                'no-colors',
                '',
                InputOption::VALUE_NONE,
                'Force no colors in output (useful to override config file)'
            ),
            new InputOption('silent', '', InputOption::VALUE_NONE, 'Only outputs suite names and final results'),
            new InputOption('steps', '', InputOption::VALUE_NONE, 'Show steps in output'),
            new InputOption('debug', 'd', InputOption::VALUE_NONE, 'Show debug and scenario output'),
            new InputOption('bootstrap', '', InputOption::VALUE_OPTIONAL, 'Execute custom PHP script before running tests. Path can be absolute or relative to current working directory', false),
            new InputOption('no-redirect', '', InputOption::VALUE_NONE, 'Do not redirect to Composer-installed version in vendor/codeception'),
            new InputOption(
                'coverage',
                '',
                InputOption::VALUE_OPTIONAL,
                'Run with code coverage'
            ),
            new InputOption(
                'coverage-html',
                '',
                InputOption::VALUE_OPTIONAL,
                'Generate CodeCoverage HTML report in path'
            ),
            new InputOption(
                'coverage-xml',
                '',
                InputOption::VALUE_OPTIONAL,
                'Generate CodeCoverage XML report in file'
            ),
            new InputOption(
                'coverage-text',
                '',
                InputOption::VALUE_OPTIONAL,
                'Generate CodeCoverage text report in file'
            ),
            new InputOption(
                'coverage-crap4j',
                '',
                InputOption::VALUE_OPTIONAL,
                'Generate CodeCoverage report in Crap4J XML format'
            ),
            new InputOption(
                'coverage-cobertura',
                '',
                InputOption::VALUE_OPTIONAL,
                'Generate CodeCoverage report in Cobertura XML format'
            ),
            new InputOption(
                'coverage-phpunit',
                '',
                InputOption::VALUE_OPTIONAL,
                'Generate CodeCoverage PHPUnit report in path'
            ),
            new InputOption('no-exit', '', InputOption::VALUE_NONE, 'Don\'t finish with exit code'),
            new InputOption(
                'group',
                'g',
                InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
                'Groups of tests to be executed'
            ),
            new InputOption(
                'skip',
                's',
                InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
                'Skip selected suites'
            ),
            new InputOption(
                'skip-group',
                'x',
                InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
                'Skip selected groups'
            ),
            new InputOption(
                'env',
                '',
                InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
                'Run tests in selected environments.'
            ),
            new InputOption('fail-fast', 'f', InputOption::VALUE_OPTIONAL, 'Stop after nth failure'),
            new InputOption('no-rebuild', '', InputOption::VALUE_NONE, 'Do not rebuild actor classes on start'),
            new InputOption(
                'seed',
                '',
                InputOption::VALUE_REQUIRED,
                'Define random seed for shuffle setting'
            ),
            new InputOption('no-artifacts', '', InputOption::VALUE_NONE, 'Don\'t report about artifacts'),
        ]);

        parent::configure();
    }

    public function getDescription()
    {
        return 'Runs the test suites';
    }

    /**
     * Executes Run
     *
     * @param \Symfony\Component\Console\Input\InputInterface $input
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     * @return int|null|void
     * @throws \RuntimeException
     */
    public function execute(InputInterface $input, OutputInterface $output)
    {
        $this->ensurePhpExtIsAvailable('CURL');
        $this->ensurePhpExtIsAvailable('mbstring');
        $this->options = $input->getOptions();
        $this->output = $output;

        if ($this->options['bootstrap']) {
            Configuration::loadBootstrap($this->options['bootstrap'], getcwd());
        }

        // load config
        $config = $this->getGlobalConfig();

        // update config from options
        if (count($this->options['override'])) {
            $config = $this->overrideConfig($this->options['override']);
        }
        if ($this->options['ext']) {
            $config = $this->enableExtensions($this->options['ext']);
        }

        if (!$this->options['colors']) {
            $this->options['colors'] = $config['settings']['colors'];
        }

        if (!$this->options['silent']) {
            $this->output->writeln(
                Codecept::versionString() . "\nPowered by " . \PHPUnit\Runner\Version::getVersionString()
            );

            if ($this->options['seed']) {
                $this->output->writeln(
                    "Running with seed: <info>" . $this->options['seed'] . "</info>\n"
                );
            }
        }
        if ($this->options['debug']) {
            $this->output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
        }

        $userOptions = array_intersect_key($this->options, array_flip($this->passedOptionKeys($input)));
        $userOptions = array_merge(
            $userOptions,
            $this->booleanOptions($input, [
                'xml' => 'report.xml',
                'phpunit-xml' => 'phpunit-report.xml',
                'html' => 'report.html',
                'json' => 'report.json',
                'tap' => 'report.tap.log',
                'coverage' => 'coverage.serialized',
                'coverage-xml' => 'coverage.xml',
                'coverage-html' => 'coverage',
                'coverage-text' => 'coverage.txt',
                'coverage-crap4j' => 'crap4j.xml',
                'coverage-cobertura' => 'cobertura.xml',
                'coverage-phpunit' => 'coverage-phpunit'])
        );
        $userOptions['verbosity'] = $this->output->getVerbosity();
        $userOptions['interactive'] = !$input->hasParameterOption(['--no-interaction', '-n']);
        $userOptions['ansi'] = (!$input->hasParameterOption('--no-ansi') xor $input->hasParameterOption('ansi'));

        if (!$this->options['seed']) {
            $userOptions['seed'] = rand();
        } else {
            $userOptions['seed'] = intval($this->options['seed']);
        }
        if ($this->options['no-colors'] || !$userOptions['ansi']) {
            $userOptions['colors'] = false;
        }
        if ($this->options['group']) {
            $userOptions['groups'] = $this->options['group'];
        }
        if ($this->options['skip-group']) {
            $userOptions['excludeGroups'] = $this->options['skip-group'];
        }
        if ($this->options['report']) {
            $userOptions['silent'] = true;
        }
        if ($this->options['coverage-xml'] or $this->options['coverage-html'] or $this->options['coverage-text'] or $this->options['coverage-crap4j'] or $this->options['coverage-phpunit']) {
            $this->options['coverage'] = true;
        }
        if (!$userOptions['ansi'] && $input->getOption('colors')) {
            $userOptions['colors'] = true; // turn on colors even in non-ansi mode if strictly passed
        }
        // array key will exist if fail-fast option is used
        if (array_key_exists('fail-fast', $userOptions)) {
            $userOptions['fail-fast'] = (int) $this->options['fail-fast'] ?: 1;
        }

        $suite = $input->getArgument('suite');
        $test = $input->getArgument('test');

        if ($this->options['group']) {
            $this->output->writeln(sprintf("[Groups] <info>%s</info> ", implode(', ', $this->options['group'])));
        }
        if ($input->getArgument('test')) {
            $this->options['steps'] = true;
        }

        if (!$test) {
            // Check if suite is given and is in an included path
            if (!empty($suite) && !empty($config['include'])) {
                $isIncludeTest = false;
                // Remember original projectDir
                $projectDir = Configuration::projectDir();

                foreach ($config['include'] as $include) {
                    // Find if the suite begins with an include path
                    if (strpos($suite, $include) === 0) {
                        // Use include config
                        $config = Configuration::config($projectDir.$include);

                        if (!isset($config['paths']['tests'])) {
                            throw new \RuntimeException(
                                sprintf("Included '%s' has no tests path configured", $include)
                            );
                        }

                        $testsPath = $include . DIRECTORY_SEPARATOR.  $config['paths']['tests'];

                        try {
                            list(, $suite, $test) = $this->matchTestFromFilename($suite, $testsPath);
                            $isIncludeTest = true;
                        } catch (\InvalidArgumentException $e) {
                            // Incorrect include match, continue trying to find one
                            continue;
                        }
                    } else {
                        $result = $this->matchSingleTest($suite, $config);
                        if ($result) {
                            list(, $suite, $test) = $result;
                        }
                    }
                }

                // Restore main config
                if (!$isIncludeTest) {
                    $config = Configuration::config($projectDir);
                }
            } elseif (!empty($suite)) {
                $result = $this->matchSingleTest($suite, $config);
                if ($result) {
                    list(, $suite, $test) = $result;
                }
            }
        }

        if ($test) {
            $userOptions['filter'] = $this->matchFilteredTestName($test);
        } elseif ($suite) {
            $userOptions['filter'] = $this->matchFilteredTestName($suite);
        }
        if (!$this->options['silent'] && $config['settings']['shuffle']) {
            $this->output->writeln(
                "[Seed] <info>" . $userOptions['seed'] . "</info>"
            );
        }

        $this->codecept = new Codecept($userOptions);

        if ($suite and $test) {
            $this->codecept->run($suite, $test, $config);
        }

        // Run all tests of given suite or all suites
        if (!$test) {
            $suites = $suite ? explode(',', $suite) : Configuration::suites();
            $this->executed = $this->runSuites($suites, $this->options['skip']);

            if (!empty($config['include']) and !$suite) {
                $current_dir = Configuration::projectDir();
                $suites += $config['include'];
                $this->runIncludedSuites($config['include'], $current_dir);
            }

            if ($this->executed === 0) {
                throw new \RuntimeException(
                    sprintf("Suite '%s' could not be found", implode(', ', $suites))
                );
            }
        }

        $this->codecept->printResult();

        if (!$input->getOption('no-exit')) {
            if (!$this->codecept->getResult()->wasSuccessful()) {
                exit(1);
            }
        }
        return 0;
    }

    protected function matchSingleTest($suite, $config)
    {
        // Workaround when codeception.yml is inside tests directory and tests path is set to "."
        // @see https://github.com/Codeception/Codeception/issues/4432
        if (isset($config['paths']['tests']) && $config['paths']['tests'] === '.' && !preg_match('~^\.[/\\\]~', $suite)) {
            $suite = './' . $suite;
        }

        // running a single test when suite has a configured path
        if (isset($config['suites'])) {
            foreach ($config['suites'] as $s => $suiteConfig) {
                if (!isset($suiteConfig['path'])) {
                    continue;
                }
                $testsPath = $config['paths']['tests'] . DIRECTORY_SEPARATOR . $suiteConfig['path'];
                if ($suiteConfig['path'] === '.') {
                    $testsPath = $config['paths']['tests'];
                }
                if (preg_match("~^$testsPath/(.*?)$~", $suite, $matches)) {
                    $matches[2] = $matches[1];
                    $matches[1] = $s;
                    return $matches;
                }
            }
        }

        if (! Configuration::isEmpty()) {
            // Run single test without included tests
            if (strpos($suite, $config['paths']['tests']) === 0) {
                return $this->matchTestFromFilename($suite, $config['paths']['tests']);
            }

            // Run single test from working directory
            $realTestDir = realpath(Configuration::testsDir());
            $cwd = getcwd();
            if (strpos($realTestDir, $cwd) === 0) {
                $file = $suite;
                if (strpos($file, ':') !== false) {
                    list($file) = explode(':', $suite, -1);
                }
                $realPath = $cwd . DIRECTORY_SEPARATOR . $file;
                if (file_exists($realPath) && strpos($realPath, $realTestDir) === 0) {
                    //only match test if file is in tests directory
                    return $this->matchTestFromFilename(
                        $cwd . DIRECTORY_SEPARATOR . $suite,
                        $realTestDir
                    );
                }
            }
        }
    }

    /**
     * Runs included suites recursively
     *
     * @param array $suites
     * @param string $parent_dir
     */
    protected function runIncludedSuites($suites, $parent_dir)
    {
        $defaultConfig = Configuration::config();
        $absolutePath = \Codeception\Configuration::projectDir();

        foreach ($suites as $relativePath) {
            $current_dir = rtrim($parent_dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $relativePath;
            $config = Configuration::config($current_dir);

            if (!empty($defaultConfig['groups'])) {
                $groups = array_map(function($g) use ($absolutePath) {
                    return $absolutePath . $g;
                }, $defaultConfig['groups']);
                Configuration::append(['groups' => $groups]);
            }

            $suites = Configuration::suites();

            $namespace = $this->currentNamespace();
            $this->output->writeln(
                "\n<fg=white;bg=magenta>\n[$namespace]: tests from $current_dir\n</fg=white;bg=magenta>"
            );

            $this->executed += $this->runSuites($suites, $this->options['skip']);
            if (!empty($config['include'])) {
                $this->runIncludedSuites($config['include'], $current_dir);
            }
        }
    }

    protected function currentNamespace()
    {
        $config = Configuration::config();
        if (!$config['namespace']) {
            throw new \RuntimeException(
                "Can't include into runner suite without a namespace;\n"
                . "Please add `namespace` section into included codeception.yml file"
            );
        }

        return $config['namespace'];
    }

    protected function runSuites($suites, $skippedSuites = [])
    {
        $executed = 0;
        foreach ($suites as $suite) {
            if (in_array($suite, $skippedSuites)) {
                continue;
            }
            if (!in_array($suite, Configuration::suites())) {
                continue;
            }
            $this->codecept->run($suite);
            $executed++;
        }

        return $executed;
    }

    protected function matchTestFromFilename($filename, $testsPath)
    {
        $filter = '';
        if (strpos($filename, ':') !== false) {
            if ((PHP_OS === 'Windows' || PHP_OS === 'WINNT') && $filename[1] === ':') {
                // match C:\...
                list($drive, $path, $filter) = explode(':', $filename, 3);
                $filename = $drive . ':' . $path;
            } else {
                list($filename, $filter) = explode(':', $filename, 2);
            }

            if ($filter) {
                $filter = ':' . $filter;
            }
        }

        $testsPath = str_replace(['//', '\/', '\\'], '/', $testsPath);
        $filename = str_replace(['//', '\/', '\\'], '/', $filename);

        if (rtrim($filename, '/') === $testsPath) {
            //codecept run tests
            return ['', '', $filter];
        }
        $res = preg_match("~^$testsPath/(.*?)(?>/(.*))?$~", $filename, $matches);

        if (!$res) {
            throw new \InvalidArgumentException("Test file can't be matched");
        }
        if (!isset($matches[2])) {
            $matches[2] = '';
        }
        if ($filter) {
            $matches[2] .= $filter;
        }

        return $matches;
    }

    private function matchFilteredTestName(&$path)
    {
        $test_parts = explode(':', $path, 2);
        if (count($test_parts) > 1) {
            list($path, $filter) = $test_parts;
            // use carat to signify start of string like in normal regex
            // phpunit --filter matches against the fully qualified method name, so tests actually begin with :
            $carat_pos = strpos($filter, '^');
            if ($carat_pos !== false) {
                $filter = substr_replace($filter, ':', $carat_pos, 1);
            }
            return $filter;
        }

        return null;
    }

    protected function passedOptionKeys(InputInterface $input)
    {
        $options = [];
        $request = (string)$input;
        $tokens = explode(' ', $request);
        foreach ($tokens as $token) {
            $token = preg_replace('~=.*~', '', $token); // strip = from options

            if (empty($token)) {
                continue;
            }

            if ($token == '--') {
                break; // there should be no options after ' -- ', only arguments
            }

            if (substr($token, 0, 2) === '--') {
                $options[] = substr($token, 2);
            } elseif ($token[0] === '-') {
                $shortOption = substr($token, 1);
                $options[] = $this->getDefinition()->getOptionForShortcut($shortOption)->getName();
            }
        }
        return $options;
    }

    protected function booleanOptions(InputInterface $input, $options = [])
    {
        $values = [];
        $request = (string)$input;
        foreach ($options as $option => $defaultValue) {
            if (strpos($request, "--$option")) {
                $values[$option] = $input->getOption($option) ? $input->getOption($option) : $defaultValue;
            } else {
                $values[$option] = false;
            }
        }

        return $values;
    }

    /**
     * @param string $ext
     * @throws \Exception
     */
    private function ensurePhpExtIsAvailable($ext)
    {
        if (!extension_loaded(strtolower($ext))) {
            throw new \Exception(
                "Codeception requires \"{$ext}\" extension installed to make tests run\n"
                . "If you are not sure, how to install \"{$ext}\", please refer to StackOverflow\n\n"
                . "Notice: PHP for Apache/Nginx and CLI can have different php.ini files.\n"
                . "Please make sure that your PHP you run from console has \"{$ext}\" enabled."
            );
        }
    }
}
<?php
namespace Codeception\Command\Shared;

use Codeception\Configuration;
use Symfony\Component\Console\Exception\InvalidOptionException;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;

trait Config
{
    protected function getSuiteConfig($suite)
    {
        return Configuration::suiteSettings($suite, $this->getGlobalConfig());
    }

    protected function getGlobalConfig($conf = null)
    {
        return Configuration::config($conf);
    }

    protected function getSuites($conf = null)
    {
        return Configuration::suites();
    }

    protected function overrideConfig($configOptions)
    {
        $updatedConfig = [];
        foreach ($configOptions as $option) {
            $keys = explode(': ', $option);
            if (count($keys) < 2) {
                throw new \InvalidArgumentException('--config-option should have config passed as "key:value"');
            }
            $value = array_pop($keys);
            $yaml = '';
            for ($ind = 0; count($keys); $ind += 2) {
                $yaml .= "\n" . str_repeat(' ', $ind) . array_shift($keys) . ': ';
            }
            $yaml .= $value;
            try {
                $config = Yaml::parse($yaml);
            } catch (ParseException $e) {
                throw new \Codeception\Exception\ParseException("Overridden config can't be parsed: \n$yaml\n" . $e->getParsedLine());
            }
            $updatedConfig = array_merge_recursive($updatedConfig, $config);
        }
        return Configuration::append($updatedConfig);
    }

    protected function enableExtensions($extensions)
    {
        $config = ['extensions' => ['enabled' => []]];
        foreach ($extensions as $name) {
            if (!class_exists($name)) {
                $className = 'Codeception\\Extension\\' . ucfirst($name);
                if (!class_exists($className)) {
                    throw new InvalidOptionException("Extension $name can't be loaded (tried by $name and $className)");
                }
                $config['extensions']['enabled'][] = $className;
                continue;
            }
            $config['extensions']['enabled'][] = $name;
        }
        return Configuration::append($config);
    }
}
<?php
namespace Codeception\Command\Shared;

use Codeception\Util\Shared\Namespaces;

trait FileSystem
{
    use Namespaces;

    protected function createDirectoryFor($basePath, $className = '')
    {
        $basePath = rtrim($basePath, DIRECTORY_SEPARATOR);
        if ($className) {
            $className = str_replace(['/', '\\'], [DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR], $className);
            $path = $basePath . DIRECTORY_SEPARATOR . $className;
            $basePath = pathinfo($path, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR;
        }
        if (!file_exists($basePath)) {
            // Second argument should be mode. Well, umask() doesn't seem to return any if not set. Config may fix this.
            mkdir($basePath, 0775, true); // Third parameter commands to create directories recursively
        }
        return $basePath;
    }

    protected function completeSuffix($filename, $suffix)
    {
        if (strpos(strrev($filename), strrev($suffix)) === 0) {
            $filename .= '.php';
        }
        if (strpos(strrev($filename), strrev($suffix . '.php')) !== 0) {
            $filename .= $suffix . '.php';
        }
        if (strpos(strrev($filename), strrev('.php')) !== 0) {
            $filename .= '.php';
        }

        return $filename;
    }

    protected function removeSuffix($classname, $suffix)
    {
        $classname = preg_replace('~\.php$~', '', $classname);
        return preg_replace("~$suffix$~", '', $classname);
    }

    protected function createFile($filename, $contents, $force = false, $flags = null)
    {
        if (file_exists($filename) && !$force) {
            return false;
        }
        file_put_contents($filename, $contents, $flags);
        return true;
    }
}
<?php
namespace Codeception\Command\Shared;

use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Output\OutputInterface;

trait Style
{
    public function addStyles(OutputInterface $output)
    {
        $output->getFormatter()->setStyle('notice', new OutputFormatterStyle('white', 'green', ['bold']));
        $output->getFormatter()->setStyle('bold', new OutputFormatterStyle(null, null, ['bold']));
        $output->getFormatter()->setStyle('warning', new OutputFormatterStyle(null, 'yellow', ['bold']));
        $output->getFormatter()->setStyle('debug', new OutputFormatterStyle('cyan'));
    }
}
<?php
namespace Codeception\Command;

use Codeception\Configuration;
use Codeception\Lib\Generator\StepObject as StepObjectGenerator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\Question;

/**
 * Generates StepObject class. You will be asked for steps you want to implement.
 *
 * * `codecept g:stepobject acceptance AdminSteps`
 * * `codecept g:stepobject acceptance UserSteps --silent` - skip action questions
 *
 */
class GenerateStepObject extends Command
{
    use Shared\FileSystem;
    use Shared\Config;

    protected function configure()
    {
        $this->setDefinition([
            new InputArgument('suite', InputArgument::REQUIRED, 'Suite for StepObject'),
            new InputArgument('step', InputArgument::REQUIRED, 'StepObject name'),
            new InputOption('silent', '', InputOption::VALUE_NONE, 'skip verification question'),
        ]);
    }

    public function getDescription()
    {
        return 'Generates empty StepObject class';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $suite = $input->getArgument('suite');
        $step = $input->getArgument('step');
        $config = $this->getSuiteConfig($suite);

        $class = $this->getShortClassName($step);

        $path = $this->createDirectoryFor(Configuration::supportDir() . 'Step' . DIRECTORY_SEPARATOR . ucfirst($suite), $step);

        $dialog = $this->getHelperSet()->get('question');
        $filename = $path . $class . '.php';

        $helper = $this->getHelper('question');
        $question = new Question("Add action to StepObject class (ENTER to exit): ");

        $gen = new StepObjectGenerator($config, ucfirst($suite) . '\\' . $step);

        if (!$input->getOption('silent')) {
            do {
                $question = new Question('Add action to StepObject class (ENTER to exit): ', null);
                $action = $dialog->ask($input, $output, $question);
                if ($action) {
                    $gen->createAction($action);
                }
            } while ($action);
        }

        $res = $this->createFile($filename, $gen->produce());

        if (!$res) {
            $output->writeln("<error>StepObject $filename already exists</error>");
            return 1;
        }
        $output->writeln("<info>StepObject was created in $filename</info>");
        return 0;
    }
}
<?php
namespace Codeception\Command;

if (!class_exists('Stecman\Component\Symfony\Console\BashCompletion\Completion')) {
    echo "Please install `stecman/symfony-console-completion\n` to enable auto completion";
    return;
}

use Codeception\Configuration;
use Stecman\Component\Symfony\Console\BashCompletion\Completion as ConsoleCompletion;
use Stecman\Component\Symfony\Console\BashCompletion\CompletionCommand;
use Stecman\Component\Symfony\Console\BashCompletion\CompletionHandler;
use Stecman\Component\Symfony\Console\BashCompletion\Completion\ShellPathCompletion;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class Completion extends CompletionCommand
{
    protected function configureCompletion(CompletionHandler $handler)
    {
        // Can't set for all commands, because it wouldn't work well with generate:suite
        $suiteCommands = [
            'run',
            'config:validate',
            'console',
            'dry-run',
            'generate:cept',
            'generate:cest',
            'generate:feature',
            'generate:phpunit',
            'generate:scenarios',
            'generate:stepobject',
            'generate:test',
            'gherkin:snippets',
            'gherkin:steps'
        ];

        foreach ($suiteCommands as $suiteCommand) {
            $handler->addHandler(new ConsoleCompletion(
                $suiteCommand,
                'suite',
                ConsoleCompletion::TYPE_ARGUMENT,
                Configuration::suites()
            ));
        }

        $handler->addHandlers([
            new ShellPathCompletion(
                ConsoleCompletion::ALL_COMMANDS,
                'path',
                ConsoleCompletion::TYPE_ARGUMENT
            ),
            new ShellPathCompletion(
                ConsoleCompletion::ALL_COMMANDS,
                'test',
                ConsoleCompletion::TYPE_ARGUMENT
            ),
        ]);
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        if ($input->getOption('generate-hook') && $input->getOption('use-vendor-bin')) {
            global $argv;
            $argv[0] = 'vendor/bin/' . basename($argv[0]);
        }

        parent::execute($input, $output);
        return 0;
    }

    protected function createDefinition()
    {
        $definition = parent::createDefinition();
        $definition->addOption(new InputOption(
            'use-vendor-bin',
            null,
            InputOption::VALUE_NONE,
            'Use the vendor bin for autocompletion.'
        ));

        return $definition;
    }
}
<?php
namespace Codeception\Command;

use Codeception\Test\Loader\Gherkin;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Prints all steps from all Gherkin contexts for a specific suite
 *
 * ```
 * codecept gherkin:steps acceptance
 * ```
 *
 */
class GherkinSteps extends Command
{
    use Shared\Config;
    use Shared\Style;

    protected function configure()
    {
        $this->setDefinition(
            [
                new InputArgument('suite', InputArgument::REQUIRED, 'suite to scan for feature files'),
                new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
            ]
        );
        parent::configure();
    }

    public function getDescription()
    {
        return 'Prints all defined feature steps';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $this->addStyles($output);
        $suite = $input->getArgument('suite');
        $config = $this->getSuiteConfig($suite);
        $config['describe_steps'] = true;

        $loader = new Gherkin($config);
        $steps = $loader->getSteps();

        foreach ($steps as $name => $context) {
            /** @var $table Table  **/
            $table = new Table($output);
            $table->setHeaders(['Step', 'Implementation']);
            $output->writeln("Steps from <bold>$name</bold> context:");

            foreach ($context as $step => $callable) {
                if (count($callable) < 2) {
                    continue;
                }
                $method = $callable[0] . '::' . $callable[1];
                $table->addRow([$step, $method]);
            }
            $table->render();
        }

        if (!isset($table)) {
            $output->writeln("No steps are defined, start creating them by running <bold>gherkin:snippets</bold>");
        }
        return 0;
    }
}
<?php
namespace Codeception\Command;

use Codeception\Lib\Generator\Cest as CestGenerator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Generates Cest (scenario-driven object-oriented test) file:
 *
 * * `codecept generate:cest suite Login`
 * * `codecept g:cest suite subdir/subdir/testnameCest.php`
 * * `codecept g:cest suite LoginCest -c path/to/project`
 * * `codecept g:cest "App\Login"`
 *
 */
class GenerateCest extends Command
{
    use Shared\FileSystem;
    use Shared\Config;

    protected function configure()
    {
        $this->setDefinition([
            new InputArgument('suite', InputArgument::REQUIRED, 'suite where tests will be put'),
            new InputArgument('class', InputArgument::REQUIRED, 'test name'),
        ]);
    }

    public function getDescription()
    {
        return 'Generates empty Cest file in suite';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $suite = $input->getArgument('suite');
        $class = $input->getArgument('class');

        $config = $this->getSuiteConfig($suite);
        $className = $this->getShortClassName($class);
        $path = $this->createDirectoryFor($config['path'], $class);

        $filename = $this->completeSuffix($className, 'Cest');
        $filename = $path . $filename;

        if (file_exists($filename)) {
            $output->writeln("<error>Test $filename already exists</error>");
            return 1;
        }
        $gen = new CestGenerator($class, $config);
        $res = $this->createFile($filename, $gen->produce());
        if (!$res) {
            $output->writeln("<error>Test $filename already exists</error>");
            return 1;
        }

        $output->writeln("<info>Test was created in $filename</info>");
        return 0;
    }
}
<?php
namespace Codeception\Command;

use Codeception\Configuration;
use Codeception\Lib\Generator\Snapshot as SnapshotGenerator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Generates Snapshot.
 * Snapshot can be used to test dynamical data.
 * If suite name is provided, an actor class will be included into placeholder
 *
 * * `codecept g:snapshot UserEmails`
 * * `codecept g:snapshot Products`
 * * `codecept g:snapshot acceptance UserEmails`
 */
class GenerateSnapshot extends Command
{
    use Shared\FileSystem;
    use Shared\Config;

    protected function configure()
    {
        $this->setDefinition([
            new InputArgument('suite', InputArgument::REQUIRED, 'Suite name or snapshot name)'),
            new InputArgument('snapshot', InputArgument::OPTIONAL, 'Name of snapshot'),
        ]);
        parent::configure();
    }

    public function getDescription()
    {
        return 'Generates empty Snapshot class';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $suite = $input->getArgument('suite');
        $class = $input->getArgument('snapshot');

        if (!$class) {
            $class = $suite;
            $suite = null;
        }

        $conf = $suite
            ? $this->getSuiteConfig($suite)
            : $this->getGlobalConfig();

        if ($suite) {
            $suite = DIRECTORY_SEPARATOR . ucfirst($suite);
        }

        $path = $this->createDirectoryFor(Configuration::supportDir() . 'Snapshot' . $suite, $class);

        $filename = $path . $this->getShortClassName($class) . '.php';

        $output->writeln($filename);

        $gen = new SnapshotGenerator($conf, ucfirst($suite) . '\\' . $class);
        $res = $this->createFile($filename, $gen->produce());

        if (!$res) {
            $output->writeln("<error>Snapshot $filename already exists</error>");
            return 1;
        }
        $output->writeln("<info>Snapshot was created in $filename</info>");
        return 0;
    }
}
<?php
namespace Codeception\Command;

use Codeception\Configuration;
use Codeception\Lib\Generator\Helper;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Creates empty Helper class.
 *
 * * `codecept g:helper MyHelper`
 * * `codecept g:helper "My\Helper"`
 *
 */
class GenerateHelper extends Command
{
    use Shared\FileSystem;
    use Shared\Config;

    protected function configure()
    {
        $this->setDefinition([
            new InputArgument('name', InputArgument::REQUIRED, 'helper name'),
        ]);
    }

    public function getDescription()
    {
        return 'Generates new helper';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $name = ucfirst($input->getArgument('name'));
        $config = $this->getGlobalConfig();

        $path = $this->createDirectoryFor(Configuration::supportDir() . 'Helper', $name);
        $filename = $path . $this->getShortClassName($name) . '.php';

        $res = $this->createFile($filename, (new Helper($name, $config['namespace']))->produce());
        if ($res) {
            $output->writeln("<info>Helper $filename created</info>");
            return 0;
        } else {
            $output->writeln("<error>Error creating helper $filename</error>");
            return 1;
        }
    }
}
<?php
namespace Codeception\Command;

use Codeception\Lib\Generator\Feature;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Generates Feature file (in Gherkin):
 *
 * * `codecept generate:feature suite Login`
 * * `codecept g:feature suite subdir/subdir/login.feature`
 * * `codecept g:feature suite login.feature -c path/to/project`
 *
 */
class GenerateFeature extends Command
{
    use Shared\FileSystem;
    use Shared\Config;

    protected function configure()
    {
        $this->setDefinition([
            new InputArgument('suite', InputArgument::REQUIRED, 'suite to be tested'),
            new InputArgument('feature', InputArgument::REQUIRED, 'feature to be generated'),
            new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
        ]);
    }

    public function getDescription()
    {
        return 'Generates empty feature file in suite';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $suite = $input->getArgument('suite');
        $filename = $input->getArgument('feature');

        $config = $this->getSuiteConfig($suite);
        $this->createDirectoryFor($config['path'], $filename);

        $gen = new Feature(basename($filename));
        if (!preg_match('~\.feature$~', $filename)) {
            $filename .= '.feature';
        }
        $full_path = rtrim($config['path'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $filename;
        $res = $this->createFile($full_path, $gen->produce());
        if (!$res) {
            $output->writeln("<error>Feature $filename already exists</error>");
            return 1;
        }
        $output->writeln("<info>Feature was created in $full_path</info>");
        return 0;
    }
}
<?php
namespace Codeception\Command;

use Codeception\Configuration;
use Codeception\Lib\Generator\Actions as ActionsGenerator;
use Codeception\Lib\Generator\Actor as ActorGenerator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Generates Actor classes (initially Guy classes) from suite configs.
 * Starting from Codeception 2.0 actor classes are auto-generated. Use this command to generate them manually.
 *
 * * `codecept build`
 * * `codecept build path/to/project`
 *
 */
class Build extends Command
{
    use Shared\Config;
    use Shared\FileSystem;

    protected $inheritedMethodTemplate = ' * @method void %s(%s)';

    /**
     * @var OutputInterface
     */
    protected $output;

    public function getDescription()
    {
        return 'Generates base classes for all suites';
    }


    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->output = $output;
        $this->buildActorsForConfig();
        return 0;
    }
    
    private function buildActor(array $settings)
    {
        $actorGenerator = new ActorGenerator($settings);
        $this->output->writeln(
            '<info>' . Configuration::config()['namespace'] . '\\' . $actorGenerator->getActorName()
            . "</info> includes modules: " . implode(', ', $actorGenerator->getModules())
        );
        
        $content = $actorGenerator->produce();

        $file = $this->createDirectoryFor(
            Configuration::supportDir(),
            $settings['actor']
        ) . $this->getShortClassName($settings['actor']);
        $file .=  '.php';
        return $this->createFile($file, $content);
    }
    
    private function buildActions(array $settings)
    {
        $actionsGenerator = new ActionsGenerator($settings);
        $content = $actionsGenerator->produce();
        $this->output->writeln(
            " -> {$settings['actor']}Actions.php generated successfully. "
            . $actionsGenerator->getNumMethods() . " methods added"
        );


        $file = $this->createDirectoryFor(Configuration::supportDir() . '_generated', $settings['actor']);
        $file .= $this->getShortClassName($settings['actor']) . 'Actions.php';
        return $this->createFile($file, $content, true);
    }

    private function buildSuiteActors()
    {
        $suites = $this->getSuites();
        if (!empty($suites)) {
            $this->output->writeln("<info>Building Actor classes for suites: " . implode(', ', $suites) . '</info>');
        }
        foreach ($suites as $suite) {
            $settings = $this->getSuiteConfig($suite);
            if (!$settings['actor']) {
                continue; // no actor
            }
            $this->buildActions($settings);
            $actorBuilt = $this->buildActor($settings);
            
            if ($actorBuilt) {
                $this->output->writeln("{$settings['actor']}.php created.");
            }
        }
    }
    
    protected function buildActorsForConfig($configFile = null)
    {
        $config = $this->getGlobalConfig($configFile);
        
        $dir = Configuration::projectDir();
        $this->buildSuiteActors();

        foreach ($config['include'] as $subConfig) {
            $this->output->writeln("\n<comment>Included Configuration: $subConfig</comment>");
            $this->buildActorsForConfig($dir . DIRECTORY_SEPARATOR . $subConfig);
        }
    }
}
<?php
namespace Codeception\Command;

use Codeception\Lib\Generator\Test as TestGenerator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Generates skeleton for Unit Test that extends `Codeception\TestCase\Test`.
 *
 * * `codecept g:test unit User`
 * * `codecept g:test unit "App\User"`
 */
class GenerateTest extends Command
{
    use Shared\FileSystem;
    use Shared\Config;

    protected function configure()
    {
        $this->setDefinition(
            [
                new InputArgument('suite', InputArgument::REQUIRED, 'suite where tests will be put'),
                new InputArgument('class', InputArgument::REQUIRED, 'class name'),
            ]
        );
        parent::configure();
    }

    public function getDescription()
    {
        return 'Generates empty unit test file in suite';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $suite = $input->getArgument('suite');
        $class = $input->getArgument('class');

        $config = $this->getSuiteConfig($suite);

        $className = $this->getShortClassName($class);
        $path = $this->createDirectoryFor($config['path'], $class);

        $filename = $this->completeSuffix($className, 'Test');
        $filename = $path . $filename;

        $gen = new TestGenerator($config, $class);

        $res = $this->createFile($filename, $gen->produce());

        if (!$res) {
            $output->writeln("<error>Test $filename already exists</error>");
            return 1;
        }
        $output->writeln("<info>Test was created in $filename</info>");
        return 0;
    }
}
<?php
namespace Codeception\Command;

use Codeception\Configuration;
use Codeception\Exception\ConfigurationException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Generates empty environment configuration file into envs dir:
 *
 *  * `codecept g:env firefox`
 *
 * Required to have `envs` path to be specified in `codeception.yml`
 */
class GenerateEnvironment extends Command
{
    use Shared\FileSystem;
    use Shared\Config;

    protected function configure()
    {
        $this->setDefinition([
            new InputArgument('env', InputArgument::REQUIRED, 'Environment name'),
        ]);
    }

    public function getDescription()
    {
        return 'Generates empty environment config';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $conf = $this->getGlobalConfig();
        if (!Configuration::envsDir()) {
            throw new ConfigurationException(
                "Path for environments configuration is not set.\n"
                . "Please specify envs path in your `codeception.yml`\n \n"
                . "envs: tests/_envs"
            );
        }
        $relativePath = $conf['paths']['envs'];
        $env = $input->getArgument('env');
        $file = "$env.yml";

        $path = $this->createDirectoryFor($relativePath, $file);
        $saved = $this->createFile($path . $file, "# `$env` environment config goes here");

        if ($saved) {
            $output->writeln("<info>$env config was created in $relativePath/$file</info>");
            return 0;
        } else {
            $output->writeln("<error>File $relativePath/$file already exists</error>");
            return 1;
        }
    }
}
<?php
namespace Codeception\Command;

use Codeception\Configuration;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Validates and prints Codeception config.
 * Use it do debug Yaml configs
 *
 * Check config:
 *
 * * `codecept config`: check global config
 * * `codecept config unit`: check suite config
 *
 * Load config:
 *
 * * `codecept config:validate -c path/to/another/config`: from another dir
 * * `codecept config:validate -c another_config.yml`: from another config file
 *
 * Check overriding config values (like in `run` command)
 *
 * * `codecept config:validate -o "settings: shuffle: true"`: enable shuffle
 * * `codecept config:validate -o "settings: lint: false"`: disable linting
 * * `codecept config:validate -o "reporters: report: \Custom\Reporter" --report`: use custom reporter
 *
 */
class ConfigValidate extends Command
{
    use Shared\Config;
    use Shared\Style;

    protected function configure()
    {
        $this->setDefinition(
            [
                new InputArgument('suite', InputArgument::OPTIONAL, 'to show suite configuration'),
                new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
                new InputOption('override', 'o', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Override config values'),
            ]
        );
        parent::configure();
    }

    public function getDescription()
    {
        return 'Validates and prints config to screen';
    }


    public function execute(InputInterface $input, OutputInterface $output)
    {
        $this->addStyles($output);

        if ($suite = $input->getArgument('suite')) {
            $output->write("Validating <bold>$suite</bold> config... ");
            $config = $this->getSuiteConfig($suite);
            $output->writeln("Ok");
            $output->writeln("------------------------------\n");
            $output->writeln("<info>$suite Suite Config</info>:\n");
            $output->writeln($this->formatOutput($config));

            return 0;
        }

        $output->write("Validating global config... ");
        $config = $this->getGlobalConfig();
        $output->writeln($input->getOption('override'));
        if (count($input->getOption('override'))) {
            $config = $this->overrideConfig($input->getOption('override'));
        }
        $suites = Configuration::suites();
        $output->writeln("Ok");

        $output->writeln("------------------------------\n");
        $output->writeln("<info>Codeception Config</info>:\n");
        $output->writeln($this->formatOutput($config));

        $output->writeln('<info>Directories</info>:');
        $output->writeln("<comment>codecept_root_dir()</comment>   " . codecept_root_dir());
        $output->writeln("<comment>codecept_output_dir()</comment> " . codecept_output_dir());
        $output->writeln("<comment>codecept_data_dir()</comment>   " . codecept_data_dir());
        $output->writeln('');

        $output->writeln("<info>Available suites</info>: " . implode(', ', $suites));

        foreach ($suites as $suite) {
            $output->write("Validating suite <bold>$suite</bold>... ");
            $this->getSuiteConfig($suite);
            $output->writeln('Ok');
        }


        $output->writeln("Execute <info>codecept config:validate [<suite>]</info> to see config for a suite");
        return 0;
    }

    protected function formatOutput($config)
    {
        $output = print_r($config, true);
        return preg_replace('~\[(.*?)\] =>~', "<fg=yellow>$1</fg=yellow> =>", $output);
    }
}
<?php
namespace Codeception\Command;

use Humbug\SelfUpdate\Updater;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Codeception\Codecept;

/**
 * Auto-updates phar archive from official site: 'http://codeception.com/codecept.phar' .
 *
 * * `php codecept.phar self-update`
 *
 * @author Franck Cassedanne <franck@cassedanne.com>
 */
class SelfUpdate extends Command
{
    /**
     * Class constants
     */
    const NAME = 'Codeception';
    const GITHUB_REPO = 'Codeception/Codeception';
    const PHAR_URL = 'http://codeception.com/';
    const PHAR_URL_PHP56 = 'http://codeception.com/php56/';

    /**
     * Holds the current script filename.
     * @var string
     */
    protected $filename;

    /**
     * {@inheritdoc}
     */
    protected function configure()
    {
        if (isset($_SERVER['argv'][0])) {
            $this->filename = $_SERVER['argv'][0];
        } else {
            $this->filename = \Phar::running(false);
        }

        $this
            ->setAliases(array('selfupdate'))
            ->setDescription(
                sprintf(
                    'Upgrade <comment>%s</comment> to the latest version',
                    $this->filename
                )
            );

        parent::configure();
    }

    /**
     * @return string
     */
    protected function getCurrentVersion()
    {
        return Codecept::VERSION;
    }

    /**
     * {@inheritdoc}
     */
    public function execute(InputInterface $input, OutputInterface $output)
    {
        $version = $this->getCurrentVersion();

        $output->writeln(
            sprintf(
                '<info>%s</info> version <comment>%s</comment>',
                self::NAME,
                $version
            )
        );

        $url = $this->getPharUrl();

        $updater = new Updater(null, false);
        $updater->getStrategy()->setPharUrl($url . 'codecept.phar');
        $updater->getStrategy()->setVersionUrl($url . 'codecept.version');

        try {
            if ($updater->hasUpdate()) {
                $output->writeln("\n<info>Updating...</info>");
                $updater->update();

                $output->writeln(
                    sprintf("\n<comment>%s</comment> has been updated.\n", $this->filename)
                );
            } else {
                $output->writeln('You are already using the latest version.');
            }
        } catch (\Exception $e) {
            $output->writeln(
                sprintf(
                    "<error>\n%s\n</error>",
                    $e->getMessage()
                )
            );
            return 1;
        }

        return 0;
    }

    /**
     * Returns base url of phar file for current PHP version
     *
     * @return string
     */
    protected function getPharUrl()
    {
        if (version_compare(PHP_VERSION, '7.2.0', '<')) {
            return self::PHAR_URL_PHP56;
        }
        return self::PHAR_URL;
    }
}
<?php
namespace Codeception\Command;

use Codeception\Configuration;
use Codeception\Lib\Generator\Group as GroupGenerator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Creates empty GroupObject - extension which handles all group events.
 *
 * * `codecept g:group Admin`
 */
class GenerateGroup extends Command
{
    use Shared\FileSystem;
    use Shared\Config;

    protected function configure()
    {
        $this->setDefinition([
            new InputArgument('group', InputArgument::REQUIRED, 'Group class name'),
        ]);
    }

    public function getDescription()
    {
        return 'Generates Group subscriber';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $config = $this->getGlobalConfig();
        $group = $input->getArgument('group');

        $class = ucfirst($group);
        $path = $this->createDirectoryFor(Configuration::supportDir() . 'Group' . DIRECTORY_SEPARATOR, $class);

        $filename = $path . $class . '.php';

        $gen = new GroupGenerator($config, $group);
        $res = $this->createFile($filename, $gen->produce());

        if (!$res) {
            $output->writeln("<error>Group $filename already exists</error>");
            return 1;
        }

        $output->writeln("<info>Group extension was created in $filename</info>");
        $output->writeln(
            'To use this group extension, include it to "extensions" option of global Codeception config.'
        );
        return 0;
    }
}
<?php

namespace Codeception\Command;

use Codeception\InitTemplate;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class Init extends Command
{

    protected function configure()
    {
        $this->setDefinition(
            [
                new InputArgument('template', InputArgument::REQUIRED, 'Init template for the setup'),
                new InputOption('path', null, InputOption::VALUE_REQUIRED, 'Change current directory', null),
                new InputOption('namespace', null, InputOption::VALUE_OPTIONAL, 'Namespace to add for actor classes and helpers\'', null),

            ]
        );
    }

    public function getDescription()
    {
        return "Creates test suites by a template";
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $template = $input->getArgument('template');

        if (class_exists($template)) {
            $className = $template;
        } else {
            $className = 'Codeception\Template\\' . ucfirst($template);

            if (!class_exists($className)) {
                throw new \Exception("Template from a $className can't be loaded; Init can't be executed");
            }
        }

        $initProcess = new $className($input, $output);
        if (!$initProcess instanceof InitTemplate) {
            throw new \Exception("$className is not a valid template");
        }
        if ($input->getOption('path')) {
            $initProcess->initDir($input->getOption('path'));
        }
        $initProcess->setup();
        return 0;
    }
}
<?php
namespace Codeception\Command;

use Codeception\Configuration;
use Codeception\Exception\ConfigurationException;
use Codeception\Test\Cest;
use Codeception\Test\Interfaces\ScenarioDriven;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\EventDispatcher\EventDispatcher;

/**
 * Generates user-friendly text scenarios from scenario-driven tests (Cest).
 *
 * * `codecept g:scenarios acceptance` - for all acceptance tests
 * * `codecept g:scenarios acceptance --format html` - in html format
 * * `codecept g:scenarios acceptance --path doc` - generate scenarios to `doc` dir
 */
class GenerateScenarios extends Command
{
    use Shared\FileSystem;
    use Shared\Config;

    protected function configure()
    {
        $this->setDefinition([
            new InputArgument('suite', InputArgument::REQUIRED, 'suite from which texts should be generated'),
            new InputOption('path', 'p', InputOption::VALUE_REQUIRED, 'Use specified path as destination instead of default'),
            new InputOption('single-file', '', InputOption::VALUE_NONE, 'Render all scenarios to only one file'),
            new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Specify output format: html or text (default)', 'text'),
        ]);
        parent::configure();
    }

    public function getDescription()
    {
        return 'Generates text representation for all scenarios';
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $suite = $input->getArgument('suite');

        $suiteConf = $this->getSuiteConfig($suite);

        $path = $input->getOption('path')
            ? $input->getOption('path')
            : Configuration::dataDir() . 'scenarios';

        $format = $input->getOption('format');

        @mkdir($path);

        if (!is_writable($path)) {
            throw new ConfigurationException(
                "Path $path is not writable. Please, set valid permissions for folder to store scenarios."
            );
        }

        $path = $path . DIRECTORY_SEPARATOR . $suite;
        if (!$input->getOption('single-file')) {
            @mkdir($path);
        }

        $suiteManager = new \Codeception\SuiteManager(new EventDispatcher(), $suite, $suiteConf);

        if ($suiteConf['bootstrap']) {
            if (file_exists($suiteConf['path'] . $suiteConf['bootstrap'])) {
                require_once $suiteConf['path'] . $suiteConf['bootstrap'];
            }
        }

        $tests = $this->getTests($suiteManager);
        $scenarios = "";

        foreach ($tests as $test) {
            if (!($test instanceof ScenarioDriven)) {
                continue;
            }
            $feature = $test->getScenarioText($format);

            $name = $this->underscore(basename($test->getFileName(), '.php'));

            // create separate file for each test in Cest
            if ($test instanceof Cest && !$input->getOption('single-file')) {
                $name .= '.' . $this->underscore($test->getTestMethod());
            }

            if ($input->getOption('single-file')) {
                $scenarios .= $feature;
                $output->writeln("* $name rendered");
            } else {
                $feature = $this->decorate($feature, $format);
                $this->createFile($path . DIRECTORY_SEPARATOR . $name . $this->formatExtension($format), $feature, true);
                $output->writeln("* $name generated");
            }
        }

        if ($input->getOption('single-file')) {
            $this->createFile($path . $this->formatExtension($format), $this->decorate($scenarios, $format), true);
        }
        return 0;
    }

    protected function decorate($text, $format)
    {
        switch ($format) {
            case 'text':
                return $text;
            case 'html':
                return "<html><body>$text</body></html>";
        }
    }

    protected function getTests($suiteManager)
    {
        $suiteManager->loadTests();
        return $suiteManager->getSuite()->tests();
    }

    protected function formatExtension($format)
    {
        switch ($format) {
            case 'text':
                return '.txt';
            case 'html':
                return '.html';
        }
    }

    private function underscore($name)
    {
        $name = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\\1_\\2', $name);
        $name = preg_replace('/([a-z\d])([A-Z])/', '\\1_\\2', $name);
        $name = str_replace(['/', '\\'], ['.', '.'], $name);
        $name = preg_replace('/_Cept$/', '', $name);
        $name = preg_replace('/_Cest$/', '', $name);
        return $name;
    }
}
<?php
namespace Codeception\Command;

use Codeception\Configuration;
use Codeception\Lib\Generator\Helper;
use Codeception\Util\Template;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Codeception\Lib\Generator\Actor as ActorGenerator;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Yaml\Yaml;

/**
 * Create new test suite. Requires suite name and actor name
 *
 * * ``
 * * `codecept g:suite api` -> api + ApiTester
 * * `codecept g:suite integration Code` -> integration + CodeTester
 * * `codecept g:suite frontend Front` -> frontend + FrontTester
 *
 */
class GenerateSuite extends Command
{
    use Shared\FileSystem;
    use Shared\Config;
    use Shared\Style;

    protected function configure()
    {
        $this->setDefinition([
            new InputArgument('suite', InputArgument::REQUIRED, 'suite to be generated'),
            new InputArgument('actor', InputArgument::OPTIONAL, 'name of new actor class'),
        ]);
    }

    public function getDescription()
    {
        return 'Generates new test suite';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $this->addStyles($output);
        $suite = $input->getArgument('suite');
        $actor = $input->getArgument('actor');

        if ($this->containsInvalidCharacters($suite)) {
            $output->writeln("<error>Suite name '$suite' contains invalid characters. ([A-Za-z0-9_]).</error>");
            return 1;
        }

        $config = $this->getGlobalConfig();
        if (!$actor) {
            $actor = ucfirst($suite) . $config['actor_suffix'];
        }

        $dir = Configuration::testsDir();
        if (file_exists($dir . $suite . '.suite.yml')) {
            throw new \Exception("Suite configuration file '$suite.suite.yml' already exists.");
        }

        $this->createDirectoryFor($dir . $suite);

        if ($config['settings']['bootstrap']) {
            // generate bootstrap file
            $this->createFile(
                $dir . $suite . DIRECTORY_SEPARATOR . $config['settings']['bootstrap'],
                "<?php\n",
                true
            );
        }

        $helperName = ucfirst($suite);

        $file = $this->createDirectoryFor(
            Configuration::supportDir() . "Helper",
            "$helperName.php"
        ) . "$helperName.php";

        $gen = new Helper($helperName, $config['namespace']);
        // generate helper
        $this->createFile(
            $file,
            $gen->produce()
        );

        $output->writeln("Helper <info>" . $gen->getHelperName() . "</info> was created in $file");

        $yamlSuiteConfigTemplate = <<<EOF
actor: {{actor}}
modules:
    enabled:
        - {{helper}}
EOF;

        $this->createFile(
            $dir . $suite . '.suite.yml',
            $yamlSuiteConfig = (new Template($yamlSuiteConfigTemplate))
                ->place('actor', $actor)
                ->place('helper', $gen->getHelperName())
                ->produce()
        );

        Configuration::append(Yaml::parse($yamlSuiteConfig));
        $actorGenerator = new ActorGenerator(Configuration::config());

        $content = $actorGenerator->produce();

        $file = $this->createDirectoryFor(
            Configuration::supportDir(),
            $actor
        ) . $this->getShortClassName($actor);
        $file .=  '.php';

        $this->createFile($file, $content);

        $output->writeln("Actor <info>" . $actor . "</info> was created in $file");

        $output->writeln("Suite config <info>$suite.suite.yml</info> was created.");
        $output->writeln(' ');
        $output->writeln("Next steps:");
        $output->writeln("1. Edit <bold>$suite.suite.yml</bold> to enable modules for this suite");
        $output->writeln("2. Create first test with <bold>generate:cest testName</bold> ( or test|cept) command");
        $output->writeln("3. Run tests of this suite with <bold>codecept run $suite</bold> command");

        $output->writeln("<info>Suite $suite generated</info>");
        return 0;
    }

    private function containsInvalidCharacters($suite)
    {
        return preg_match('#[^A-Za-z0-9_]#', $suite) ? true : false;
    }
}
<?php

namespace Codeception;

use Codeception\Exception\ModuleException;
use Codeception\Lib\Interfaces\RequiresPackage;
use Codeception\Lib\ModuleContainer;
use Codeception\Util\Shared\Asserts;

/**
 * Basic class for Modules and Helpers.
 * You must extend from it while implementing own helpers.
 *
 * Public methods of this class start with `_` prefix in order to ignore them in actor classes.
 * Module contains **HOOKS** which allow to handle test execution routine.
 *
 */
abstract class Module
{
    use Asserts;

    /**
     * @var ModuleContainer
     */
    protected $moduleContainer;

    /**
     * By setting it to false module wan't inherit methods of parent class.
     *
     * @var bool
     */
    public static $includeInheritedActions = true;

    /**
     * Allows to explicitly set what methods have this class.
     *
     * @var array
     */
    public static $onlyActions = [];

    /**
     * Allows to explicitly exclude actions from module.
     *
     * @var array
     */
    public static $excludeActions = [];

    /**
     * Allows to rename actions
     *
     * @var array
     */
    public static $aliases = [];

    protected $storage = [];

    protected $config = [];

    protected $backupConfig = [];

    protected $requiredFields = [];

    /**
     * Module constructor.
     *
     * Requires module container (to provide access between modules of suite) and config.
     *
     * @param ModuleContainer $moduleContainer
     * @param array|null $config
     */
    public function __construct(ModuleContainer $moduleContainer, $config = null)
    {
        $this->moduleContainer = $moduleContainer;

        $this->backupConfig = $this->config;
        if (is_array($config)) {
            $this->_setConfig($config);
        }
    }

    /**
     * Allows to define initial module config.
     * Can be used in `_beforeSuite` hook of Helpers or Extensions
     *
     * ```php
     * <?php
     * public function _beforeSuite($settings = []) {
     *     $this->getModule('otherModule')->_setConfig($this->myOtherConfig);
     * }
     * ```
     *
     * @param $config
     * @throws Exception\ModuleConfigException
     * @throws ModuleException
     */
    public function _setConfig($config)
    {
        $this->config = $this->backupConfig = array_merge($this->config, $config);
        $this->validateConfig();
    }

    /**
     * Allows to redefine config for a specific test.
     * Config is restored at the end of a test.
     *
     * ```php
     * <?php
     * // cleanup DB only for specific group of tests
     * public function _before(Test $test) {
     *     if (in_array('cleanup', $test->getMetadata()->getGroups()) {
     *         $this->getModule('Db')->_reconfigure(['cleanup' => true]);
     *     }
     * }
     * ```
     *
     * @param $config
     * @throws Exception\ModuleConfigException
     * @throws ModuleException
     */
    public function _reconfigure($config)
    {
        $this->config = array_merge($this->backupConfig, $config);
        $this->onReconfigure();
        $this->validateConfig();
    }

    /**
     * HOOK to be executed when config changes with `_reconfigure`.
     */
    protected function onReconfigure()
    {
        // update client on reconfigurations
    }

    /**
     * Reverts config changed by `_reconfigure`
     */
    public function _resetConfig()
    {
        $this->config = $this->backupConfig;
    }

    /**
     * Validates current config for required fields and required packages.
     *
     * @throws Exception\ModuleConfigException
     * @throws ModuleException
     */
    protected function validateConfig()
    {
        $fields = array_keys($this->config);
        if (array_intersect($this->requiredFields, $fields) != $this->requiredFields) {
            throw new Exception\ModuleConfigException(
                get_class($this),
                "\nOptions: " . implode(', ', $this->requiredFields) . " are required\n" .
                "Please, update the configuration and set all the required fields\n\n"
            );
        }
        if ($this instanceof RequiresPackage) {
            $errorMessage = '';
            foreach ($this->_requires() as $className => $package) {
                if (class_exists($className)) {
                    continue;
                }
                $errorMessage .= "Class $className can't be loaded, please add $package to composer.json\n";
            }
            if ($errorMessage) {
                throw new ModuleException($this, $errorMessage);
            }
        }
    }

    /**
     * Returns a module name for a Module, a class name for Helper
     *
     * @return string
     */
    public function _getName()
    {
        $moduleName = '\\' . get_class($this);

        if (strpos($moduleName, ModuleContainer::MODULE_NAMESPACE) === 0) {
            return substr($moduleName, strlen(ModuleContainer::MODULE_NAMESPACE));
        }

        return $moduleName;
    }

    /**
     * Checks if a module has required fields
     *
     * @return bool
     */
    public function _hasRequiredFields()
    {
        return !empty($this->requiredFields);
    }

    /**
     * **HOOK** triggered after module is created and configuration is loaded
     */
    public function _initialize()
    {
    }

    /**
     * **HOOK** executed before suite
     *
     * @param array $settings
     */
    public function _beforeSuite($settings = [])
    {
    }

    /**
     * **HOOK** executed after suite
     */
    public function _afterSuite()
    {
    }

    /**
     * **HOOK** executed before step
     *
     * @param Step $step
     */
    public function _beforeStep(Step $step)
    {
    }

    /**
     * **HOOK** executed after step
     *
     * @param Step $step
     */
    public function _afterStep(Step $step)
    {
    }

    /**
     * **HOOK** executed before test
     *
     * @param TestInterface $test
     */
    public function _before(TestInterface $test)
    {
    }

    /**
     * **HOOK** executed after test
     *
     * @param TestInterface $test
     */
    public function _after(TestInterface $test)
    {
    }

    /**
     * **HOOK** executed when test fails but before `_after`
     *
     * @param TestInterface $test
     * @param \Exception $fail
     */
    public function _failed(TestInterface $test, $fail)
    {
    }

    /**
     * Print debug message to the screen.
     *
     * @param $message
     */
    protected function debug($message)
    {
        codecept_debug($message);
    }

    /**
     * Print debug message with a title
     *
     * @param $title
     * @param $message
     */
    protected function debugSection($title, $message)
    {
        if (is_array($message) or is_object($message)) {
            $message = stripslashes(json_encode($message));
        }
        $this->debug("[$title] $message");
    }

    /**
     * Short text message to an amount of chars
     *
     * @param $message
     * @param $chars
     * @return string
     */
    protected function shortenMessage($message, $chars = 150)
    {
        return mb_substr($message, 0, $chars, 'utf-8');
    }

    /**
     * Checks that module is enabled.
     *
     * @param $name
     * @return bool
     */
    protected function hasModule($name)
    {
        return $this->moduleContainer->hasModule($name);
    }

    /**
     * Get all enabled modules
     *
     * @return array
     */
    protected function getModules()
    {
        return $this->moduleContainer->all();
    }

    /**
     * Get another module by its name:
     *
     * ```php
     * <?php
     * $this->getModule('WebDriver')->_findElements('.items');
     * ```
     *
     * @param $name
     * @return Module
     * @throws ModuleException
     */
    protected function getModule($name)
    {
        if (!$this->hasModule($name)) {
            $this->moduleContainer->throwMissingModuleExceptionWithSuggestion(__CLASS__, $name);
        }
        return $this->moduleContainer->getModule($name);
    }

    /**
     * Get config values or specific config item.
     *
     * @param mixed $key
     * @return mixed the config item's value or null if it doesn't exist
     */
    public function _getConfig($key = null)
    {
        if (!$key) {
            return $this->config;
        }
        if (isset($this->config[$key])) {
            return $this->config[$key];
        }
        return null;
    }

    protected function scalarizeArray($array)
    {
        foreach ($array as $k => $v) {
            if (!is_null($v) && !is_scalar($v)) {
                $array[$k] = (is_array($v) || $v instanceof \ArrayAccess)
                    ? $this->scalarizeArray($v)
                    : (string)$v;
            }
        }

        return $array;
    }
}
<?php
namespace Codeception;

use Codeception\Lib\ModuleContainer;
use Codeception\Step\Argument\FormattedOutput;
use Codeception\Step\Meta as MetaStep;
use Codeception\Util\Locator;
use PHPUnit\Framework\MockObject\MockObject;

abstract class Step
{
    const DEFAULT_MAX_LENGTH = 200;

    const STACK_POSITION = 3;
    /**
     * @var    string
     */
    protected $action;

    /**
     * @var    array
     */
    protected $arguments;

    protected $debugOutput;

    public $executed = false;

    protected $line = null;
    protected $file = null;
    protected $prefix = 'I';

    /**
     * @var MetaStep
     */
    protected $metaStep = null;

    protected $failed = false;
    protected $isTry = false;

    public function __construct($action, array $arguments = [])
    {
        $this->action = $action;
        $this->arguments = $arguments;
    }

    public function saveTrace()
    {
        $stack = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT);

        if (count($stack) <= self::STACK_POSITION) {
            return;
        }

        $traceLine = $stack[self::STACK_POSITION - 1];

        if (!isset($traceLine['file'])) {
            return;
        }
        $this->file = $traceLine['file'];
        $this->line = $traceLine['line'];

        $this->addMetaStep($traceLine, $stack);
    }

    private function isTestFile($file)
    {
        return preg_match('~[^\\'.DIRECTORY_SEPARATOR.'](Cest|Cept|Test).php$~', $file);
    }

    public function getName()
    {
        $class = explode('\\', __CLASS__);
        return end($class);
    }

    public function getAction()
    {
        return $this->action;
    }

    public function getLine()
    {
        if ($this->line && $this->file) {
            return codecept_relative_path($this->file) . ':' . $this->line;
        }
    }

    public function hasFailed()
    {
        return $this->failed;
    }

    public function getArguments()
    {
        return $this->arguments;
    }

    public function getArgumentsAsString($maxLength = self::DEFAULT_MAX_LENGTH)
    {
        $arguments = $this->arguments;

        $argumentCount = count($arguments);
        $totalLength = $argumentCount - 1; // count separators before adding length of individual arguments

        foreach ($arguments as $key => $argument) {
            $stringifiedArgument = $this->stringifyArgument($argument);
            $arguments[$key] = $stringifiedArgument;
            $totalLength += mb_strlen($stringifiedArgument, 'utf-8');
        }

        if ($totalLength > $maxLength && $maxLength > 0) {
            //sort arguments from shortest to longest
            uasort($arguments, function ($arg1, $arg2) {
                $length1 = mb_strlen($arg1, 'utf-8');
                $length2 = mb_strlen($arg2, 'utf-8');
                if ($length1 === $length2) {
                    return 0;
                }
                return ($length1 < $length2) ? -1 : 1;
            });

            $allowedLength = floor(($maxLength - $argumentCount + 1) / $argumentCount);

            $lengthRemaining = $maxLength;
            $argumentsRemaining = $argumentCount;
            foreach ($arguments as $key => $argument) {
                $argumentsRemaining--;
                if (mb_strlen($argument, 'utf-8') > $allowedLength) {
                    $arguments[$key] = mb_substr($argument, 0, $allowedLength - 4, 'utf-8') . '...' . mb_substr($argument, -1, 1, 'utf-8');
                    $lengthRemaining -= ($allowedLength + 1);
                } else {
                    $lengthRemaining -= (mb_strlen($arguments[$key], 'utf-8') + 1);
                    //recalculate allowed length because this argument was short
                    if ($argumentsRemaining > 0) {
                        $allowedLength = floor(($lengthRemaining - $argumentsRemaining + 1) / $argumentsRemaining);
                    }
                }
            }

            //restore original order of arguments
            ksort($arguments);
        }

        return implode(',', $arguments);
    }

    protected function stringifyArgument($argument)
    {
        if (is_string($argument)) {
            return '"' . strtr($argument, ["\n" => '\n', "\r" => '\r', "\t" => ' ']) . '"';
        } elseif (is_resource($argument)) {
            $argument = (string)$argument;
        } elseif (is_array($argument)) {
            foreach ($argument as $key => $value) {
                if (is_object($value)) {
                    $argument[$key] = $this->getClassName($value);
                }
            }
        } elseif (is_object($argument)) {
            if ($argument instanceof FormattedOutput) {
                $argument = $argument->getOutput();
            } elseif (method_exists($argument, '__toString')) {
                $argument = (string)$argument;
            } elseif (get_class($argument) == 'Facebook\WebDriver\WebDriverBy') {
                $argument = Locator::humanReadableString($argument);
            } else {
                $argument = $this->getClassName($argument);
            }
        }
        $arg_str = json_encode($argument, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        $arg_str = str_replace('\"', '"', $arg_str);
        return $arg_str;
    }

    protected function getClassName($argument)
    {
        if ($argument instanceof \Closure) {
            return 'Closure';
        } elseif ($argument instanceof MockObject && isset($argument->__mocked)) {
            return $this->formatClassName($argument->__mocked);
        }

        return $this->formatClassName(get_class($argument));
    }

    protected function formatClassName($classname)
    {
        return trim($classname, "\\");
    }

    public function getPhpCode($maxLength)
    {
        $result = "\${$this->prefix}->" . $this->getAction() . '(';
        $maxLength = $maxLength - mb_strlen($result, 'utf-8') - 1;

        $result .= $this->getHumanizedArguments($maxLength) .')';
        return $result;
    }

    /**
     * @return MetaStep
     */
    public function getMetaStep()
    {
        return $this->metaStep;
    }

    public function __toString()
    {
        $humanizedAction = $this->humanize($this->getAction());
        return $humanizedAction . ' ' . $this->getHumanizedArguments();
    }


    public function toString($maxLength)
    {
        $humanizedAction = $this->humanize($this->getAction());
        $maxLength = $maxLength - mb_strlen($humanizedAction, 'utf-8') - 1;
        return $humanizedAction . ' ' . $this->getHumanizedArguments($maxLength);
    }

    public function getHtml($highlightColor = '#732E81')
    {
        if (empty($this->arguments)) {
            return sprintf('%s %s', ucfirst($this->prefix), $this->humanize($this->getAction()));
        }

        return sprintf('%s %s <span style="color: %s">%s</span>', ucfirst($this->prefix), htmlspecialchars($this->humanize($this->getAction()), ENT_QUOTES | ENT_SUBSTITUTE), $highlightColor, htmlspecialchars($this->getHumanizedArguments(0), ENT_QUOTES | ENT_SUBSTITUTE));
    }

    public function getHumanizedActionWithoutArguments()
    {
        return $this->humanize($this->getAction());
    }

    public function getHumanizedArguments($maxLength = self::DEFAULT_MAX_LENGTH)
    {
        return $this->getArgumentsAsString($maxLength);
    }

    protected function clean($text)
    {
        return str_replace('\/', '', $text);
    }

    protected function humanize($text)
    {
        $text = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\\1 \\2', $text);
        $text = preg_replace('/([a-z\d])([A-Z])/', '\\1 \\2', $text);
        $text = preg_replace('~\bdont\b~', 'don\'t', $text);
        return mb_strtolower($text, 'UTF-8');
    }

    public function run(ModuleContainer $container = null)
    {
        $this->executed = true;
        if (!$container) {
            return null;
        }
        $activeModule = $container->moduleForAction($this->action);

        if (!is_callable([$activeModule, $this->action])) {
            throw new \RuntimeException("Action '{$this->action}' can't be called");
        }

        try {
            $res = call_user_func_array([$activeModule, $this->action], $this->arguments);
        } catch (\Exception $e) {
            if ($this->isTry) {
                throw $e;
            }
            $this->failed = true;
            if ($this->getMetaStep()) {
                $this->getMetaStep()->setFailed(true);
            }
            throw $e;
        }
        return $res;
    }

    /**
     * If steps are combined into one method they can be reproduced as meta-step.
     * We are using stack trace to analyze if steps were called from test, if not - they were called from meta-step.
     *
     * @param $step
     * @param $stack
     */
    protected function addMetaStep($step, $stack)
    {
        if (($this->isTestFile($this->file)) || ($step['class'] == 'Codeception\Scenario')) {
            return;
        }

        $i = count($stack) - self::STACK_POSITION - 1;

        // get into test file and retrieve its actual call
        while (isset($stack[$i])) {
            $step = $stack[$i];
            $i--;
            if (!isset($step['file']) or !isset($step['function']) or !isset($step['class'])) {
                continue;
            }

            if (!$this->isTestFile($step['file'])) {
                continue;
            }

            // in case arguments were passed by reference, copy args array to ensure dereference.  array_values() does not dereference values
            $this->metaStep = new Step\Meta($step['function'], array_map(function ($i) {
                return $i;
            }, array_values($step['args'])));
            $this->metaStep->setTraceInfo($step['file'], $step['line']);

            // pageobjects or other classes should not be included with "I"
            if (!in_array('Codeception\Actor', class_parents($step['class']))) {
                if (isset($step['object'])) {
                    $this->metaStep->setPrefix(get_class($step['object']) . ':');
                    return;
                }

                $this->metaStep->setPrefix($step['class'] . ':');
            }
            return;
        }
    }

    /**
     * @param MetaStep $metaStep
     */
    public function setMetaStep($metaStep)
    {
        $this->metaStep = $metaStep;
    }

    /**
     * @return string
     */
    public function getPrefix()
    {
        return $this->prefix . ' ';
    }
}
<?php
namespace Codeception;

use Codeception\Event\DispatcherWrapper;
use Codeception\Lib\Di;
use Codeception\Lib\GroupManager;
use Codeception\Lib\ModuleContainer;
use Codeception\Lib\Notification;
use Codeception\Test\Interfaces\ScenarioDriven;
use Codeception\Test\Loader;
use Codeception\Test\Descriptor;
use Symfony\Component\EventDispatcher\EventDispatcher;

class SuiteManager
{
    use DispatcherWrapper;

    public static $environment;
    public static $name;

    /**
     * @var \PHPUnit\Framework\TestSuite
     */
    protected $suite = null;

    /**
     * @var null|\Symfony\Component\EventDispatcher\EventDispatcher
     */
    protected $dispatcher = null;

    /**
     * @var GroupManager
     */
    protected $groupManager;

    /**
     * @var Loader
     */
    protected $testLoader;

    /**
     * @var ModuleContainer
     */
    protected $moduleContainer;

    /**
     * @var Di
     */
    protected $di;

    protected $tests = [];
    protected $debug = false;
    protected $path = '';
    protected $printer = null;

    protected $env = null;
    protected $settings;

    public function __construct(EventDispatcher $dispatcher, $name, array $settings)
    {
        $this->settings = $settings;
        $this->dispatcher = $dispatcher;
        $this->di = new Di();
        $this->path = $settings['path'];
        $this->groupManager = new GroupManager($settings['groups']);
        $this->moduleContainer = new ModuleContainer($this->di, $settings);

        $modules = Configuration::modules($this->settings);
        foreach ($modules as $moduleName) {
            $this->moduleContainer->create($moduleName);
        }
        $this->moduleContainer->validateConflicts();
        if (isset($settings['current_environment'])) {
            $this->env = $settings['current_environment'];
        }
        $this->suite = $this->createSuite($name);
    }

    public function initialize()
    {
        $this->dispatch($this->dispatcher, Events::MODULE_INIT, new Event\SuiteEvent($this->suite, null, $this->settings));
        foreach ($this->moduleContainer->all() as $module) {
            $module->_initialize();
        }
        if ($this->settings['actor'] && !file_exists(Configuration::supportDir() . $this->settings['actor'] . '.php')) {
            throw new Exception\ConfigurationException(
                $this->settings['actor']
                . " class doesn't exist in suite folder.\nRun the 'build' command to generate it"
            );
        }
        $this->dispatch($this->dispatcher, Events::SUITE_INIT, new Event\SuiteEvent($this->suite, null, $this->settings));
        ini_set('xdebug.show_exception_trace', 0); // Issue https://github.com/symfony/symfony/issues/7646
    }

    public function loadTests($path = null)
    {
        $testLoader = new Loader($this->settings);
        $testLoader->loadTests($path);

        $tests = $testLoader->getTests();
        if ($this->settings['shuffle']) {
            shuffle($tests);
        }
        foreach ($tests as $test) {
            $this->addToSuite($test);
        }
        $this->suite->reorderDependencies();
    }

    protected function addToSuite($test)
    {
        $this->configureTest($test);

        if ($test instanceof \PHPUnit\Framework\DataProviderTestSuite) {
            foreach ($test->tests() as $t) {
                $this->addToSuite($t);
            }
            return;
        }
        if ($test instanceof TestInterface) {
            $this->checkEnvironmentExists($test);
            if (!$this->isExecutedInCurrentEnvironment($test)) {
                return; // skip tests from other environments
            }
        }

        $groups = $this->groupManager->groupsForTest($test);

        $this->suite->addTest($test, $groups);

        if (!empty($groups) && $test instanceof TestInterface) {
            $test->getMetadata()->setGroups($groups);
        }
    }

    protected function createSuite($name)
    {
        $suite = new Suite();
        $suite->setBaseName(preg_replace('~\s.+$~', '', $name)); // replace everything after space (env name)
        if ($this->settings['namespace']) {
            $name = $this->settings['namespace'] . ".$name";
        }
        $suite->setName($name);
        if (isset($this->settings['backup_globals'])) {
            $suite->setBackupGlobals((bool) $this->settings['backup_globals']);
        }

        if (isset($this->settings['be_strict_about_changes_to_global_state']) && method_exists($suite, 'setbeStrictAboutChangesToGlobalState')) {
            $suite->setbeStrictAboutChangesToGlobalState((bool)$this->settings['be_strict_about_changes_to_global_state']);
        }
        $suite->setModules($this->moduleContainer->all());
        return $suite;
    }


    public function run(PHPUnit\Runner $runner, \PHPUnit\Framework\TestResult $result, $options)
    {
        $runner->prepareSuite($this->suite, $options);
        $this->dispatch($this->dispatcher, Events::SUITE_BEFORE, new Event\SuiteEvent($this->suite, $result, $this->settings));
        try {
            $runner->doEnhancedRun($this->suite, $result, $options);
        } finally {
            $this->dispatch($this->dispatcher, Events::SUITE_AFTER, new Event\SuiteEvent($this->suite, $result, $this->settings));
        }
    }

    /**
     * @return \Codeception\Suite
     */
    public function getSuite()
    {
        return $this->suite;
    }

    /**
     * @return ModuleContainer
     */
    public function getModuleContainer()
    {
        return $this->moduleContainer;
    }

    protected function getActor()
    {
        if (!$this->settings['actor']) {
            return null;
        }
        return $this->settings['namespace']
            ? rtrim($this->settings['namespace'], '\\') . '\\' . $this->settings['actor']
            : $this->settings['actor'];
    }

    protected function checkEnvironmentExists(TestInterface $test)
    {
        $envs = $test->getMetadata()->getEnv();
        if (empty($envs)) {
            return;
        }
        if (!isset($this->settings['env'])) {
            Notification::warning("Environments are not configured", Descriptor::getTestFullName($test));
            return;
        }
        $availableEnvironments = array_keys($this->settings['env']);
        $listedEnvironments = explode(',', implode(',', $envs));
        foreach ($listedEnvironments as $env) {
            if (!in_array($env, $availableEnvironments)) {
                Notification::warning("Environment $env was not configured but used in test", Descriptor::getTestFullName($test));
            }
        }
    }

    protected function isExecutedInCurrentEnvironment(TestInterface $test)
    {
        $envs = $test->getMetadata()->getEnv();
        if (empty($envs)) {
            return true;
        }
        $currentEnvironments = $this->env === null ? [] : explode(',', $this->env);
        foreach ($envs as $envList) {
            $envList = explode(',', $envList);
            if (count($envList) == count(array_intersect($currentEnvironments, $envList))) {
                return true;
            }
        }
        return false;
    }

    /**
     * @param $t
     * @throws Exception\InjectionException
     */
    protected function configureTest($t)
    {
        if (!$t instanceof TestInterface) {
            return;
        }
        $t->getMetadata()->setServices([
            'di' => clone($this->di),
            'dispatcher' => $this->dispatcher,
            'modules' => $this->moduleContainer
        ]);
        $t->getMetadata()->setCurrent([
            'actor' => $this->getActor(),
            'env' => $this->env,
            'modules' => $this->moduleContainer->all()
        ]);
        if ($t instanceof ScenarioDriven) {
            $t->preload();
        }
    }
}
<?php

namespace Codeception\Template;

use Codeception\InitTemplate;
use Codeception\Util\Template;
use Symfony\Component\Yaml\Yaml;

class Acceptance extends InitTemplate
{
    protected $configTemplate = <<<EOF
# suite config
suites:
    acceptance:
        actor: AcceptanceTester
        path: .
        modules:
            enabled:
                - WebDriver:
                    url: {{url}}
                    browser: {{browser}}
                - \Helper\Acceptance
                
        # add Codeception\Step\Retry trait to AcceptanceTester to enable retries
        step_decorators:
            - Codeception\Step\ConditionalAssertion
            - Codeception\Step\TryTo
            - Codeception\Step\Retry
                
extensions:
    enabled: [Codeception\Extension\RunFailed]

params: 
    - env

gherkin: []    

# additional paths
paths:
    tests: {{baseDir}}
    output: {{baseDir}}/_output
    data: {{baseDir}}/_data
    support: {{baseDir}}/_support
    envs: {{baseDir}}/_envs

settings:
    shuffle: false
    lint: true
EOF;

    protected $firstTest = <<<EOF
<?php
class LoginCest 
{    
    public function _before(AcceptanceTester \$I)
    {
        \$I->amOnPage('/');
    }

    public function loginSuccessfully(AcceptanceTester \$I)
    {
        // write a positive login test 
    }
    
    public function loginWithInvalidPassword(AcceptanceTester \$I)
    {
        // write a negative login test
    }       
}
EOF;


    public function setup()
    {
        $this->checkInstalled();
        $this->say("Let's prepare Codeception for acceptance testing");
        $this->say("Create your tests and run them in real browser");
        $this->say("");

        $dir = $this->ask("Where tests will be stored?", 'tests');

        $browser = $this->ask("Select a browser for testing", ['chrome', 'firefox']);
        if ($browser === 'chrome') {
            $this->sayInfo("Ensure that you have Selenium Server and ChromeDriver installed before running tests");
        }
        if ($browser === 'firefox') {
            $this->sayInfo("Ensure that you have Selenium Server and GeckoDriver installed before running tests");
        }
        $url = $this->ask("Start url for tests", "http://localhost");

        $this->createEmptyDirectory($outputDir = $dir . DIRECTORY_SEPARATOR . '_output');
        $this->createEmptyDirectory($dir . DIRECTORY_SEPARATOR . '_data');
        $this->createDirectoryFor($supportDir = $dir . DIRECTORY_SEPARATOR . '_support');
        $this->createDirectoryFor($supportDir . DIRECTORY_SEPARATOR . '_generated');
        $this->gitIgnore($outputDir);
        $this->gitIgnore($supportDir . DIRECTORY_SEPARATOR . '_generated');
        $this->sayInfo("Created test directories inside at $dir");

        if (!class_exists('\\Codeception\\Module\\WebDriver')) {
            // composer version
            $this->addModulesToComposer(['WebDriver']);
        }

        $configFile = (new Template($this->configTemplate))
            ->place('url', $url)
            ->place('browser', $browser)
            ->place('baseDir', $dir)
            ->produce();

        if ($this->namespace) {
            $namespace = rtrim($this->namespace, '\\');
            $configFile = "namespace: $namespace\n" . $configFile;
        }

        $this->createFile('codeception.yml', $configFile);
        $this->createHelper('Acceptance', $supportDir);
        $this->createActor('AcceptanceTester', $supportDir, Yaml::parse($configFile)['suites']['acceptance']);

        $this->sayInfo("Created global config codeception.yml inside the root directory");
        $this->createFile($dir . DIRECTORY_SEPARATOR . 'LoginCest.php', $this->firstTest);
        $this->sayInfo("Created a demo test LoginCest.php");

        $this->say();
        $this->saySuccess("INSTALLATION COMPLETE");

        $this->say();
        $this->say("<bold>Next steps:</bold>");
        $this->say('1. Launch Selenium Server and webserver');
        $this->say("2. Edit <bold>$dir/LoginCest.php</bold> to test login of your application");
        $this->say("3. Run tests using: <comment>codecept run</comment>");
        $this->say();
        $this->say("HINT: Add '\\Codeception\\Step\\Retry' trait to AcceptanceTester class to enable auto-retries");
        $this->say("HINT: See https://codeception.com/docs/03-AcceptanceTests#retry");
        $this->say("<bold>Happy testing!</bold>");
    }
}
<?php

namespace Codeception\Template;

use Codeception\InitTemplate;
use Symfony\Component\Yaml\Yaml;

class Bootstrap extends InitTemplate
{
    // defaults
    protected $supportDir = 'tests/_support';
    protected $outputDir = 'tests/_output';
    protected $dataDir = 'tests/_data';
    protected $envsDir = 'tests/_envs';

    public function setup()
    {
        $this->checkInstalled($this->workDir);

        $input = $this->input;
        if ($input->getOption('namespace')) {
            $this->namespace = trim($input->getOption('namespace'), '\\') . '\\';
        }

        if ($input->hasOption('actor') && $input->getOption('actor')) {
            $this->actorSuffix = $input->getOption('actor');
        }

        $this->say(
            "<fg=white;bg=magenta> Bootstrapping Codeception </fg=white;bg=magenta>\n"
        );

        $this->createGlobalConfig();
        $this->say("File codeception.yml created       <- global configuration");

        $this->createDirs();

        if ($input->hasOption('empty') && $input->getOption('empty')) {
            return;
        }

        if (!class_exists('\\Codeception\\Module\\Asserts') || !class_exists('\\Codeception\\Module\\PhpBrowser')) {
            $this->addModulesToComposer(['PhpBrowser', 'Asserts']);
        }

        $this->createUnitSuite();
        $this->createFunctionalSuite();
        $this->createAcceptanceSuite();

        $this->say(" --- ");
        $this->say();
        $this->saySuccess('Codeception is installed for acceptance, functional, and unit testing');
        $this->say();

        $this->say("<bold>Next steps:</bold>");
        $this->say('1. Edit <bold>tests/acceptance.suite.yml</bold> to set url of your application. Change PhpBrowser to WebDriver to enable browser testing');
        $this->say("2. Edit <bold>tests/functional.suite.yml</bold> to enable a framework module. Remove this file if you don't use a framework");
        $this->say("3. Create your first acceptance tests using <comment>codecept g:cest acceptance First</comment>");
        $this->say("4. Write first test in <bold>tests/acceptance/FirstCest.php</bold>");
        $this->say("5. Run tests using: <comment>codecept run</comment>");
    }

    protected function createDirs()
    {
         $this->createDirectoryFor('tests');
         $this->createEmptyDirectory($this->outputDir);
         $this->createEmptyDirectory($this->dataDir);
         $this->createDirectoryFor($this->supportDir . DIRECTORY_SEPARATOR . '_generated');
         $this->createDirectoryFor($this->supportDir . DIRECTORY_SEPARATOR . "Helper");
         $this->gitIgnore('tests/_output');
         $this->gitIgnore('tests/_support/_generated');
    }

    protected function createFunctionalSuite($actor = 'Functional')
    {
        $suiteConfig = <<<EOF
# Codeception Test Suite Configuration
#
# Suite for functional tests
# Emulate web requests and make application process them
# Include one of framework modules (Symfony2, Yii2, Laravel5, Phalcon4) to use it
# Remove this suite if you don't use frameworks

actor: $actor{$this->actorSuffix}
modules:
    enabled:
        # add a framework module here
        - \\{$this->namespace}Helper\Functional
    step_decorators: ~        
EOF;
        $this->createSuite('functional', $actor, $suiteConfig);
        $this->say("tests/functional created           <- functional tests");
        $this->say("tests/functional.suite.yml written <- functional tests suite configuration");
    }

    protected function createAcceptanceSuite($actor = 'Acceptance')
    {
        $suiteConfig = <<<EOF
# Codeception Test Suite Configuration
#
# Suite for acceptance tests.
# Perform tests in browser using the WebDriver or PhpBrowser.
# If you need both WebDriver and PHPBrowser tests - create a separate suite.

actor: $actor{$this->actorSuffix}
modules:
    enabled:
        - PhpBrowser:
            url: http://localhost/myapp
        - \\{$this->namespace}Helper\Acceptance
step_decorators: ~        
EOF;
        $this->createSuite('acceptance', $actor, $suiteConfig);
        $this->say("tests/acceptance created           <- acceptance tests");
        $this->say("tests/acceptance.suite.yml written <- acceptance tests suite configuration");
    }

    protected function createUnitSuite($actor = 'Unit')
    {
        $suiteConfig = <<<EOF
# Codeception Test Suite Configuration
#
# Suite for unit or integration tests.

actor: $actor{$this->actorSuffix}
modules:
    enabled:
        - Asserts
        - \\{$this->namespace}Helper\Unit
    step_decorators: ~        
EOF;
        $this->createSuite('unit', $actor, $suiteConfig);
        $this->say("tests/unit created                 <- unit tests");
        $this->say("tests/unit.suite.yml written       <- unit tests suite configuration");
    }

    public function createGlobalConfig()
    {
        $basicConfig = [
            'paths'    => [
                'tests'   => 'tests',
                'output'  => $this->outputDir,
                'data'    => $this->dataDir,
                'support' => $this->supportDir,
                'envs'    => $this->envsDir,
            ],
            'actor_suffix' => 'Tester',
            'extensions' => [
                'enabled' => ['Codeception\Extension\RunFailed']
            ]
        ];

        $str = Yaml::dump($basicConfig, 4);
        if ($this->namespace) {
            $namespace = rtrim($this->namespace, '\\');
            $str = "namespace: $namespace\n" . $str;
        }
        $this->createFile('codeception.yml', $str);
    }


    protected function createSuite($suite, $actor, $config)
    {
        $this->createDirectoryFor("tests/$suite", "$suite.suite.yml");
        $this->createHelper($actor, $this->supportDir);
        $this->createActor($actor . $this->actorSuffix, $this->supportDir, Yaml::parse($config));
        $this->createFile('tests' . DIRECTORY_SEPARATOR . "$suite.suite.yml", $config);
    }
}
<?php
namespace Codeception\Template;

use Codeception\Configuration;
use Codeception\InitTemplate;

class Upgrade4 extends InitTemplate
{
    const SURVEY_LINK = 'http://bit.ly/codecept-survey';
    const DONATE_LINK = 'https://opencollective.com/codeception';

    public function setup()
    {
        if (!$this->isInstalled()) {
            $this->sayWarning('Codeception is not installed in this dir.');
            return;
        }
        $this->sayInfo('Welcome to Codeception v4 Upgrade wizard!');
        $this->say('');
        $this->say('Codeception is maintained since 2011, is free & open-source.');
        $this->say('To make it better we need your feedback on it!');
        $this->say('');
        $this->say('Please take a minute and fill in a brief survey:');
        $this->say('<bold>'  . self::SURVEY_LINK . '</bold>');
        sleep(5);
        $this->say('');
        $result = $this->ask('<question>Did you fill in the survey?</question>', true);
        if ($result) {
            $this->say('Thank you! ');
        } else {
            $this->say('Anyway...');
        }
        $config = Configuration::config();
        $modules = [];
        $suites = Configuration::suites();
        if (empty($suites)) {
            $this->sayError("No suites found in current config.");
            $this->sayWarning('If you use sub-configs with `include` option, run this script on subconfigs:');
            $this->sayWarning('Example: php vendor/bin/codecept init upgrade4 -c backend/');
            throw new \Exception("No suites found, can't upgrade");
        }
        foreach (Configuration::suites() as $suite) {
            $suiteConfig = Configuration::suiteSettings($suite, $config);
            $modules = array_merge($modules, Configuration::modules($suiteConfig));
        }

        $numPackages = $this->addModulesToComposer($modules);

        if ($numPackages === 0) {
            $this->sayWarning("No upgrade needed! Everything is fine already");
            return;
        }

        $this->saySuccess("Done upgrading!");
        $this->say('');

        $this->say('Please consider donating to Codeception on regular basis:');
        $this->say('');
        $this->say('<bold>' . self::DONATE_LINK . '</bold>');
        $this->say('');
        $this->say('It\'s ok to pay for reliable software.');
        $this->say('Talk to your manager & support further development of Codeception!');
    }

    private function isInstalled()
    {
        try {
            $this->checkInstalled();
        } catch (\Exception $e) {
            return true;
        }
        return false;
    }
}
<?php

namespace Codeception\Template;

use Codeception\InitTemplate;
use Codeception\Util\Template;
use Symfony\Component\Yaml\Yaml;

class Api extends InitTemplate
{
    protected $configTemplate = <<<EOF
# suite config
suites:
    api:
        actor: ApiTester
        path: .
        modules:
            enabled:
                - REST:
                    url: {{url}}
                    depends: PhpBrowser
        step_decorators:
            - \Codeception\Step\AsJson

paths:
    tests: {{baseDir}}
    output: {{baseDir}}/_output
    data: {{baseDir}}/_data
    support: {{baseDir}}/_support

settings:
    shuffle: false
    lint: true
EOF;

    protected $firstTest = <<<EOF
<?php
class ApiCest 
{    
    public function tryApi(ApiTester \$I)
    {
        \$I->sendGet('/');
        \$I->seeResponseCodeIs(200);
        \$I->seeResponseIsJson();
    }
}
EOF;


    public function setup()
    {
        $this->checkInstalled();
        $this->say("Let's prepare Codeception for REST API testing");
        $this->say("");

        $dir = $this->ask("Where tests will be stored?", 'tests');

        $url = $this->ask("Start url for tests", "http://localhost/api");

        if (!class_exists('\\Codeception\\Module\\REST') || !class_exists('\\Codeception\\Module\\PhpBrowser')) {
            $this->addModulesToComposer(['REST', 'PhpBrowser']);
        }

        $this->createEmptyDirectory($outputDir = $dir . DIRECTORY_SEPARATOR . '_output');
        $this->createEmptyDirectory($dir . DIRECTORY_SEPARATOR . '_data');
        $this->createDirectoryFor($supportDir = $dir . DIRECTORY_SEPARATOR . '_support');
        $this->createDirectoryFor($supportDir . DIRECTORY_SEPARATOR . '_generated');
        $this->gitIgnore($outputDir);
        $this->gitIgnore($supportDir . DIRECTORY_SEPARATOR . '_generated');
        $this->sayInfo("Created test directories inside at $dir");

        $configFile = (new Template($this->configTemplate))
            ->place('url', $url)
            ->place('baseDir', $dir)
            ->produce();

        if ($this->namespace) {
            $namespace = rtrim($this->namespace, '\\');
            $configFile = "namespace: $namespace\n" . $configFile;
        }

        $this->createFile('codeception.yml', $configFile);
        $this->createHelper('Api', $supportDir);
        $this->createActor('ApiTester', $supportDir, Yaml::parse($configFile)['suites']['api']);


        $this->sayInfo("Created global config codeception.yml inside the root directory");
        $this->createFile($dir . DIRECTORY_SEPARATOR . 'ApiCest.php', $this->firstTest);
        $this->sayInfo("Created a demo test ApiCest.php");


        $this->say();
        $this->saySuccess("INSTALLATION COMPLETE");

        $this->say();
        $this->say("<bold>Next steps:</bold>");
        $this->say("1. Edit <bold>$dir/ApiCest.php</bold> to write first API tests");
        $this->say("2. Run tests using: <comment>codecept run</comment>");
        $this->say();
        $this->say("<bold>Happy testing!</bold>");
    }
}
<?php

namespace Codeception\Template;

use Codeception\InitTemplate;
use Codeception\Util\Template;
use Symfony\Component\Yaml\Yaml;

class Unit extends InitTemplate
{
    protected $configTemplate = <<<EOF
suites:
    unit:
        path: .
{{tester}}
settings:
    shuffle: true
    lint: true
paths:
    tests: {{dir}}
    output: {{dir}}/_output
    support: {{dir}}/_support
    data: {{dir}}
     
EOF;

    protected $testerAndModules = <<<EOF
        actor: UnitTester
        modules:
            enabled:
                # add more modules here
                - Asserts
        step_decorators: ~ 
EOF;


    public function setup()
    {
        $this->sayInfo('This will install Codeception for unit testing only');
        $this->say();
        $dir = $this->ask("Where tests will be stored?", 'tests');

        if (!$this->namespace) {
            $this->namespace = $this->ask("Enter a default namespace for tests (or skip this step)");
        }

        $this->say();
        $this->say("Codeception provides additional features for integration tests");
        $this->say("Like accessing frameworks, ORM, Database.");
        $haveTester = $this->ask("Do you wish to enable them?", false);

        $this->createEmptyDirectory($outputDir = $dir . DIRECTORY_SEPARATOR . '_output');
        $this->createEmptyDirectory($supportDir = $dir . DIRECTORY_SEPARATOR . '_support');

        $configFile = (new Template($this->configTemplate))
            ->place('dir', $dir)
            ->place('tester', $haveTester ? $this->testerAndModules : '')
            ->produce();

        if ($this->namespace) {
            $namespace = rtrim($this->namespace, '\\');
            $configFile = "namespace: $namespace\n" . $configFile;
        }

        $this->createFile('codeception.yml', $configFile);

        if (!class_exists('\\Codeception\\Module\\Asserts')) {
            $this->addModulesToComposer(['Asserts']);
        }

        if ($haveTester) {
            $this->createHelper('Unit', $supportDir);
            $this->createActor('UnitTester', $supportDir, Yaml::parse($configFile)['suites']['unit']);
        }

        $this->gitIgnore($outputDir);
        $this->sayInfo("Created test directory inside at $dir");

        $this->say();
        $this->saySuccess("INSTALLATION COMPLETE");
        $this->say();
        $this->say('Unit tests will be executed in random order');
        $this->say('Use @depends annotation to change the order of tests');

        if ($haveTester) {
            $this->say('To access DI, ORM, Database enable corresponding modules in codeception.yml');
            $this->say('Use <bold>$this->tester</bold> object inside Codeception\Test\Unit to call their methods');
            $this->say("For example: \$this->tester->seeInDatabase('users', ['name' => 'davert'])");
        }

        $this->say();
        $this->say("<bold>Next steps:</bold>");
        $this->say("Create the first test using <comment>codecept g:test unit MyTest</comment>");
        $this->say("Run tests with <comment>codecept run</comment>");
        $this->say("<bold>Happy testing!</bold>");
    }
}
<?php

namespace Codeception;

use Codeception\Exception\ContentNotFound;
use Codeception\Util\Debug;
use Codeception\Util\Shared\Asserts;
use PHPUnit\Framework\AssertionFailedError;

abstract class Snapshot
{
    use Asserts;

    protected $fileName;

    protected $dataSet;

    protected $refresh;

    protected $showDiff = false;

    protected $saveAsJson = true;

    protected $extension = 'json';

    /**
     * Should return data from current test run
     *
     * @return mixed
     */
    abstract protected function fetchData();

    /**
     * Performs assertion on saved data set against current dataset.
     * Can be overridden to implement custom assertion
     *
     * @param $data
     */
    protected function assertData($data)
    {
        $this->assertEquals($this->dataSet, $data, 'Snapshot doesn\'t match real data');
    }

    /**
     * Loads data set from file.
     */
    protected function load()
    {
        if (!file_exists($this->getFileName())) {
            return;
        }
        $fileContents = file_get_contents($this->getFileName());
        if ($this->saveAsJson) {
            $fileContents = json_decode($fileContents);
        }
        $this->dataSet = $fileContents;
        if (!$this->dataSet) {
            throw new ContentNotFound("Loaded snapshot is empty");
        }
    }

    /**
     * Saves data set to file
     */
    protected function save()
    {
        $fileContents = $this->dataSet;
        if ($this->saveAsJson) {
            $fileContents = json_encode($fileContents);
        }
        file_put_contents($this->getFileName(), $fileContents);
    }

    /**
     * If no filename is defined, generates one from class name
     *
     * @return string
     */
    protected function getFileName()
    {
        if (!$this->fileName) {
            $this->fileName = preg_replace('/\W/', '.', get_class($this)) . '.' . $this->extension;
        }
        return codecept_data_dir() . $this->fileName;
    }

    /**
     * Performs assertion for data sets
     */
    public function assert()
    {
        // fetch data
        $data = $this->fetchData();
        if (!$data) {
            throw new ContentNotFound("Fetched snapshot is empty.");
        }

        $this->load();

        if (!$this->dataSet) {
            $this->printDebug('Snapshot is empty. Updating snapshot...');
            $this->dataSet = $data;
            $this->save();
            return;
        }

        try {
            $this->assertData($data);
            $this->printDebug('Data matches snapshot');
        } catch (AssertionFailedError $exception) {
            $this->printDebug('Snapshot assertion failed');

            if (!is_bool($this->refresh)) {
                $confirm = Debug::confirm('Should we update snapshot with fresh data? (Y/n) ');
            } else {
                $confirm = $this->refresh;
            }

            if ($confirm) {
                $this->dataSet = $data;
                $this->save();
                $this->printDebug('Snapshot data updated');
                return;
            }

            if ($this->showDiff) {
                throw $exception;
            }

            $this->fail($exception->getMessage());
        }
    }

    /**
     * Force update snapshot data.
     *
     * @param bool $refresh
     */
    public function shouldRefreshSnapshot($refresh = true)
    {
        $this->refresh = $refresh;
    }

    /**
     * Show detailed diff if snapshot test fails
     *
     * @param bool $showDiff
     */
    public function shouldShowDiffOnFail($showDiff = true)
    {
        $this->showDiff = $showDiff;
    }

    /**
     * json_encode/json_decode the snapshot data on storing/reading.
     *
     * @param bool $saveAsJson
     */
    public function shouldSaveAsJson($saveAsJson = true)
    {
        $this->saveAsJson = $saveAsJson;
    }

    /**
     * Set the snapshot file extension.
     * By default it will be stored as `.json`.
     *
     * The file extension will not perform any formatting in the data,
     * it is only used as the snapshot file extension.
     *
     * @param string $fileExtension
     * @return void
     */
    public function setSnapshotFileExtension($fileExtension = 'json')
    {
        $this->extension = $fileExtension;
    }

    private function printDebug($message)
    {
        Debug::debug(get_class($this) . ': ' . $message);
    }
}
<?php
namespace Codeception\Exception;

class ModuleConfigException extends \Exception
{
    public function __construct($module, $message, \Exception $previous = null)
    {
        if (is_object($module)) {
            $module = get_class($module);
        }
        $module = str_replace('Codeception\Module\\', '', ltrim($module, '\\'));
        parent::__construct($message, 0, $previous);
        $this->message = $module . " module is not configured!\n \n" . $this->message;
    }
}
<?php
namespace Codeception\Exception;

class ParseException extends \Exception
{
}
<?php
namespace Codeception\Exception;

use Codeception\Util\Locator;

class ElementNotFound extends \PHPUnit\Framework\AssertionFailedError
{
    public function __construct($selector, $message = null)
    {
        if (!is_string($selector) || strpos($selector, "'") === false) {
            $selector = Locator::humanReadableString($selector);
        }
        parent::__construct($message . " element with $selector was not found.");
    }
}
<?php
namespace Codeception\Exception;

class RemoteException extends \Exception
{
    public function __construct($message)
    {
        parent::__construct($message);
        $this->message = "Remote Application Error:\n" . $this->message;
    }
}
<?php
namespace Codeception\Exception;

class TestRuntimeException extends \RuntimeException
{
}
<?php
namespace Codeception\Exception;

class ContentNotFound extends \PHPUnit\Framework\AssertionFailedError
{
}
<?php
namespace Codeception\Exception;

class ConfigurationException extends \Exception
{
}
<?php
namespace Codeception\Exception;

class TestParseException extends \Exception
{
    public function __construct($fileName, $errors = null, $line = null)
    {
        if ($line) {
            $this->message = "Couldn't parse test '$fileName' on line $line";
        } else {
            $this->message = "Couldn't parse test '$fileName'";
        }
        if ($errors) {
            $this->message .= "\n$errors";
        }
    }
}
<?php
namespace Codeception\Exception;

class ModuleRequireException extends \Exception
{
    public function __construct($module, $message)
    {
        if (is_object($module)) {
            $module = get_class($module);
        }
        $module = str_replace('Codeception\\Module\\', '', ltrim($module, '\\'));
        parent::__construct($message);
        $this->message = "[$module] module requirements not met --\n \n" . $this->message;
    }
}
<?php
namespace Codeception\Exception;

class ModuleException extends \Exception
{
    protected $module;

    public function __construct($module, $message)
    {
        if (is_object($module)) {
            $module = get_class($module);
        }
        $module = ltrim(str_replace('Codeception\Module\\', '', $module), '\\');
        $this->module = $module;
        parent::__construct($message);
        $this->message = "$module: {$this->message}";
    }
}
<?php
namespace Codeception\Exception;

class MalformedLocatorException extends TestRuntimeException
{
    public function __construct($locator, $type = "CSS or XPath")
    {
        parent::__construct(ucfirst($type) . " locator is malformed: $locator");
    }
}
<?php
namespace Codeception\Exception;

class ConditionalAssertionFailed extends \PHPUnit\Framework\AssertionFailedError
{
}
<?php
namespace Codeception\Exception;

class ModuleConflictException extends \Exception
{
    public function __construct($module, $conflicted, $additional = '')
    {
        if (is_object($module)) {
            $module = get_class($module);
        }
        if (is_object($conflicted)) {
            $conflicted = get_class($conflicted);
        }
        $module = ltrim(str_replace('Codeception\Module\\', '', $module), '\\');
        $conflicted = ltrim(str_replace('Codeception\Module\\', '', $conflicted), '\\');
        $this->message = "$module module conflicts with $conflicted\n\n--\n"
            . "This usually happens when you enable two modules with the same actions but with different backends.\n"
            . "For instance, you can't run PhpBrowser, WebDriver, Laravel5 modules in one suite,\n"
            . "as they implement similar methods but use different drivers to execute them.\n"
            . "You can load a part of module (like: ORM) to avoid conflict.\n"
            . $additional;
    }
}
<?php
namespace Codeception\Exception;

class ExtensionException extends \Exception
{
    public function __construct($extension, $message, \Exception $previous = null)
    {
        parent::__construct($message, $previous);
        if (is_object($extension)) {
            $extension = get_class($extension);
        }
        $this->message = $extension . "\n\n" . $this->message;
    }
}
<?php
namespace Codeception\Exception;

class InjectionException extends \Exception
{
}
<?php

namespace Codeception;

use Codeception\Command\Shared\FileSystem;
use Codeception\Command\Shared\Style;
use Codeception\Lib\ModuleContainer;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;

/**
 * Codeception templates allow creating a customized setup and configuration for your project.
 * An abstract class for installation template. Each init template should extend it and implement a `setup` method.
 * Use it to build a custom setup class which can be started with `codecept init` command.
 *
 *
 * ```php
 * <?php
 * namespace Codeception\Template; // it is important to use this namespace so codecept init could locate this template
 * class CustomInstall extends \Codeception\InitTemplate
 * {
 *      public function setup()
 *      {
 *         // implement this
 *      }
 * }
 * ```
 * This class provides various helper methods for building customized setup
 */
abstract class InitTemplate
{
    use FileSystem;
    use Style;

    const GIT_IGNORE = '.gitignore';

    /**
     * @var string
     */
    protected $namespace = '';

    /**
     * @var string
     */
    protected $actorSuffix = 'Tester';

    /**
     * @var string
     */
    protected $workDir = '.';

    /**
     * @var InputInterface
     */
    protected $input;

    /**
     * @var OutputInterface
     */
    protected $output;

    public function __construct(InputInterface $input, OutputInterface $output)
    {
        $this->input = $input;
        $this->addStyles($output);
        $this->output = $output;
    }

    /**
     * Change the directory where Codeception should be installed.
     */
    public function initDir($workDir)
    {
        $this->checkInstalled($workDir);
        $this->sayInfo("Initializing Codeception in $workDir");
        $this->createDirectoryFor($workDir);
        chdir($workDir);
        $this->workDir = $workDir;
    }

    /**
     * Override this class to create customized setup.
     * @return mixed
     */
    abstract public function setup();

    /**
     * ```php
     * <?php
     * // propose firefox as default browser
     * $this->ask('select the browser of your choice', 'firefox');
     *
     * // propose firefox or chrome possible options
     * $this->ask('select the browser of your choice', ['firefox', 'chrome']);
     *
     * // ask true/false question
     * $this->ask('do you want to proceed (y/n)', true);
     * ```
     *
     * @param string $question
     * @param mixed $answer
     * @return mixed|string
     */
    protected function ask($question, $answer = null)
    {
        $question = "? $question";
        $dialog = new QuestionHelper();
        if (is_array($answer)) {
            $question .= " <info>(" . $answer[0] . ")</info> ";
            return $dialog->ask($this->input, $this->output, new ChoiceQuestion($question, $answer, 0));
        }
        if (is_bool($answer)) {
            $question .= " (y/n) ";
            return $dialog->ask($this->input, $this->output, new ConfirmationQuestion($question, $answer));
        }
        if ($answer) {
            $question .= " <info>($answer)</info>";
        }
        return $dialog->ask($this->input, $this->output, new Question("$question ", $answer));
    }

    /**
     * Print a message to console.
     *
     * ```php
     * <?php
     * $this->say('Welcome to Setup');
     * ```
     *
     *
     * @param string $message
     */
    protected function say($message = '')
    {
        $this->output->writeln($message);
    }

    /**
     * Print a successful message
     * @param string $message
     */
    protected function saySuccess($message)
    {
        $this->say("<notice> $message </notice>");
    }

    /**
     * Print error message
     * @param string $message
     */
    protected function sayError($message)
    {
        $this->say("<error> $message </error>");
    }

    /**
     * Print warning message
     * @param $message
     */
    protected function sayWarning($message)
    {
        $this->say("<warning> $message </warning>");
    }

    /**
     * Print info message
     * @param string $message
     */
    protected function sayInfo($message)
    {
        $this->say("<debug> $message</debug>");
    }

    /**
     * Create a helper class inside a directory
     *
     * @param $name
     * @param $directory
     */
    protected function createHelper($name, $directory)
    {
        $file = $this->createDirectoryFor(
            $dir = $directory . DIRECTORY_SEPARATOR . "Helper",
            "$name.php"
        ) . "$name.php";

        $gen = new Lib\Generator\Helper($name, $this->namespace);
        // generate helper
        $this->createFile(
            $file,
            $gen->produce()
        );
        require_once $file;
        $this->sayInfo("$name helper has been created in $dir");
    }

    /**
     * Create an empty directory and add a placeholder file into it
     * @param $dir
     */
    protected function createEmptyDirectory($dir)
    {
        $this->createDirectoryFor($dir);
        $this->createFile($dir . DIRECTORY_SEPARATOR . '.gitkeep', '');
    }

    protected function gitIgnore($path)
    {
        if (file_exists(self::GIT_IGNORE)) {
            file_put_contents($path . DIRECTORY_SEPARATOR . self::GIT_IGNORE, "*\n!" . self::GIT_IGNORE);
        }
    }

    protected function checkInstalled($dir = '.')
    {
        if (file_exists($dir . DIRECTORY_SEPARATOR . 'codeception.yml') || file_exists($dir . DIRECTORY_SEPARATOR . 'codeception.dist.yml')) {
            throw new \Exception("Codeception is already installed in this directory");
        }
    }

    /**
     * Create an Actor class and generate actions for it.
     * Requires a suite config as array in 3rd parameter.
     *
     * @param $name
     * @param $directory
     * @param $suiteConfig
     */
    protected function createActor($name, $directory, $suiteConfig)
    {
        $file = $this->createDirectoryFor(
            $directory,
            $name
        ) . $this->getShortClassName($name);
        $file .= '.php';

        $suiteConfig['namespace'] = $this->namespace;
        $config = Configuration::mergeConfigs(Configuration::$defaultSuiteSettings, $suiteConfig);

        $actorGenerator = new Lib\Generator\Actor($config);

        $content = $actorGenerator->produce();

        $this->createFile($file, $content);
        $this->sayInfo("$name actor has been created in $directory");

        $actionsGenerator = new Lib\Generator\Actions($config);
        $content = $actionsGenerator->produce();

        $generatedDir = $directory . DIRECTORY_SEPARATOR . '_generated';
        $this->createDirectoryFor($generatedDir, 'Actions.php');
        $this->createFile($generatedDir . DIRECTORY_SEPARATOR . $actorGenerator->getActorName() . 'Actions.php', $content);
        $this->sayInfo("Actions have been loaded");
    }

    protected function addModulesToComposer($modules)
    {
        $packages = ModuleContainer::$packages;
        $section = null;
        if (!file_exists('composer.json')) {
            $this->say('');
            $this->sayWarning('Can\'t locate composer.json, please add following packages into "require-dev" section of composer.json:');
            $this->say('');

            foreach (array_unique($modules) as $module) {
                if (!isset($packages[$module])) {
                    continue;
                }
                $package = $packages[$module];
                $this->say(sprintf('"%s": "%s"', $package, "^1.0.0"));
                $composer[$section][$package] = "^1.0.0";
            }
            $this->say('');
            return;
        }
        $composer = json_decode(file_get_contents('composer.json'), true);
        if ($composer === null) {
            throw new \Exception("Invalid composer.json file. JSON can't be decoded");
        }
        $section = null;
        if (isset($composer['require'])) {
            if (isset($composer['require']['codeception/codeception'])) {
                $section = 'require';
            }
        }
        if (isset($composer['require-dev'])) {
            if (isset($composer['require-dev']['codeception/codeception'])) {
                $section = 'require-dev';
            }
        }
        if (!$section) {
            $section = 'require';
        }

        $packageCounter = 0;
        foreach (array_unique($modules) as $module) {
            if (!isset($packages[$module])) {
                continue;
            }
            $package = $packages[$module];
            if (isset($composer[$section][$package])) {
                continue;
            }
            $this->sayInfo("Adding $package for $module to composer.json");
            $composer[$section][$package] = "^1.0.0";
            $packageCounter++;
        }

        file_put_contents('composer.json', json_encode($composer, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));

        if ($packageCounter) {
            $this->say("$packageCounter new packages added to $section");
        }

        if ($packageCounter && $this->ask('composer.json updated. Do you want to run "composer update"?', true)) {
            $this->sayInfo('Running composer update');
            exec('composer update', $output, $status);
            if ($status !== 0) {
                $this->sayInfo('Composer installation failed. Please check composer.json and try to run "composer update" manually');
                return;
            }
            if (!empty($composer['config']['vendor_dir'])) {
                $this->updateComposerClassMap($composer['config']['vendor_dir']);
            } else {
                $this->updateComposerClassMap();
            }
        }

        return $packageCounter;
    }

    private function updateComposerClassMap($vendorDir = 'vendor')
    {
        $loader = require $vendorDir . '/autoload.php';
        $classMap = require $vendorDir . '/composer/autoload_classmap.php';
        $loader->addClassMap($classMap);
        $map = require $vendorDir . '/composer/autoload_psr4.php';
        foreach ($map as $namespace => $path) {
            $loader->setPsr4($namespace, $path);
        }
    }
}
<?php
namespace Codeception\Subscriber;

use Codeception\Configuration;
use Codeception\Event\SuiteEvent;
use Codeception\Events;
use Codeception\Lib\Generator\Actions;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class AutoRebuild implements EventSubscriberInterface
{
    use Shared\StaticEvents;

    public static $events = [
        Events::SUITE_INIT => 'updateActor'
    ];

    public function updateActor(SuiteEvent $e)
    {
        $settings = $e->getSettings();
        if (!$settings['actor']) {
            codecept_debug('actor is empty');
            return; // no actor
        }

        $modules = $e->getSuite()->getModules();

        $actorActionsFile = Configuration::supportDir() . '_generated' . DIRECTORY_SEPARATOR
            . $settings['actor'] . 'Actions.php';

        if (!file_exists($actorActionsFile)) {
            codecept_debug("Generating {$settings['actor']}Actions...");
            $this->generateActorActions($actorActionsFile, $settings);
            return;
        }
        
        // load actor class to see hash
        $handle = @fopen($actorActionsFile, "r");
        if ($handle and is_writable($actorActionsFile)) {
            $line = @fgets($handle);
            if (preg_match('~\[STAMP\] ([a-f0-9]*)~', $line, $matches)) {
                $hash = $matches[1];
                $currentHash = Actions::genHash($modules, $settings);

                // regenerate actor class when hashes do not match
                if ($hash != $currentHash) {
                    codecept_debug("Rebuilding {$settings['actor']}...");
                    @fclose($handle);
                    $this->generateActorActions($actorActionsFile, $settings);
                    return;
                }
            }
            @fclose($handle);
        }
    }

    protected function generateActorActions($actorActionsFile, $settings)
    {
        if (!file_exists(Configuration::supportDir() . '_generated')) {
            @mkdir(Configuration::supportDir() . '_generated');
        }
        $actionsGenerator = new Actions($settings);
        $generated = $actionsGenerator->produce();
        @file_put_contents($actorActionsFile, $generated);
    }
}
<?php
namespace Codeception\Subscriber;

use Codeception\Configuration;
use Codeception\Event\SuiteEvent;
use Codeception\Events;
use Codeception\Exception\ConfigurationException;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ExtensionLoader implements EventSubscriberInterface
{
    use Shared\StaticEvents;

    public static $events = [
        Events::MODULE_INIT => 'registerSuiteExtensions',
        Events::SUITE_AFTER  => 'stopSuiteExtensions'
    ];

    protected $config;
    protected $options = [];

    protected $globalExtensions = [];
    protected $suiteExtensions = [];

    /**
     * @var EventDispatcher
     */
    protected $dispatcher;

    public function __construct(EventDispatcher $dispatcher)
    {
        $this->dispatcher = $dispatcher;
        $this->config = Configuration::config();
    }

    public function bootGlobalExtensions($options)
    {
        $this->options = $options;
        $this->globalExtensions = $this->bootExtensions($this->config);
    }

    public function registerGlobalExtensions()
    {
        foreach ($this->globalExtensions as $extension) {
            $this->dispatcher->addSubscriber($extension);
        }
    }

    public function registerSuiteExtensions(SuiteEvent $e)
    {
        $suiteConfig = $e->getSettings();
        $extensions = $this->bootExtensions($suiteConfig);

        $this->suiteExtensions = [];
        foreach ($extensions as $extension) {
            $extensionClass = get_class($extension);
            if (isset($this->globalExtensions[$extensionClass])) {
                continue; // already globally enabled
            }
            $this->dispatcher->addSubscriber($extension);
            $this->suiteExtensions[$extensionClass] = $extension;
        }
    }

    public function stopSuiteExtensions()
    {
        foreach ($this->suiteExtensions as $extension) {
            $this->dispatcher->removeSubscriber($extension);
        }
        $this->suiteExtensions = [];
    }

    protected function bootExtensions($config)
    {
        $extensions = [];

        foreach ($config['extensions']['enabled'] as $extensionClass) {
            if (is_array($extensionClass)) {
                $extensionClass = key($extensionClass);
            }
            if (!class_exists($extensionClass)) {
                throw new ConfigurationException(
                    "Class `$extensionClass` is not defined. Autoload it or include into "
                    . "'_bootstrap.php' file of 'tests' directory"
                );
            }
            $extensionConfig = $this->getExtensionConfig($extensionClass, $config);

            $extension = new $extensionClass($extensionConfig, $this->options);
            if (!$extension instanceof EventSubscriberInterface) {
                throw new ConfigurationException(
                    "Class $extensionClass is not an EventListener. Please create it as Extension or GroupObject."
                );
            }
            $extensions[get_class($extension)] = $extension;
        }
        return $extensions;
    }

    private function getExtensionConfig($extension, $config)
    {
        $extensionConfig = isset($config['extensions']['config'][$extension])
            ? $config['extensions']['config'][$extension]
            : [];

        if (!isset($config['extensions']['enabled'])) {
            return $extensionConfig;
        }

        if (!is_array($config['extensions']['enabled'])) {
            return $extensionConfig;
        }

        foreach ($config['extensions']['enabled'] as $enabledExtensionsConfig) {
            if (!is_array($enabledExtensionsConfig)) {
                continue;
            }

            $enabledExtension = key($enabledExtensionsConfig);
            if ($enabledExtension === $extension) {
                return Configuration::mergeConfigs(reset($enabledExtensionsConfig), $extensionConfig);
            }
        }

        return $extensionConfig;
    }
}
<?php
namespace Codeception\Subscriber;

use Codeception\Event\FailEvent;
use Codeception\Event\PrintResultEvent;
use Codeception\Event\StepEvent;
use Codeception\Event\SuiteEvent;
use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\Lib\Console\Message;
use Codeception\Lib\Console\MessageFactory;
use Codeception\Lib\Console\Output;
use Codeception\Lib\Notification;
use Codeception\Step;
use Codeception\Step\Comment;
use Codeception\Suite;
use Codeception\Test\Descriptor;
use Codeception\Test\Interfaces\ScenarioDriven;
use Codeception\TestInterface;
use Codeception\Util\Debug;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class Console implements EventSubscriberInterface
{
    use Shared\StaticEvents;

    /**
     * @var string[]
     */
    public static $events = [
        Events::SUITE_BEFORE       => 'beforeSuite',
        Events::SUITE_AFTER        => 'afterSuite',
        Events::TEST_START         => 'startTest',
        Events::TEST_END           => 'endTest',
        Events::STEP_BEFORE        => 'beforeStep',
        Events::STEP_AFTER         => 'afterStep',
        Events::TEST_SUCCESS       => 'testSuccess',
        Events::TEST_FAIL          => 'testFail',
        Events::TEST_ERROR         => 'testError',
        Events::TEST_INCOMPLETE    => 'testIncomplete',
        Events::TEST_SKIPPED       => 'testSkipped',
        Events::TEST_WARNING       => 'testWarning',
        Events::TEST_FAIL_PRINT    => 'printFail',
        Events::RESULT_PRINT_AFTER => 'afterResult',
    ];

    /**
     * @var Step
     */
    protected $metaStep;

    /**
     * @var Message
     */
    protected $message = null;
    protected $steps = true;
    protected $debug = false;
    protected $ansi = true;
    protected $silent = false;
    protected $lastTestFailed = false;
    protected $printedTest = null;
    protected $rawStackTrace = false;
    protected $traceLength = 5;
    protected $width;

    /**
     * @var OutputInterface
     */
    protected $output;
    protected $conditionalFails = [];
    protected $failedStep = [];
    protected $reports = [];
    protected $namespace = '';
    protected $chars = ['success' => '+', 'fail' => 'x', 'of' => ':'];

    protected $options = [
        'debug'         => false,
        'ansi'          => false,
        'steps'         => true,
        'verbosity'     => 0,
        'xml'           => null,
        'phpunit-xml'   => null,
        'html'          => null,
        'tap'           => null,
        'json'          => null,
        'no-artifacts'  => false,
    ];

    /**
     * @var MessageFactory
     */
    protected $messageFactory;

    public function __construct($options)
    {
        $this->prepareOptions($options);
        $this->output = new Output($options);
        $this->messageFactory = new MessageFactory($this->output);
        if ($this->debug) {
            Debug::setOutput($this->output);
        }
        $this->detectWidth();

        if ($this->options['ansi'] && !$this->isWin()) {
            $this->chars['success'] = '✔';
            $this->chars['fail'] = '✖';
        }

        foreach (['html', 'xml', 'phpunit-xml', 'tap', 'json'] as $report) {
            if (!$this->options[$report]) {
                continue;
            }
            $path = $this->absolutePath($this->options[$report]);
            $this->reports[] = sprintf(
                "- <bold>%s</bold> report generated in <comment>file://%s</comment>",
                strtoupper($report),
                $path
            );
        }
    }

    // triggered for scenario based tests: cept, cest
    public function beforeSuite(SuiteEvent $e)
    {
        $this->namespace = "";
        $settings = $e->getSettings();
        if (isset($settings['namespace'])) {
            $this->namespace = $settings['namespace'];
        }
        $this->message("%s Tests (%d) ")
            ->with(ucfirst($e->getSuite()->getName()), $e->getSuite()->count())
            ->style('bold')
            ->width($this->width, '-')
            ->prepend("\n")
            ->writeln();

        if ($e->getSuite() instanceof Suite) {
            $message = $this->message(
                implode(
                    ', ',
                    array_map(
                        function ($module) {
                            return $module->_getName();
                        },
                        $e->getSuite()->getModules()
                    )
                )
            );

            $message->style('info')
                ->prepend('Modules: ')
                ->writeln(OutputInterface::VERBOSITY_VERBOSE);
        }

        $this->message('')->width($this->width, '-')->writeln(OutputInterface::VERBOSITY_VERBOSE);
    }

    // triggered for all tests
    public function startTest(TestEvent $e)
    {
        $this->conditionalFails = [];
        $test = $e->getTest();
        $this->printedTest = $test;
        $this->message = null;

        if (!$this->output->isInteractive() and !$this->isDetailed($test)) {
            return;
        }
        $this->writeCurrentTest($test);
        if ($this->isDetailed($test)) {
            $this->output->writeln('');
            $this->message(Descriptor::getTestSignature($test))
                ->style('info')
                ->prepend('Signature: ')
                ->writeln();

            $this->message(codecept_relative_path(Descriptor::getTestFullName($test)))
                ->style('info')
                ->prepend('Test: ')
                ->writeln();

            if ($this->steps) {
                $this->message('Scenario --')->style('comment')->writeln();
                $this->output->waitForDebugOutput = false;
            }
        }
    }

    public function afterStep(StepEvent $e)
    {
        $step = $e->getStep();
        if (!$step->hasFailed()) {
            return;
        }
        if ($step instanceof Step\ConditionalAssertion) {
            $this->conditionalFails[] = $step;
            return;
        }
        $this->failedStep[] = $step;
    }

    /**
     * @param PrintResultEvent $event
     */
    public function afterResult(PrintResultEvent $event)
    {
        $result = $event->getResult();
        if ($result->skippedCount() + $result->notImplementedCount() > 0 and $this->options['verbosity'] < OutputInterface::VERBOSITY_VERBOSE) {
            $this->output->writeln("run with `-v` to get more info about skipped or incomplete tests");
        }
        foreach ($this->reports as $message) {
            $this->output->writeln($message);
        }
    }

    private function absolutePath($path)
    {
        if ((strpos($path, '/') === 0) or (strpos($path, ':') === 1)) { // absolute path
            return $path;
        }

        return codecept_output_dir() . $path;
    }

    public function testSuccess(TestEvent $e)
    {
        if ($this->isDetailed($e->getTest())) {
            $this->message('PASSED')->center(' ')->style('ok')->append("\n")->writeln();

            return;
        }
        $this->writelnFinishedTest($e, $this->message($this->chars['success'])->style('ok'));
    }

    public function endTest(TestEvent $e)
    {
        $this->metaStep = null;
        $this->printedTest = null;
    }

    public function testWarning(TestEvent $e)
    {
        if ($this->isDetailed($e->getTest())) {
            $this->message('WARNING')->center(' ')->style('pending')->append("\n")->writeln();

            return;
        }
        $this->writelnFinishedTest($e, $this->message('W')->style('pending'));
    }

    public function testFail(FailEvent $e)
    {
        if ($this->isDetailed($e->getTest())) {
            $this->message('FAIL')->center(' ')->style('fail')->append("\n")->writeln();

            return;
        }
        $this->writelnFinishedTest($e, $this->message($this->chars['fail'])->style('fail'));
    }

    public function testError(FailEvent $e)
    {
        if ($this->isDetailed($e->getTest())) {
            $this->message('ERROR')->center(' ')->style('fail')->append("\n")->writeln();

            return;
        }
        $this->writelnFinishedTest($e, $this->message('E')->style('fail'));
    }

    public function testSkipped(FailEvent $e)
    {
        if ($this->isDetailed($e->getTest())) {
            $msg = $e->getFail()->getMessage();
            $this->message('SKIPPED')->append($msg ? ": $msg" : '')->center(' ')->style('pending')->writeln();

            return;
        }
        $this->writelnFinishedTest($e, $this->message('S')->style('pending'));
    }

    public function testIncomplete(FailEvent $e)
    {
        if ($this->isDetailed($e->getTest())) {
            $msg = $e->getFail()->getMessage();
            $this->message('INCOMPLETE')->append($msg ? ": $msg" : '')->center(' ')->style('pending')->writeln();

            return;
        }
        $this->writelnFinishedTest($e, $this->message('I')->style('pending'));
    }

    protected function isDetailed($test)
    {
        return $test instanceof ScenarioDriven && $this->steps;
    }

    public function beforeStep(StepEvent $e)
    {
        if (!$this->steps or !$e->getTest() instanceof ScenarioDriven) {
            return;
        }
        $metaStep = $e->getStep()->getMetaStep();
        if ($metaStep and $this->metaStep != $metaStep) {
            $this->message(' ' . $metaStep->getPrefix())
                ->style('bold')
                ->append($metaStep->__toString())
                ->writeln();
        }
        $this->metaStep = $metaStep;

        $this->printStep($e->getStep());
    }

    private function printStep(Step $step)
    {
        if ($step instanceof Comment and $step->__toString() == '') {
            return; // don't print empty comments
        }
        $msg = $this->message(' ');
        if ($this->metaStep) {
            $msg->append('  ');
        }
        $msg->append($step->getPrefix());
        $prefixLength = $msg->getLength();
        if (!$this->metaStep) {
            $msg->style('bold');
        }
        $maxLength = $this->width - $prefixLength;
        $msg->append(OutputFormatter::escape($step->toString($maxLength)));
        if ($this->metaStep) {
            $msg->style('info');
        }
        $msg->writeln();
    }

    public function afterSuite(SuiteEvent $e)
    {
        $this->message()->width($this->width, '-')->writeln();
        $messages = Notification::all();
        foreach (array_count_values($messages) as $message => $count) {
            if ($count > 1) {
                $message = $count . 'x ' . $message;
            }
            $this->output->notification($message);
        }
    }

    public function printFail(FailEvent $e)
    {
        $failedTest = $e->getTest();
        $fail = $e->getFail();

        $this->output->write($e->getCount() . ") ");
        $this->writeCurrentTest($failedTest, false);
        $this->output->writeln('');
        $this->message("<error> Test </error> ")
            ->append(codecept_relative_path(Descriptor::getTestFullName($failedTest)))
            ->write();

        if ($failedTest instanceof ScenarioDriven) {
            $this->printScenarioFail($failedTest, $fail);
            $this->printReports($failedTest);
            return;
        }

        $this->printException($fail);
        $this->printExceptionTrace($fail);
    }

    public function printReports(TestInterface $failedTest)
    {
        if ($this->options['no-artifacts']) {
            return;
        }
        $reports = $failedTest->getMetadata()->getReports();
        if (count($reports)) {
            $this->output->writeln('<comment>Artifacts:</comment>');
            $this->output->writeln('');
        }

        foreach ($reports as $type => $report) {
            $type = ucfirst($type);
            $this->output->writeln("$type: <debug>$report</debug>");
        }
    }

    public function printException($e, $cause = null)
    {
        if ($e instanceof \PHPUnit\Framework\SkippedTestError or $e instanceof \PHPUnit\Framework_IncompleteTestError) {
            if ($e->getMessage()) {
                $this->message(OutputFormatter::escape($e->getMessage()))->prepend("\n")->writeln();
            }

            return;
        }

        $class = $e instanceof \PHPUnit\Framework\ExceptionWrapper
            ? $e->getClassname()
            : get_class($e);

        if (strpos($class, 'Codeception\Exception') === 0) {
            $class = substr($class, strlen('Codeception\Exception\\'));
        }

        $this->output->writeln('');
        $message = $this->message(OutputFormatter::escape($e->getMessage()));

        if ($e instanceof \PHPUnit\Framework\ExpectationFailedException) {
            $comparisonFailure = $e->getComparisonFailure();
            if ($comparisonFailure) {
                $message->append($this->messageFactory->prepareComparisonFailureMessage($comparisonFailure));
            }
        }

        $isFailure = $e instanceof \PHPUnit\Framework\AssertionFailedError
            || $class === 'PHPUnit\Framework\ExpectationFailedException'
            || $class === 'PHPUnit\Framework\AssertionFailedError';

        if (!$isFailure) {
            $message->prepend("[$class] ")->block('error');
        }

        if ($isFailure && $cause) {
            $cause = OutputFormatter::escape(ucfirst($cause));
            $message->prepend("<error> Step </error> $cause\n<error> Fail </error> ");
        }

        $message->writeln();
    }

    public function printScenarioFail(ScenarioDriven $failedTest, $fail)
    {
        if ($this->conditionalFails) {
            $failedStep = (string) array_shift($this->conditionalFails);
        } else {
            $failedStep = (string) $failedTest->getScenario()->getMetaStep();
            if ($failedStep === '') {
                $failedStep = (string) array_shift($this->failedStep);
            }
        }

        $this->printException($fail, $failedStep);

        $this->printScenarioTrace($failedTest);
        if ($this->output->getVerbosity() == OutputInterface::VERBOSITY_DEBUG) {
            $this->printExceptionTrace($fail);

            return;
        }
        if (!$fail instanceof \PHPUnit\Framework\AssertionFailedError) {
            $this->printExceptionTrace($fail);

            return;
        }
    }

    public function printExceptionTrace($e)
    {
        static $limit = 10;

        if ($e instanceof \PHPUnit\Framework\SkippedTestError or $e instanceof \PHPUnit\Framework_IncompleteTestError) {
            return;
        }

        if ($this->rawStackTrace) {
            $this->message(OutputFormatter::escape(\PHPUnit\Util\Filter::getFilteredStacktrace($e, true, false)))->writeln();

            return;
        }

        $trace = \PHPUnit\Util\Filter::getFilteredStacktrace($e, false);

        $i = 0;
        foreach ($trace as $step) {
            if ($i >= $limit) {
                break;
            }
            $i++;

            $message = $this->message($i)->prepend('#')->width(4);

            if (!isset($step['file'])) {
                foreach (['class', 'type', 'function'] as $info) {
                    if (!isset($step[$info])) {
                        continue;
                    }
                    $message->append($step[$info]);
                }
                $message->writeln();
                continue;
            }
            $message->append($step['file'] . ':' . $step['line']);
            $message->writeln();
        }

        $prev = $e->getPrevious();
        if ($prev) {
            $this->printExceptionTrace($prev);
        }
    }


    /**
     * @param $failedTest
     */
    public function printScenarioTrace(ScenarioDriven $failedTest)
    {
        $trace = array_reverse($failedTest->getScenario()->getSteps());
        $length = $stepNumber = count($trace);

        if (!$length) {
            return;
        }

        $this->message("\nScenario Steps:\n")->style('comment')->writeln();

        foreach ($trace as $step) {
            /**
             * @var $step Step
             */
            if (!$step->__toString()) {
                continue;
            }

            $message = $this
                ->message($stepNumber)
                ->prepend(' ')
                ->width(strlen($length))
                ->append(". ");
            $message->append(OutputFormatter::escape($step->getPhpCode($this->width - $message->getLength())));

            if ($step->hasFailed()) {
                $message->style('bold');
            }

            $line = $step->getLine();
            if ($line and (!$step instanceof Comment)) {
                $message->append(" at <info>$line</info>");
            }

            $stepNumber--;
            $message->writeln();
            if (($length - $stepNumber - 1) >= $this->traceLength) {
                break;
            }
        }
        $this->output->writeln("");
    }

    public function detectWidth()
    {
        $this->width = 60;
        if (!$this->isWin()
            && (php_sapi_name() === "cli")
            && (getenv('TERM'))
            && (getenv('TERM') != 'unknown')
        ) {
            // try to get terminal width from ENV variable (bash), see also https://github.com/Codeception/Codeception/issues/3788
            if (getenv('COLUMNS')) {
                $this->width = getenv('COLUMNS');
            } else {
                $this->width = (int) (`command -v tput >> /dev/null 2>&1 && tput cols`) - 2;
            }
        } elseif ($this->isWin() && (php_sapi_name() === "cli")) {
            exec('mode con', $output);
            if (isset($output[4])) {
                preg_match('/^ +.* +(\d+)$/', $output[4], $matches);
                if (!empty($matches[1])) {
                    $this->width = (int) $matches[1];
                }
            }
        }
        return $this->width;
    }

    private function isWin()
    {
        return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
    }

    /**
     * @param \PHPUnit\Framework\SelfDescribing $test
     * @param bool                              $inProgress
     */
    protected function writeCurrentTest(\PHPUnit\Framework\SelfDescribing $test, $inProgress = true)
    {
        $prefix = ($this->output->isInteractive() and !$this->isDetailed($test) and $inProgress) ? '- ' : '';

        $testString = Descriptor::getTestAsString($test);
        $testString = preg_replace('~^([^:]+):\s~', "<focus>$1{$this->chars['of']}</focus> ", $testString);

        $this
            ->message($testString)
            ->prepend($prefix)
            ->write();
    }

    protected function writelnFinishedTest(TestEvent $event, Message $result)
    {
        $test = $event->getTest();
        if ($this->isDetailed($test)) {
            return;
        }

        if ($this->output->isInteractive()) {
            $this->output->write("\x0D");
        }
        $result->append(' ')->write();
        $this->writeCurrentTest($test, false);

        $conditionalFailsMessage = "";
        $numFails = count($this->conditionalFails);
        if ($numFails == 1) {
            $conditionalFailsMessage = "[F]";
        } elseif ($numFails) {
            $conditionalFailsMessage = "{$numFails}x[F]";
        }
        $conditionalFailsMessage = "<error>$conditionalFailsMessage</error> ";
        $this->message($conditionalFailsMessage)->write();
        $this->writeTimeInformation($event);
        $this->output->writeln('');
    }

    /**
     * @param $string
     * @return Message
     */
    private function message($string = '')
    {
        return $this->messageFactory->message($string);
    }

    /**
     * @param TestEvent $event
     */
    protected function writeTimeInformation(TestEvent $event)
    {
        $time = $event->getTime();
        if ($time) {
            $this
                ->message(number_format(round($time, 2), 2))
                ->prepend('(')
                ->append('s)')
                ->style('info')
                ->write();
        }
    }

    /**
     * @param $options
     */
    private function prepareOptions($options)
    {
        $this->options = array_merge($this->options, $options);
        $this->debug = $this->options['debug'] || $this->options['verbosity'] >= OutputInterface::VERBOSITY_VERY_VERBOSE;
        $this->steps = $this->debug || $this->options['steps'];
        $this->rawStackTrace = ($this->options['verbosity'] === OutputInterface::VERBOSITY_DEBUG);
    }
}
<?php
namespace Codeception\Subscriber;

use Codeception\Event\TestEvent;
use Codeception\Test\Descriptor;
use Codeception\Test\Interfaces\Dependent;
use Codeception\TestInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Codeception\Events;

class Dependencies implements EventSubscriberInterface
{
    use Shared\StaticEvents;

    static $events = [
        Events::TEST_START => 'testStart',
        Events::TEST_SUCCESS => 'testSuccess'
    ];

    protected $successfulTests = [];

    public function testStart(TestEvent $event)
    {
        $test = $event->getTest();
        if (!$test instanceof Dependent) {
            return;
        }

        $testSignatures = $test->fetchDependencies();
        foreach ($testSignatures as $signature) {
            if (!in_array($signature, $this->successfulTests)) {
                $test->getMetadata()->setSkip("This test depends on $signature to pass");
                return;
            }
        }
    }

    public function testSuccess(TestEvent $event)
    {
        $test = $event->getTest();
        if (!$test instanceof TestInterface) {
            return;
        }
        $this->successfulTests[] = Descriptor::getTestSignature($test);
    }
}
<?php

namespace Codeception\Subscriber;

use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\Lib\Di;
use Codeception\Test\Cest;
use Codeception\Test\Unit;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class PrepareTest implements EventSubscriberInterface
{
    use Shared\StaticEvents;

    public static $events = [
        Events::TEST_BEFORE => 'prepare',
    ];

    protected $modules = [];

    public function prepare(TestEvent $event)
    {
        $test = $event->getTest();
        /** @var $di Di  **/
        $prepareMethods = $test->getMetadata()->getParam('prepare');

        if (!$prepareMethods) {
            return;
        }
        $di = $test->getMetadata()->getService('di');

        foreach ($prepareMethods as $method) {

            /** @var $module \Codeception\Module  **/
            if ($test instanceof Cest) {
                $di->injectDependencies($test->getTestClass(), $method);
            }
            if ($test instanceof Unit) {
                $di->injectDependencies($test, $method);
            }
        }
    }
}
<?php
namespace Codeception\Subscriber;

use Codeception\Configuration;
use Codeception\Event\SuiteEvent;
use Codeception\Events;
use Codeception\Exception\ConfigurationException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class Bootstrap implements EventSubscriberInterface
{
    use Shared\StaticEvents;

    public static $events = [
        Events::SUITE_INIT => 'loadBootstrap',
    ];

    public function loadBootstrap(SuiteEvent $e)
    {
        $settings = $e->getSettings();

        if (!isset($settings['bootstrap'])) {
            return;
        }

        Configuration::loadBootstrap($settings['bootstrap'], $settings['path']);
    }
}
<?php
namespace Codeception\Subscriber\Shared;

trait StaticEvents
{
    public static function getSubscribedEvents()
    {
        return static::$events;
    }
}
<?php
namespace Codeception\Subscriber;

use Codeception\Event\SuiteEvent;
use Codeception\Events;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class BeforeAfterTest implements EventSubscriberInterface
{
    use Shared\StaticEvents;

    public static $events = [
        Events::SUITE_BEFORE => 'beforeClass',
        Events::SUITE_AFTER  => ['afterClass', 100]
    ];

    protected $hooks = [];
    protected $startedTests = [];
    protected $unsuccessfulTests = [];

    public function beforeClass(SuiteEvent $e)
    {
        foreach ($e->getSuite()->tests() as $test) {
            /** @var $test \PHPUnit\Framework\Test  * */
            $testClass = get_class($test);
            $this->hooks[$testClass] = \PHPUnit\Util\Test::getHookMethods($testClass);
        }
        $this->runHooks('beforeClass');
    }


    public function afterClass(SuiteEvent $e)
    {
        $this->runHooks('afterClass');
    }

    protected function runHooks($hookName)
    {
        foreach ($this->hooks as $className => $hook) {
            foreach ($hook[$hookName] as $method) {
                if (is_callable([$className, $method])) {
                    call_user_func([$className, $method]);
                }
            }
        }
    }
}
<?php
namespace Codeception\Subscriber;

use Codeception\Event\SuiteEvent;
use Codeception\Events;
use Codeception\Lib\Notification;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ErrorHandler implements EventSubscriberInterface
{
    use Shared\StaticEvents;

    public static $events = [
        Events::SUITE_BEFORE => 'handle',
        Events::SUITE_AFTER  => 'onFinish'
    ];

    /**
     * @var bool $stopped to keep shutdownHandler from possible looping.
     */
    private $stopped = false;

    /**
     * @var bool $initialized to avoid double error handler substitution
     */
    private $initialized = false;

    private $deprecationsInstalled = false;
    private $oldHandler;

    private $suiteFinished = false;

    /**
     * @var int stores bitmask for errors
     */
    private $errorLevel;

    public function __construct()
    {
        $this->errorLevel = E_ALL & ~E_STRICT & ~E_DEPRECATED;
    }

    public function onFinish(SuiteEvent $e)
    {
        $this->suiteFinished = true;
    }

    public function handle(SuiteEvent $e)
    {
        $settings = $e->getSettings();
        if ($settings['error_level']) {
            $this->errorLevel = eval("return {$settings['error_level']};");
        }
        error_reporting($this->errorLevel);

        if ($this->initialized) {
            return;
        }
        // We must register shutdown function before deprecation error handler to restore previous error handler
        // and silence DeprecationErrorHandler yelling about 'THE ERROR HANDLER HAS CHANGED!'
        register_shutdown_function([$this, 'shutdownHandler']);
        $this->registerDeprecationErrorHandler();
        $this->oldHandler = set_error_handler([$this, 'errorHandler']);
        $this->initialized = true;
    }

    public function errorHandler($errno, $errstr, $errfile, $errline, $context = array())
    {
        if (E_USER_DEPRECATED === $errno) {
            $this->handleDeprecationError($errno, $errstr, $errfile, $errline, $context);
            return;
        }

        if (!(error_reporting() & $errno)) {
            // This error code is not included in error_reporting
            return false;
        }

        if (strpos($errstr, 'Cannot modify header information') !== false) {
            return false;
        }

        $relativePath = codecept_relative_path($errfile);
        throw new \PHPUnit\Framework\Exception("$errstr at $relativePath:$errline", $errno);
    }

    public function shutdownHandler()
    {
        if ($this->deprecationsInstalled) {
            restore_error_handler();
        }

        if ($this->stopped) {
            return;
        }
        $this->stopped = true;
        $error = error_get_last();

        if (!$this->suiteFinished && (
            $error === null || !in_array($error['type'], [E_ERROR, E_COMPILE_ERROR, E_CORE_ERROR])
        )) {
            echo "\n\n\nCOMMAND DID NOT FINISH PROPERLY.\n";
            exit(255);
        }
        if (!is_array($error)) {
            return;
        }
        if (error_reporting() === 0) {
            return;
        }
        // not fatal
        if (!in_array($error['type'], [E_ERROR, E_COMPILE_ERROR, E_CORE_ERROR])) {
            return;
        }

        echo "\n\n\nFATAL ERROR. TESTS NOT FINISHED.\n";
        echo sprintf("%s \nin %s:%d\n", $error['message'], $error['file'], $error['line']);
    }

    private function registerDeprecationErrorHandler()
    {
        if (class_exists('\Symfony\Bridge\PhpUnit\DeprecationErrorHandler') && 'disabled' !== getenv('SYMFONY_DEPRECATIONS_HELPER')) {
            // DeprecationErrorHandler only will be installed if array('PHPUnit\Util\ErrorHandler', 'handleError')
            // is installed or no other error handlers are installed.
            // So we will remove Symfony\Component\Debug\ErrorHandler if it's installed.
            $old = set_error_handler('var_dump');
            restore_error_handler();

            if ($old
                && is_array($old)
                && count($old) > 0
                && is_object($old[0])
                && get_class($old[0]) === 'Symfony\Component\Debug\ErrorHandler'
            ) {
                restore_error_handler();
            }

            $this->deprecationsInstalled = true;
            \Symfony\Bridge\PhpUnit\DeprecationErrorHandler::register(getenv('SYMFONY_DEPRECATIONS_HELPER'));
        }
    }

    private function handleDeprecationError($type, $message, $file, $line, $context)
    {
        if (!($this->errorLevel & $type)) {
            return;
        }
        if (strpos($message, 'Symfony 4.3')) { // skip Symfony 4.3 deprecations
            return;
        }
        if ($this->deprecationsInstalled && $this->oldHandler) {
            call_user_func($this->oldHandler, $type, $message, $file, $line, $context);
            return;
        }
        Notification::deprecate("$message", "$file:$line");
    }
}
<?php
declare (ticks = 1);
namespace Codeception\Subscriber;

use Codeception\Event\SuiteEvent;
use Codeception\Events;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class GracefulTermination implements EventSubscriberInterface
{
    const SIGNAL_FUNC = 'pcntl_signal';
    const ASYNC_SIGNAL_HANDLING_FUNC = 'pcntl_async_signals';

    /**
     * @var SuiteEvent
     */
    protected $suiteEvent;

    public function handleSuite(SuiteEvent $event)
    {
        if (PHP_MAJOR_VERSION === 7 && PHP_MINOR_VERSION === 0) {
            // skip for PHP 7.0: https://github.com/Codeception/Codeception/issues/3607
            return;
        }
        if (function_exists(self::ASYNC_SIGNAL_HANDLING_FUNC)) {
            pcntl_async_signals(true);
        }
        if (function_exists(self::SIGNAL_FUNC)) {
            pcntl_signal(SIGTERM, [$this, 'terminate']);
            pcntl_signal(SIGINT, [$this, 'terminate']);
        }

        $this->suiteEvent = $event;
    }

    public function terminate()
    {
        if ($this->suiteEvent) {
            $this->suiteEvent->getResult()->stopOnError(true);
            $this->suiteEvent->getResult()->stopOnFailure(true);
        }
        throw new \RuntimeException(
            "\n\n---------------------------\nTESTS EXECUTION TERMINATED\n---------------------------\n"
        );
    }

    public static function getSubscribedEvents()
    {
        if (!function_exists(self::SIGNAL_FUNC)) {
            return [];
        }
        return [Events::SUITE_BEFORE => 'handleSuite'];
    }
}
<?php
namespace Codeception\Subscriber;

use Codeception\Event\FailEvent;
use Codeception\Event\StepEvent;
use Codeception\Event\SuiteEvent;
use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\Suite;
use Codeception\TestInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class Module implements EventSubscriberInterface
{
    use Shared\StaticEvents;

    public static $events = [
        Events::TEST_BEFORE  => 'before',
        Events::TEST_AFTER   => 'after',
        Events::STEP_BEFORE  => 'beforeStep',
        Events::STEP_AFTER   => 'afterStep',
        Events::TEST_FAIL    => 'failed',
        Events::TEST_ERROR   => 'failed',
        Events::SUITE_BEFORE => 'beforeSuite',
        Events::SUITE_AFTER  => 'afterSuite'
    ];

    protected $modules = [];

    public function beforeSuite(SuiteEvent $e)
    {
        $suite = $e->getSuite();
        if (!$suite instanceof Suite) {
            return;
        }
        $this->modules = $suite->getModules();
        foreach ($this->modules as $module) {
            $module->_beforeSuite($e->getSettings());
        }
    }

    public function afterSuite()
    {
        foreach ($this->modules as $module) {
            $module->_afterSuite();
        }
    }

    public function before(TestEvent $event)
    {
        if (!$event->getTest() instanceof TestInterface) {
            return;
        }

        foreach ($this->modules as $module) {
            $module->_before($event->getTest());
        }
    }

    public function after(TestEvent $e)
    {
        if (!$e->getTest() instanceof TestInterface) {
            return;
        }
        foreach ($this->modules as $module) {
            $module->_after($e->getTest());
            $module->_resetConfig();
        }
    }

    public function failed(FailEvent $e)
    {
        if (!$e->getTest() instanceof TestInterface) {
            return;
        }
        foreach ($this->modules as $module) {
            $module->_failed($e->getTest(), $e->getFail());
        }
    }

    public function beforeStep(StepEvent $e)
    {
        foreach ($this->modules as $module) {
            $module->_beforeStep($e->getStep(), $e->getTest());
        }
    }

    public function afterStep(StepEvent $e)
    {
        foreach ($this->modules as $module) {
            $module->_afterStep($e->getStep(), $e->getTest());
        }
    }
}
<?php
namespace Codeception\Subscriber;

use Codeception\Event\SuiteEvent;
use Codeception\Event\TestEvent;
use Codeception\Events;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class FailFast implements EventSubscriberInterface
{
    use Shared\StaticEvents;

    public static $events = [
        Events::TEST_FAIL => 'stopOnFail',
        Events::TEST_ERROR => 'stopOnFail',
        Events::SUITE_BEFORE => 'cacheSuite'
    ];

    private $failureCount = 0;

    private $stopFailureCount;

    private $suiteCache;

    public function __construct($stopFailureCount)
    {
        $this->stopFailureCount = (int) $stopFailureCount;
    }

    public function cacheSuite(SuiteEvent $e)
    {
        $this->suiteCache = $e->getResult();
    }

    public function stopOnFail(TestEvent $e)
    {
        $this->failureCount++;

        if ($this->failureCount >= $this->stopFailureCount) {
            $this->suiteCache->stop();
        }
    }
}
<?php

namespace Codeception;

interface CustomCommandInterface
{

    /**
     * returns the name of the command
     *
     * @return string
     */
    public static function getCommandName();
}
<?php
namespace Codeception;

use Traversable;

class Example implements \ArrayAccess, \Countable, \IteratorAggregate
{
    protected $data;

    public function __construct($data)
    {
        $this->data = $data;
    }

    /**
     * Whether a offset exists
     * @link http://php.net/manual/en/arrayaccess.offsetexists.php
     * @param mixed $offset <p>
     * An offset to check for.
     * </p>
     * @return boolean true on success or false on failure.
     * </p>
     * <p>
     * The return value will be casted to boolean if non-boolean was returned.
     * @since 5.0.0
     */
    public function offsetExists($offset)
    {
        return array_key_exists($offset, $this->data);
    }

    /**
     * Offset to retrieve
     * @link http://php.net/manual/en/arrayaccess.offsetget.php
     * @param mixed $offset <p>
     * The offset to retrieve.
     * </p>
     * @return mixed Can return all value types.
     * @since 5.0.0
     */
    public function offsetGet($offset)
    {
        if (!$this->offsetExists($offset)) {
            throw new \PHPUnit\Framework\AssertionFailedError("Example $offset doesn't exist");
        };
        return $this->data[$offset];
    }

    /**
     * Offset to set
     * @link http://php.net/manual/en/arrayaccess.offsetset.php
     * @param mixed $offset <p>
     * The offset to assign the value to.
     * </p>
     * @param mixed $value <p>
     * The value to set.
     * </p>
     * @return void
     * @since 5.0.0
     */
    public function offsetSet($offset, $value)
    {
        $this->data[$offset] = $value;
    }

    /**
     * Offset to unset
     * @link http://php.net/manual/en/arrayaccess.offsetunset.php
     * @param mixed $offset <p>
     * The offset to unset.
     * </p>
     * @return void
     * @since 5.0.0
     */
    public function offsetUnset($offset)
    {
        unset($this->data[$offset]);
    }

    /**
     * Count elements of an object
     * @link http://php.net/manual/en/countable.count.php
     * @return int The custom count as an integer.
     * </p>
     * <p>
     * The return value is cast to an integer.
     * @since 5.1.0
     */
    public function count()
    {
        return count($this->data);
    }

    /**
     * Retrieve an external iterator
     * @link http://php.net/manual/en/iteratoraggregate.getiterator.php
     * @return Traversable An instance of an object implementing <b>Iterator</b> or
     * <b>Traversable</b>
     * @since 5.0.0
     */
    public function getIterator()
    {
        return new \ArrayIterator($this->data);
    }
}
<?php

$autoloadFile = './vendor/codeception/codeception/autoload.php';
if (( !isset($argv) || (isset($argv) && !in_array('--no-redirect', $argv)) ) && file_exists('./vendor/autoload.php') && file_exists($autoloadFile) && __FILE__ != realpath($autoloadFile)) {
    //for global installation or phar file
    fwrite(
        STDERR,
        "\n==== Redirecting to Composer-installed version in vendor/codeception. You can skip this using --no-redirect ====\n"
    );

    if (file_exists('./vendor/codeception/codeception/app.php')) {
        //codeception v4+
        require './vendor/codeception/codeception/app.php';
    } else {
        //older version
        require $autoloadFile;
        //require package/bin instead of codecept to avoid printing hashbang line
        require './vendor/codeception/codeception/package/bin';
    }

    die;
} elseif (file_exists(__DIR__ . '/vendor/autoload.php')) {
    // for phar
    require_once __DIR__ . '/vendor/autoload.php';
} elseif (file_exists(__DIR__ . '/../../autoload.php')) {
    //for composer
    require_once __DIR__ . '/../../autoload.php';
}
unset($autoloadFile);
if (isset($argv)) {
    $argv = array_values(array_diff($argv, ['--no-redirect']));
}
if (isset($_SERVER['argv'])) {
    $_SERVER['argv'] = array_values(array_diff($_SERVER['argv'], ['--no-redirect']));
}

// @codingStandardsIgnoreStart

include_once __DIR__ . DIRECTORY_SEPARATOR . 'shim.php';
// compat
if (PHP_MAJOR_VERSION < 7) {
    if (false === interface_exists('Throwable', false)) {
        interface Throwable {};
    }
    if (false === class_exists('ParseError', false)) {
        class ParseError extends \Exception {};
    }
}
// @codingStandardsIgnoreEnd
<?php

require_once __DIR__ . '/autoload.php';

use Codeception\Application;

call_user_func(static function () {
    $app = new Application('Codeception', Codeception\Codecept::VERSION);
    $app->add(new Codeception\Command\Build('build'));
    $app->add(new Codeception\Command\Run('run'));
    $app->add(new Codeception\Command\Init('init'));
    $app->add(new Codeception\Command\Console('console'));
    $app->add(new Codeception\Command\Bootstrap('bootstrap'));
    $app->add(new Codeception\Command\GenerateCept('generate:cept'));
    $app->add(new Codeception\Command\GenerateCest('generate:cest'));
    $app->add(new Codeception\Command\GenerateTest('generate:test'));
    $app->add(new Codeception\Command\GenerateSuite('generate:suite'));
    $app->add(new Codeception\Command\GenerateHelper('generate:helper'));
    $app->add(new Codeception\Command\GenerateScenarios('generate:scenarios'));
    $app->add(new Codeception\Command\Clean('clean'));
    $app->add(new Codeception\Command\GenerateGroup('generate:groupobject'));
    $app->add(new Codeception\Command\GeneratePageObject('generate:pageobject'));
    $app->add(new Codeception\Command\GenerateStepObject('generate:stepobject'));
    $app->add(new Codeception\Command\GenerateSnapshot('generate:snapshot'));
    $app->add(new Codeception\Command\GenerateEnvironment('generate:environment'));
    $app->add(new Codeception\Command\GenerateFeature('generate:feature'));
    $app->add(new Codeception\Command\GherkinSnippets('gherkin:snippets'));
    $app->add(new Codeception\Command\GherkinSteps('gherkin:steps'));
    $app->add(new Codeception\Command\DryRun('dry-run'));
    $app->add(new Codeception\Command\ConfigValidate('config:validate'));

    // Suggests package	
    if (class_exists('Stecman\Component\Symfony\Console\BashCompletion\CompletionCommand')) {
        $app->add(new Codeception\Command\Completion());
    } else {
        $app->add(new Codeception\Command\CompletionFallback());
    }

    $app->registerCustomCommands();

    // add only if within a phar archive.
    if ('phar:' === substr(__FILE__, 0, 5)) {
        $app->add(new Codeception\Command\SelfUpdate('self-update'));
    }

    $app->run();
});
<?php
// @codingStandardsIgnoreStart

namespace {
    \Codeception\PHPUnit\Init::init();
}

namespace Symfony\Component\CssSelector {
    if (!class_exists('Symfony\Component\CssSelector\CssSelectorConverter')) {
        class CssSelectorConverter {
            function toXPath($cssExpr, $prefix = 'descendant-or-self::') {
                return CssSelector::toXPath($cssExpr, $prefix);
            }
        }
    }
}


// prefering old names

namespace Codeception\TestCase {

    class Test extends \Codeception\Test\Unit {
    }
}

namespace Codeception\Platform {
    abstract class Group extends \Codeception\GroupObject
    {
    }
    abstract class Extension extends \Codeception\Extension
    {
    }
}

namespace {
    class_alias('Codeception\TestInterface', 'Codeception\TestCase');

    //Compatibility with Symfony 5
    if (!class_exists('Symfony\Component\EventDispatcher\Event') && class_exists('Symfony\Contracts\EventDispatcher\Event')) {
        class_alias('Symfony\Contracts\EventDispatcher\Event', 'Symfony\Component\EventDispatcher\Event');
    }
}
<?php

if (!function_exists('codecept_debug')) {
    function codecept_debug($data)
    {
        \Codeception\Util\Debug::debug($data);
    }
}

if (!function_exists('codecept_root_dir')) {
    function codecept_root_dir($appendPath = '')
    {
        return \Codeception\Configuration::projectDir() . $appendPath;
    }
}

if (!function_exists('codecept_output_dir')) {
    function codecept_output_dir($appendPath = '')
    {
        return \Codeception\Configuration::outputDir() . $appendPath;
    }
}

if (!function_exists('codecept_log_dir')) {
    function codecept_log_dir($appendPath = '')
    {
        return \Codeception\Configuration::outputDir() . $appendPath;
    }
}

if (!function_exists('codecept_data_dir')) {
    function codecept_data_dir($appendPath = '')
    {
        return \Codeception\Configuration::dataDir() . $appendPath;
    }
}

if (!function_exists('codecept_relative_path')) {
    function codecept_relative_path($path)
    {
        return \Codeception\Util\PathResolver::getRelativeDir(
            $path,
            \Codeception\Configuration::projectDir(),
            DIRECTORY_SEPARATOR
        );
    }
}

if (!function_exists('codecept_absolute_path')) {
    /**
     * If $path is absolute, it will be returned without changes.
     * If $path is relative, it will be passed to `codecept_root_dir()` function
     * to make it absolute.
     *
     * @param string $path
     * @return string the absolute path
     */
    function codecept_absolute_path($path)
    {
        return codecept_is_path_absolute($path) ? $path : codecept_root_dir($path);
    }
}

if (!function_exists('codecept_is_path_absolute')) {
    /**
     * Check whether the given $path is absolute.
     *
     * @param string $path
     * @return bool
     * @since 2.4.4
     */
    function codecept_is_path_absolute($path)
    {
        return \Codeception\Util\PathResolver::isPathAbsolute($path);
    }
}
<?php
namespace Codeception\Module;

use Codeception\Module;
use Codeception\TestInterface;
use Codeception\Exception\ModuleException;

/**
 * This module interacts with the [Alternative PHP Cache (APC)](http://php.net/manual/en/intro.apcu.php)
 * using either _APCu_ or _APC_ extension.
 *
 * Performs a cleanup by flushing all values after each test run.
 *
 * ## Status
 *
 * * Maintainer: **Serghei Iakovlev**
 * * Stability: **stable**
 * * Contact: serghei@phalcon.io
 *
 * ### Example (`unit.suite.yml`)
 *
 * ```yaml
 *    modules:
 *        - Apc
 * ```
 *
 * Be sure you don't use the production server to connect.
 *
 */
class Apc extends Module
{
    /**
     * Code to run before each test.
     *
     * @param TestInterface $test
     * @throws ModuleException
     */
    public function _before(TestInterface $test)
    {
        if (!extension_loaded('apc') && !extension_loaded('apcu')) {
            throw new ModuleException(
                __CLASS__,
                'The APC(u) extension not loaded.'
            );
        }

        if (!ini_get('apc.enabled') || (PHP_SAPI === 'cli' && !ini_get('apc.enable_cli'))) {
            throw new ModuleException(
                __CLASS__,
                'The "apc.enable_cli" parameter must be set to "On".'
            );
        }
    }

    /**
     * Code to run after each test.
     *
     * @param TestInterface $test
     */
    public function _after(TestInterface $test)
    {
        $this->clear();
    }

    /**
     * Grabs value from APC(u) by key.
     *
     * Example:
     *
     * ``` php
     * <?php
     * $users_count = $I->grabValueFromApc('users_count');
     * ?>
     * ```
     *
     * @param string|string[] $key
     * @return mixed
     */
    public function grabValueFromApc($key)
    {
        $value = $this->fetch($key);
        $this->debugSection('Value', $value);

        return $value;
    }

    /**
     * Checks item in APC(u) exists and the same as expected.
     *
     * Examples:
     *
     * ``` php
     * <?php
     * // With only one argument, only checks the key exists
     * $I->seeInApc('users_count');
     *
     * // Checks a 'users_count' exists and has the value 200
     * $I->seeInApc('users_count', 200);
     * ?>
     * ```
     *
     * @param string|string[] $key
     * @param mixed $value
     */
    public function seeInApc($key, $value = null)
    {
        if (null === $value) {
            $this->assertTrue($this->exists($key), "Cannot find key '$key' in APC(u).");
            return;
        }

        $actual = $this->grabValueFromApc($key);
        $this->assertEquals($value, $actual, "Cannot find key '$key' in APC(u) with the provided value.");
    }

    /**
     * Checks item in APC(u) doesn't exist or is the same as expected.
     *
     * Examples:
     *
     * ``` php
     * <?php
     * // With only one argument, only checks the key does not exist
     * $I->dontSeeInApc('users_count');
     *
     * // Checks a 'users_count' exists does not exist or its value is not the one provided
     * $I->dontSeeInApc('users_count', 200);
     * ?>
     * ```
     *
     * @param string|string[] $key
     * @param mixed $value
     */
    public function dontSeeInApc($key, $value = null)
    {
        if (null === $value) {
            $this->assertFalse($this->exists($key), "The key '$key' exists in APC(u).");
            return;
        }

        $actual = $this->grabValueFromApc($key);
        if (false !== $actual) {
            $this->assertEquals($value, $actual, "The key '$key' exists in APC(u) with the provided value.");
        }
    }

    /**
     * Stores an item `$value` with `$key` on the APC(u).
     *
     * Examples:
     *
     * ```php
     * <?php
     * // Array
     * $I->haveInApc('users', ['name' => 'miles', 'email' => 'miles@davis.com']);
     *
     * // Object
     * $I->haveInApc('user', UserRepository::findFirst());
     *
     * // Key as array of 'key => value'
     * $entries = [];
     * $entries['key1'] = 'value1';
     * $entries['key2'] = 'value2';
     * $entries['key3'] = ['value3a','value3b'];
     * $entries['key4'] = 4;
     * $I->haveInApc($entries, null);
     * ?>
     * ```
     *
     * @param string|array $key
     * @param mixed $value
     * @param int $expiration
     * @return mixed
     */
    public function haveInApc($key, $value, $expiration = null)
    {
        $this->store($key, $value, $expiration);

        return $key;
    }

    /**
     * Clears the APC(u) cache
     */
    public function flushApc()
    {
        // Returns TRUE always
        $this->clear();
    }

    /**
     * Clears the APC(u) cache.
     *
     * @return bool
     */
    protected function clear()
    {
        if (function_exists('apcu_clear_cache')) {
            return apcu_clear_cache();
        }

        return apc_clear_cache('user');
    }

    /**
     * Checks if entry exists
     *
     * @param string|string[] $key
     *
     * @return bool|\string[]
     */
    protected function exists($key)
    {
        if (function_exists('apcu_exists')) {
            return apcu_exists($key);
        }

        return apc_exists($key);
    }

    /**
     * Fetch a stored variable from the cache
     *
     * @param string|string[] $key
     *
     * @return mixed
     */
    protected function fetch($key)
    {
        $success = false;

        if (function_exists('apcu_fetch')) {
            $data = apcu_fetch($key, $success);
        } else {
            $data = apc_fetch($key, $success);
        }

        $this->debugSection('Fetching a stored variable', $success ? 'OK' : 'FAILED');

        return $data;
    }

    /**
     * Cache a variable in the data store.
     *
     * @param string|array $key
     * @param mixed $var
     * @param int $ttl
     *
     * @return array|bool
     */
    protected function store($key, $var, $ttl = 0)
    {
        if (function_exists('apcu_store')) {
            return apcu_store($key, $var, $ttl);
        }

        return apc_store($key, $var, $ttl);
    }
}
<?php
namespace Codeception\Module;

use Codeception\Util\FileSystem as Util;
use Symfony\Component\Finder\Finder;
use Codeception\Module as CodeceptionModule;
use Codeception\TestInterface;
use Codeception\Configuration;

/**
 * Module for testing local filesystem.
 * Fork it to extend the module for FTP, Amazon S3, others.
 *
 * ## Status
 *
 * * Maintainer: **davert**
 * * Stability: **stable**
 * * Contact: codecept@davert.mail.ua
 *
 * Module was developed to test Codeception itself.
 */
class Filesystem extends CodeceptionModule
{
    protected $file = null;
    protected $filepath = null;

    protected $path = '';

    public function _before(TestInterface $test)
    {
        $this->path = Configuration::projectDir();
    }

    /**
     * Enters a directory In local filesystem.
     * Project root directory is used by default
     *
     * @param string $path
     */
    public function amInPath($path)
    {
        chdir($this->path = $this->absolutizePath($path) . DIRECTORY_SEPARATOR);
        $this->debug('Moved to ' . getcwd());
    }

    /**
     * @param string $path
     * @return string
     */
    protected function absolutizePath($path)
    {
        // *nix way
        if (strpos($path, '/') === 0) {
            return $path;
        }
        // windows
        if (strpos($path, ':\\') === 1) {
            return $path;
        }

        return $this->path . $path;
    }

    /**
     * Opens a file and stores it's content.
     *
     * Usage:
     *
     * ``` php
     * <?php
     * $I->openFile('composer.json');
     * $I->seeInThisFile('codeception/codeception');
     * ?>
     * ```
     *
     * @param string $filename
     */
    public function openFile($filename)
    {
        $this->file = file_get_contents($this->absolutizePath($filename));
        $this->filepath = $filename;
    }

    /**
     * Deletes a file
     *
     * ``` php
     * <?php
     * $I->deleteFile('composer.lock');
     * ?>
     * ```
     *
     * @param string $filename
     */
    public function deleteFile($filename)
    {
        if (!file_exists($this->absolutizePath($filename))) {
            \Codeception\PHPUnit\TestCase::fail('file not found');
        }
        unlink($this->absolutizePath($filename));
    }

    /**
     * Deletes directory with all subdirectories
     *
     * ``` php
     * <?php
     * $I->deleteDir('vendor');
     * ?>
     * ```
     *
     * @param string $dirname
     */
    public function deleteDir($dirname)
    {
        $dir = $this->absolutizePath($dirname);
        Util::deleteDir($dir);
    }

    /**
     * Copies directory with all contents
     *
     * ``` php
     * <?php
     * $I->copyDir('vendor','old_vendor');
     * ?>
     * ```
     *
     * @param string $src
     * @param string $dst
     */
    public function copyDir($src, $dst)
    {
        Util::copyDir($src, $dst);
    }

    /**
     * Checks If opened file has `text` in it.
     *
     * Usage:
     *
     * ``` php
     * <?php
     * $I->openFile('composer.json');
     * $I->seeInThisFile('codeception/codeception');
     * ?>
     * ```
     *
     * @param string $text
     */
    public function seeInThisFile($text)
    {
        $this->assertStringContainsString($text, $this->file, "No text '$text' in currently opened file");
    }

    /**
     * Checks If opened file has the `number` of new lines.
     *
     * Usage:
     *
     * ``` php
     * <?php
     * $I->openFile('composer.json');
     * $I->seeNumberNewLines(5);
     * ?>
     * ```
     *
     * @param int $number New lines
     */
    public function seeNumberNewLines($number)
    {
        $lines = preg_split('/\n|\r/', $this->file);

        $this->assertTrue(
            (int) $number === count($lines),
            "The number of new lines does not match with $number"
        );
    }
    /**
     * Checks that contents of currently opened file matches $regex
     *
     * @param string $regex
     */
    public function seeThisFileMatches($regex)
    {
        $this->assertRegExp($regex, $this->file, "Contents of currently opened file does not match '$regex'");
    }

    /**
     * Checks the strict matching of file contents.
     * Unlike `seeInThisFile` will fail if file has something more than expected lines.
     * Better to use with HEREDOC strings.
     * Matching is done after removing "\r" chars from file content.
     *
     * ``` php
     * <?php
     * $I->openFile('process.pid');
     * $I->seeFileContentsEqual('3192');
     * ?>
     * ```
     *
     * @param string $text
     */
    public function seeFileContentsEqual($text)
    {
        $file = str_replace("\r", '', $this->file);
        \Codeception\PHPUnit\TestCase::assertEquals($text, $file);
    }

    /**
     * Checks If opened file doesn't contain `text` in it
     *
     * ``` php
     * <?php
     * $I->openFile('composer.json');
     * $I->dontSeeInThisFile('codeception/codeception');
     * ?>
     * ```
     *
     * @param string $text
     */
    public function dontSeeInThisFile($text)
    {
        $this->assertStringNotContainsString($text, $this->file, "Found text '$text' in currently opened file");
    }

    /**
     * Deletes a file
     */
    public function deleteThisFile()
    {
        $this->deleteFile($this->filepath);
    }

    /**
     * Checks if file exists in path.
     * Opens a file when it's exists
     *
     * ``` php
     * <?php
     * $I->seeFileFound('UserModel.php','app/models');
     * ?>
     * ```
     *
     * @param string $filename
     * @param string $path
     */
    public function seeFileFound($filename, $path = '')
    {
        if ($path === '' && file_exists($filename)) {
            $this->openFile($filename);
            \Codeception\PHPUnit\TestCase::assertFileExists($filename);
            return;
        }

        $found = $this->findFileInPath($filename, $path);

        if ($found === false) {
            $this->fail("File \"$filename\" not found at \"$path\"");
        }

        $this->openFile($found);
        \Codeception\PHPUnit\TestCase::assertFileExists($found);
    }

    /**
     * Checks if file does not exist in path
     *
     * @param string $filename
     * @param string $path
     */
    public function dontSeeFileFound($filename, $path = '')
    {
        if ($path === '') {
            \Codeception\PHPUnit\TestCase::assertFileNotExists($filename);
            return;
        }

        $found = $this->findFileInPath($filename, $path);

        if ($found === false) {
            //this line keeps a count of assertions correct
            \Codeception\PHPUnit\TestCase::assertTrue(true);
            return;
        }

        \Codeception\PHPUnit\TestCase::assertFileNotExists($found);
    }

    /**
     * Finds the first matching file
     *
     * @param string $filename
     * @param string $path
     * @throws \PHPUnit\Framework\AssertionFailedError When path does not exist
     * @return string|false Path to the first matching file
     */
    private function findFileInPath($filename, $path)
    {
        $path = $this->absolutizePath($path);
        if (!file_exists($path)) {
            $this->fail("Directory does not exist: $path");
        }

        $files = Finder::create()->files()->name($filename)->in($path);
        if ($files->count() === 0) {
            return false;
        }

        foreach ($files as $file) {
            return $file->getRealPath();
        }
    }


    /**
     * Erases directory contents
     *
     * ``` php
     * <?php
     * $I->cleanDir('logs');
     * ?>
     * ```
     *
     * @param string $dirname
     */
    public function cleanDir($dirname)
    {
        $path = $this->absolutizePath($dirname);
        Util::doEmptyDir($path);
    }

    /**
     * Saves contents to file
     *
     * @param string $filename
     * @param string $contents
     */
    public function writeToFile($filename, $contents)
    {
        file_put_contents($filename, $contents);
    }
}
<?php
namespace Codeception\Module;

use Codeception\Lib\Interfaces\DependsOnModule;
use Codeception\Module as CodeceptionModule;
use Codeception\TestInterface;
use Codeception\Exception\ModuleException;
use Codeception\Exception\ModuleRequireException;
use Codeception\Lib\Framework;
use Codeception\Lib\InnerBrowser;
use Codeception\Util\Soap as SoapUtils;
use Codeception\Util\XmlStructure;

/**
 * Module for testing SOAP WSDL web services.
 * Send requests and check if response matches the pattern.
 *
 * This module can be used either with frameworks or PHPBrowser.
 * It tries to guess the framework is is attached to.
 * If a endpoint is a full url then it uses PHPBrowser.
 *
 * ### Using Inside Framework
 *
 * Please note, that PHP SoapServer::handle method sends additional headers.
 * This may trigger warning: "Cannot modify header information"
 * If you use PHP SoapServer with framework, try to block call to this method in testing environment.
 *
 * ## Status
 *
 * * Maintainer: **davert**
 * * Stability: **stable**
 * * Contact: codecept@davert.mail.ua
 *
 * ## Configuration
 *
 * * endpoint *required* - soap wsdl endpoint
 * * SOAPAction - replace SOAPAction HTTP header (Set to '' to SOAP 1.2)
 *
 * ## Public Properties
 *
 * * xmlRequest - last SOAP request (DOMDocument)
 * * xmlResponse - last SOAP response (DOMDocument)
 *
 */
class SOAP extends CodeceptionModule implements DependsOnModule
{
    protected $config = [
        'schema' => "",
        'schema_url' => 'http://schemas.xmlsoap.org/soap/envelope/',
        'framework_collect_buffer' => true
    ];

    protected $requiredFields = ['endpoint'];

    protected $dependencyMessage = <<<EOF
Example using PhpBrowser as backend for SOAP module.
--
modules:
    enabled:
        - SOAP:
            depends: PhpBrowser
--
Framework modules can be used as well for functional testing of SOAP API.
EOF;

    /**
     * @var \Symfony\Component\BrowserKit\AbstractBrowser
     */
    public $client = null;
    public $isFunctional = false;

    /**
     * @var \DOMDocument
     */
    public $xmlRequest = null;
    /**
     * @var \DOMDocument
     */
    public $xmlResponse = null;

    /**
     * @var XmlStructure
     */
    protected $xmlStructure = null;

    /**
     * @var InnerBrowser
     */
    protected $connectionModule;

    public function _before(TestInterface $test)
    {
        $this->client = &$this->connectionModule->client;
        $this->buildRequest();
        $this->xmlResponse = null;
        $this->xmlStructure = null;
    }

    protected function onReconfigure()
    {
        $this->buildRequest();
        $this->xmlResponse = null;
        $this->xmlStructure = null;
    }

    public function _depends()
    {
        return ['Codeception\Lib\InnerBrowser' => $this->dependencyMessage];
    }

    public function _inject(InnerBrowser $connectionModule)
    {
        $this->connectionModule = $connectionModule;
        if ($connectionModule instanceof Framework) {
            $this->isFunctional = true;
        }
    }

    private function getClient()
    {
        if (!$this->client) {
            throw new ModuleRequireException($this, "Connection client is not available.");
        }
        return $this->client;
    }

    private function getXmlResponse()
    {
        if (!$this->xmlResponse) {
            throw new ModuleException($this, "No XML response, use `\$I->sendSoapRequest` to receive it");
        }
        return $this->xmlResponse;
    }

    private function getXmlStructure()
    {
        if (!$this->xmlStructure) {
            $this->xmlStructure = new XmlStructure($this->getXmlResponse());
        }
        return $this->xmlStructure;
    }

    /**
     * Prepare SOAP header.
     * Receives header name and parameters as array.
     *
     * Example:
     *
     * ``` php
     * <?php
     * $I->haveSoapHeader('AuthHeader', array('username' => 'davert', 'password' => '123345'));
     * ```
     *
     * Will produce header:
     *
     * ```
     *    <soapenv:Header>
     *      <SessionHeader>
     *      <AuthHeader>
     *          <username>davert</username>
     *          <password>12345</password>
     *      </AuthHeader>
     *   </soapenv:Header>
     * ```
     *
     * @param $header
     * @param array $params
     */
    public function haveSoapHeader($header, $params = [])
    {
        $soap_schema_url = $this->config['schema_url'];
        $xml = $this->xmlRequest;
        $xmlHeader = $xml->documentElement->getElementsByTagNameNS($soap_schema_url, 'Header')->item(0);
        $headerEl = $xml->createElement($header);
        SoapUtils::arrayToXml($xml, $headerEl, $params);
        $xmlHeader->appendChild($headerEl);
    }

    /**
     * Submits request to endpoint.
     *
     * Requires of api function name and parameters.
     * Parameters can be passed either as DOMDocument, DOMNode, XML string, or array (if no attributes).
     *
     * You are allowed to execute as much requests as you need inside test.
     *
     * Example:
     *
     * ``` php
     * $I->sendSoapRequest('UpdateUser', '<user><id>1</id><name>notdavert</name></user>');
     * $I->sendSoapRequest('UpdateUser', \Codeception\Utils\Soap::request()->user
     *   ->id->val(1)->parent()
     *   ->name->val('notdavert');
     * ```
     *
     * @param $request
     * @param $body
     */
    public function sendSoapRequest($action, $body = "")
    {
        $soap_schema_url = $this->config['schema_url'];
        $xml = $this->xmlRequest;
        $call = $xml->createElement('ns:' . $action);
        if ($body) {
            $bodyXml = SoapUtils::toXml($body);
            if ($bodyXml->hasChildNodes()) {
                foreach ($bodyXml->childNodes as $bodyChildNode) {
                    $bodyNode = $xml->importNode($bodyChildNode, true);
                    $call->appendChild($bodyNode);
                }
            }
        }

        $xmlBody = $xml->getElementsByTagNameNS($soap_schema_url, 'Body')->item(0);

        // cleanup if body already set
        foreach ($xmlBody->childNodes as $node) {
            $xmlBody->removeChild($node);
        }

        $xmlBody->appendChild($call);
        $this->debugSection("Request", $req = $xml->C14N());

        if ($this->isFunctional && $this->config['framework_collect_buffer']) {
            $response = $this->processInternalRequest($action, $req);
        } else {
            $response = $this->processExternalRequest($action, $req);
        }

        $this->debugSection("Response", (string) $response);
        $this->xmlResponse = SoapUtils::toXml($response);
        $this->xmlStructure = null;
    }

    /**
     * Checks XML response equals provided XML.
     * Comparison is done by canonicalizing both xml`s.
     *
     * Parameters can be passed either as DOMDocument, DOMNode, XML string, or array (if no attributes).
     *
     * Example:
     *
     * ``` php
     * <?php
     * $I->seeSoapResponseEquals("<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope><SOAP-ENV:Body><result>1</result></SOAP-ENV:Envelope>");
     *
     * $dom = new \DOMDocument();
     * $dom->load($file);
     * $I->seeSoapRequestIncludes($dom);
     *
     * ```
     *
     * @param $xml
     */
    public function seeSoapResponseEquals($xml)
    {
        $xml = SoapUtils::toXml($xml);
        $this->assertEquals($xml->C14N(), $this->getXmlResponse()->C14N());
    }

    /**
     * Checks XML response includes provided XML.
     * Comparison is done by canonicalizing both xml`s.
     * Parameter can be passed either as XmlBuilder, DOMDocument, DOMNode, XML string, or array (if no attributes).
     *
     * Example:
     *
     * ``` php
     * <?php
     * $I->seeSoapResponseIncludes("<result>1</result>");
     * $I->seeSoapRequestIncludes(\Codeception\Utils\Soap::response()->result->val(1));
     *
     * $dom = new \DDOMDocument();
     * $dom->load('template.xml');
     * $I->seeSoapRequestIncludes($dom);
     * ?>
     * ```
     *
     * @param $xml
     */
    public function seeSoapResponseIncludes($xml)
    {
        $xml = $this->canonicalize($xml);
        $this->assertStringContainsString($xml, $this->getXmlResponse()->C14N(), "found in XML Response");
    }


    /**
     * Checks XML response equals provided XML.
     * Comparison is done by canonicalizing both xml`s.
     *
     * Parameter can be passed either as XmlBuilder, DOMDocument, DOMNode, XML string, or array (if no attributes).
     *
     * @param $xml
     */
    public function dontSeeSoapResponseEquals($xml)
    {
        $xml = SoapUtils::toXml($xml);
        \PHPUnit\Framework\Assert::assertXmlStringNotEqualsXmlString($xml->C14N(), $this->getXmlResponse()->C14N());
    }


    /**
     * Checks XML response does not include provided XML.
     * Comparison is done by canonicalizing both xml`s.
     * Parameter can be passed either as XmlBuilder, DOMDocument, DOMNode, XML string, or array (if no attributes).
     *
     * @param $xml
     */
    public function dontSeeSoapResponseIncludes($xml)
    {
        $xml = $this->canonicalize($xml);
        $this->assertStringNotContainsString($xml, $this->getXmlResponse()->C14N(), "found in XML Response");
    }

    /**
     * Checks XML response contains provided structure.
     * Response elements will be compared with XML provided.
     * Only nodeNames are checked to see elements match.
     *
     * Example:
     *
     * ``` php
     * <?php
     *
     * $I->seeSoapResponseContainsStructure("<query><name></name></query>");
     * ?>
     * ```
     *
     * Use this method to check XML of valid structure is returned.
     * This method does not use schema for validation.
     * This method does not require path from root to match the structure.
     *
     * @param $xml
     */
    public function seeSoapResponseContainsStructure($xml)
    {
        $xml = SoapUtils::toXml($xml);
        $this->debugSection("Structure", $xml->saveXML());
        $this->assertTrue((bool)$this->getXmlStructure()->matchXmlStructure($xml), "this structure is in response");
    }

    /**
     * Opposite to `seeSoapResponseContainsStructure`
     * @param $xml
     */
    public function dontSeeSoapResponseContainsStructure($xml)
    {
        $xml = SoapUtils::toXml($xml);
        $this->debugSection("Structure", $xml->saveXML());
        $this->assertFalse((bool)$this->getXmlStructure()->matchXmlStructure($xml), "this structure is in response");
    }

    /**
     * Checks XML response with XPath locator
     *
     * ``` php
     * <?php
     * $I->seeSoapResponseContainsXPath('//root/user[@id=1]');
     * ?>
     * ```
     *
     * @param $xpath
     */
    public function seeSoapResponseContainsXPath($xpath)
    {
        $this->assertTrue($this->getXmlStructure()->matchesXpath($xpath));
    }

    /**
     * Checks XML response doesn't contain XPath locator
     *
     * ``` php
     * <?php
     * $I->dontSeeSoapResponseContainsXPath('//root/user[@id=1]');
     * ?>
     * ```
     *
     * @param $xpath
     */
    public function dontSeeSoapResponseContainsXPath($xpath)
    {
        $this->assertFalse($this->getXmlStructure()->matchesXpath($xpath));
    }


    /**
     * Checks response code from server.
     *
     * @param $code
     */
    public function seeSoapResponseCodeIs($code)
    {
        $this->assertEquals(
            $code,
            $this->client->getInternalResponse()->getStatus(),
            "soap response code matches expected"
        );
    }

    /**
     * Finds and returns text contents of element.
     * Element is matched by either CSS or XPath
     *
     * @version 1.1
     * @param $cssOrXPath
     * @return string
     */
    public function grabTextContentFrom($cssOrXPath)
    {
        $el = $this->getXmlStructure()->matchElement($cssOrXPath);
        return $el->textContent;
    }

    /**
     * Finds and returns attribute of element.
     * Element is matched by either CSS or XPath
     *
     * @version 1.1
     * @param $cssOrXPath
     * @param $attribute
     * @return string
     */
    public function grabAttributeFrom($cssOrXPath, $attribute)
    {
        $el = $this->getXmlStructure()->matchElement($cssOrXPath);
        if (!$el->hasAttribute($attribute)) {
            $this->fail("Attribute not found in element matched by '$cssOrXPath'");
        }
        return $el->getAttribute($attribute);
    }

    protected function getSchema()
    {
        return $this->config['schema'];
    }

    protected function canonicalize($xml)
    {
        return SoapUtils::toXml($xml)->C14N();
    }

    /**
     * @return \DOMDocument
     */
    protected function buildRequest()
    {
        $soap_schema_url = $this->config['schema_url'];
        $xml = new \DOMDocument();
        $root = $xml->createElement('soapenv:Envelope');
        $xml->appendChild($root);
        $root->setAttribute('xmlns:ns', $this->getSchema());
        $root->setAttribute('xmlns:soapenv', $soap_schema_url);
        $body = $xml->createElementNS($soap_schema_url, 'soapenv:Body');
        $header = $xml->createElementNS($soap_schema_url, 'soapenv:Header');
        $root->appendChild($header);
        $root->appendChild($body);
        $this->xmlRequest = $xml;
        return $xml;
    }

    protected function processRequest($action, $body)
    {
        $this->getClient()->request(
            'POST',
            $this->config['endpoint'],
            [],
            [],
            [
                'HTTP_Content-Type' => 'text/xml; charset=UTF-8',
                'HTTP_Content-Length' => strlen($body),
                'HTTP_SOAPAction' => isset($this->config['SOAPAction']) ? $this->config['SOAPAction'] : $action
            ],
            $body
        );
    }

    protected function processInternalRequest($action, $body)
    {
        ob_start();
        try {
            $this->getClient()->setServerParameter('HTTP_HOST', 'localhost');
            $this->processRequest($action, $body);
        } catch (\ErrorException $e) {
            // Zend_Soap outputs warning as an exception
            if (strpos($e->getMessage(), 'Warning: Cannot modify header information') === false) {
                ob_end_clean();
                throw $e;
            }
        }
        $response = ob_get_contents();
        ob_end_clean();
        return $response;
    }

    protected function processExternalRequest($action, $body)
    {
        $this->processRequest($action, $body);
        return $this->client->getInternalResponse()->getContent();
    }
}
<?php

namespace Codeception\Lib;

use Codeception\Exception\ElementNotFound;
use Codeception\Exception\ExternalUrlException;
use Codeception\Exception\MalformedLocatorException;
use Codeception\Exception\ModuleException;
use Codeception\Exception\TestRuntimeException;
use Codeception\Lib\Interfaces\ConflictsWithModule;
use Codeception\Lib\Interfaces\ElementLocator;
use Codeception\Lib\Interfaces\PageSourceSaver;
use Codeception\Lib\Interfaces\Web;
use Codeception\Module;
use Codeception\PHPUnit\Constraint\Crawler as CrawlerConstraint;
use Codeception\PHPUnit\Constraint\CrawlerNot as CrawlerNotConstraint;
use Codeception\PHPUnit\Constraint\Page as PageConstraint;
use Codeception\Test\Descriptor;
use Codeception\TestInterface;
use Codeception\Util\HttpCode;
use Codeception\Util\Locator;
use Codeception\Util\ReflectionHelper;
use Codeception\Util\Uri;
use DOMDocument;
use DOMNode;
use InvalidArgumentException;
use LogicException;
use Symfony\Component\BrowserKit\AbstractBrowser;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\BrowserKit\Exception\BadMethodCallException;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\DomCrawler\Crawler as SymfonyCrawler;
use Symfony\Component\DomCrawler\Field\ChoiceFormField;
use Symfony\Component\DomCrawler\Field\FileFormField;
use Symfony\Component\DomCrawler\Field\FormField;
use Symfony\Component\DomCrawler\Field\InputFormField;
use Symfony\Component\DomCrawler\Field\TextareaFormField;
use Symfony\Component\DomCrawler\Form as SymfonyForm;
use Symfony\Component\DomCrawler\Link;

//Alias for Symfony < 4.3
if (!class_exists('Symfony\Component\BrowserKit\AbstractBrowser') && class_exists('Symfony\Component\BrowserKit\Client')) {
    class_alias('Symfony\Component\BrowserKit\Client', 'Symfony\Component\BrowserKit\AbstractBrowser');
}

class InnerBrowser extends Module implements Web, PageSourceSaver, ElementLocator, ConflictsWithModule
{
    /**
     * @var SymfonyCrawler
     */
    protected $crawler;

    /**
     * @api
     * @var AbstractBrowser
     */
    public $client;

    /**
     * @var array|SymfonyForm[]
     */
    protected $forms = [];

    /**
     * @var string[]
     */
    public $headers = [];

    /**
     * @var array<string, string>|array<string, bool>|array<string, null>
     */
    protected $defaultCookieParameters = ['expires' => null, 'path' => '/', 'domain' => '', 'secure' => false];

    protected $internalDomains;

    private $baseUrl;

    public function _failed(TestInterface $test, $fail)
    {
        try {
            if (!$this->client || !$this->client->getInternalResponse()) {
                return;
            }
        } catch (BadMethodCallException $e) {
            //Symfony 5 throws exception if request() method threw an exception.
            //The "request()" method must be called before "Symfony\Component\BrowserKit\AbstractBrowser::getInternalResponse()"
            return;
        }
        $filename = preg_replace('#\W#', '.', Descriptor::getTestSignatureUnique($test));

        $extensions = [
            'application/json' => 'json',
            'text/xml' => 'xml',
            'application/xml' => 'xml',
            'text/plain' => 'txt'
        ];

        try {
            $internalResponse = $this->client->getInternalResponse();
        } catch (BadMethodCallException $e) {
            $internalResponse = false;
        }

        $responseContentType = $internalResponse ? $internalResponse->getHeader('content-type') : '';
        list($responseMimeType) = explode(';', $responseContentType);

        $extension = isset($extensions[$responseMimeType]) ? $extensions[$responseMimeType] : 'html';

        $filename = mb_strcut($filename, 0, 244, 'utf-8') . '.fail.' . $extension;
        $this->_savePageSource($report = codecept_output_dir() . $filename);
        $test->getMetadata()->addReport('html', $report);
        $test->getMetadata()->addReport('response', $report);
    }

    public function _after(TestInterface $test)
    {
        $this->client = null;
        $this->crawler = null;
        $this->forms = [];
        $this->headers = [];
    }

    public function _conflicts()
    {
        return \Codeception\Lib\Interfaces\Web::class;
    }

    public function _findElements($locator)
    {
        return $this->match($locator);
    }

    /**
     * Send custom request to a backend using method, uri, parameters, etc.
     * Use it in Helpers to create special request actions, like accessing API
     * Returns a string with response body.
     *
     * ```php
     * <?php
     * // in Helper class
     * public function createUserByApi($name) {
     *     $userData = $this->getModule('{{MODULE_NAME}}')->_request('POST', '/api/v1/users', ['name' => $name]);
     *     $user = json_decode($userData);
     *     return $user->id;
     * }
     * ```
     * Does not load the response into the module so you can't interact with response page (click, fill forms).
     * To load arbitrary page for interaction, use `_loadPage` method.
     *
     * @api
     * @param string $method
     * @param string $uri
     * @param string $content
     * @return string
     * @throws ExternalUrlException
     * @see `_loadPage`
     */
    public function _request(
        $method,
        $uri,
        array $parameters = [],
        array $files = [],
        array $server = [],
        $content = null
    ) {
        $this->clientRequest($method, $uri, $parameters, $files, $server, $content);
        return $this->_getResponseContent();
    }

    /**
     * Returns content of the last response
     * Use it in Helpers when you want to retrieve response of request performed by another module.
     *
     * ```php
     * <?php
     * // in Helper class
     * public function seeResponseContains($text)
     * {
     *    $this->assertStringContainsString($text, $this->getModule('{{MODULE_NAME}}')->_getResponseContent(), "response contains");
     * }
     * ```
     *
     * @api
     * @return string
     * @throws ModuleException
     */
    public function _getResponseContent()
    {
        return (string)$this->getRunningClient()->getInternalResponse()->getContent();
    }

    /**
     * @param string $method
     * @param string $uri
     * @param string $content
     * @param bool $changeHistory
     * @return SymfonyCrawler
     */
    protected function clientRequest($method, $uri, array $parameters = [], array $files = [], array $server = [], $content = null, $changeHistory = true)
    {
        $this->debugSection("Request Headers", $this->headers);

        foreach ($this->headers as $header => $val) { // moved from REST module

            if ($val === null || $val === '') {
                continue;
            }

            $header = str_replace('-', '_', strtoupper($header));
            $server["HTTP_$header"] = $val;

            // Issue #827 - symfony foundation requires 'CONTENT_TYPE' without HTTP_
            if ($this instanceof Framework && $header === 'CONTENT_TYPE') {
                $server[$header] = $val;
            }
        }
        $server['REQUEST_TIME'] = time();
        $server['REQUEST_TIME_FLOAT'] = microtime(true);
        if ($this instanceof Framework) {
            if (preg_match('#^(//|https?://(?!localhost))#', $uri)) {
                $hostname = parse_url($uri, PHP_URL_HOST);
                if (!$this->isInternalDomain($hostname)) {
                    throw new ExternalUrlException(get_class($this) . " can't open external URL: " . $uri);
                }
            }

            if (!in_array($method, ['GET', 'HEAD', 'OPTIONS'], true) && $content === null && !empty($parameters)) {
                $content = http_build_query($parameters);
            }
        }

        if (method_exists($this->client, 'isFollowingRedirects')) {
            $isFollowingRedirects = $this->client->isFollowingRedirects();
            $maxRedirects = $this->client->getMaxRedirects();
        } else {
            //Symfony 2.7 support
            $isFollowingRedirects = ReflectionHelper::readPrivateProperty($this->client, 'followRedirects', 'Symfony\Component\BrowserKit\Client');
            $maxRedirects = ReflectionHelper::readPrivateProperty($this->client, 'maxRedirects', 'Symfony\Component\BrowserKit\Client');
        }

        if (!$isFollowingRedirects) {
            $result = $this->client->request($method, $uri, $parameters, $files, $server, $content, $changeHistory);
            $this->debugResponse($uri);
            return $result;
        }

        $this->client->followRedirects(false);
        $result = $this->client->request($method, $uri, $parameters, $files, $server, $content, $changeHistory);
        $this->debugResponse($uri);
        return $this->redirectIfNecessary($result, $maxRedirects, 0);
    }

    /**
     * @return bool
     */
    protected function isInternalDomain($domain)
    {
        if ($this->internalDomains === null) {
            $this->internalDomains = $this->getInternalDomains();
        }

        foreach ($this->internalDomains as $pattern) {
            if (preg_match($pattern, $domain)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Opens a page with arbitrary request parameters.
     * Useful for testing multi-step forms on a specific step.
     *
     * ```php
     * <?php
     * // in Helper class
     * public function openCheckoutFormStep2($orderId) {
     *     $this->getModule('{{MODULE_NAME}}')->_loadPage('POST', '/checkout/step2', ['order' => $orderId]);
     * }
     * ```
     *
     * @api
     * @param string $method
     * @param string $uri
     * @param string $content
     */
    public function _loadPage(
        $method,
        $uri,
        array $parameters = [],
        array $files = [],
        array $server = [],
        $content = null
    ) {
        $this->crawler = $this->clientRequest($method, $uri, $parameters, $files, $server, $content);
        $this->baseUrl = $this->retrieveBaseUrl();
        $this->forms = [];
    }

    /**
     * @return SymfonyCrawler
     * @throws ModuleException
     */
    private function getCrawler()
    {
        if (!$this->crawler) {
            throw new ModuleException($this, 'Crawler is null. Perhaps you forgot to call "amOnPage"?');
        }
        return $this->crawler;
    }

    private function getRunningClient()
    {
        try {
            if ($this->client->getInternalRequest() === null) {
                throw new ModuleException(
                    $this,
                    "Page not loaded. Use `\$I->amOnPage` (or hidden API methods `_request` and `_loadPage`) to open it"
                );
            }
        } catch (BadMethodCallException $e) {
            //Symfony 5
            throw new ModuleException(
                $this,
                "Page not loaded. Use `\$I->amOnPage` (or hidden API methods `_request` and `_loadPage`) to open it"
            );
        }
        return $this->client;
    }

    public function _savePageSource($filename)
    {
        file_put_contents($filename, $this->_getResponseContent());
    }

    /**
     * Authenticates user for HTTP_AUTH
     *
     * @param string $username
     * @param string $password
     */
    public function amHttpAuthenticated($username, $password)
    {
        $this->client->setServerParameter('PHP_AUTH_USER', $username);
        $this->client->setServerParameter('PHP_AUTH_PW', $password);
    }

    /**
     * Sets the HTTP header to the passed value - which is used on
     * subsequent HTTP requests through PhpBrowser.
     *
     * Example:
     * ```php
     * <?php
     * $I->haveHttpHeader('X-Requested-With', 'Codeception');
     * $I->amOnPage('test-headers.php');
     * ```
     *
     * To use special chars in Header Key use HTML Character Entities:
     * Example:
     * Header with underscore - 'Client_Id'
     * should be represented as - 'Client&#x0005F;Id' or 'Client&#95;Id'
     *
     * ```php
     * <?php
     * $I->haveHttpHeader('Client&#95;Id', 'Codeception');
     * ```
     *
     * @param string $name the name of the request header
     * @param string $value the value to set it to for subsequent
     *        requests
     */
    public function haveHttpHeader($name, $value)
    {
        $name = implode('-', array_map('ucfirst', explode('-', strtolower(str_replace('_', '-', $name)))));
        $this->headers[$name] = $value;
    }

    /**
     * Deletes the header with the passed name.  Subsequent requests
     * will not have the deleted header in its request.
     *
     * Example:
     * ```php
     * <?php
     * $I->haveHttpHeader('X-Requested-With', 'Codeception');
     * $I->amOnPage('test-headers.php');
     * // ...
     * $I->deleteHeader('X-Requested-With');
     * $I->amOnPage('some-other-page.php');
     * ```
     *
     * @param string $name the name of the header to delete.
     */
    public function deleteHeader($name)
    {
        $name = implode('-', array_map('ucfirst', explode('-', strtolower(str_replace('_', '-', $name)))));
        unset($this->headers[$name]);
    }

    public function amOnPage($page)
    {
        $this->_loadPage('GET', $page);
    }

    public function click($link, $context = null)
    {
        if ($context) {
            $this->crawler = $this->match($context);
        }

        if (is_array($link)) {
            $this->clickByLocator($link);
            return;
        }

        $anchor = $this->strictMatch(['link' => $link]);
        if (count($anchor) === 0) {
            $anchor = $this->getCrawler()->selectLink($link);
        }
        if (count($anchor) > 0) {
            $this->openHrefFromDomNode($anchor->getNode(0));
            return;
        }

        $buttonText = str_replace('"', "'", $link);
        $button = $this->crawler->selectButton($buttonText);

        if (count($button) && $this->clickButton($button->getNode(0))) {
            return;
        }

        try {
            $this->clickByLocator($link);
        } catch (MalformedLocatorException $e) {
            throw new ElementNotFound("name=$link", "'$link' is invalid CSS and XPath selector and Link or Button");
        }
    }

    /**
     * @param $link
     * @return bool
     */
    protected function clickByLocator($link)
    {
        $nodes = $this->match($link);
        if ($nodes->count() === 0) {
            throw new ElementNotFound($link, 'Link or Button by name or CSS or XPath');
        }

        foreach ($nodes as $node) {
            $tag = $node->tagName;
            $type = $node->getAttribute('type');

            if ($tag === 'a') {
                $this->openHrefFromDomNode($node);
                return true;
            }

            if (in_array($tag, ['input', 'button']) && in_array($type, ['submit', 'image'])) {
                return $this->clickButton($node);
            }
        }
    }

    /**
     * Clicks the link or submits the form when the button is clicked
     *
     * @return bool clicked something
     */
    private function clickButton(DOMNode $node)
    {
        /**
         * First we check if the button is associated to a form.
         * It is associated to a form when it has a nonempty form
         */
        $formAttribute = $node->attributes->getNamedItem('form');
        if (isset($formAttribute)) {
            $form = empty($formAttribute->nodeValue) ? null : $this->filterByCSS('#' . $formAttribute->nodeValue)->getNode(0);
        } else {
            // Check parents
            $currentNode = $node;
            $form = null;
            while ($currentNode->parentNode !== null) {
                $currentNode = $currentNode->parentNode;
                if ($currentNode->nodeName === 'form') {
                    $form = $node;
                    break;
                }
            }
        }

        if (isset($form)) {
            $buttonName = $node->getAttribute('name');
            $formParams = $buttonName !== '' ? [$buttonName => $node->getAttribute('value')] : [];
            $this->proceedSubmitForm(
                new SymfonyCrawler($form, $this->getAbsoluteUrlFor($this->_getCurrentUri()), $this->getBaseUrl()),
                $formParams
            );
            return true;
        }

        // Check if the button is inside an anchor.
        $currentNode = $node;
        while ($currentNode->parentNode !== null) {
            $currentNode = $currentNode->parentNode;
            if ($currentNode->nodeName === 'a') {
                $this->openHrefFromDomNode($currentNode);
                return true;
            }
        }
        throw new TestRuntimeException('Button is not inside a link or a form');
    }

    private function openHrefFromDomNode(DOMNode $node)
    {
        $link = new Link($node, $this->getBaseUrl());
        $this->amOnPage(preg_replace('/#.*/', '', $link->getUri()));
    }

    private function getBaseUrl()
    {
        return $this->baseUrl;
    }

    /**
     * @return string
     */
    private function retrieveBaseUrl()
    {
        $baseUrl = '';

        $baseHref = $this->crawler->filter('base');
        if (count($baseHref) > 0) {
            $baseUrl = $baseHref->getNode(0)->getAttribute('href');
        }
        if ($baseUrl === '') {
            $baseUrl = $this->_getCurrentUri();
        }
        return $this->getAbsoluteUrlFor($baseUrl);
    }

    public function see($text, $selector = null)
    {
        if (!$selector) {
            $this->assertPageContains($text);
            return;
        }

        $nodes = $this->match($selector);
        $this->assertDomContains($nodes, $this->stringifySelector($selector), $text);
    }

    public function dontSee($text, $selector = null)
    {
        if (!$selector) {
            $this->assertPageNotContains($text);
            return;
        }

        $nodes = $this->match($selector);
        $this->assertDomNotContains($nodes, $this->stringifySelector($selector), $text);
    }

    public function seeInSource($raw)
    {
        $this->assertPageSourceContains($raw);
    }

    public function dontSeeInSource($raw)
    {
        $this->assertPageSourceNotContains($raw);
    }

    public function seeLink($text, $url = null)
    {
        $crawler = $this->getCrawler()->selectLink($text);
        if ($crawler->count() === 0) {
            $this->fail("No links containing text '$text' were found in page " . $this->_getCurrentUri());
        }
        if ($url) {
            $crawler = $crawler->filterXPath(sprintf('.//a[substring(@href, string-length(@href) - string-length(%1$s) + 1)=%1$s]', SymfonyCrawler::xpathLiteral($url)));
            if ($crawler->count() === 0) {
                $this->fail("No links containing text '$text' and URL '$url' were found in page " . $this->_getCurrentUri());
            }
        }
        $this->assertTrue(true);
    }

    public function dontSeeLink($text, $url = '')
    {
        $crawler = $this->getCrawler()->selectLink($text);
        if (!$url && $crawler->count() > 0) {
            $this->fail("Link containing text '$text' was found in page " . $this->_getCurrentUri());
        }
        $crawler = $crawler->filterXPath(
            sprintf('.//a[substring(@href, string-length(@href) - string-length(%1$s) + 1)=%1$s]',
                SymfonyCrawler::xpathLiteral($url))
        );
        if ($crawler->count() > 0) {
            $this->fail("Link containing text '$text' and URL '$url' was found in page " . $this->_getCurrentUri());
        }
    }

    /**
     * @return string
     * @throws ModuleException
     */
    public function _getCurrentUri()
    {
        return Uri::retrieveUri($this->getRunningClient()->getHistory()->current()->getUri());
    }

    public function seeInCurrentUrl($uri)
    {
        $this->assertStringContainsString($uri, $this->_getCurrentUri());
    }

    public function dontSeeInCurrentUrl($uri)
    {
        $this->assertStringNotContainsString($uri, $this->_getCurrentUri());
    }

    public function seeCurrentUrlEquals($uri)
    {
        $this->assertEquals(rtrim($uri, '/'), rtrim($this->_getCurrentUri(), '/'));
    }

    public function dontSeeCurrentUrlEquals($uri)
    {
        $this->assertNotEquals(rtrim($uri, '/'), rtrim($this->_getCurrentUri(), '/'));
    }

    public function seeCurrentUrlMatches($uri)
    {
        $this->assertRegExp($uri, $this->_getCurrentUri());
    }

    public function dontSeeCurrentUrlMatches($uri)
    {
        $this->assertNotRegExp($uri, $this->_getCurrentUri());
    }

    public function grabFromCurrentUrl($uri = null)
    {
        if (!$uri) {
            return $this->_getCurrentUri();
        }
        $matches = [];
        $res     = preg_match($uri, $this->_getCurrentUri(), $matches);
        if (!$res) {
            $this->fail("Couldn't match $uri in " . $this->_getCurrentUri());
        }
        if (!isset($matches[1])) {
            $this->fail("Nothing to grab. A regex parameter required. Ex: '/user/(\\d+)'");
        }
        return $matches[1];
    }

    public function seeCheckboxIsChecked($checkbox)
    {
        $checkboxes = $this->getFieldsByLabelOrCss($checkbox);
        $this->assertDomContains($checkboxes->filter('input[checked=checked]'), 'checkbox');
    }

    public function dontSeeCheckboxIsChecked($checkbox)
    {
        $checkboxes = $this->getFieldsByLabelOrCss($checkbox);
        $this->assertEquals(0, $checkboxes->filter('input[checked=checked]')->count());
    }

    public function seeInField($field, $value)
    {
        $nodes = $this->getFieldsByLabelOrCss($field);
        $this->assert($this->proceedSeeInField($nodes, $value));
    }

    public function dontSeeInField($field, $value)
    {
        $nodes = $this->getFieldsByLabelOrCss($field);
        $this->assertNot($this->proceedSeeInField($nodes, $value));
    }

    public function seeInFormFields($formSelector, array $params)
    {
        $this->proceedSeeInFormFields($formSelector, $params, false);
    }

    public function dontSeeInFormFields($formSelector, array $params)
    {
        $this->proceedSeeInFormFields($formSelector, $params, true);
    }

    protected function proceedSeeInFormFields($formSelector, array $params, $assertNot)
    {
        $form = $this->match($formSelector)->first();
        if ($form->count() === 0) {
            throw new ElementNotFound($formSelector, 'Form');
        }

        $fields = [];
        foreach ($params as $name => $values) {
            $this->pushFormField($fields, $form, $name, $values);
        }

        foreach ($fields as list($field, $values)) {
            if (!is_array($values)) {
                $values = [$values];
            }

            foreach ($values as $value) {
                $ret = $this->proceedSeeInField($field, $value);
                if ($assertNot) {
                    $this->assertNot($ret);
                } else {
                    $this->assert($ret);
                }
            }
        }
    }

    /**
     * Map an array element passed to seeInFormFields to its corresponding field,
     * recursing through array values if the field is not found.
     *
     * @param array $fields The previously found fields.
     * @param SymfonyCrawler $form The form in which to search for fields.
     * @param string $name The field's name.
     * @param mixed $values
     * @return void
     */
    protected function pushFormField(&$fields, $form, $name, $values)
    {
        $field = $form->filterXPath(sprintf('.//*[@name=%s]', SymfonyCrawler::xpathLiteral($name)));

        if ($field->count()) {
            $fields[] = [$field, $values];
        } elseif (is_array($values)) {
            foreach ($values as $key => $value) {
                $this->pushFormField($fields, $form, "{$name}[$key]", $value);
            }
        } else {
            throw new ElementNotFound(
                sprintf('//*[@name=%s]', SymfonyCrawler::xpathLiteral($name)),
                'Form'
            );
        }
    }

    protected function proceedSeeInField(Crawler $fields, $value)
    {
        $testValues = $this->getValueAndTextFromField($fields);
        if (!is_array($testValues)) {
            $testValues = [$testValues];
        }
        if (is_bool($value) && $value && !empty($testValues)) {
            $value = reset($testValues);
        } elseif (empty($testValues)) {
            $testValues = [''];
        }
        return [
            'Contains',
            (string)$value,
            $testValues,
            sprintf(
                "Failed asserting that `%s` is in %s's value: %s",
                $value,
                $fields->getNode(0)->nodeName,
                var_export($testValues, true)
            )
        ];
    }

    /**
     * Get the values of a set of fields and also the texts of selected options.
     *
     * @return array|string
     */
    protected function getValueAndTextFromField(Crawler $nodes)
    {
        if ($nodes->filter('textarea')->count()) {
            return (new TextareaFormField($nodes->filter('textarea')->getNode(0)))->getValue();
        }

        $input = $nodes->filter('input');
        if ($input->count() !== 0) {
            return $this->getInputValue($input);
        }

        if ($nodes->filter('select')->count()) {
            $options = $nodes->filter('option[selected]');
            $values = [];

            foreach ($options as $option) {
                $values[] = $option->getAttribute('value');
                $values[] = $option->textContent;
                $values[] = trim($option->textContent);
            }

            return $values;
        }

        $this->fail("Element $nodes is not a form field or does not contain a form field");
    }

    /**
     * Get the values of a set of input fields.
     *
     * @param SymfonyCrawler $input
     * @return array|string
     */
    protected function getInputValue($input)
    {
        $inputType = $input->attr('type');
        if ($inputType === 'checkbox' || $inputType === 'radio') {
            $values = [];

            foreach ($input->filter(':checked') as $checkbox) {
                $values[] = $checkbox->getAttribute('value');
            }

            return $values;
        }

        return (new InputFormField($input->getNode(0)))->getValue();
    }

    /**
     * Strips out one pair of trailing square brackets from a field's
     * name.
     *
     * @param string $name the field name
     * @return string the name after stripping trailing square brackets
     */
    protected function getSubmissionFormFieldName($name)
    {
        if (substr($name, -2) === '[]') {
            return substr($name, 0, -2);
        }
        return $name;
    }

    /**
     * Replaces boolean values in $params with the corresponding field's
     * value for checkbox form fields.
     *
     * The function loops over all input checkbox fields, checking if a
     * corresponding key is set in $params.  If it is, and the value is
     * boolean or an array containing booleans, the value(s) are
     * replaced in the array with the real value of the checkbox, and
     * the array is returned.
     *
     * @param SymfonyCrawler $form the form to find checkbox elements
     * @param array $params the parameters to be submitted
     * @return array the $params array after replacing bool values
     */
    protected function setCheckboxBoolValues(Crawler $form, array $params)
    {
        $checkboxes = $form->filter('input[type=checkbox]');
        $chFoundByName = [];
        foreach ($checkboxes as $checkbox) {
            $fieldName = $this->getSubmissionFormFieldName($checkbox->getAttribute('name'));
            $pos = (isset($chFoundByName[$fieldName])) ? $chFoundByName[$fieldName] : 0;
            $skip = !isset($params[$fieldName])
                || (!is_array($params[$fieldName]) && !is_bool($params[$fieldName]))
                || (is_array($params[$fieldName]) &&
                    ($pos >= count($params[$fieldName]) || !is_bool($params[$fieldName][$pos]))
                );

            if ($skip) {
                continue;
            }
            $values = $params[$fieldName];
            if ($values === true) {
                $params[$fieldName] = $checkbox->hasAttribute('value') ? $checkbox->getAttribute('value') : 'on';
                $chFoundByName[$fieldName] = $pos + 1;
            } elseif (is_array($values)) {
                if ($values[$pos] === true) {
                    $params[$fieldName][$pos] = $checkbox->hasAttribute('value') ? $checkbox->getAttribute('value') : 'on';
                    $chFoundByName[$fieldName] = $pos + 1;
                } else {
                    array_splice($params[$fieldName], $pos, 1);
                }
            } else {
                unset($params[$fieldName]);
            }
        }
        return $params;
    }

    /**
     * Submits the form currently selected in the passed SymfonyCrawler, after
     * setting any values passed in $params and setting the value of the
     * passed button name.
     *
     * @param SymfonyCrawler $frmCrawl the form to submit
     * @param array $params additional parameter values to set on the
     *        form
     * @param string $button the name of a submit button in the form
     */
    protected function proceedSubmitForm(Crawler $frmCrawl, array $params, $button = null)
    {
        $url = null;
        $form = $this->getFormFor($frmCrawl);
        $defaults = $this->getFormValuesFor($form);
        $merged = array_merge($defaults, $params);
        $requestParams = $this->setCheckboxBoolValues($frmCrawl, $merged);

        if (!empty($button)) {
            $btnCrawl = $frmCrawl->filterXPath(sprintf(
                '//*[not(@disabled) and @type="submit" and @name=%s]',
                SymfonyCrawler::xpathLiteral($button)
            ));
            if (count($btnCrawl) > 0) {
                $requestParams[$button] = $btnCrawl->attr('value');
                $formaction = $btnCrawl->attr('formaction');
                if ($formaction) {
                    $url = $formaction;
                }
            }
        }

        if (!$url) {
            $url = $this->getFormUrl($frmCrawl);
        }

        if (strcasecmp($form->getMethod(), 'GET') === 0) {
            $url = Uri::mergeUrls($url, '?' . http_build_query($requestParams));
        }

        $url = preg_replace('#\#.*#', '', $url);

        $this->debugSection('Uri', $url);
        $this->debugSection('Method', $form->getMethod());
        $this->debugSection('Parameters', $requestParams);

        $requestParams= $this->getFormPhpValues($requestParams);

        $this->crawler = $this->clientRequest(
            $form->getMethod(),
            $url,
            $requestParams,
            $form->getPhpFiles()
        );
        $this->forms = [];
    }

    public function submitForm($selector, array $params, $button = null)
    {
        $form = $this->match($selector)->first();
        if (count($form) === 0) {
            throw new ElementNotFound($this->stringifySelector($selector), 'Form');
        }
        $this->proceedSubmitForm($form, $params, $button);
    }

    /**
     * Returns an absolute URL for the passed URI with the current URL
     * as the base path.
     *
     * @param string $uri the absolute or relative URI
     * @return string the absolute URL
     * @throws \Codeception\Exception\TestRuntimeException if either the current
     *         URL or the passed URI can't be parsed
     */
    protected function getAbsoluteUrlFor($uri)
    {
        $currentUrl = $this->getRunningClient()->getHistory()->current()->getUri();
        if (empty($uri) || strpos($uri, '#') === 0) {
            return $currentUrl;
        }
        return Uri::mergeUrls($currentUrl, $uri);
    }

    /**
     * Returns the form action's absolute URL.
     *
     * @return string
     * @throws \Codeception\Exception\TestRuntimeException if either the current
     *         URL or the URI of the form's action can't be parsed
     */
    protected function getFormUrl(Crawler $form)
    {
        $action = $form->form()->getUri();
        return $this->getAbsoluteUrlFor($action);
    }

    /**
     * Returns a crawler Form object for the form pointed to by the
     * passed SymfonyCrawler.
     *
     * The returned form is an independent Crawler created to take care
     * of the following issues currently experienced by Crawler's form
     * object:
     *  - input fields disabled at a higher level (e.g. by a surrounding
     *    fieldset) still return values
     *  - Codeception expects an empty value to match an unselected
     *    select box.
     *
     * The function clones the crawler's node and creates a new crawler
     * because it destroys or adds to the DOM for the form to achieve
     * the desired functionality.  Other functions simply querying the
     * DOM wouldn't expect them.
     *
     * @param SymfonyCrawler $form the form
     * @return SymfonyForm
     */
    private function getFormFromCrawler(Crawler $form)
    {
        $fakeDom = new DOMDocument();
        $fakeDom->appendChild($fakeDom->importNode($form->getNode(0), true));

        //add fields having form attribute with id of this form
        $formId = $form->attr('id');
        if ($formId !== null) {
            $fakeForm = $fakeDom->firstChild;

            // The parents() method is deprecated since symfony/dom-crawler v5.3 (https://github.com/symfony/symfony/pull/39684)
            if (method_exists($form, 'ancestors')) {
                $topParent = $form->ancestors()->last();
            } else {
                $topParent = $form->parents()->last();
            }

            $fieldsByFormAttribute = $topParent->filter("input[form=$formId],select[form=$formId],textarea[form=$formId]");
            foreach ($fieldsByFormAttribute as $field) {
                $fakeForm->appendChild($fakeDom->importNode($field, true));
            }
        }

        $node = $fakeDom->documentElement;
        $action = $this->getFormUrl($form);
        $cloned = new SymfonyCrawler($node, $action, $this->getBaseUrl());
        $shouldDisable = $cloned->filter(
            'input:disabled:not([disabled]),select option:disabled,select optgroup:disabled option:not([disabled]),textarea:disabled:not([disabled]),select:disabled:not([disabled])'
        );
        foreach ($shouldDisable as $field) {
            $field->parentNode->removeChild($field);
        }
        return $cloned->form();
    }

    /**
     * Returns the DomCrawler\Form object for the form pointed to by
     * $node or its closes form parent.
     *
     * @return SymfonyForm
     */
    protected function getFormFor(Crawler $node)
    {
        if (strcasecmp($node->first()->getNode(0)->tagName, 'form') === 0) {
            $form = $node->first();
        } else {
            // The parents() method is deprecated since symfony/dom-crawler v5.3 (https://github.com/symfony/symfony/pull/39684)
            if (method_exists($node, 'ancestors')) {
                $form = $node->ancestors()->filter('form')->first();
            } else {
                $form = $node->parents()->filter('form')->first();
            }
        }
        if (!$form) {
            $this->fail('The selected node is not a form and does not have a form ancestor.');
        }

        $identifier = $form->attr('id') ?: $form->attr('action');
        if (!isset($this->forms[$identifier])) {
            $this->forms[$identifier] = $this->getFormFromCrawler($form);
        }
        return $this->forms[$identifier];
    }

    /**
     * Returns an array of name => value pairs for the passed form.
     *
     * For form fields containing a name ending in [], an array is
     * created out of all field values with the given name.
     *
     * @param SymfonyForm $form the form
     * @return array an array of name => value pairs
     */
    protected function getFormValuesFor(SymfonyForm $form)
    {
        $formNodeCrawler = new Crawler($form->getFormNode());
        $values = [];
        $fields = $form->all();
        foreach ($fields as $field) {
            if ($field instanceof FileFormField || $field->isDisabled()) {
                continue;
            }

            if (!$field->hasValue()) {
                // if unchecked a checkbox and if there is hidden input with same name to submit unchecked value
                $hiddenInput = $formNodeCrawler->filter('input[type=hidden][name="'.$field->getName().'"]:not([disabled])');
                if (!count($hiddenInput)) {
                    continue;
                } else {
                    // there might be multiple hidden input with same name, but we will only grab last one's value
                    $fieldValue = $hiddenInput->last()->attr('value');
                }
            } else {
                $fieldValue = $field->getValue();
            }


            $fieldName = $this->getSubmissionFormFieldName($field->getName());
            if (substr($field->getName(), -2) === '[]') {
                if (!isset($values[$fieldName])) {
                    $values[$fieldName] = [];
                }
                $values[$fieldName][] = $fieldValue;
            } else {
                $values[$fieldName] = $fieldValue;
            }
        }
        return $values;
    }

    public function fillField($field, $value)
    {
        $input = $this->getFieldByLabelOrCss($field);
        $form = $this->getFormFor($input);
        $name = $input->attr('name');

        $dynamicField = $input->getNode(0)->tagName === 'textarea'
            ? new TextareaFormField($input->getNode(0))
            : new InputFormField($input->getNode(0));
        $formField = $this->matchFormField($name, $form, $dynamicField);
        $formField->setValue($value);
        $input->getNode(0)->setAttribute('value', htmlspecialchars($value));
        $inputGetNode = $input->getNode(0);
        if ($inputGetNode->tagName === 'textarea') {
            $input->getNode(0)->nodeValue = htmlspecialchars($value);
        }
    }

    /**
     * @param $field
     * @return SymfonyCrawler
     */
    protected function getFieldsByLabelOrCss($field)
    {
        if (is_array($field)) {
            $input = $this->strictMatch($field);
            if (count($input) === 0) {
                throw new ElementNotFound($field);
            }
            return $input;
        }

        // by label
        $label = $this->strictMatch(['xpath' => sprintf('.//label[descendant-or-self::node()[text()[normalize-space()=%s]]]', SymfonyCrawler::xpathLiteral($field))]);
        if (count($label) > 0) {
            $label = $label->first();
            if ($label->attr('for')) {
                $input = $this->strictMatch(['id' => $label->attr('for')]);
            } else {
                $input = $this->strictMatch(['xpath' => sprintf('.//label[descendant-or-self::node()[text()[normalize-space()=%s]]]//input', SymfonyCrawler::xpathLiteral($field))]);
            }
        }

        // by name
        if (!isset($input)) {
            $input = $this->strictMatch(['name' => $field]);
        }

        // by CSS and XPath
        if (count($input) === 0) {
            $input = $this->match($field);
        }

        if (count($input) === 0) {
            throw new ElementNotFound($field, 'Form field by Label or CSS');
        }

        return $input;
    }

    /**
     * @return SymfonyCrawler
     */
    protected function getFieldByLabelOrCss($field)
    {
        $input = $this->getFieldsByLabelOrCss($field);
        return $input->first();
    }

    public function selectOption($select, $option)
    {
        $field = $this->getFieldByLabelOrCss($select);
        $form = $this->getFormFor($field);
        $fieldName = $this->getSubmissionFormFieldName($field->attr('name'));

        if (is_array($option)) {
            if (!isset($option[0])) { // strict option locator
                $form[$fieldName]->select($this->matchOption($field, $option));
                codecept_debug($option);
                return;
            }
            $options = [];
            foreach ($option as $opt) {
                $options[] = $this->matchOption($field, $opt);
            }
            $form[$fieldName]->select($options);
            return;
        }

        $dynamicField = new ChoiceFormField($field->getNode(0));
        $formField = $this->matchFormField($fieldName, $form, $dynamicField);
        $selValue = $this->matchOption($field, $option);

        if (is_array($formField)) {
            foreach ($formField as $field) {
                $values = $field->availableOptionValues();
                foreach ($values as $val) {
                    if ($val === $option) {
                        $field->select($selValue);
                        return;
                    }
                }
            }
            return;
        }

        $formField->select($this->matchOption($field, $option));
    }

    /**
     * @param string|array $option
     * @return string
     */
    protected function matchOption(Crawler $field, $option)
    {
        if (isset($option['value'])) {
            return $option['value'];
        }
        if (isset($option['text'])) {
            $option = $option['text'];
        }
        $options = $field->filterXPath(sprintf('//option[text()=normalize-space("%s")]|//input[@type="radio" and @value=normalize-space("%s")]', $option, $option));
        if ($options->count() !== 0) {
            $firstMatchingDomNode = $options->getNode(0);
            if ($firstMatchingDomNode->tagName === 'option') {
                $firstMatchingDomNode->setAttribute('selected', 'selected');
            } else {
                $firstMatchingDomNode->setAttribute('checked', 'checked');
            }
            $valueAttribute = $options->first()->attr('value');
            //attr() returns null when option has no value attribute
            if ($valueAttribute !== null) {
                return $valueAttribute;
            }
            return $options->first()->text();
        }
        return $option;
    }

    public function checkOption($option)
    {
        $this->proceedCheckOption($option)->tick();
    }

    public function uncheckOption($option)
    {
        $this->proceedCheckOption($option)->untick();
    }

    /**
     * @param $option
     * @return ChoiceFormField
     */
    protected function proceedCheckOption($option)
    {
        $form = $this->getFormFor($field = $this->getFieldByLabelOrCss($option));
        $name = $field->attr('name');

        if ($field->getNode(0) === null) {
            throw new TestRuntimeException("Form field $name is not located");
        }
        // If the name is an array than we compare objects to find right checkbox
        $formField = $this->matchFormField($name, $form, new ChoiceFormField($field->getNode(0)));
        $field->getNode(0)->setAttribute('checked', 'checked');
        if (!$formField instanceof ChoiceFormField) {
            throw new TestRuntimeException("Form field $name is not a checkable");
        }
        return $formField;
    }

    public function attachFile($field, $filename)
    {
        $form = $this->getFormFor($field = $this->getFieldByLabelOrCss($field));
        $filePath = codecept_data_dir() . $filename;
        if (!file_exists($filePath)) {
            throw new InvalidArgumentException("File does not exist: $filePath");
        }
        if (!is_readable($filePath)) {
            throw new InvalidArgumentException("File is not readable: $filePath");
        }

        $name = $field->attr('name');
        $formField = $this->matchFormField($name, $form, new FileFormField($field->getNode(0)));
        if (is_array($formField)) {
            $this->fail("Field $name is ignored on upload, field $name is treated as array.");
        }

        $formField->upload($filePath);
    }

    /**
     * Sends an ajax GET request with the passed parameters.
     * See `sendAjaxPostRequest()`
     *
     * @param $uri
     * @param $params
     */
    public function sendAjaxGetRequest($uri, $params = [])
    {
        $this->sendAjaxRequest('GET', $uri, $params);
    }

    /**
     * Sends an ajax POST request with the passed parameters.
     * The appropriate HTTP header is added automatically:
     * `X-Requested-With: XMLHttpRequest`
     * Example:
     * ``` php
     * <?php
     * $I->sendAjaxPostRequest('/add-task', ['task' => 'lorem ipsum']);
     * ```
     * Some frameworks (e.g. Symfony) create field names in the form of an "array":
     * `<input type="text" name="form[task]">`
     * In this case you need to pass the fields like this:
     * ``` php
     * <?php
     * $I->sendAjaxPostRequest('/add-task', ['form' => [
     *     'task' => 'lorem ipsum',
     *     'category' => 'miscellaneous',
     * ]]);
     * ```
     *
     * @param string $uri
     * @param array $params
     */
    public function sendAjaxPostRequest($uri, $params = [])
    {
        $this->sendAjaxRequest('POST', $uri, $params);
    }

    /**
     * Sends an ajax request, using the passed HTTP method.
     * See `sendAjaxPostRequest()`
     * Example:
     * ``` php
     * <?php
     * $I->sendAjaxRequest('PUT', '/posts/7', ['title' => 'new title']);
     * ```
     *
     * @param $method
     * @param $uri
     * @param array $params
     */
    public function sendAjaxRequest($method, $uri, $params = [])
    {
        $this->clientRequest($method, $uri, $params, [], ['HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'], null, false);
    }

    /**
     * @param $url
     */
    protected function debugResponse($url)
    {
        $this->debugSection('Page', $url);
        $this->debugSection('Response', $this->getResponseStatusCode());
        $this->debugSection('Request Cookies', $this->getRunningClient()->getInternalRequest()->getCookies());
        $this->debugSection('Response Headers', $this->getRunningClient()->getInternalResponse()->getHeaders());
    }

    public function makeHtmlSnapshot($name = null)
    {
        if (empty($name)) {
            $name = uniqid(date("Y-m-d_H-i-s_"), true);
        }
        $debugDir = codecept_output_dir() . 'debug';
        if (!is_dir($debugDir)) {
            mkdir($debugDir);
        }
        $fileName = $debugDir . DIRECTORY_SEPARATOR . $name . '.html';

        $this->_savePageSource($fileName);
        $this->debugSection('Snapshot Saved', "file://$fileName");
    }

    public function _getResponseStatusCode()
    {
        return $this->getResponseStatusCode();
    }

    protected function getResponseStatusCode()
    {
        // depending on Symfony version
        $response = $this->getRunningClient()->getInternalResponse();
        if (method_exists($response, 'getStatusCode')) {
            return $response->getStatusCode();
        }
        if (method_exists($response, 'getStatus')) {
            return $response->getStatus();
        }
        return "N/A";
    }

    /**
     * @param $selector
     * @return SymfonyCrawler
     */
    protected function match($selector)
    {
        if (is_array($selector)) {
            return $this->strictMatch($selector);
        }

        if (Locator::isCSS($selector)) {
            return $this->getCrawler()->filter($selector);
        }
        if (Locator::isXPath($selector)) {
            return $this->getCrawler()->filterXPath($selector);
        }
        throw new MalformedLocatorException($selector, 'XPath or CSS');
    }

    /**
     * @throws TestRuntimeException
     * @return SymfonyCrawler
     */
    protected function strictMatch(array $by)
    {
        $type = key($by);
        $locator = $by[$type];
        switch ($type) {
            case 'id':
                return $this->filterByCSS("#$locator");
            case 'name':
                return $this->filterByXPath(sprintf('.//*[@name=%s]', SymfonyCrawler::xpathLiteral($locator)));
            case 'css':
                return $this->filterByCSS($locator);
            case 'xpath':
                return $this->filterByXPath($locator);
            case 'link':
                return $this->filterByXPath(sprintf('.//a[.=%s or contains(./@title, %s)]', SymfonyCrawler::xpathLiteral($locator), SymfonyCrawler::xpathLiteral($locator)));
            case 'class':
                return $this->filterByCSS(".$locator");
            default:
                throw new TestRuntimeException(
                    "Locator type '$by' is not defined. Use either: xpath, css, id, link, class, name"
                );
        }
    }

    protected function filterByAttributes(Crawler $nodes, array $attributes)
    {
        foreach ($attributes as $attr => $val) {
            $nodes = $nodes->reduce(
                static function (Crawler $node) use ($attr, $val) {
                    return $node->attr($attr) === $val;
                }
            );
        }
        return $nodes;
    }

    public function grabTextFrom($cssOrXPathOrRegex)
    {
        if (is_string($cssOrXPathOrRegex) && @preg_match($cssOrXPathOrRegex, $this->client->getInternalResponse()->getContent(), $matches)) {
            return $matches[1];
        }
        $nodes = $this->match($cssOrXPathOrRegex);
        if ($nodes->count() !== 0) {
            return $nodes->first()->text();
        }
        throw new ElementNotFound($cssOrXPathOrRegex, 'Element that matches CSS or XPath or Regex');
    }

    public function grabAttributeFrom($cssOrXpath, $attribute)
    {
        $nodes = $this->match($cssOrXpath);
        if ($nodes->count() === 0) {
            throw new ElementNotFound($cssOrXpath, 'Element that matches CSS or XPath');
        }
        return $nodes->first()->attr($attribute);
    }

    public function grabMultiple($cssOrXpath, $attribute = null)
    {
        $result = [];
        $nodes = $this->match($cssOrXpath);

        foreach ($nodes as $node) {
            $result[] = $attribute !== null ? $node->getAttribute($attribute) : $node->textContent;
        }
        return $result;
    }

    /**
     * @param $field
     *
     * @return array|mixed|null|string
     */
    public function grabValueFrom($field)
    {
        $nodes = $this->match($field);
        if ($nodes->count() === 0) {
            throw new ElementNotFound($field, 'Field');
        }

        if ($nodes->filter('textarea')->count() !== 0) {
            return (new TextareaFormField($nodes->filter('textarea')->getNode(0)))->getValue();
        }

        $input = $nodes->filter('input');
        if ($input->count() !== 0) {
            return $this->getInputValue($input);
        }

        if ($nodes->filter('select')->count() !== 0) {
            $field = new ChoiceFormField($nodes->filter('select')->getNode(0));
            $options = $nodes->filter('option[selected]');
            $values = [];

            foreach ($options as $option) {
                $values[] = $option->getAttribute('value');
            }

            if (!$field->isMultiple()) {
                return reset($values);
            }

            return $values;
        }

        $this->fail("Element $nodes is not a form field or does not contain a form field");
    }

    public function setCookie($name, $val, array $params = [])
    {
        $cookies = $this->client->getCookieJar();
        $params = array_merge($this->defaultCookieParameters, $params);

        $expires      = isset($params['expiry']) ? $params['expiry'] : null; // WebDriver compatibility
        $expires      = isset($params['expires']) && !$expires ? $params['expires'] : null;

        $path         = isset($params['path'])    ? $params['path'] : null;
        $domain       = isset($params['domain'])  ? $params['domain'] : '';
        $secure       = isset($params['secure'])  ? $params['secure'] : false;
        $httpOnly     = isset($params['httpOnly'])  ? $params['httpOnly'] : true;
        $encodedValue = isset($params['encodedValue'])  ? $params['encodedValue'] : false;



        $cookies->set(new Cookie($name, $val, $expires, $path, $domain, $secure, $httpOnly, $encodedValue));
        $this->debugCookieJar();
    }

    public function grabCookie($cookie, array $params = [])
    {
        $params = array_merge($this->defaultCookieParameters, $params);
        $this->debugCookieJar();
        $cookies = $this->getRunningClient()->getCookieJar()->get($cookie, $params['path'], $params['domain']);
        if (!$cookies) {
            return null;
        }
        return $cookies->getValue();
    }

    /**
     * Grabs current page source code.
     *
     * @throws ModuleException if no page was opened.
     * @return string Current page source code.
     */
    public function grabPageSource()
    {
        return $this->_getResponseContent();
    }

    public function seeCookie($cookie, array $params = [])
    {
        $params = array_merge($this->defaultCookieParameters, $params);
        $this->debugCookieJar();
        $this->assertNotNull($this->client->getCookieJar()->get($cookie, $params['path'], $params['domain']));
    }

    public function dontSeeCookie($cookie, array $params = [])
    {
        $params = array_merge($this->defaultCookieParameters, $params);
        $this->debugCookieJar();
        $this->assertNull($this->client->getCookieJar()->get($cookie, $params['path'], $params['domain']));
    }

    public function resetCookie($cookie, array $params = [])
    {
        $params = array_merge($this->defaultCookieParameters, $params);
        $this->client->getCookieJar()->expire($cookie, $params['path'], $params['domain']);
        $this->debugCookieJar();
    }

    private function stringifySelector($selector)
    {
        if (is_array($selector)) {
            return trim(json_encode($selector), '{}');
        }
        return $selector;
    }

    public function seeElement($selector, $attributes = [])
    {
        $nodes = $this->match($selector);
        $selector = $this->stringifySelector($selector);
        if (!empty($attributes)) {
            $nodes = $this->filterByAttributes($nodes, $attributes);
            $selector .= "' with attribute(s) '" . trim(json_encode($attributes), '{}');
        }
        $this->assertDomContains($nodes, $selector);
    }

    public function dontSeeElement($selector, $attributes = [])
    {
        $nodes = $this->match($selector);
        $selector = $this->stringifySelector($selector);
        if (!empty($attributes)) {
            $nodes = $this->filterByAttributes($nodes, $attributes);
            $selector .= "' with attribute(s) '" . trim(json_encode($attributes), '{}');
        }
        $this->assertDomNotContains($nodes, $selector);
    }

    public function seeNumberOfElements($selector, $expected)
    {
        $counted = count($this->match($selector));
        if (is_array($expected)) {
            list($floor, $ceil) = $expected;
            $this->assertTrue(
                $floor <= $counted && $ceil >= $counted,
                'Number of elements counted differs from expected range'
            );
        } else {
            $this->assertEquals(
                $expected,
                $counted,
                'Number of elements counted differs from expected number'
            );
        }
    }

    public function seeOptionIsSelected($selector, $optionText)
    {
        $selected = $this->matchSelectedOption($selector);
        $this->assertDomContains($selected, 'selected option');
        //If element is radio then we need to check value
        $value = $selected->getNode(0)->tagName === 'option'
            ? $selected->text()
            : $selected->getNode(0)->getAttribute('value');
        $this->assertEquals($optionText, $value);
    }

    public function dontSeeOptionIsSelected($selector, $optionText)
    {
        $selected = $this->matchSelectedOption($selector);
        if (!$selected->count()) {
            $this->assertEquals(0, $selected->count());
            return;
        }
        //If element is radio then we need to check value
        $value = $selected->getNode(0)->tagName === 'option'
            ? $selected->text()
            : $selected->getNode(0)->getAttribute('value');
        $this->assertNotEquals($optionText, $value);
    }

    /**
     * @return SymfonyCrawler
     */
    protected function matchSelectedOption($select)
    {
        $nodes = $this->getFieldsByLabelOrCss($select);
        $selectedOptions = $nodes->filter('option[selected],input:checked');
        if ($selectedOptions->count() === 0) {
            $selectedOptions = $nodes->filter('option,input')->first();
        }
        return $selectedOptions;
    }

    /**
     * Asserts that current page has 404 response status code.
     */
    public function seePageNotFound()
    {
        $this->seeResponseCodeIs(404);
    }

    /**
     * Checks that response code is equal to value provided.
     *
     * ```php
     * <?php
     * $I->seeResponseCodeIs(200);
     *
     * // recommended \Codeception\Util\HttpCode
     * $I->seeResponseCodeIs(\Codeception\Util\HttpCode::OK);
     * ```
     *
     * @param int $code
     */
    public function seeResponseCodeIs($code)
    {
        $failureMessage = sprintf(
            'Expected HTTP Status Code: %s. Actual Status Code: %s',
            HttpCode::getDescription($code),
            HttpCode::getDescription($this->getResponseStatusCode())
        );
        $this->assertEquals($code, $this->getResponseStatusCode(), $failureMessage);
    }

    /**
     * Checks that response code is between a certain range. Between actually means [from <= CODE <= to]
     *
     * @param int $from
     * @param int $to
     */
    public function seeResponseCodeIsBetween($from, $to)
    {
        $failureMessage = sprintf(
            'Expected HTTP Status Code between %s and %s. Actual Status Code: %s',
            HttpCode::getDescription($from),
            HttpCode::getDescription($to),
            HttpCode::getDescription($this->getResponseStatusCode())
        );
        $this->assertGreaterThanOrEqual($from, $this->getResponseStatusCode(), $failureMessage);
        $this->assertLessThanOrEqual($to, $this->getResponseStatusCode(), $failureMessage);
    }

    /**
     * Checks that response code is equal to value provided.
     *
     * ```php
     * <?php
     * $I->dontSeeResponseCodeIs(200);
     *
     * // recommended \Codeception\Util\HttpCode
     * $I->dontSeeResponseCodeIs(\Codeception\Util\HttpCode::OK);
     * ```
     * @param int $code
     */
    public function dontSeeResponseCodeIs($code)
    {
        $failureMessage = sprintf(
            'Expected HTTP status code other than %s',
            HttpCode::getDescription($code)
        );
        $this->assertNotEquals($code, $this->getResponseStatusCode(), $failureMessage);
    }

    /**
     * Checks that the response code 2xx
     */
    public function seeResponseCodeIsSuccessful()
    {
        $this->seeResponseCodeIsBetween(200, 299);
    }

    /**
     * Checks that the response code 3xx
     */
    public function seeResponseCodeIsRedirection()
    {
        $this->seeResponseCodeIsBetween(300, 399);
    }

    /**
     * Checks that the response code is 4xx
     */
    public function seeResponseCodeIsClientError()
    {
        $this->seeResponseCodeIsBetween(400, 499);
    }

    /**
     * Checks that the response code is 5xx
     */
    public function seeResponseCodeIsServerError()
    {
        $this->seeResponseCodeIsBetween(500, 599);
    }

    public function seeInTitle($title)
    {
        $nodes = $this->getCrawler()->filter('title');
        if ($nodes->count() === 0) {
            throw new ElementNotFound("<title>", "Tag");
        }
        $this->assertStringContainsString($title, $nodes->first()->text(), "page title contains $title");
    }

    public function dontSeeInTitle($title)
    {
        $nodes = $this->getCrawler()->filter('title');
        if ($nodes->count() === 0) {
            $this->assertTrue(true);
            return;
        }
        $this->assertStringNotContainsString($title, $nodes->first()->text(), "page title contains $title");
    }

    /**
     * @param string $message
     */
    protected function assertDomContains($nodes, $message, $text = '')
    {
        $constraint = new CrawlerConstraint($text, $this->_getCurrentUri());
        $this->assertThat($nodes, $constraint, $message);
    }

    /**
     * @param string $message
     */
    protected function assertDomNotContains($nodes, $message, $text = '')
    {
        $constraint = new CrawlerNotConstraint($text, $this->_getCurrentUri());
        $this->assertThat($nodes, $constraint, $message);
    }

    /**
     * @param string $message
     */
    protected function assertPageContains($needle, $message = '')
    {
        $constraint = new PageConstraint($needle, $this->_getCurrentUri());
        $this->assertThat(
            $this->getNormalizedResponseContent(),
            $constraint,
            $message
        );
    }

    /**
     * @param string $message
     */
    protected function assertPageNotContains($needle, $message = '')
    {
        $constraint = new PageConstraint($needle, $this->_getCurrentUri());
        $this->assertThatItsNot(
            $this->getNormalizedResponseContent(),
            $constraint,
            $message
        );
    }

    /**
     * @param string $message
     */
    protected function assertPageSourceContains($needle, $message = '')
    {
        $constraint = new PageConstraint($needle, $this->_getCurrentUri());
        $this->assertThat(
            $this->_getResponseContent(),
            $constraint,
            $message
        );
    }

    /**
     * @param string $message
     */
    protected function assertPageSourceNotContains($needle, $message = '')
    {
        $constraint = new PageConstraint($needle, $this->_getCurrentUri());
        $this->assertThatItsNot(
            $this->_getResponseContent(),
            $constraint,
            $message
        );
    }

    /**
     * @param string $name
     * @param array $form
     * @param FormField $dynamicField
     * @return FormField
     */
    protected function matchFormField($name, $form, $dynamicField)
    {
        if (substr($name, -2) !== '[]') {
            return $form[$name];
        }
        $name = substr($name, 0, -2);
        /** @var FormField $item */
        foreach ($form[$name] as $item) {
            if ($item == $dynamicField) {
                return $item;
            }
        }
        throw new TestRuntimeException("None of form fields by {$name}[] were not matched");
    }

    /**
     * @param $locator
     * @return SymfonyCrawler
     */
    protected function filterByCSS($locator)
    {
        if (!Locator::isCSS($locator)) {
            throw new MalformedLocatorException($locator, 'css');
        }
        return $this->getCrawler()->filter($locator);
    }

    /**
     * @param $locator
     * @return SymfonyCrawler
     */
    protected function filterByXPath($locator)
    {
        if (!Locator::isXPath($locator)) {
            throw new MalformedLocatorException($locator, 'xpath');
        }
        return $this->getCrawler()->filterXPath($locator);
    }

    /**
     * @param array $requestParams
     * @return array
     */
    protected function getFormPhpValues($requestParams)
    {
        foreach ($requestParams as $name => $value) {
            $qs = http_build_query([$name => $value]);
            if (!empty($qs)) {
                // If the field's name is of the form of "array[key]",
                // we'll remove it from the request parameters
                // and set the "array" key instead which will contain the actual array.
                if (strpos($name, '[') && strpos($name, ']') > strpos($name, '[')) {
                    unset($requestParams[$name]);
                }

                parse_str($qs, $expandedValue);
                $varName = substr($name, 0, strlen(key($expandedValue)));
                $requestParams = array_replace_recursive($requestParams, [$varName => current($expandedValue)]);
            }
        }
        return $requestParams;
    }

    /**
     * @param SymfonyCrawler $result
     * @param int $maxRedirects
     * @param int $redirectCount
     * @return SymfonyCrawler
     */
    protected function redirectIfNecessary($result, $maxRedirects, $redirectCount)
    {
        $locationHeader = $this->client->getInternalResponse()->getHeader('Location');
        $statusCode = $this->getResponseStatusCode();
        if ($locationHeader && $statusCode >= 300 && $statusCode < 400) {
            if ($redirectCount === $maxRedirects) {
                throw new LogicException(sprintf(
                    'The maximum number (%d) of redirections was reached.',
                    $maxRedirects
                ));
            }

            $this->debugSection('Redirecting to', $locationHeader);

            $result = $this->client->followRedirect();
            $this->debugResponse($locationHeader);
            return $this->redirectIfNecessary($result, $maxRedirects, $redirectCount + 1);
        }
        $this->client->followRedirects(true);
        return $result;
    }

    /**
     * Switch to iframe or frame on the page.
     *
     * Example:
     * ``` html
     * <iframe name="another_frame" src="http://example.com">
     * ```
     *
     * ``` php
     * <?php
     * # switch to iframe
     * $I->switchToIframe("another_frame");
     * ```
     *
     * @param string $name
     */

    public function switchToIframe($name)
    {
        $iframe = $this->match("iframe[name=$name]")->first();
        if (count($iframe) === 0) {
            $iframe = $this->match("frame[name=$name]")->first();
        }
        if (count($iframe) === 0) {
            throw new ElementNotFound("name=$name", 'Iframe');
        }

        $uri = $iframe->getNode(0)->getAttribute('src');
        $this->amOnPage($uri);
    }

    /**
     * Moves back in history.
     *
     * @param int $numberOfSteps (default value 1)
     */
    public function moveBack($numberOfSteps = 1)
    {
        if (!is_int($numberOfSteps) || $numberOfSteps < 1) {
            throw new InvalidArgumentException('numberOfSteps must be positive integer');
        }
        try {
            $history = $this->getRunningClient()->getHistory();
            for ($i = $numberOfSteps; $i > 0; $i--) {
                $request = $history->back();
            }
        } catch (LogicException $e) {
            throw new InvalidArgumentException(
                sprintf(
                    'numberOfSteps is set to %d, but there are only %d previous steps in the history',
                    $numberOfSteps,
                    $numberOfSteps - $i
                )
            );
        }
        $this->_loadPage(
            $request->getMethod(),
            $request->getUri(),
            $request->getParameters(),
            $request->getFiles(),
            $request->getServer(),
            $request->getContent()
        );
    }

    protected function debugCookieJar()
    {
        $cookies = $this->client->getCookieJar()->all();
        $cookieStrings = array_map('strval', $cookies);
        $this->debugSection('Cookie Jar', $cookieStrings);
    }

    protected function setCookiesFromOptions()
    {
        if (isset($this->config['cookies']) && is_array($this->config['cookies']) && !empty($this->config['cookies'])) {
            $domain = parse_url($this->config['url'], PHP_URL_HOST);
            $cookieJar = $this->client->getCookieJar();
            foreach ($this->config['cookies'] as &$cookie) {
                if (!is_array($cookie) || !array_key_exists('Name', $cookie) || !array_key_exists('Value', $cookie)) {
                    throw new InvalidArgumentException('Cookies must have at least Name and Value attributes');
                }
                if (!isset($cookie['Domain'])) {
                    $cookie['Domain'] = $domain;
                }
                if (!isset($cookie['Expires'])) {
                    $cookie['Expires'] = null;
                }
                if (!isset($cookie['Path'])) {
                    $cookie['Path'] = '/';
                }
                if (!isset($cookie['Secure'])) {
                    $cookie['Secure'] = false;
                }
                if (!isset($cookie['HttpOnly'])) {
                    $cookie['HttpOnly'] = false;
                }
                $cookieJar->set(new Cookie(
                    $cookie['Name'],
                    $cookie['Value'],
                    $cookie['Expires'],
                    $cookie['Path'],
                    $cookie['Domain'],
                    $cookie['Secure'],
                    $cookie['HttpOnly']
                ));
            }
        }
    }

    /**
     * @return string
     */
    protected function getNormalizedResponseContent()
    {
        $content = $this->_getResponseContent();
        // Since strip_tags has problems with JS code that contains
        // an <= operator the script tags have to be removed manually first.
        $content = preg_replace('#<script(.*?)>(.*?)</script>#is', '', $content);

        $content = strip_tags($content);
        $content = html_entity_decode($content, ENT_QUOTES);
        $content = str_replace("\n", ' ', $content);

        return preg_replace('#\s{2,}#', ' ', $content);
    }

    /**
     * Sets SERVER parameters valid for all next requests.
     * this will remove old ones.
     *
     * ```php
     * $I->setServerParameters([]);
     * ```
     */
    public function setServerParameters(array $params)
    {
        $this->client->setServerParameters($params);
    }

    /**
     * Sets SERVER parameter valid for all next requests.
     *
     * ```php
     * $I->haveServerParameter('name', 'value');
     * ```
     * @param string $name
     * @param string $value
     */
    public function haveServerParameter($name, $value)
    {
        $this->client->setServerParameter($name, $value);
    }

    /**
     * Prevents automatic redirects to be followed by the client.
     *
     * ```php
     * <?php
     * $I->stopFollowingRedirects();
     * ```
     *
     */
    public function stopFollowingRedirects()
    {
        $this->client->followRedirects(false);
    }

    /**
     * Enables automatic redirects to be followed by the client.
     *
     * ```php
     * <?php
     * $I->startFollowingRedirects();
     * ```
     *
     */
    public function startFollowingRedirects()
    {
        $this->client->followRedirects(true);
    }

    /**
     * Follow pending redirect if there is one.
     *
     * ```php
     * <?php
     * $I->followRedirect();
     * ```
     *
     */
    public function followRedirect()
    {
        $this->client->followRedirect();
    }

    /**
     * Sets the maximum number of redirects that the Client can follow.
     *
     * ```php
     * <?php
     * $I->setMaxRedirects(2);
     * ```
     *
     * @param int $maxRedirects
     */
    public function setMaxRedirects($maxRedirects)
    {
        $this->client->setMaxRedirects($maxRedirects);
    }
}
<?php

namespace Codeception\Lib;

/**
 * Abstract module for PHP frameworks connected via Symfony BrowserKit components
 * Each framework is connected with it's own connector defined in \Codeception\Lib\Connector
 * Each module for framework should extend this class.
 *
 */
abstract class Framework extends InnerBrowser
{
    /**
     * Returns a list of recognized domain names
     *
     * @return array
     */
    protected function getInternalDomains()
    {
        return [];
    }

    /**
     * @param array $settings
     */
    public function _beforeSuite($settings = [])
    {
        /**
         * reset internal domains before suite, because each suite can have a different configuration
         */
        $this->internalDomains = null;
    }
}
<?php

namespace Codeception\Util;

/**
 * Class containing constants of HTTP Status Codes
 * and method to print HTTP code with its description.
 *
 * Usage:
 *
 * ```php
 * <?php
 * use \Codeception\Util\HttpCode;
 *
 * // using REST, PhpBrowser, or any Framework module
 * $I->seeResponseCodeIs(HttpCode::OK);
 * $I->dontSeeResponseCodeIs(HttpCode::NOT_FOUND);
 * ```
 *
 *
 */
class HttpCode
{
    // const CONTINUE = 100;
    /**
     * @var int
     */
    const SWITCHING_PROTOCOLS = 101;
    /**
     * @var int
     */
    const PROCESSING = 102;            // RFC2518
    /**
     * @var int
     */
    const EARLY_HINTS = 103;           // RFC8297
    /**
     * @var int
     */
    const OK = 200;
    /**
     * @var int
     */
    const CREATED = 201;
    /**
     * @var int
     */
    const ACCEPTED = 202;
    /**
     * @var int
     */
    const NON_AUTHORITATIVE_INFORMATION = 203;
    /**
     * @var int
     */
    const NO_CONTENT = 204;
    /**
     * @var int
     */
    const RESET_CONTENT = 205;
    /**
     * @var int
     */
    const PARTIAL_CONTENT = 206;
    /**
     * @var int
     */
    const MULTI_STATUS = 207;          // RFC4918
    /**
     * @var int
     */
    const ALREADY_REPORTED = 208;      // RFC5842
    /**
     * @var int
     */
    const IM_USED = 226;               // RFC3229
    /**
     * @var int
     */
    const MULTIPLE_CHOICES = 300;
    /**
     * @var int
     */
    const MOVED_PERMANENTLY = 301;
    /**
     * @var int
     */
    const FOUND = 302;
    /**
     * @var int
     */
    const SEE_OTHER = 303;
    /**
     * @var int
     */
    const NOT_MODIFIED = 304;
    /**
     * @var int
     */
    const USE_PROXY = 305;
    /**
     * @var int
     */
    const RESERVED = 306;
    /**
     * @var int
     */
    const TEMPORARY_REDIRECT = 307;
    /**
     * @var int
     */
    const PERMANENTLY_REDIRECT = 308;  // RFC7238
    /**
     * @var int
     */
    const BAD_REQUEST = 400;
    /**
     * @var int
     */
    const UNAUTHORIZED = 401;
    /**
     * @var int
     */
    const PAYMENT_REQUIRED = 402;
    /**
     * @var int
     */
    const FORBIDDEN = 403;
    /**
     * @var int
     */
    const NOT_FOUND = 404;
    /**
     * @var int
     */
    const METHOD_NOT_ALLOWED = 405;
    /**
     * @var int
     */
    const NOT_ACCEPTABLE = 406;
    /**
     * @var int
     */
    const PROXY_AUTHENTICATION_REQUIRED = 407;
    /**
     * @var int
     */
    const REQUEST_TIMEOUT = 408;
    /**
     * @var int
     */
    const CONFLICT = 409;
    /**
     * @var int
     */
    const GONE = 410;
    /**
     * @var int
     */
    const LENGTH_REQUIRED = 411;
    /**
     * @var int
     */
    const PRECONDITION_FAILED = 412;
    /**
     * @var int
     */
    const REQUEST_ENTITY_TOO_LARGE = 413;
    /**
     * @var int
     */
    const REQUEST_URI_TOO_LONG = 414;
    /**
     * @var int
     */
    const UNSUPPORTED_MEDIA_TYPE = 415;
    /**
     * @var int
     */
    const REQUESTED_RANGE_NOT_SATISFIABLE = 416;
    /**
     * @var int
     */
    const EXPECTATION_FAILED = 417;
    /**
     * @var int
     */
    const I_AM_A_TEAPOT = 418;                                               // RFC2324
    /**
     * @var int
     */
    const MISDIRECTED_REQUEST = 421;                                         // RFC7540
    /**
     * @var int
     */
    const UNPROCESSABLE_ENTITY = 422;                                        // RFC4918
    /**
     * @var int
     */
    const LOCKED = 423;                                                      // RFC4918
    /**
     * @var int
     */
    const FAILED_DEPENDENCY = 424;                                           // RFC4918
    /**
     * @var int
     */
    const RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL = 425;   // RFC2817
    /**
     * @var int
     */
    const UPGRADE_REQUIRED = 426;                                            // RFC2817
    /**
     * @var int
     */
    const PRECONDITION_REQUIRED = 428;                                       // RFC6585
    /**
     * @var int
     */
    const TOO_MANY_REQUESTS = 429;                                           // RFC6585
    /**
     * @var int
     */
    const REQUEST_HEADER_FIELDS_TOO_LARGE = 431;                             // RFC6585
    /**
     * @var int
     */
    const UNAVAILABLE_FOR_LEGAL_REASONS = 451;
    /**
     * @var int
     */
    const INTERNAL_SERVER_ERROR = 500;
    /**
     * @var int
     */
    const NOT_IMPLEMENTED = 501;
    /**
     * @var int
     */
    const BAD_GATEWAY = 502;
    /**
     * @var int
     */
    const SERVICE_UNAVAILABLE = 503;
    /**
     * @var int
     */
    const GATEWAY_TIMEOUT = 504;
    /**
     * @var int
     */
    const VERSION_NOT_SUPPORTED = 505;
    /**
     * @var int
     */
    const VARIANT_ALSO_NEGOTIATES_EXPERIMENTAL = 506;                        // RFC2295
    /**
     * @var int
     */
    const INSUFFICIENT_STORAGE = 507;                                        // RFC4918
    /**
     * @var int
     */
    const LOOP_DETECTED = 508;                                               // RFC5842
    /**
     * @var int
     */
    const NOT_EXTENDED = 510;                                                // RFC2774
    /**
     * @var int
     */
    const NETWORK_AUTHENTICATION_REQUIRED = 511;                             // RFC6585
    /**
     * @var array<int, string>
     */
    private static $codes = [
         100 => 'Continue',
         102 => 'Processing',
         103 => 'Early Hints',
         200 => 'OK',
         201 => 'Created',
         202 => 'Accepted',
         203 => 'Non-Authoritative Information',
         204 => 'No Content',
         205 => 'Reset Content',
         206 => 'Partial Content',
         207 => 'Multi-Status',
         208 => 'Already Reported',
         226 => 'IM Used',
         300 => 'Multiple Choices',
         301 => 'Moved Permanently',
         302 => 'Found',
         303 => 'See Other',
         304 => 'Not Modified',
         305 => 'Use Proxy',
         306 => 'Reserved',
         307 => 'Temporary Redirect',
         308 => 'Permanent Redirect',
         400 => 'Bad Request',
         401 => 'Unauthorized',
         402 => 'Payment Required',
         403 => 'Forbidden',
         404 => 'Not Found',
         405 => 'Method Not Allowed',
         406 => 'Not Acceptable',
         407 => 'Proxy Authentication Required',
         408 => 'Request Timeout',
         409 => 'Conflict',
         410 => 'Gone',
         411 => 'Length Required',
         412 => 'Precondition Failed',
         413 => 'Request Entity Too Large',
         414 => 'Request-URI Too Long',
         415 => 'Unsupported Media Type',
         416 => 'Requested Range Not Satisfiable',
         417 => 'Expectation Failed',
         418 => 'Unassigned',
         421 => 'Misdirected Request',
         422 => 'Unprocessable Entity',
         423 => 'Locked',
         424 => 'Failed Dependency',
         425 => 'Too Early',
         426 => 'Upgrade Required',
         428 => 'Precondition Required',
         429 => 'Too Many Requests',
         431 => 'Request Header Fields Too Large',
         451 => 'Unavailable For Legal Reasons',
         500 => 'Internal Server Error',
         501 => 'Not Implemented',
         502 => 'Bad Gateway',
         503 => 'Service Unavailable',
         504 => 'Gateway Timeout',
         505 => 'HTTP Version Not Supported',
         506 => 'Variant Also Negotiates',
         507 => 'Insufficient Storage',
         508 => 'Loop Detected',
         510 => 'Not Extended',
         511 => 'Network Authentication Required'
    ];

    /**
     * Returns string with HTTP code and its description
     *
     * ```php
     * <?php
     * HttpCode::getDescription(200); // '200 (OK)'
     * HttpCode::getDescription(401); // '401 (Unauthorized)'
     * ```
     *
     * @param int $code
     * @return int|string
     */
    public static function getDescription($code)
    {
        if (isset(self::$codes[$code])) {
            return sprintf('%d (%s)', $code, self::$codes[$code]);
        }
        return $code;
    }
}
<?php

namespace Codeception\Exception;

class ExternalUrlException extends \Exception
{
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection;

use phpDocumentor\Reflection\Exception\PcreException;
use Webmozart\Assert\Assert;

use function preg_last_error;
use function preg_split as php_preg_split;

abstract class Utils
{



























public static function pregSplit(string $pattern, string $subject, int $limit = -1, int $flags = 0): array
{
$parts = php_preg_split($pattern, $subject, $limit, $flags);
if ($parts === false) {
throw PcreException::createFromPhpError(preg_last_error());
}

Assert::allString($parts);

return $parts;
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection;

use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\TagWithType;
use Webmozart\Assert\Assert;

final class DocBlock
{

private $summary;


private $description;


private $tags = [];


private $context;


private $location;


private $isTemplateStart;


private $isTemplateEnd;






public function __construct(
string $summary = '',
?DocBlock\Description $description = null,
array $tags = [],
?Types\Context $context = null,
?Location $location = null,
bool $isTemplateStart = false,
bool $isTemplateEnd = false
) {
Assert::allIsInstanceOf($tags, Tag::class);

$this->summary = $summary;
$this->description = $description ?: new DocBlock\Description('');
foreach ($tags as $tag) {
$this->addTag($tag);
}

$this->context = $context;
$this->location = $location;

$this->isTemplateEnd = $isTemplateEnd;
$this->isTemplateStart = $isTemplateStart;
}

public function getSummary(): string
{
return $this->summary;
}

public function getDescription(): DocBlock\Description
{
return $this->description;
}




public function getContext(): ?Types\Context
{
return $this->context;
}




public function getLocation(): ?Location
{
return $this->location;
}




















public function isTemplateStart(): bool
{
return $this->isTemplateStart;
}






public function isTemplateEnd(): bool
{
return $this->isTemplateEnd;
}






public function getTags(): array
{
return $this->tags;
}









public function getTagsByName(string $name): array
{
$result = [];

foreach ($this->getTags() as $tag) {
if ($tag->getName() !== $name) {
continue;
}

$result[] = $tag;
}

return $result;
}









public function getTagsWithTypeByName(string $name): array
{
$result = [];

foreach ($this->getTagsByName($name) as $tag) {
if (!$tag instanceof TagWithType) {
continue;
}

$result[] = $tag;
}

return $result;
}






public function hasTag(string $name): bool
{
foreach ($this->getTags() as $tag) {
if ($tag->getName() === $name) {
return true;
}
}

return false;
}






public function removeTag(Tag $tagToRemove): void
{
foreach ($this->tags as $key => $tag) {
if ($tag === $tagToRemove) {
unset($this->tags[$key]);
break;
}
}
}






private function addTag(Tag $tag): void
{
$this->tags[] = $tag;
}
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection;

use phpDocumentor\Reflection\DocBlock\Tag;


interface DocBlockFactoryInterface
{





public static function createInstance(array $additionalTags = []): DocBlockFactory;




public function create($docblock, ?Types\Context $context = null, ?Location $location = null): DocBlock;
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock;

use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tags\Formatter;
use phpDocumentor\Reflection\DocBlock\Tags\Formatter\PassthroughFormatter;

use function sprintf;
use function str_repeat;
use function str_replace;
use function strlen;
use function wordwrap;




class Serializer
{

protected $indentString = ' ';


protected $indent = 0;


protected $isFirstLineIndented = true;


protected $lineLength;


protected $tagFormatter;

private $lineEnding;











public function __construct(
int $indent = 0,
string $indentString = ' ',
bool $indentFirstLine = true,
?int $lineLength = null,
?Formatter $tagFormatter = null,
string $lineEnding = "\n"
) {
$this->indent = $indent;
$this->indentString = $indentString;
$this->isFirstLineIndented = $indentFirstLine;
$this->lineLength = $lineLength;
$this->tagFormatter = $tagFormatter ?: new PassthroughFormatter();
$this->lineEnding = $lineEnding;
}








public function getDocComment(DocBlock $docblock): string
{
$indent = str_repeat($this->indentString, $this->indent);
$firstIndent = $this->isFirstLineIndented ? $indent : '';

 $wrapLength = $this->lineLength ? $this->lineLength - strlen($indent) - 3 : null;

$text = $this->removeTrailingSpaces(
$indent,
$this->addAsterisksForEachLine(
$indent,
$this->getSummaryAndDescriptionTextBlock($docblock, $wrapLength)
)
);

$comment = $firstIndent . "/**\n";
if ($text) {
$comment .= $indent . ' * ' . $text . "\n";
$comment .= $indent . " *\n";
}

$comment = $this->addTagBlock($docblock, $wrapLength, $indent, $comment);

return str_replace("\n", $this->lineEnding, $comment . $indent . ' */');
}

private function removeTrailingSpaces(string $indent, string $text): string
{
return str_replace(
sprintf("\n%s * \n", $indent),
sprintf("\n%s *\n", $indent),
$text
);
}

private function addAsterisksForEachLine(string $indent, string $text): string
{
return str_replace(
"\n",
sprintf("\n%s * ", $indent),
$text
);
}

private function getSummaryAndDescriptionTextBlock(DocBlock $docblock, ?int $wrapLength): string
{
$text = $docblock->getSummary() . ((string) $docblock->getDescription() ? "\n\n" . $docblock->getDescription()
: '');
if ($wrapLength !== null) {
$text = wordwrap($text, $wrapLength);

return $text;
}

return $text;
}

private function addTagBlock(DocBlock $docblock, ?int $wrapLength, string $indent, string $comment): string
{
foreach ($docblock->getTags() as $tag) {
$tagText = $this->tagFormatter->format($tag);
if ($wrapLength !== null) {
$tagText = wordwrap($tagText, $wrapLength);
}

$tagText = str_replace(
"\n",
sprintf("\n%s * ", $indent),
$tagText
);

$comment .= sprintf("%s * %s\n", $indent, $tagText);
}

return $comment;
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock;

use phpDocumentor\Reflection\DocBlock\Tags\Formatter;
use phpDocumentor\Reflection\DocBlock\Tags\Formatter\PassthroughFormatter;

use function vsprintf;

































class Description
{

private $bodyTemplate;


private $tags;






public function __construct(string $bodyTemplate, array $tags = [])
{
$this->bodyTemplate = $bodyTemplate;
$this->tags = $tags;
}




public function getBodyTemplate(): string
{
return $this->bodyTemplate;
}






public function getTags(): array
{
return $this->tags;
}





public function render(?Formatter $formatter = null): string
{
if ($formatter === null) {
$formatter = new PassthroughFormatter();
}

$tags = [];
foreach ($this->tags as $tag) {
$tags[] = '{' . $formatter->format($tag) . '}';
}

return vsprintf($this->bodyTemplate, $tags);
}




public function __toString(): string
{
return $this->render();
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock;

use phpDocumentor\Reflection\DocBlock\Tags\Example;

use function array_slice;
use function file;
use function getcwd;
use function implode;
use function is_readable;
use function rtrim;
use function sprintf;
use function trim;

use const DIRECTORY_SEPARATOR;




class ExampleFinder
{

private $sourceDirectory = '';


private $exampleDirectories = [];




public function find(Example $example): string
{
$filename = $example->getFilePath();

$file = $this->getExampleFileContents($filename);
if (!$file) {
return sprintf('** File not found : %s **', $filename);
}

return implode('', array_slice($file, $example->getStartingLine() - 1, $example->getLineCount()));
}




public function setSourceDirectory(string $directory = ''): void
{
$this->sourceDirectory = $directory;
}




public function getSourceDirectory(): string
{
return $this->sourceDirectory;
}






public function setExampleDirectories(array $directories): void
{
$this->exampleDirectories = $directories;
}






public function getExampleDirectories(): array
{
return $this->exampleDirectories;
}














private function getExampleFileContents(string $filename): ?array
{
$normalizedPath = null;

foreach ($this->exampleDirectories as $directory) {
$exampleFileFromConfig = $this->constructExamplePath($directory, $filename);
if (is_readable($exampleFileFromConfig)) {
$normalizedPath = $exampleFileFromConfig;
break;
}
}

if (!$normalizedPath) {
if (is_readable($this->getExamplePathFromSource($filename))) {
$normalizedPath = $this->getExamplePathFromSource($filename);
} elseif (is_readable($this->getExamplePathFromExampleDirectory($filename))) {
$normalizedPath = $this->getExamplePathFromExampleDirectory($filename);
} elseif (is_readable($filename)) {
$normalizedPath = $filename;
}
}

$lines = $normalizedPath && is_readable($normalizedPath) ? file($normalizedPath) : false;

return $lines !== false ? $lines : null;
}




private function getExamplePathFromExampleDirectory(string $file): string
{
return getcwd() . DIRECTORY_SEPARATOR . 'examples' . DIRECTORY_SEPARATOR . $file;
}




private function constructExamplePath(string $directory, string $file): string
{
return rtrim($directory, '\\/') . DIRECTORY_SEPARATOR . $file;
}




private function getExamplePathFromSource(string $file): string
{
return sprintf(
'%s%s%s',
trim($this->getSourceDirectory(), '\\/'),
DIRECTORY_SEPARATOR,
trim($file, '"')
);
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock;

use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;

use function count;
use function implode;
use function ltrim;
use function min;
use function str_replace;
use function strlen;
use function strpos;
use function substr;
use function trim;

use const PREG_SPLIT_DELIM_CAPTURE;


















class DescriptionFactory
{

private $tagFactory;




public function __construct(TagFactory $tagFactory)
{
$this->tagFactory = $tagFactory;
}




public function create(string $contents, ?TypeContext $context = null): Description
{
$tokens = $this->lex($contents);
$count = count($tokens);
$tagCount = 0;
$tags = [];

for ($i = 1; $i < $count; $i += 2) {
$tags[] = $this->tagFactory->create($tokens[$i], $context);
$tokens[$i] = '%' . ++$tagCount . '$s';
}


 
 
 
 for ($i = 0; $i < $count; $i += 2) {
$tokens[$i] = str_replace(['{@}', '{}', '%'], ['@', '}', '%%'], $tokens[$i]);
}

return new Description(implode('', $tokens), $tags);
}






private function lex(string $contents): array
{
$contents = $this->removeSuperfluousStartingWhitespace($contents);


 if (strpos($contents, '{@') === false) {
return [$contents];
}

return Utils::pregSplit(
'/\{
                # "{@}" is not a valid inline tag. This ensures that we do not treat it as one, but treat it literally.
                (?!@\})
                # We want to capture the whole tag line, but without the inline tag delimiters.
                (\@
                    # Match everything up to the next delimiter.
                    [^{}]*
                    # Nested inline tag content should not be captured, or it will appear in the result separately.
                    (?:
                        # Match nested inline tags.
                        (?:
                            # Because we did not catch the tag delimiters earlier, we must be explicit with them here.
                            # Notice that this also matches "{}", as a way to later introduce it as an escape sequence.
                            \{(?1)?\}
                            |
                            # Make sure we match hanging "{".
                            \{
                        )
                        # Match content after the nested inline tag.
                        [^{}]*
                    )* # If there are more inline tags, match them as well. We use "*" since there may not be any
                       # nested inline tags.
                )
            \}/Sux',
$contents,
0,
PREG_SPLIT_DELIM_CAPTURE
);
}















private function removeSuperfluousStartingWhitespace(string $contents): string
{
$lines = Utils::pregSplit("/\r\n?|\n/", $contents);


 
 if (count($lines) <= 1) {
return $contents;
}


 $startingSpaceCount = 9999999;
for ($i = 1, $iMax = count($lines); $i < $iMax; ++$i) {

 if (trim($lines[$i]) === '') {
continue;
}


 
 $startingSpaceCount = min($startingSpaceCount, strlen($lines[$i]) - strlen(ltrim($lines[$i])));
}


 if ($startingSpaceCount > 0) {
for ($i = 1, $iMax = count($lines); $i < $iMax; ++$i) {
$lines[$i] = substr($lines[$i], $startingSpaceCount);
}
}

return implode("\n", $lines);
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use Webmozart\Assert\Assert;

use function preg_match;




final class Source extends BaseTag implements Factory\StaticMethod
{

protected $name = 'source';


private $startingLine;


private $lineCount;





public function __construct($startingLine, $lineCount = null, ?Description $description = null)
{
Assert::integerish($startingLine);
Assert::nullOrIntegerish($lineCount);

$this->startingLine = (int) $startingLine;
$this->lineCount = $lineCount !== null ? (int) $lineCount : null;
$this->description = $description;
}

public static function create(
string $body,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Assert::stringNotEmpty($body);
Assert::notNull($descriptionFactory);

$startingLine = 1;
$lineCount = null;
$description = null;


 if (preg_match('/^([1-9]\d*)\s*(?:((?1))\s+)?(.*)$/sux', $body, $matches)) {
$startingLine = (int) $matches[1];
if (isset($matches[2]) && $matches[2] !== '') {
$lineCount = (int) $matches[2];
}

$description = $matches[3];
}

return new static($startingLine, $lineCount, $descriptionFactory->create($description ?? '', $context));
}







public function getStartingLine(): int
{
return $this->startingLine;
}







public function getLineCount(): ?int
{
return $this->lineCount;
}

public function __toString(): string
{
if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

$startingLine = (string) $this->startingLine;

$lineCount = $this->lineCount !== null ? ' ' . $this->lineCount : '';

return $startingLine
. $lineCount
. ($description !== ''
? ' ' . $description
: '');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use InvalidArgumentException;

use function filter_var;
use function preg_match;
use function trim;

use const FILTER_VALIDATE_EMAIL;




final class Author extends BaseTag implements Factory\StaticMethod
{

protected $name = 'author';


private $authorName;


private $authorEmail;




public function __construct(string $authorName, string $authorEmail)
{
if ($authorEmail && !filter_var($authorEmail, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('The author tag does not have a valid e-mail address');
}

$this->authorName = $authorName;
$this->authorEmail = $authorEmail;
}






public function getAuthorName(): string
{
return $this->authorName;
}






public function getEmail(): string
{
return $this->authorEmail;
}




public function __toString(): string
{
if ($this->authorEmail) {
$authorEmail = '<' . $this->authorEmail . '>';
} else {
$authorEmail = '';
}

$authorName = $this->authorName;

return $authorName . ($authorEmail !== '' ? ($authorName !== '' ? ' ' : '') . $authorEmail : '');
}




public static function create(string $body): ?self
{
$splitTagContent = preg_match('/^([^\<]*)(?:\<([^\>]*)\>)?$/u', $body, $matches);
if (!$splitTagContent) {
return null;
}

$authorName = trim($matches[1]);
$email = isset($matches[2]) ? trim($matches[2]) : '';

return new static($authorName, $email);
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use InvalidArgumentException;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\StandardTagFactory;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use Webmozart\Assert\Assert;

use function preg_match;




final class Generic extends BaseTag implements Factory\StaticMethod
{






public function __construct(string $name, ?Description $description = null)
{
$this->validateTagName($name);

$this->name = $name;
$this->description = $description;
}






public static function create(
string $body,
string $name = '',
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Assert::stringNotEmpty($name);
Assert::notNull($descriptionFactory);

$description = $body !== '' ? $descriptionFactory->create($body, $context) : null;

return new static($name, $description);
}




public function __toString(): string
{
if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

return $description;
}




private function validateTagName(string $name): void
{
if (!preg_match('/^' . StandardTagFactory::REGEX_TAGNAME . '$/u', $name)) {
throw new InvalidArgumentException(
'The tag name "' . $name . '" is not wellformed. Tags may only consist of letters, underscores, '
. 'hyphens and backslashes.'
);
}
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use Webmozart\Assert\Assert;




final class Return_ extends TagWithType implements Factory\StaticMethod
{
public function __construct(Type $type, ?Description $description = null)
{
$this->name = 'return';
$this->type = $type;
$this->description = $description;
}

public static function create(
string $body,
?TypeResolver $typeResolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Assert::notNull($typeResolver);
Assert::notNull($descriptionFactory);

[$type, $description] = self::extractTypeFromBody($body);

$type = $typeResolver->resolve($type, $context);
$description = $descriptionFactory->create($description, $context);

return new static($type, $description);
}

public function __toString(): string
{
if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

$type = $this->type ? '' . $this->type : 'mixed';

return $type . ($description !== '' ? ' ' . $description : '');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

use function array_shift;
use function array_unshift;
use function implode;
use function strpos;
use function substr;

use const PREG_SPLIT_DELIM_CAPTURE;




final class Param extends TagWithType implements Factory\StaticMethod
{

private $variableName;


private $isVariadic;


private $isReference;

public function __construct(
?string $variableName,
?Type $type = null,
bool $isVariadic = false,
?Description $description = null,
bool $isReference = false
) {
$this->name = 'param';
$this->variableName = $variableName;
$this->type = $type;
$this->isVariadic = $isVariadic;
$this->description = $description;
$this->isReference = $isReference;
}

public static function create(
string $body,
?TypeResolver $typeResolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Assert::stringNotEmpty($body);
Assert::notNull($typeResolver);
Assert::notNull($descriptionFactory);

[$firstPart, $body] = self::extractTypeFromBody($body);

$type = null;
$parts = Utils::pregSplit('/(\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE);
$variableName = '';
$isVariadic = false;
$isReference = false;


 if ($firstPart && !self::strStartsWithVariable($firstPart)) {
$type = $typeResolver->resolve($firstPart, $context);
} else {

 array_unshift($parts, $firstPart);
}


 if (isset($parts[0]) && self::strStartsWithVariable($parts[0])) {
$variableName = array_shift($parts);
if ($type) {
array_shift($parts);
}

Assert::notNull($variableName);

if (strpos($variableName, '$') === 0) {
$variableName = substr($variableName, 1);
} elseif (strpos($variableName, '&$') === 0) {
$isReference = true;
$variableName = substr($variableName, 2);
} elseif (strpos($variableName, '...$') === 0) {
$isVariadic = true;
$variableName = substr($variableName, 4);
} elseif (strpos($variableName, '&...$') === 0) {
$isVariadic = true;
$isReference = true;
$variableName = substr($variableName, 5);
}
}

$description = $descriptionFactory->create(implode('', $parts), $context);

return new static($variableName, $type, $isVariadic, $description, $isReference);
}




public function getVariableName(): ?string
{
return $this->variableName;
}




public function isVariadic(): bool
{
return $this->isVariadic;
}




public function isReference(): bool
{
return $this->isReference;
}




public function __toString(): string
{
if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

$variableName = '';
if ($this->variableName) {
$variableName .= ($this->isReference ? '&' : '') . ($this->isVariadic ? '...' : '');
$variableName .= '$' . $this->variableName;
}

$type = (string) $this->type;

return $type
. ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '')
. ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : '');
}

private static function strStartsWithVariable(string $str): bool
{
return strpos($str, '$') === 0
||
strpos($str, '...$') === 0
||
strpos($str, '&$') === 0
||
strpos($str, '&...$') === 0;
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use Webmozart\Assert\Assert;

use function preg_match;




final class Since extends BaseTag implements Factory\StaticMethod
{

protected $name = 'since';





public const REGEX_VECTOR = '(?:
        # Normal release vectors.
        \d\S*
        |
        # VCS version vectors. Per PHPCS, they are expected to
        # follow the form of the VCS name, followed by ":", followed
        # by the version vector itself.
        # By convention, popular VCSes like CVS, SVN and GIT use "$"
        # around the actual version vector.
        [^\s\:]+\:\s*\$[^\$]+\$
    )';


private $version;

public function __construct(?string $version = null, ?Description $description = null)
{
Assert::nullOrNotEmpty($version);

$this->version = $version;
$this->description = $description;
}

public static function create(
?string $body,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): ?self {
if (empty($body)) {
return new static();
}

$matches = [];
if (!preg_match('/^(' . self::REGEX_VECTOR . ')\s*(.+)?$/sux', $body, $matches)) {
return null;
}

Assert::notNull($descriptionFactory);

return new static(
$matches[1],
$descriptionFactory->create($matches[2] ?? '', $context)
);
}




public function getVersion(): ?string
{
return $this->version;
}




public function __toString(): string
{
if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

$version = (string) $this->version;

return $version . ($description !== '' ? ($version !== '' ? ' ' : '') . $description : '');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Tag;

interface Formatter
{



public function format(Tag $tag): string;
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\FqsenResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

use function array_key_exists;
use function explode;




final class Covers extends BaseTag implements Factory\StaticMethod
{

protected $name = 'covers';


private $refers;




public function __construct(Fqsen $refers, ?Description $description = null)
{
$this->refers = $refers;
$this->description = $description;
}

public static function create(
string $body,
?DescriptionFactory $descriptionFactory = null,
?FqsenResolver $resolver = null,
?TypeContext $context = null
): self {
Assert::stringNotEmpty($body);
Assert::notNull($descriptionFactory);
Assert::notNull($resolver);

$parts = Utils::pregSplit('/\s+/Su', $body, 2);

return new static(
self::resolveFqsen($parts[0], $resolver, $context),
$descriptionFactory->create($parts[1] ?? '', $context)
);
}

private static function resolveFqsen(string $parts, ?FqsenResolver $fqsenResolver, ?TypeContext $context): Fqsen
{
Assert::notNull($fqsenResolver);
$fqsenParts = explode('::', $parts);
$resolved = $fqsenResolver->resolve($fqsenParts[0], $context);

if (!array_key_exists(1, $fqsenParts)) {
return $resolved;
}

return new Fqsen($resolved . '::' . $fqsenParts[1]);
}




public function getReference(): Fqsen
{
return $this->refers;
}




public function __toString(): string
{
if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

$refers = (string) $this->refers;

return $refers . ($description !== '' ? ($refers !== '' ? ' ' : '') . $description : '');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

use function array_shift;
use function array_unshift;
use function implode;
use function strpos;
use function substr;

use const PREG_SPLIT_DELIM_CAPTURE;




final class Var_ extends TagWithType implements Factory\StaticMethod
{

protected $variableName = '';

public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null)
{
Assert::string($variableName);

$this->name = 'var';
$this->variableName = $variableName;
$this->type = $type;
$this->description = $description;
}

public static function create(
string $body,
?TypeResolver $typeResolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Assert::stringNotEmpty($body);
Assert::notNull($typeResolver);
Assert::notNull($descriptionFactory);

[$firstPart, $body] = self::extractTypeFromBody($body);

$parts = Utils::pregSplit('/(\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE);
$type = null;
$variableName = '';


 if ($firstPart && $firstPart[0] !== '$') {
$type = $typeResolver->resolve($firstPart, $context);
} else {

 array_unshift($parts, $firstPart);
}


 if (isset($parts[0]) && strpos($parts[0], '$') === 0) {
$variableName = array_shift($parts);
if ($type) {
array_shift($parts);
}

Assert::notNull($variableName);

$variableName = substr($variableName, 1);
}

$description = $descriptionFactory->create(implode('', $parts), $context);

return new static($variableName, $type, $description);
}




public function getVariableName(): ?string
{
return $this->variableName;
}




public function __toString(): string
{
if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

if ($this->variableName) {
$variableName = '$' . $this->variableName;
} else {
$variableName = '';
}

$type = (string) $this->type;

return $type
. ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '')
. ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : '');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\Type;

use function in_array;
use function strlen;
use function substr;
use function trim;

abstract class TagWithType extends BaseTag
{

protected $type;




public function getType(): ?Type
{
return $this->type;
}




protected static function extractTypeFromBody(string $body): array
{
$type = '';
$nestingLevel = 0;
for ($i = 0, $iMax = strlen($body); $i < $iMax; $i++) {
$character = $body[$i];

if ($nestingLevel === 0 && trim($character) === '') {
break;
}

$type .= $character;
if (in_array($character, ['<', '(', '[', '{'])) {
$nestingLevel++;
continue;
}

if (in_array($character, ['>', ')', ']', '}'])) {
$nestingLevel--;
continue;
}
}

$description = trim(substr($body, strlen($type)));

return [$type, $description];
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

use function array_shift;
use function array_unshift;
use function implode;
use function strpos;
use function substr;

use const PREG_SPLIT_DELIM_CAPTURE;




final class PropertyWrite extends TagWithType implements Factory\StaticMethod
{

protected $variableName;

public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null)
{
Assert::string($variableName);

$this->name = 'property-write';
$this->variableName = $variableName;
$this->type = $type;
$this->description = $description;
}

public static function create(
string $body,
?TypeResolver $typeResolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Assert::stringNotEmpty($body);
Assert::notNull($typeResolver);
Assert::notNull($descriptionFactory);

[$firstPart, $body] = self::extractTypeFromBody($body);
$type = null;
$parts = Utils::pregSplit('/(\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE);
$variableName = '';


 if ($firstPart && $firstPart[0] !== '$') {
$type = $typeResolver->resolve($firstPart, $context);
} else {

 array_unshift($parts, $firstPart);
}


 if (isset($parts[0]) && strpos($parts[0], '$') === 0) {
$variableName = array_shift($parts);
if ($type) {
array_shift($parts);
}

Assert::notNull($variableName);

$variableName = substr($variableName, 1);
}

$description = $descriptionFactory->create(implode('', $parts), $context);

return new static($variableName, $type, $description);
}




public function getVariableName(): ?string
{
return $this->variableName;
}




public function __toString(): string
{
if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

if ($this->variableName) {
$variableName = '$' . $this->variableName;
} else {
$variableName = '';
}

$type = (string) $this->type;

return $type
. ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '')
. ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : '');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;




interface StaticMethod
{



public static function create(string $body);
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Description;




abstract class BaseTag implements DocBlock\Tag
{

protected $name = '';


protected $description;






public function getName(): string
{
return $this->name;
}

public function getDescription(): ?Description
{
return $this->description;
}

public function render(?Formatter $formatter = null): string
{
if ($formatter === null) {
$formatter = new Formatter\PassthroughFormatter();
}

return $formatter->format($this);
}
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags;

use Closure;
use Exception;
use phpDocumentor\Reflection\DocBlock\Tag;
use ReflectionClass;
use ReflectionException;
use ReflectionFunction;
use Throwable;

use function array_map;
use function get_class;
use function get_resource_type;
use function is_array;
use function is_object;
use function is_resource;
use function sprintf;











final class InvalidTag implements Tag
{

private $name;


private $body;


private $throwable;

private function __construct(string $name, string $body)
{
$this->name = $name;
$this->body = $body;
}

public function getException(): ?Throwable
{
return $this->throwable;
}

public function getName(): string
{
return $this->name;
}

public static function create(string $body, string $name = ''): self
{
return new self($name, $body);
}

public function withError(Throwable $exception): self
{
$this->flattenExceptionBacktrace($exception);
$tag = new self($this->name, $this->body);
$tag->throwable = $exception;

return $tag;
}







private function flattenExceptionBacktrace(Throwable $exception): void
{
$traceProperty = (new ReflectionClass(Exception::class))->getProperty('trace');
$traceProperty->setAccessible(true);

do {
$trace = $exception->getTrace();
if (isset($trace[0]['args'])) {
$trace = array_map(
function (array $call): array {
$call['args'] = array_map([$this, 'flattenArguments'], $call['args'] ?? []);

return $call;
},
$trace
);
}

$traceProperty->setValue($exception, $trace);
$exception = $exception->getPrevious();
} while ($exception !== null);

$traceProperty->setAccessible(false);
}








private function flattenArguments($value)
{
if ($value instanceof Closure) {
$closureReflection = new ReflectionFunction($value);
$value = sprintf(
'(Closure at %s:%s)',
$closureReflection->getFileName(),
$closureReflection->getStartLine()
);
} elseif (is_object($value)) {
$value = sprintf('object(%s)', get_class($value));
} elseif (is_resource($value)) {
$value = sprintf('resource(%s)', get_resource_type($value));
} elseif (is_array($value)) {
$value = array_map([$this, 'flattenArguments'], $value);
}

return $value;
}

public function render(?Formatter $formatter = null): string
{
if ($formatter === null) {
$formatter = new Formatter\PassthroughFormatter();
}

return $formatter->format($this);
}

public function __toString(): string
{
return $this->body;
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Reference\Fqsen as FqsenRef;
use phpDocumentor\Reflection\DocBlock\Tags\Reference\Reference;
use phpDocumentor\Reflection\DocBlock\Tags\Reference\Url;
use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\FqsenResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

use function array_key_exists;
use function explode;
use function preg_match;




final class See extends BaseTag implements Factory\StaticMethod
{

protected $name = 'see';


protected $refers;




public function __construct(Reference $refers, ?Description $description = null)
{
$this->refers = $refers;
$this->description = $description;
}

public static function create(
string $body,
?FqsenResolver $typeResolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Assert::notNull($descriptionFactory);

$parts = Utils::pregSplit('/\s+/Su', $body, 2);
$description = isset($parts[1]) ? $descriptionFactory->create($parts[1], $context) : null;


 if (preg_match('#\w://\w#', $parts[0])) {
return new static(new Url($parts[0]), $description);
}

return new static(new FqsenRef(self::resolveFqsen($parts[0], $typeResolver, $context)), $description);
}

private static function resolveFqsen(string $parts, ?FqsenResolver $fqsenResolver, ?TypeContext $context): Fqsen
{
Assert::notNull($fqsenResolver);
$fqsenParts = explode('::', $parts);
$resolved = $fqsenResolver->resolve($fqsenParts[0], $context);

if (!array_key_exists(1, $fqsenParts)) {
return $resolved;
}

return new Fqsen($resolved . '::' . $fqsenParts[1]);
}




public function getReference(): Reference
{
return $this->refers;
}




public function __toString(): string
{
if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

$refers = (string) $this->refers;

return $refers . ($description !== '' ? ($refers !== '' ? ' ' : '') . $description : '');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;




final class Link extends BaseTag implements Factory\StaticMethod
{

protected $name = 'link';


private $link;




public function __construct(string $link, ?Description $description = null)
{
$this->link = $link;
$this->description = $description;
}

public static function create(
string $body,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Assert::notNull($descriptionFactory);

$parts = Utils::pregSplit('/\s+/Su', $body, 2);
$description = isset($parts[1]) ? $descriptionFactory->create($parts[1], $context) : null;

return new static($parts[0], $description);
}




public function getLink(): string
{
return $this->link;
}




public function __toString(): string
{
if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

$link = $this->link;

return $link . ($description !== '' ? ($link !== '' ? ' ' : '') . $description : '');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use Webmozart\Assert\Assert;

use function preg_match;




final class Version extends BaseTag implements Factory\StaticMethod
{

protected $name = 'version';





public const REGEX_VECTOR = '(?:
        # Normal release vectors.
        \d\S*
        |
        # VCS version vectors. Per PHPCS, they are expected to
        # follow the form of the VCS name, followed by ":", followed
        # by the version vector itself.
        # By convention, popular VCSes like CVS, SVN and GIT use "$"
        # around the actual version vector.
        [^\s\:]+\:\s*\$[^\$]+\$
    )';


private $version;

public function __construct(?string $version = null, ?Description $description = null)
{
Assert::nullOrStringNotEmpty($version);

$this->version = $version;
$this->description = $description;
}

public static function create(
?string $body,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): ?self {
if (empty($body)) {
return new static();
}

$matches = [];
if (!preg_match('/^(' . self::REGEX_VECTOR . ')\s*(.+)?$/sux', $body, $matches)) {
return null;
}

$description = null;
if ($descriptionFactory !== null) {
$description = $descriptionFactory->create($matches[2] ?? '', $context);
}

return new static(
$matches[1],
$description
);
}




public function getVersion(): ?string
{
return $this->version;
}




public function __toString(): string
{
if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

$version = (string) $this->version;

return $version . ($description !== '' ? ($version !== '' ? ' ' : '') . $description : '');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use Webmozart\Assert\Assert;




final class Throws extends TagWithType implements Factory\StaticMethod
{
public function __construct(Type $type, ?Description $description = null)
{
$this->name = 'throws';
$this->type = $type;
$this->description = $description;
}

public static function create(
string $body,
?TypeResolver $typeResolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Assert::notNull($typeResolver);
Assert::notNull($descriptionFactory);

[$type, $description] = self::extractTypeFromBody($body);

$type = $typeResolver->resolve($type, $context);
$description = $descriptionFactory->create($description, $context);

return new static($type, $description);
}

public function __toString(): string
{
if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

$type = (string) $this->type;

return $type . ($description !== '' ? ($type !== '' ? ' ' : '') . $description : '');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use Webmozart\Assert\Assert;

use function preg_match;




final class Deprecated extends BaseTag implements Factory\StaticMethod
{

protected $name = 'deprecated';





public const REGEX_VECTOR = '(?:
        # Normal release vectors.
        \d\S*
        |
        # VCS version vectors. Per PHPCS, they are expected to
        # follow the form of the VCS name, followed by ":", followed
        # by the version vector itself.
        # By convention, popular VCSes like CVS, SVN and GIT use "$"
        # around the actual version vector.
        [^\s\:]+\:\s*\$[^\$]+\$
    )';


private $version;

public function __construct(?string $version = null, ?Description $description = null)
{
Assert::nullOrNotEmpty($version);

$this->version = $version;
$this->description = $description;
}




public static function create(
?string $body,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
if (empty($body)) {
return new static();
}

$matches = [];
if (!preg_match('/^(' . self::REGEX_VECTOR . ')\s*(.+)?$/sux', $body, $matches)) {
return new static(
null,
$descriptionFactory !== null ? $descriptionFactory->create($body, $context) : null
);
}

Assert::notNull($descriptionFactory);

return new static(
$matches[1],
$descriptionFactory->create($matches[2] ?? '', $context)
);
}




public function getVersion(): ?string
{
return $this->version;
}




public function __toString(): string
{
if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

$version = (string) $this->version;

return $version . ($description !== '' ? ($version !== '' ? ' ' : '') . $description : '');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\FqsenResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

use function array_key_exists;
use function explode;




final class Uses extends BaseTag implements Factory\StaticMethod
{

protected $name = 'uses';


protected $refers;




public function __construct(Fqsen $refers, ?Description $description = null)
{
$this->refers = $refers;
$this->description = $description;
}

public static function create(
string $body,
?FqsenResolver $resolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Assert::notNull($resolver);
Assert::notNull($descriptionFactory);

$parts = Utils::pregSplit('/\s+/Su', $body, 2);

return new static(
self::resolveFqsen($parts[0], $resolver, $context),
$descriptionFactory->create($parts[1] ?? '', $context)
);
}

private static function resolveFqsen(string $parts, ?FqsenResolver $fqsenResolver, ?TypeContext $context): Fqsen
{
Assert::notNull($fqsenResolver);
$fqsenParts = explode('::', $parts);
$resolved = $fqsenResolver->resolve($fqsenParts[0], $context);

if (!array_key_exists(1, $fqsenParts)) {
return $resolved;
}

return new Fqsen($resolved . '::' . $fqsenParts[1]);
}




public function getReference(): Fqsen
{
return $this->refers;
}




public function __toString(): string
{
if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

$refers = (string) $this->refers;

return $refers . ($description !== '' ? ($refers !== '' ? ' ' : '') . $description : '');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

use function array_shift;
use function array_unshift;
use function implode;
use function strpos;
use function substr;

use const PREG_SPLIT_DELIM_CAPTURE;




final class Property extends TagWithType implements Factory\StaticMethod
{

protected $variableName;

public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null)
{
Assert::string($variableName);

$this->name = 'property';
$this->variableName = $variableName;
$this->type = $type;
$this->description = $description;
}

public static function create(
string $body,
?TypeResolver $typeResolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Assert::stringNotEmpty($body);
Assert::notNull($typeResolver);
Assert::notNull($descriptionFactory);

[$firstPart, $body] = self::extractTypeFromBody($body);
$type = null;
$parts = Utils::pregSplit('/(\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE);
$variableName = '';


 if ($firstPart && $firstPart[0] !== '$') {
$type = $typeResolver->resolve($firstPart, $context);
} else {

 array_unshift($parts, $firstPart);
}


 if (isset($parts[0]) && strpos($parts[0], '$') === 0) {
$variableName = array_shift($parts);
if ($type) {
array_shift($parts);
}

Assert::notNull($variableName);

$variableName = substr($variableName, 1);
}

$description = $descriptionFactory->create(implode('', $parts), $context);

return new static($variableName, $type, $description);
}




public function getVariableName(): ?string
{
return $this->variableName;
}




public function __toString(): string
{
if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

if ($this->variableName) {
$variableName = '$' . $this->variableName;
} else {
$variableName = '';
}

$type = (string) $this->type;

return $type
. ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '')
. ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : '');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use InvalidArgumentException;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Types\Mixed_;
use phpDocumentor\Reflection\Types\Void_;
use Webmozart\Assert\Assert;

use function array_keys;
use function explode;
use function implode;
use function is_string;
use function preg_match;
use function sort;
use function strpos;
use function substr;
use function trim;
use function var_export;




final class Method extends BaseTag implements Factory\StaticMethod
{

protected $name = 'method';


private $methodName;





private $arguments;


private $isStatic;


private $returnType;





public function __construct(
string $methodName,
array $arguments = [],
?Type $returnType = null,
bool $static = false,
?Description $description = null
) {
Assert::stringNotEmpty($methodName);

if ($returnType === null) {
$returnType = new Void_();
}

$this->methodName = $methodName;
$this->arguments = $this->filterArguments($arguments);
$this->returnType = $returnType;
$this->isStatic = $static;
$this->description = $description;
}

public static function create(
string $body,
?TypeResolver $typeResolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): ?self {
Assert::stringNotEmpty($body);
Assert::notNull($typeResolver);
Assert::notNull($descriptionFactory);


 
 
 
 
 
 
 
 
 if (
!preg_match(
'/^
                # Static keyword
                # Declares a static method ONLY if type is also present
                (?:
                    (static)
                    \s+
                )?
                # Return type
                (?:
                    (
                        (?:[\w\|_\\\\]*\$this[\w\|_\\\\]*)
                        |
                        (?:
                            (?:[\w\|_\\\\]+)
                            # array notation
                            (?:\[\])*
                        )*+
                    )
                    \s+
                )?
                # Method name
                ([\w_]+)
                # Arguments
                (?:
                    \(([^\)]*)\)
                )?
                \s*
                # Description
                (.*)
            $/sux',
$body,
$matches
)
) {
return null;
}

[, $static, $returnType, $methodName, $argumentLines, $description] = $matches;

$static = $static === 'static';

if ($returnType === '') {
$returnType = 'void';
}

$returnType = $typeResolver->resolve($returnType, $context);
$description = $descriptionFactory->create($description, $context);


$arguments = [];
if ($argumentLines !== '') {
$argumentsExploded = explode(',', $argumentLines);
foreach ($argumentsExploded as $argument) {
$argument = explode(' ', self::stripRestArg(trim($argument)), 2);
if (strpos($argument[0], '$') === 0) {
$argumentName = substr($argument[0], 1);
$argumentType = new Mixed_();
} else {
$argumentType = $typeResolver->resolve($argument[0], $context);
$argumentName = '';
if (isset($argument[1])) {
$argument[1] = self::stripRestArg($argument[1]);
$argumentName = substr($argument[1], 1);
}
}

$arguments[] = ['name' => $argumentName, 'type' => $argumentType];
}
}

return new static($methodName, $arguments, $returnType, $static, $description);
}




public function getMethodName(): string
{
return $this->methodName;
}





public function getArguments(): array
{
return $this->arguments;
}






public function isStatic(): bool
{
return $this->isStatic;
}

public function getReturnType(): Type
{
return $this->returnType;
}

public function __toString(): string
{
$arguments = [];
foreach ($this->arguments as $argument) {
$arguments[] = $argument['type'] . ' $' . $argument['name'];
}

$argumentStr = '(' . implode(', ', $arguments) . ')';

if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

$static = $this->isStatic ? 'static' : '';

$returnType = (string) $this->returnType;

$methodName = $this->methodName;

return $static
. ($returnType !== '' ? ($static !== '' ? ' ' : '') . $returnType : '')
. ($methodName !== '' ? ($static !== '' || $returnType !== '' ? ' ' : '') . $methodName : '')
. $argumentStr
. ($description !== '' ? ' ' . $description : '');
}








private function filterArguments(array $arguments = []): array
{
$result = [];
foreach ($arguments as $argument) {
if (is_string($argument)) {
$argument = ['name' => $argument];
}

if (!isset($argument['type'])) {
$argument['type'] = new Mixed_();
}

$keys = array_keys($argument);
sort($keys);
if ($keys !== ['name', 'type']) {
throw new InvalidArgumentException(
'Arguments can only have the "name" and "type" fields, found: ' . var_export($keys, true)
);
}

$result[] = $argument;
}

return $result;
}

private static function stripRestArg(string $argument): string
{
if (strpos($argument, '...') === 0) {
$argument = trim(substr($argument, 3));
}

return $argument;
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags\Reference;

use phpDocumentor\Reflection\Fqsen as RealFqsen;




final class Fqsen implements Reference
{

private $fqsen;

public function __construct(RealFqsen $fqsen)
{
$this->fqsen = $fqsen;
}




public function __toString(): string
{
return (string) $this->fqsen;
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags\Reference;

use Webmozart\Assert\Assert;




final class Url implements Reference
{

private $uri;

public function __construct(string $uri)
{
Assert::stringNotEmpty($uri);
$this->uri = $uri;
}

public function __toString(): string
{
return $this->uri;
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags\Reference;




interface Reference
{
public function __toString(): string;
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

use function array_shift;
use function array_unshift;
use function implode;
use function strpos;
use function substr;

use const PREG_SPLIT_DELIM_CAPTURE;




final class PropertyRead extends TagWithType implements Factory\StaticMethod
{

protected $variableName;

public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null)
{
Assert::string($variableName);

$this->name = 'property-read';
$this->variableName = $variableName;
$this->type = $type;
$this->description = $description;
}

public static function create(
string $body,
?TypeResolver $typeResolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Assert::stringNotEmpty($body);
Assert::notNull($typeResolver);
Assert::notNull($descriptionFactory);

[$firstPart, $body] = self::extractTypeFromBody($body);
$type = null;
$parts = Utils::pregSplit('/(\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE);
$variableName = '';


 if ($firstPart && $firstPart[0] !== '$') {
$type = $typeResolver->resolve($firstPart, $context);
} else {

 array_unshift($parts, $firstPart);
}


 if (isset($parts[0]) && strpos($parts[0], '$') === 0) {
$variableName = array_shift($parts);
if ($type) {
array_shift($parts);
}

Assert::notNull($variableName);

$variableName = substr($variableName, 1);
}

$description = $descriptionFactory->create(implode('', $parts), $context);

return new static($variableName, $type, $description);
}




public function getVariableName(): ?string
{
return $this->variableName;
}




public function __toString(): string
{
if ($this->description) {
$description = $this->description->render();
} else {
$description = '';
}

if ($this->variableName) {
$variableName = '$' . $this->variableName;
} else {
$variableName = '';
}

$type = (string) $this->type;

return $type
. ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '')
. ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : '');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Tag;
use Webmozart\Assert\Assert;

use function array_key_exists;
use function preg_match;
use function rawurlencode;
use function str_replace;
use function strpos;
use function trim;




final class Example implements Tag, Factory\StaticMethod
{

private $filePath;





private $isURI;


private $startingLine;


private $lineCount;


private $content;

public function __construct(
string $filePath,
bool $isURI,
int $startingLine,
int $lineCount,
?string $content
) {
Assert::stringNotEmpty($filePath);
Assert::greaterThanEq($startingLine, 1);
Assert::greaterThanEq($lineCount, 0);

$this->filePath = $filePath;
$this->startingLine = $startingLine;
$this->lineCount = $lineCount;
if ($content !== null) {
$this->content = trim($content);
}

$this->isURI = $isURI;
}

public function getContent(): string
{
if ($this->content === null || $this->content === '') {
$filePath = $this->filePath;
if ($this->isURI) {
$filePath = $this->isUriRelative($this->filePath)
? str_replace('%2F', '/', rawurlencode($this->filePath))
: $this->filePath;
}

return trim($filePath);
}

return $this->content;
}

public function getDescription(): ?string
{
return $this->content;
}

public static function create(string $body): ?Tag
{

 if (!preg_match('/^\s*(?:(\"[^\"]+\")|(\S+))(?:\s+(.*))?$/sux', $body, $matches)) {
return null;
}

$filePath = null;
$fileUri = null;
if ($matches[1] !== '') {
$filePath = $matches[1];
} else {
$fileUri = $matches[2];
}

$startingLine = 1;
$lineCount = 0;
$description = null;

if (array_key_exists(3, $matches)) {
$description = $matches[3];


 if (preg_match('/^([1-9]\d*)(?:\s+((?1))\s*)?(.*)$/sux', $matches[3], $contentMatches)) {
$startingLine = (int) $contentMatches[1];
if (isset($contentMatches[2])) {
$lineCount = (int) $contentMatches[2];
}

if (array_key_exists(3, $contentMatches)) {
$description = $contentMatches[3];
}
}
}

return new static(
$filePath ?? ($fileUri ?? ''),
$fileUri !== null,
$startingLine,
$lineCount,
$description
);
}







public function getFilePath(): string
{
return trim($this->filePath, '"');
}




public function __toString(): string
{
$filePath = $this->filePath;
$isDefaultLine = $this->startingLine === 1 && $this->lineCount === 0;
$startingLine = !$isDefaultLine ? (string) $this->startingLine : '';
$lineCount = !$isDefaultLine ? (string) $this->lineCount : '';
$content = (string) $this->content;

return $filePath
. ($startingLine !== ''
? ($filePath !== '' ? ' ' : '') . $startingLine
: '')
. ($lineCount !== ''
? ($filePath !== '' || $startingLine !== '' ? ' ' : '') . $lineCount
: '')
. ($content !== ''
? ($filePath !== '' || $startingLine !== '' || $lineCount !== '' ? ' ' : '') . $content
: '');
}




private function isUriRelative(string $uri): bool
{
return strpos($uri, ':') === false;
}

public function getStartingLine(): int
{
return $this->startingLine;
}

public function getLineCount(): int
{
return $this->lineCount;
}

public function getName(): string
{
return 'example';
}

public function render(?Formatter $formatter = null): string
{
if ($formatter === null) {
$formatter = new Formatter\PassthroughFormatter();
}

return $formatter->format($this);
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags\Formatter;

use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Formatter;

use function max;
use function str_repeat;
use function strlen;

class AlignFormatter implements Formatter
{

protected $maxLen = 0;




public function __construct(array $tags)
{
foreach ($tags as $tag) {
$this->maxLen = max($this->maxLen, strlen($tag->getName()));
}
}




public function format(Tag $tag): string
{
return '@' . $tag->getName() .
str_repeat(
' ',
$this->maxLen - strlen($tag->getName()) + 1
) .
$tag;
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock\Tags\Formatter;

use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Formatter;

use function trim;

class PassthroughFormatter implements Formatter
{



public function format(Tag $tag): string
{
return trim('@' . $tag->getName() . ' ' . $tag);
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock;

use phpDocumentor\Reflection\DocBlock\Tags\Formatter;

interface Tag
{
public function getName(): string;





public static function create(string $body);

public function render(?Formatter $formatter = null): string;

public function __toString(): string;
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock;

use InvalidArgumentException;
use phpDocumentor\Reflection\DocBlock\Tags\Author;
use phpDocumentor\Reflection\DocBlock\Tags\Covers;
use phpDocumentor\Reflection\DocBlock\Tags\Deprecated;
use phpDocumentor\Reflection\DocBlock\Tags\Generic;
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
use phpDocumentor\Reflection\DocBlock\Tags\Link as LinkTag;
use phpDocumentor\Reflection\DocBlock\Tags\Method;
use phpDocumentor\Reflection\DocBlock\Tags\Param;
use phpDocumentor\Reflection\DocBlock\Tags\Property;
use phpDocumentor\Reflection\DocBlock\Tags\PropertyRead;
use phpDocumentor\Reflection\DocBlock\Tags\PropertyWrite;
use phpDocumentor\Reflection\DocBlock\Tags\Return_;
use phpDocumentor\Reflection\DocBlock\Tags\See as SeeTag;
use phpDocumentor\Reflection\DocBlock\Tags\Since;
use phpDocumentor\Reflection\DocBlock\Tags\Source;
use phpDocumentor\Reflection\DocBlock\Tags\Throws;
use phpDocumentor\Reflection\DocBlock\Tags\Uses;
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
use phpDocumentor\Reflection\DocBlock\Tags\Version;
use phpDocumentor\Reflection\FqsenResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use ReflectionMethod;
use ReflectionNamedType;
use ReflectionParameter;
use Webmozart\Assert\Assert;

use function array_merge;
use function array_slice;
use function call_user_func_array;
use function count;
use function get_class;
use function preg_match;
use function strpos;
use function trim;


















final class StandardTagFactory implements TagFactory
{

public const REGEX_TAGNAME = '[\w\-\_\\\\:]+';





private $tagHandlerMappings = [
'author' => Author::class,
'covers' => Covers::class,
'deprecated' => Deprecated::class,

 'link' => LinkTag::class,
'method' => Method::class,
'param' => Param::class,
'property-read' => PropertyRead::class,
'property' => Property::class,
'property-write' => PropertyWrite::class,
'return' => Return_::class,
'see' => SeeTag::class,
'since' => Since::class,
'source' => Source::class,
'throw' => Throws::class,
'throws' => Throws::class,
'uses' => Uses::class,
'var' => Var_::class,
'version' => Version::class,
];





private $annotationMappings = [];





private $tagHandlerParameterCache = [];


private $fqsenResolver;





private $serviceLocator = [];











public function __construct(FqsenResolver $fqsenResolver, ?array $tagHandlers = null)
{
$this->fqsenResolver = $fqsenResolver;
if ($tagHandlers !== null) {
$this->tagHandlerMappings = $tagHandlers;
}

$this->addService($fqsenResolver, FqsenResolver::class);
}

public function create(string $tagLine, ?TypeContext $context = null): Tag
{
if (!$context) {
$context = new TypeContext('');
}

[$tagName, $tagBody] = $this->extractTagParts($tagLine);

return $this->createTag(trim($tagBody), $tagName, $context);
}




public function addParameter(string $name, $value): void
{
$this->serviceLocator[$name] = $value;
}

public function addService(object $service, ?string $alias = null): void
{
$this->serviceLocator[$alias ?: get_class($service)] = $service;
}

public function registerTagHandler(string $tagName, string $handler): void
{
Assert::stringNotEmpty($tagName);
Assert::classExists($handler);
Assert::implementsInterface($handler, Tag::class);

if (strpos($tagName, '\\') && $tagName[0] !== '\\') {
throw new InvalidArgumentException(
'A namespaced tag must have a leading backslash as it must be fully qualified'
);
}

$this->tagHandlerMappings[$tagName] = $handler;
}






private function extractTagParts(string $tagLine): array
{
$matches = [];
if (!preg_match('/^@(' . self::REGEX_TAGNAME . ')((?:[\s\(\{])\s*([^\s].*)|$)/us', $tagLine, $matches)) {
throw new InvalidArgumentException(
'The tag "' . $tagLine . '" does not seem to be wellformed, please check it for errors'
);
}

if (count($matches) < 3) {
$matches[] = '';
}

return array_slice($matches, 1);
}





private function createTag(string $body, string $name, TypeContext $context): Tag
{
$handlerClassName = $this->findHandlerClassName($name, $context);
$arguments = $this->getArgumentsForParametersFromWiring(
$this->fetchParametersForHandlerFactoryMethod($handlerClassName),
$this->getServiceLocatorWithDynamicParameters($context, $name, $body)
);

try {
$callable = [$handlerClassName, 'create'];
Assert::isCallable($callable);

$tag = call_user_func_array($callable, $arguments);

return $tag ?? InvalidTag::create($body, $name);
} catch (InvalidArgumentException $e) {
return InvalidTag::create($body, $name)->withError($e);
}
}






private function findHandlerClassName(string $tagName, TypeContext $context): string
{
$handlerClassName = Generic::class;
if (isset($this->tagHandlerMappings[$tagName])) {
$handlerClassName = $this->tagHandlerMappings[$tagName];
} elseif ($this->isAnnotation($tagName)) {

 $tagName = (string) $this->fqsenResolver->resolve($tagName, $context);
if (isset($this->annotationMappings[$tagName])) {
$handlerClassName = $this->annotationMappings[$tagName];
}
}

return $handlerClassName;
}










private function getArgumentsForParametersFromWiring(array $parameters, array $locator): array
{
$arguments = [];
foreach ($parameters as $parameter) {
$type = $parameter->getType();
$typeHint = null;
if ($type instanceof ReflectionNamedType) {
$typeHint = $type->getName();
if ($typeHint === 'self') {
$declaringClass = $parameter->getDeclaringClass();
if ($declaringClass !== null) {
$typeHint = $declaringClass->getName();
}
}
}

if (isset($locator[$typeHint])) {
$arguments[] = $locator[$typeHint];
continue;
}

$parameterName = $parameter->getName();
if (isset($locator[$parameterName])) {
$arguments[] = $locator[$parameterName];
continue;
}

$arguments[] = null;
}

return $arguments;
}









private function fetchParametersForHandlerFactoryMethod(string $handlerClassName): array
{
if (!isset($this->tagHandlerParameterCache[$handlerClassName])) {
$methodReflection = new ReflectionMethod($handlerClassName, 'create');
$this->tagHandlerParameterCache[$handlerClassName] = $methodReflection->getParameters();
}

return $this->tagHandlerParameterCache[$handlerClassName];
}














private function getServiceLocatorWithDynamicParameters(
TypeContext $context,
string $tagName,
string $tagBody
): array {
return array_merge(
$this->serviceLocator,
[
'name' => $tagName,
'body' => $tagBody,
TypeContext::class => $context,
]
);
}






private function isAnnotation(string $tagContent): bool
{

 
 
 

return false;
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\DocBlock;

use InvalidArgumentException;
use phpDocumentor\Reflection\Types\Context as TypeContext;

interface TagFactory
{




















public function addParameter(string $name, $value): void;










public function create(string $tagLine, ?TypeContext $context = null): Tag;










public function addService(object $service): void;



















public function registerTagHandler(string $tagName, string $handler): void;
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\Exception;

use InvalidArgumentException;

use const PREG_BACKTRACK_LIMIT_ERROR;
use const PREG_BAD_UTF8_ERROR;
use const PREG_BAD_UTF8_OFFSET_ERROR;
use const PREG_INTERNAL_ERROR;
use const PREG_JIT_STACKLIMIT_ERROR;
use const PREG_NO_ERROR;
use const PREG_RECURSION_LIMIT_ERROR;

final class PcreException extends InvalidArgumentException
{
public static function createFromPhpError(int $errorCode): self
{
switch ($errorCode) {
case PREG_BACKTRACK_LIMIT_ERROR:
return new self('Backtrack limit error');

case PREG_RECURSION_LIMIT_ERROR:
return new self('Recursion limit error');

case PREG_BAD_UTF8_ERROR:
return new self('Bad UTF8 error');

case PREG_BAD_UTF8_OFFSET_ERROR:
return new self('Bad UTF8 offset error');

case PREG_JIT_STACKLIMIT_ERROR:
return new self('Jit stacklimit error');

case PREG_NO_ERROR:
case PREG_INTERNAL_ERROR:
default:
}

return new self('Unknown Pcre error');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection;

use InvalidArgumentException;
use LogicException;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\StandardTagFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\TagFactory;
use Webmozart\Assert\Assert;

use function array_shift;
use function count;
use function explode;
use function is_object;
use function method_exists;
use function preg_match;
use function preg_replace;
use function str_replace;
use function strpos;
use function substr;
use function trim;

final class DocBlockFactory implements DocBlockFactoryInterface
{

private $descriptionFactory;


private $tagFactory;




public function __construct(DescriptionFactory $descriptionFactory, TagFactory $tagFactory)
{
$this->descriptionFactory = $descriptionFactory;
$this->tagFactory = $tagFactory;
}






public static function createInstance(array $additionalTags = []): self
{
$fqsenResolver = new FqsenResolver();
$tagFactory = new StandardTagFactory($fqsenResolver);
$descriptionFactory = new DescriptionFactory($tagFactory);

$tagFactory->addService($descriptionFactory);
$tagFactory->addService(new TypeResolver($fqsenResolver));

$docBlockFactory = new self($descriptionFactory, $tagFactory);
foreach ($additionalTags as $tagName => $tagHandler) {
$docBlockFactory->registerTagHandler($tagName, $tagHandler);
}

return $docBlockFactory;
}





public function create($docblock, ?Types\Context $context = null, ?Location $location = null): DocBlock
{
if (is_object($docblock)) {
if (!method_exists($docblock, 'getDocComment')) {
$exceptionMessage = 'Invalid object passed; the given object must support the getDocComment method';

throw new InvalidArgumentException($exceptionMessage);
}

$docblock = $docblock->getDocComment();
Assert::string($docblock);
}

Assert::stringNotEmpty($docblock);

if ($context === null) {
$context = new Types\Context('');
}

$parts = $this->splitDocBlock($this->stripDocComment($docblock));

[$templateMarker, $summary, $description, $tags] = $parts;

return new DocBlock(
$summary,
$description ? $this->descriptionFactory->create($description, $context) : null,
$this->parseTagBlock($tags, $context),
$context,
$location,
$templateMarker === '#@+',
$templateMarker === '#@-'
);
}




public function registerTagHandler(string $tagName, string $handler): void
{
$this->tagFactory->registerTagHandler($tagName, $handler);
}






private function stripDocComment(string $comment): string
{
$comment = preg_replace('#[ \t]*(?:\/\*\*|\*\/|\*)?[ \t]?(.*)?#u', '$1', $comment);
Assert::string($comment);
$comment = trim($comment);


 if (substr($comment, -2) === '*/') {
$comment = trim(substr($comment, 0, -2));
}

return str_replace(["\r\n", "\r"], "\n", $comment);
}


 










private function splitDocBlock(string $comment) : array
{

 
 
 
 if (strpos($comment, '@') === 0) {
return ['', '', '', $comment];
}


 $comment = preg_replace('/\h*$/Sum', '', $comment);
Assert::string($comment);














preg_match(
'/
            \A
            # 1. Extract the template marker
            (?:(\#\@\+|\#\@\-)\n?)?

            # 2. Extract the summary
            (?:
              (?! @\pL ) # The summary may not start with an @
              (
                [^\n.]+
                (?:
                  (?! \. \n | \n{2} )     # End summary upon a dot followed by newline or two newlines
                  [\n.]* (?! [ \t]* @\pL ) # End summary when an @ is found as first character on a new line
                  [^\n.]+                 # Include anything else
                )*
                \.?
              )?
            )

            # 3. Extract the description
            (?:
              \s*        # Some form of whitespace _must_ precede a description because a summary must be there
              (?! @\pL ) # The description may not start with an @
              (
                [^\n]+
                (?: \n+
                  (?! [ \t]* @\pL ) # End description when an @ is found as first character on a new line
                  [^\n]+            # Include anything else
                )*
              )
            )?

            # 4. Extract the tags (anything that follows)
            (\s+ [\s\S]*)? # everything that follows
            /ux',
$comment,
$matches
);
array_shift($matches);

while (count($matches) < 4) {
$matches[] = '';
}

return $matches;
}









private function parseTagBlock(string $tags, Types\Context $context): array
{
$tags = $this->filterTagBlock($tags);
if ($tags === null) {
return [];
}

$result = [];
$lines = $this->splitTagBlockIntoTagLines($tags);
foreach ($lines as $key => $tagLine) {
$result[$key] = $this->tagFactory->create(trim($tagLine), $context);
}

return $result;
}




private function splitTagBlockIntoTagLines(string $tags): array
{
$result = [];
foreach (explode("\n", $tags) as $tagLine) {
if ($tagLine !== '' && strpos($tagLine, '@') === 0) {
$result[] = $tagLine;
} else {
$result[count($result) - 1] .= "\n" . $tagLine;
}
}

return $result;
}

private function filterTagBlock(string $tags): ?string
{
$tags = trim($tags);
if (!$tags) {
return null;
}

if ($tags[0] !== '@') {

 
 

throw new LogicException('A tag block started with text instead of an at-sign(@): ' . $tags);


 }

return $tags;
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection;

interface PseudoType extends Type
{
public function underlyingType(): Type;
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection;

use ArrayIterator;
use InvalidArgumentException;
use phpDocumentor\Reflection\Types\Array_;
use phpDocumentor\Reflection\Types\ArrayKey;
use phpDocumentor\Reflection\Types\ClassString;
use phpDocumentor\Reflection\Types\Collection;
use phpDocumentor\Reflection\Types\Compound;
use phpDocumentor\Reflection\Types\Context;
use phpDocumentor\Reflection\Types\Expression;
use phpDocumentor\Reflection\Types\Integer;
use phpDocumentor\Reflection\Types\InterfaceString;
use phpDocumentor\Reflection\Types\Intersection;
use phpDocumentor\Reflection\Types\Iterable_;
use phpDocumentor\Reflection\Types\Nullable;
use phpDocumentor\Reflection\Types\Object_;
use phpDocumentor\Reflection\Types\String_;
use RuntimeException;

use function array_key_exists;
use function array_pop;
use function array_values;
use function class_exists;
use function class_implements;
use function count;
use function end;
use function in_array;
use function key;
use function preg_split;
use function strpos;
use function strtolower;
use function trim;

use const PREG_SPLIT_DELIM_CAPTURE;
use const PREG_SPLIT_NO_EMPTY;

final class TypeResolver
{

private const OPERATOR_ARRAY = '[]';


private const OPERATOR_NAMESPACE = '\\';


private const PARSER_IN_COMPOUND = 0;


private const PARSER_IN_NULLABLE = 1;


private const PARSER_IN_ARRAY_EXPRESSION = 2;


private const PARSER_IN_COLLECTION_EXPRESSION = 3;





private $keywords = [
'string' => Types\String_::class,
'class-string' => Types\ClassString::class,
'interface-string' => Types\InterfaceString::class,
'html-escaped-string' => PseudoTypes\HtmlEscapedString::class,
'lowercase-string' => PseudoTypes\LowercaseString::class,
'non-empty-lowercase-string' => PseudoTypes\NonEmptyLowercaseString::class,
'non-empty-string' => PseudoTypes\NonEmptyString::class,
'numeric-string' => PseudoTypes\NumericString::class,
'trait-string' => PseudoTypes\TraitString::class,
'int' => Types\Integer::class,
'integer' => Types\Integer::class,
'positive-int' => PseudoTypes\PositiveInteger::class,
'bool' => Types\Boolean::class,
'boolean' => Types\Boolean::class,
'real' => Types\Float_::class,
'float' => Types\Float_::class,
'double' => Types\Float_::class,
'object' => Types\Object_::class,
'mixed' => Types\Mixed_::class,
'array' => Types\Array_::class,
'array-key' => Types\ArrayKey::class,
'resource' => Types\Resource_::class,
'void' => Types\Void_::class,
'null' => Types\Null_::class,
'scalar' => Types\Scalar::class,
'callback' => Types\Callable_::class,
'callable' => Types\Callable_::class,
'callable-string' => PseudoTypes\CallableString::class,
'false' => PseudoTypes\False_::class,
'true' => PseudoTypes\True_::class,
'literal-string' => PseudoTypes\LiteralString::class,
'self' => Types\Self_::class,
'$this' => Types\This::class,
'static' => Types\Static_::class,
'parent' => Types\Parent_::class,
'iterable' => Types\Iterable_::class,
'never' => Types\Never_::class,
];





private $fqsenResolver;




public function __construct(?FqsenResolver $fqsenResolver = null)
{
$this->fqsenResolver = $fqsenResolver ?: new FqsenResolver();
}

















public function resolve(string $type, ?Context $context = null): Type
{
$type = trim($type);
if (!$type) {
throw new InvalidArgumentException('Attempted to resolve "' . $type . '" but it appears to be empty');
}

if ($context === null) {
$context = new Context('');
}


 $tokens = preg_split(
'/(\\||\\?|<|>|&|, ?|\\(|\\)|\\[\\]+)/',
$type,
-1,
PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE
);

if ($tokens === false) {
throw new InvalidArgumentException('Unable to split the type string "' . $type . '" into tokens');
}


$tokenIterator = new ArrayIterator($tokens);

return $this->parseTypes($tokenIterator, $context, self::PARSER_IN_COMPOUND);
}








private function parseTypes(ArrayIterator $tokens, Context $context, int $parserContext): Type
{
$types = [];
$token = '';
$compoundToken = '|';
while ($tokens->valid()) {
$token = $tokens->current();
if ($token === null) {
throw new RuntimeException(
'Unexpected nullable character'
);
}

if ($token === '|' || $token === '&') {
if (count($types) === 0) {
throw new RuntimeException(
'A type is missing before a type separator'
);
}

if (
!in_array($parserContext, [
self::PARSER_IN_COMPOUND,
self::PARSER_IN_ARRAY_EXPRESSION,
self::PARSER_IN_COLLECTION_EXPRESSION,
], true)
) {
throw new RuntimeException(
'Unexpected type separator'
);
}

$compoundToken = $token;
$tokens->next();
} elseif ($token === '?') {
if (
!in_array($parserContext, [
self::PARSER_IN_COMPOUND,
self::PARSER_IN_ARRAY_EXPRESSION,
self::PARSER_IN_COLLECTION_EXPRESSION,
], true)
) {
throw new RuntimeException(
'Unexpected nullable character'
);
}

$tokens->next();
$type = $this->parseTypes($tokens, $context, self::PARSER_IN_NULLABLE);
$types[] = new Nullable($type);
} elseif ($token === '(') {
$tokens->next();
$type = $this->parseTypes($tokens, $context, self::PARSER_IN_ARRAY_EXPRESSION);

$token = $tokens->current();
if ($token === null) { 
 break;
}

$tokens->next();

$resolvedType = new Expression($type);

$types[] = $resolvedType;
} elseif ($parserContext === self::PARSER_IN_ARRAY_EXPRESSION && isset($token[0]) && $token[0] === ')') {
break;
} elseif ($token === '<') {
if (count($types) === 0) {
throw new RuntimeException(
'Unexpected collection operator "<", class name is missing'
);
}

$classType = array_pop($types);
if ($classType !== null) {
if ((string) $classType === 'class-string') {
$types[] = $this->resolveClassString($tokens, $context);
} elseif ((string) $classType === 'interface-string') {
$types[] = $this->resolveInterfaceString($tokens, $context);
} else {
$types[] = $this->resolveCollection($tokens, $classType, $context);
}
}

$tokens->next();
} elseif (
$parserContext === self::PARSER_IN_COLLECTION_EXPRESSION
&& ($token === '>' || trim($token) === ',')
) {
break;
} elseif ($token === self::OPERATOR_ARRAY) {
end($types);
$last = key($types);
$lastItem = $types[$last];
if ($lastItem instanceof Expression) {
$lastItem = $lastItem->getValueType();
}

$types[$last] = new Array_($lastItem);

$tokens->next();
} else {
$type = $this->resolveSingleType($token, $context);
$tokens->next();
if ($parserContext === self::PARSER_IN_NULLABLE) {
return $type;
}

$types[] = $type;
}
}

if ($token === '|' || $token === '&') {
throw new RuntimeException(
'A type is missing after a type separator'
);
}

if (count($types) === 0) {
if ($parserContext === self::PARSER_IN_NULLABLE) {
throw new RuntimeException(
'A type is missing after a nullable character'
);
}

if ($parserContext === self::PARSER_IN_ARRAY_EXPRESSION) {
throw new RuntimeException(
'A type is missing in an array expression'
);
}

if ($parserContext === self::PARSER_IN_COLLECTION_EXPRESSION) {
throw new RuntimeException(
'A type is missing in a collection expression'
);
}
} elseif (count($types) === 1) {
return $types[0];
}

if ($compoundToken === '|') {
return new Compound(array_values($types));
}

return new Intersection(array_values($types));
}










private function resolveSingleType(string $type, Context $context): object
{
switch (true) {
case $this->isKeyword($type):
return $this->resolveKeyword($type);

case $this->isFqsen($type):
return $this->resolveTypedObject($type);

case $this->isPartialStructuralElementName($type):
return $this->resolveTypedObject($type, $context);


 default:

 throw new RuntimeException(
'Unable to resolve type "' . $type . '", there is no known method to resolve it'
);
}


 }






public function addKeyword(string $keyword, string $typeClassName): void
{
if (!class_exists($typeClassName)) {
throw new InvalidArgumentException(
'The Value Object that needs to be created with a keyword "' . $keyword . '" must be an existing class'
. ' but we could not find the class ' . $typeClassName
);
}

$interfaces = class_implements($typeClassName);
if ($interfaces === false) {
throw new InvalidArgumentException(
'The Value Object that needs to be created with a keyword "' . $keyword . '" must be an existing class'
. ' but we could not find the class ' . $typeClassName
);
}

if (!in_array(Type::class, $interfaces, true)) {
throw new InvalidArgumentException(
'The class "' . $typeClassName . '" must implement the interface "phpDocumentor\Reflection\Type"'
);
}

$this->keywords[$keyword] = $typeClassName;
}








private function isKeyword(string $type): bool
{
return array_key_exists(strtolower($type), $this->keywords);
}








private function isPartialStructuralElementName(string $type): bool
{
return (isset($type[0]) && $type[0] !== self::OPERATOR_NAMESPACE) && !$this->isKeyword($type);
}






private function isFqsen(string $type): bool
{
return strpos($type, self::OPERATOR_NAMESPACE) === 0;
}






private function resolveKeyword(string $type): Type
{
$className = $this->keywords[strtolower($type)];

return new $className();
}






private function resolveTypedObject(string $type, ?Context $context = null): Object_
{
return new Object_($this->fqsenResolver->resolve($type, $context));
}






private function resolveClassString(ArrayIterator $tokens, Context $context): Type
{
$tokens->next();

$classType = $this->parseTypes($tokens, $context, self::PARSER_IN_COLLECTION_EXPRESSION);

if (!$classType instanceof Object_ || $classType->getFqsen() === null) {
throw new RuntimeException(
$classType . ' is not a class string'
);
}

$token = $tokens->current();
if ($token !== '>') {
if (empty($token)) {
throw new RuntimeException(
'class-string: ">" is missing'
);
}

throw new RuntimeException(
'Unexpected character "' . $token . '", ">" is missing'
);
}

return new ClassString($classType->getFqsen());
}






private function resolveInterfaceString(ArrayIterator $tokens, Context $context): Type
{
$tokens->next();

$classType = $this->parseTypes($tokens, $context, self::PARSER_IN_COLLECTION_EXPRESSION);

if (!$classType instanceof Object_ || $classType->getFqsen() === null) {
throw new RuntimeException(
$classType . ' is not a interface string'
);
}

$token = $tokens->current();
if ($token !== '>') {
if (empty($token)) {
throw new RuntimeException(
'interface-string: ">" is missing'
);
}

throw new RuntimeException(
'Unexpected character "' . $token . '", ">" is missing'
);
}

return new InterfaceString($classType->getFqsen());
}








private function resolveCollection(ArrayIterator $tokens, Type $classType, Context $context): Type
{
$isArray = ((string) $classType === 'array');
$isIterable = ((string) $classType === 'iterable');


 if (
!$isArray && !$isIterable
&& (!$classType instanceof Object_ || $classType->getFqsen() === null)
) {
throw new RuntimeException(
$classType . ' is not a collection'
);
}

$tokens->next();

$valueType = $this->parseTypes($tokens, $context, self::PARSER_IN_COLLECTION_EXPRESSION);
$keyType = null;

$token = $tokens->current();
if ($token !== null && trim($token) === ',') {

 $keyType = $valueType;
if ($isArray) {

 
 if (
!$keyType instanceof ArrayKey &&
!$keyType instanceof String_ &&
!$keyType instanceof Integer &&
!$keyType instanceof Compound
) {
throw new RuntimeException(
'An array can have only integers or strings as keys'
);
}

if ($keyType instanceof Compound) {
foreach ($keyType->getIterator() as $item) {
if (
!$item instanceof ArrayKey &&
!$item instanceof String_ &&
!$item instanceof Integer
) {
throw new RuntimeException(
'An array can have only integers or strings as keys'
);
}
}
}
}

$tokens->next();

 $valueType = $this->parseTypes($tokens, $context, self::PARSER_IN_COLLECTION_EXPRESSION);
}

$token = $tokens->current();
if ($token !== '>') {
if (empty($token)) {
throw new RuntimeException(
'Collection: ">" is missing'
);
}

throw new RuntimeException(
'Unexpected character "' . $token . '", ">" is missing'
);
}

if ($isArray) {
return new Array_($valueType, $keyType);
}

if ($isIterable) {
return new Iterable_($valueType, $keyType);
}

if ($classType instanceof Object_) {
return $this->makeCollectionFromObject($classType, $valueType, $keyType);
}

throw new RuntimeException('Invalid $classType provided');
}




private function makeCollectionFromObject(Object_ $object, Type $valueType, ?Type $keyType = null): Collection
{
return new Collection($object->getFqsen(), $valueType, $keyType);
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection;

use InvalidArgumentException;
use phpDocumentor\Reflection\Types\Context;

use function explode;
use function implode;
use function strpos;






class FqsenResolver
{

private const OPERATOR_NAMESPACE = '\\';

public function resolve(string $fqsen, ?Context $context = null): Fqsen
{
if ($context === null) {
$context = new Context('');
}

if ($this->isFqsen($fqsen)) {
return new Fqsen($fqsen);
}

return $this->resolvePartialStructuralElementName($fqsen, $context);
}




private function isFqsen(string $type): bool
{
return strpos($type, self::OPERATOR_NAMESPACE) === 0;
}







private function resolvePartialStructuralElementName(string $type, Context $context): Fqsen
{
$typeParts = explode(self::OPERATOR_NAMESPACE, $type, 2);

$namespaceAliases = $context->getNamespaceAliases();


 if (!isset($namespaceAliases[$typeParts[0]])) {
$namespace = $context->getNamespace();
if ($namespace !== '') {
$namespace .= self::OPERATOR_NAMESPACE;
}

return new Fqsen(self::OPERATOR_NAMESPACE . $namespace . $type);
}

$typeParts[0] = $namespaceAliases[$typeParts[0]];

return new Fqsen(self::OPERATOR_NAMESPACE . implode(self::OPERATOR_NAMESPACE, $typeParts));
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;






final class HtmlEscapedString extends String_ implements PseudoType
{
public function underlyingType(): Type
{
return new String_();
}




public function __toString(): string
{
return 'html-escaped-string';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;






final class CallableString extends String_ implements PseudoType
{
public function underlyingType(): Type
{
return new String_();
}




public function __toString(): string
{
return 'callable-string';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;






final class LowercaseString extends String_ implements PseudoType
{
public function underlyingType(): Type
{
return new String_();
}




public function __toString(): string
{
return 'lowercase-string';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;






final class NonEmptyLowercaseString extends String_ implements PseudoType
{
public function underlyingType(): Type
{
return new String_();
}




public function __toString(): string
{
return 'non-empty-lowercase-string';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;






final class NonEmptyString extends String_ implements PseudoType
{
public function underlyingType(): Type
{
return new String_();
}




public function __toString(): string
{
return 'non-empty-string';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;






final class NumericString extends String_ implements PseudoType
{
public function underlyingType(): Type
{
return new String_();
}




public function __toString(): string
{
return 'numeric-string';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Integer;






final class PositiveInteger extends Integer implements PseudoType
{
public function underlyingType(): Type
{
return new Integer();
}




public function __toString(): string
{
return 'positive-int';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;






final class LiteralString extends String_ implements PseudoType
{
public function underlyingType(): Type
{
return new String_();
}




public function __toString(): string
{
return 'literal-string';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Boolean;

use function class_alias;






final class False_ extends Boolean implements PseudoType
{
public function underlyingType(): Type
{
return new Boolean();
}

public function __toString(): string
{
return 'false';
}
}

class_alias('\phpDocumentor\Reflection\PseudoTypes\False_', 'phpDocumentor\Reflection\Types\False_', false);
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;






final class TraitString extends String_ implements PseudoType
{
public function underlyingType(): Type
{
return new String_();
}




public function __toString(): string
{
return 'trait-string';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Boolean;

use function class_alias;






final class True_ extends Boolean implements PseudoType
{
public function underlyingType(): Type
{
return new Boolean();
}

public function __toString(): string
{
return 'true';
}
}

class_alias('\phpDocumentor\Reflection\PseudoTypes\True_', 'phpDocumentor\Reflection\Types\True_', false);
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection;




interface Type
{



public function __toString(): string;
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;






final class Callable_ implements Type
{



public function __toString(): string
{
return 'callable';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\Type;






final class InterfaceString implements Type
{

private $fqsen;




public function __construct(?Fqsen $fqsen = null)
{
$this->fqsen = $fqsen;
}




public function getFqsen(): ?Fqsen
{
return $this->fqsen;
}




public function __toString(): string
{
if ($this->fqsen === null) {
return 'interface-string';
}

return 'interface-string<' . (string) $this->fqsen . '>';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;








final class Self_ implements Type
{



public function __toString(): string
{
return 'self';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;






final class Expression implements Type
{

protected $valueType;




public function __construct(Type $valueType)
{
$this->valueType = $valueType;
}




public function getValueType(): Type
{
return $this->valueType;
}




public function __toString(): string
{
return '(' . $this->valueType . ')';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;






final class Mixed_ implements Type
{



public function __toString(): string
{
return 'mixed';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;






final class Iterable_ extends AbstractList
{



public function __toString(): string
{
if ($this->keyType) {
return 'iterable<' . $this->keyType . ',' . $this->valueType . '>';
}

if ($this->valueType instanceof Mixed_) {
return 'iterable';
}

return 'iterable<' . $this->valueType . '>';
}
}
<?php









declare(strict_types=1);

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;










final class Intersection extends AggregatedType
{





public function __construct(array $types)
{
parent::__construct($types, '&');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;






final class Nullable implements Type
{

private $realType;




public function __construct(Type $realType)
{
$this->realType = $realType;
}




public function getActualType(): Type
{
return $this->realType;
}




public function __toString(): string
{
return '?' . $this->realType->__toString();
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;






final class Null_ implements Type
{



public function __toString(): string
{
return 'null';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;






final class Float_ implements Type
{



public function __toString(): string
{
return 'float';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;






final class ClassString extends String_ implements PseudoType
{

private $fqsen;




public function __construct(?Fqsen $fqsen = null)
{
$this->fqsen = $fqsen;
}

public function underlyingType(): Type
{
return new String_();
}




public function getFqsen(): ?Fqsen
{
return $this->fqsen;
}




public function __toString(): string
{
if ($this->fqsen === null) {
return 'class-string';
}

return 'class-string<' . (string) $this->fqsen . '>';
}
}
<?php









declare(strict_types=1);

namespace phpDocumentor\Reflection\Types;

use ArrayIterator;
use IteratorAggregate;
use phpDocumentor\Reflection\Type;

use function array_key_exists;
use function implode;










abstract class AggregatedType implements Type, IteratorAggregate
{




private $types = [];


private $token;




public function __construct(array $types, string $token)
{
foreach ($types as $type) {
$this->add($type);
}

$this->token = $token;
}




public function get(int $index): ?Type
{
if (!$this->has($index)) {
return null;
}

return $this->types[$index];
}




public function has(int $index): bool
{
return array_key_exists($index, $this->types);
}




public function contains(Type $type): bool
{
foreach ($this->types as $typePart) {

 if ((string) $typePart === (string) $type) {
return true;
}
}

return false;
}




public function __toString(): string
{
return implode($this->token, $this->types);
}




public function getIterator(): ArrayIterator
{
return new ArrayIterator($this->types);
}




private function add(Type $type): void
{
if ($type instanceof self) {
foreach ($type->getIterator() as $subType) {
$this->add($subType);
}

return;
}


 if ($this->contains($type)) {
return;
}

$this->types[] = $type;
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;









final class Void_ implements Type
{



public function __toString(): string
{
return 'void';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;






final class Resource_ implements Type
{



public function __toString(): string
{
return 'resource';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;






class Boolean implements Type
{



public function __toString(): string
{
return 'bool';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use ArrayIterator;
use InvalidArgumentException;
use ReflectionClass;
use ReflectionClassConstant;
use ReflectionMethod;
use ReflectionParameter;
use ReflectionProperty;
use Reflector;
use RuntimeException;
use UnexpectedValueException;

use function define;
use function defined;
use function file_exists;
use function file_get_contents;
use function get_class;
use function in_array;
use function is_string;
use function strrpos;
use function substr;
use function token_get_all;
use function trim;

use const T_AS;
use const T_CLASS;
use const T_CURLY_OPEN;
use const T_DOLLAR_OPEN_CURLY_BRACES;
use const T_NAME_FULLY_QUALIFIED;
use const T_NAME_QUALIFIED;
use const T_NAMESPACE;
use const T_NS_SEPARATOR;
use const T_STRING;
use const T_USE;

if (!defined('T_NAME_QUALIFIED')) {
define('T_NAME_QUALIFIED', 'T_NAME_QUALIFIED');
}

if (!defined('T_NAME_FULLY_QUALIFIED')) {
define('T_NAME_FULLY_QUALIFIED', 'T_NAME_FULLY_QUALIFIED');
}










final class ContextFactory
{

private const T_LITERAL_END_OF_USE = ';';


private const T_LITERAL_USE_SEPARATOR = ',';






public function createFromReflector(Reflector $reflector): Context
{
if ($reflector instanceof ReflectionClass) {

 

return $this->createFromReflectionClass($reflector);
}

if ($reflector instanceof ReflectionParameter) {
return $this->createFromReflectionParameter($reflector);
}

if ($reflector instanceof ReflectionMethod) {
return $this->createFromReflectionMethod($reflector);
}

if ($reflector instanceof ReflectionProperty) {
return $this->createFromReflectionProperty($reflector);
}

if ($reflector instanceof ReflectionClassConstant) {
return $this->createFromReflectionClassConstant($reflector);
}

throw new UnexpectedValueException('Unhandled \Reflector instance given:  ' . get_class($reflector));
}

private function createFromReflectionParameter(ReflectionParameter $parameter): Context
{
$class = $parameter->getDeclaringClass();
if (!$class) {
throw new InvalidArgumentException('Unable to get class of ' . $parameter->getName());
}

return $this->createFromReflectionClass($class);
}

private function createFromReflectionMethod(ReflectionMethod $method): Context
{
$class = $method->getDeclaringClass();

return $this->createFromReflectionClass($class);
}

private function createFromReflectionProperty(ReflectionProperty $property): Context
{
$class = $property->getDeclaringClass();

return $this->createFromReflectionClass($class);
}

private function createFromReflectionClassConstant(ReflectionClassConstant $constant): Context
{

 
$class = $constant->getDeclaringClass();

return $this->createFromReflectionClass($class);
}




private function createFromReflectionClass(ReflectionClass $class): Context
{
$fileName = $class->getFileName();
$namespace = $class->getNamespaceName();

if (is_string($fileName) && file_exists($fileName)) {
$contents = file_get_contents($fileName);
if ($contents === false) {
throw new RuntimeException('Unable to read file "' . $fileName . '"');
}

return $this->createForNamespace($namespace, $contents);
}

return new Context($namespace, []);
}










public function createForNamespace(string $namespace, string $fileContents): Context
{
$namespace = trim($namespace, '\\');
$useStatements = [];
$currentNamespace = '';
$tokens = new ArrayIterator(token_get_all($fileContents));

while ($tokens->valid()) {
$currentToken = $tokens->current();
switch ($currentToken[0]) {
case T_NAMESPACE:
$currentNamespace = $this->parseNamespace($tokens);
break;
case T_CLASS:

 
 
 $braceLevel = 0;
$firstBraceFound = false;
while ($tokens->valid() && ($braceLevel > 0 || !$firstBraceFound)) {
$currentToken = $tokens->current();
if (
$currentToken === '{'
|| in_array($currentToken[0], [T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES], true)
) {
if (!$firstBraceFound) {
$firstBraceFound = true;
}

++$braceLevel;
}

if ($currentToken === '}') {
--$braceLevel;
}

$tokens->next();
}

break;
case T_USE:
if ($currentNamespace === $namespace) {
$useStatements += $this->parseUseStatement($tokens);
}

break;
}

$tokens->next();
}

return new Context($namespace, $useStatements);
}






private function parseNamespace(ArrayIterator $tokens): string
{

 $this->skipToNextStringOrNamespaceSeparator($tokens);

$name = '';
$acceptedTokens = [T_STRING, T_NS_SEPARATOR, T_NAME_QUALIFIED];
while ($tokens->valid() && in_array($tokens->current()[0], $acceptedTokens, true)) {
$name .= $tokens->current()[1];
$tokens->next();
}

return $name;
}









private function parseUseStatement(ArrayIterator $tokens): array
{
$uses = [];

while ($tokens->valid()) {
$this->skipToNextStringOrNamespaceSeparator($tokens);

$uses += $this->extractUseStatements($tokens);
$currentToken = $tokens->current();
if ($currentToken[0] === self::T_LITERAL_END_OF_USE) {
return $uses;
}
}

return $uses;
}






private function skipToNextStringOrNamespaceSeparator(ArrayIterator $tokens): void
{
while ($tokens->valid()) {
$currentToken = $tokens->current();
if (in_array($currentToken[0], [T_STRING, T_NS_SEPARATOR], true)) {
break;
}

if ($currentToken[0] === T_NAME_QUALIFIED) {
break;
}

if (defined('T_NAME_FULLY_QUALIFIED') && $currentToken[0] === T_NAME_FULLY_QUALIFIED) {
break;
}

$tokens->next();
}
}












private function extractUseStatements(ArrayIterator $tokens): array
{
$extractedUseStatements = [];
$groupedNs = '';
$currentNs = '';
$currentAlias = '';
$state = 'start';

while ($tokens->valid()) {
$currentToken = $tokens->current();
$tokenId = is_string($currentToken) ? $currentToken : $currentToken[0];
$tokenValue = is_string($currentToken) ? null : $currentToken[1];
switch ($state) {
case 'start':
switch ($tokenId) {
case T_STRING:
case T_NS_SEPARATOR:
$currentNs .= (string) $tokenValue;
$currentAlias = $tokenValue;
break;
case T_NAME_QUALIFIED:
case T_NAME_FULLY_QUALIFIED:
$currentNs .= (string) $tokenValue;
$currentAlias = substr(
(string) $tokenValue,
(int) (strrpos((string) $tokenValue, '\\')) + 1
);
break;
case T_CURLY_OPEN:
case '{':
$state = 'grouped';
$groupedNs = $currentNs;
break;
case T_AS:
$state = 'start-alias';
break;
case self::T_LITERAL_USE_SEPARATOR:
case self::T_LITERAL_END_OF_USE:
$state = 'end';
break;
default:
break;
}

break;
case 'start-alias':
switch ($tokenId) {
case T_STRING:
$currentAlias = $tokenValue;
break;
case self::T_LITERAL_USE_SEPARATOR:
case self::T_LITERAL_END_OF_USE:
$state = 'end';
break;
default:
break;
}

break;
case 'grouped':
switch ($tokenId) {
case T_STRING:
case T_NS_SEPARATOR:
$currentNs .= (string) $tokenValue;
$currentAlias = $tokenValue;
break;
case T_AS:
$state = 'grouped-alias';
break;
case self::T_LITERAL_USE_SEPARATOR:
$state = 'grouped';
$extractedUseStatements[(string) $currentAlias] = $currentNs;
$currentNs = $groupedNs;
$currentAlias = '';
break;
case self::T_LITERAL_END_OF_USE:
$state = 'end';
break;
default:
break;
}

break;
case 'grouped-alias':
switch ($tokenId) {
case T_STRING:
$currentAlias = $tokenValue;
break;
case self::T_LITERAL_USE_SEPARATOR:
$state = 'grouped';
$extractedUseStatements[(string) $currentAlias] = $currentNs;
$currentNs = $groupedNs;
$currentAlias = '';
break;
case self::T_LITERAL_END_OF_USE:
$state = 'end';
break;
default:
break;
}
}

if ($state === 'end') {
break;
}

$tokens->next();
}

if ($groupedNs !== $currentNs) {
$extractedUseStatements[(string) $currentAlias] = $currentNs;
}

return $extractedUseStatements;
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;









final class This implements Type
{



public function __toString(): string
{
return '$this';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use function strlen;
use function substr;
use function trim;

















final class Context
{

private $namespace;





private $namespaceAliases;









public function __construct(string $namespace, array $namespaceAliases = [])
{
$this->namespace = $namespace !== 'global' && $namespace !== 'default'
? trim($namespace, '\\')
: '';

foreach ($namespaceAliases as $alias => $fqnn) {
if ($fqnn[0] === '\\') {
$fqnn = substr($fqnn, 1);
}

if ($fqnn[strlen($fqnn) - 1] === '\\') {
$fqnn = substr($fqnn, 0, -1);
}

$namespaceAliases[$alias] = $fqnn;
}

$this->namespaceAliases = $namespaceAliases;
}




public function getNamespace(): string
{
return $this->namespace;
}








public function getNamespaceAliases(): array
{
return $this->namespaceAliases;
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;












final class Array_ extends AbstractList
{
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;








final class Parent_ implements Type
{



public function __toString(): string
{
return 'parent';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;








final class ArrayKey extends AggregatedType implements PseudoType
{
public function __construct()
{
parent::__construct([new String_(), new Integer()], '|');
}

public function underlyingType(): Type
{
return new Compound([new String_(), new Integer()]);
}

public function __toString(): string
{
return 'array-key';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;






abstract class AbstractList implements Type
{

protected $valueType;


protected $keyType;


protected $defaultKeyType;




public function __construct(?Type $valueType = null, ?Type $keyType = null)
{
if ($valueType === null) {
$valueType = new Mixed_();
}

$this->valueType = $valueType;
$this->defaultKeyType = new Compound([new String_(), new Integer()]);
$this->keyType = $keyType;
}




public function getKeyType(): Type
{
return $this->keyType ?? $this->defaultKeyType;
}




public function getValueType(): Type
{
return $this->valueType;
}




public function __toString(): string
{
if ($this->keyType) {
return 'array<' . $this->keyType . ',' . $this->valueType . '>';
}

if ($this->valueType instanceof Mixed_) {
return 'array';
}

if ($this->valueType instanceof Compound) {
return '(' . $this->valueType . ')[]';
}

return $this->valueType . '[]';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;






class String_ implements Type
{



public function __toString(): string
{
return 'string';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;













final class Static_ implements Type
{



public function __toString(): string
{
return 'static';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;






class Integer implements Type
{



public function __toString(): string
{
return 'int';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use InvalidArgumentException;
use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\Type;

use function strpos;










final class Object_ implements Type
{

private $fqsen;






public function __construct(?Fqsen $fqsen = null)
{
if (strpos((string) $fqsen, '::') !== false || strpos((string) $fqsen, '()') !== false) {
throw new InvalidArgumentException(
'Object types can only refer to a class, interface or trait but a method, function, constant or '
. 'property was received: ' . (string) $fqsen
);
}

$this->fqsen = $fqsen;
}




public function getFqsen(): ?Fqsen
{
return $this->fqsen;
}

public function __toString(): string
{
if ($this->fqsen) {
return (string) $this->fqsen;
}

return 'object';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;










final class Compound extends AggregatedType
{





public function __construct(array $types)
{
parent::__construct($types, '|');
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\Type;














final class Collection extends AbstractList
{

private $fqsen;




public function __construct(?Fqsen $fqsen, Type $valueType, ?Type $keyType = null)
{
parent::__construct($valueType, $keyType);

$this->fqsen = $fqsen;
}




public function getFqsen(): ?Fqsen
{
return $this->fqsen;
}




public function __toString(): string
{
$objectType = (string) ($this->fqsen ?? 'object');

if ($this->keyType === null) {
return $objectType . '<' . $this->valueType . '>';
}

return $objectType . '<' . $this->keyType . ',' . $this->valueType . '>';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;






final class Scalar implements Type
{



public function __toString(): string
{
return 'scalar';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;









final class Never_ implements Type
{



public function __toString(): string
{
return 'never';
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection;

use InvalidArgumentException;
use function assert;
use function end;
use function explode;
use function is_string;
use function preg_match;
use function sprintf;
use function trim;








final class Fqsen
{

private $fqsen;


private $name;






public function __construct(string $fqsen)
{
$matches = [];

$result = preg_match(

 '/^\\\\([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff\\\\]*)?(?:[:]{2}\\$?([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*))?(?:\\(\\))?$/',
$fqsen,
$matches
);

if ($result === 0) {
throw new InvalidArgumentException(
sprintf('"%s" is not a valid Fqsen.', $fqsen)
);
}

$this->fqsen = $fqsen;

if (isset($matches[2])) {
$this->name = $matches[2];
} else {
$matches = explode('\\', $fqsen);
$name = end($matches);
assert(is_string($name));
$this->name = trim($name, '()');
}
}




public function __toString() : string
{
return $this->fqsen;
}




public function getName() : string
{
return $this->name;
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection;






final class Location
{

private $lineNumber = 0;


private $columnNumber = 0;




public function __construct(int $lineNumber, int $columnNumber = 0)
{
$this->lineNumber = $lineNumber;
$this->columnNumber = $columnNumber;
}




public function getLineNumber() : int
{
return $this->lineNumber;
}




public function getColumnNumber() : int
{
return $this->columnNumber;
}
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection;





interface ProjectFactory
{





public function create(string $name, array $files) : Project;
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection;




interface Element
{



public function getFqsen() : Fqsen;




public function getName() : string;
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection;




interface File
{



public function getContents() : string;




public function md5() : string;




public function path() : string;
}
<?php

declare(strict_types=1);










namespace phpDocumentor\Reflection;




interface Project
{



public function getName() : string;
}
<?php











namespace Humbug\SelfUpdate;

use Humbug\SelfUpdate\Exception\RuntimeException;
use Humbug\SelfUpdate\Exception\InvalidArgumentException;
use Humbug\SelfUpdate\Exception\FilesystemException;
use Humbug\SelfUpdate\Exception\HttpRequestException;
use Humbug\SelfUpdate\Exception\NoSignatureException;
use Humbug\SelfUpdate\Strategy\StrategyInterface;
use Humbug\SelfUpdate\Strategy\ShaStrategy;
use Humbug\SelfUpdate\Strategy\GithubStrategy;

class Updater
{

const STRATEGY_SHA1 = 'sha1';

const STRATEGY_GITHUB = 'github';




protected $strategy;




protected $localPharFile;




protected $localPharFileBasename;




protected $localPubKeyFile;




protected $hasPubKey;




protected $tempDirectory;




protected $newVersion;




protected $oldVersion;




protected $backupExtension = '-old.phar';




protected $backupPath;




protected $restorePath;




protected $newVersionAvailable;








public function __construct($localPharFile = null, $hasPubKey = true, $strategy = self::STRATEGY_SHA1)
{
ini_set('phar.require_hash', 1);
$this->setLocalPharFile($localPharFile);
if (!is_bool($hasPubKey)) {
throw new InvalidArgumentException(
'Constructor parameter $hasPubKey must be boolean or null.'
);
} else {
$this->hasPubKey = $hasPubKey;
}
if ($this->hasPubKey) {
$this->setLocalPubKeyFile();
}
$this->setTempDirectory();
$this->setStrategy($strategy);
}






public function hasUpdate()
{
$this->newVersionAvailable = $this->newVersionAvailable();
return $this->newVersionAvailable;
}






public function update()
{
if ($this->newVersionAvailable === false
|| (!is_bool($this->newVersionAvailable) && !$this->hasUpdate())) {
return false;
}
$this->backupPhar();
$this->downloadPhar();
$this->replacePhar();
return true;
}






public function rollback()
{
if (!$this->restorePhar()) {
return false;
}
return true;
}




public function setStrategy($strategy)
{
switch ($strategy) {
case self::STRATEGY_GITHUB:
$this->strategy = new GithubStrategy;
break;

default:
$this->strategy = new ShaStrategy;
break;
}
}

public function setStrategyObject(StrategyInterface $strategy)
{
$this->strategy = $strategy;
}

public function getStrategy()
{
return $this->strategy;
}






public function setBackupExtension($extension)
{
$this->backupExtension = $extension;
}






public function getBackupExtension()
{
return $this->backupExtension;
}

public function getLocalPharFile()
{
return $this->localPharFile;
}

public function getLocalPharFileBasename()
{
return $this->localPharFileBasename;
}

public function getLocalPubKeyFile()
{
return $this->localPubKeyFile;
}

public function getTempDirectory()
{
return $this->tempDirectory;
}

public function getTempPharFile()
{
return $this->getTempDirectory()
. '/'
. sprintf('%s.phar.temp', $this->getLocalPharFileBasename());
}

public function getNewVersion()
{
return $this->newVersion;
}

public function getOldVersion()
{
return $this->oldVersion;
}






public function setBackupPath($filePath)
{
$path = realpath(dirname($filePath));
if (!is_dir($path)) {
throw new FilesystemException(sprintf(
'The backup directory does not exist: %s.', $path
));
}
if (!is_writable($path)) {
throw new FilesystemException(sprintf(
'The backup directory is not writeable: %s.', $path
));
}
$this->backupPath = $filePath;
}






public function getBackupPath()
{
return $this->backupPath;
}






public function setRestorePath($filePath)
{
$path = realpath(dirname($filePath));
if (!file_exists($path)) {
throw new FilesystemException(sprintf(
'The restore phar does not exist: %s.', $path
));
}
if (!is_readable($path)) {
throw new FilesystemException(sprintf(
'The restore file is not readable: %s.', $path
));
}
$this->restorePath = $filePath;
}






public function getRestorePath()
{
return $this->restorePath;
}

public function throwRuntimeException($errno, $errstr)
{
if (E_USER_DEPRECATED === $errno) {
return;
}

throw new RuntimeException($errstr);
}

public function throwHttpRequestException($errno, $errstr)
{
if (E_USER_DEPRECATED === $errno) {
return;
}

throw new HttpRequestException($errstr);
}

protected function hasPubKey()
{
return $this->hasPubKey;
}

protected function newVersionAvailable()
{
$this->newVersion = $this->strategy->getCurrentRemoteVersion($this);
$this->oldVersion = $this->strategy->getCurrentLocalVersion($this);

if (!empty($this->newVersion) && ($this->newVersion !== $this->oldVersion)) {
return true;
}
return false;
}

protected function backupPhar()
{
$result = copy($this->getLocalPharFile(), $this->getBackupPharFile());
if ($result === false) {
$this->cleanupAfterError();
throw new FilesystemException(sprintf(
'Unable to backup %s to %s.',
$this->getLocalPharFile(),
$this->getBackupPharFile()
));
}
}

protected function downloadPhar()
{
$this->strategy->download($this);

if (!file_exists($this->getTempPharFile())) {
throw new FilesystemException(
'Creation of download file failed.'
);
}

if ($this->getStrategy() instanceof ShaStrategy) {
$tmpVersion = sha1_file($this->getTempPharFile());
if ($tmpVersion !== $this->getNewVersion()) {
$this->cleanupAfterError();
throw new HttpRequestException(sprintf(
'Download file appears to be corrupted or outdated. The file '
. 'received does not have the expected SHA-1 hash: %s.',
$this->getNewVersion()
));
}
}

try {
$this->validatePhar($this->getTempPharFile());
} catch (\Exception $e) {
restore_error_handler();
$this->cleanupAfterError();
throw $e;
}
}

protected function replacePhar()
{
rename($this->getTempPharFile(), $this->getLocalPharFile());
}

protected function restorePhar()
{
$backup = $this->getRestorePharFile();
if (!file_exists($backup)) {
throw new RuntimeException(sprintf(
'The backup file does not exist: %s.', $backup
));
}
$this->validatePhar($backup);
return rename($backup, $this->getLocalPharFile());
}

protected function getBackupPharFile()
{
if (null !== $this->getBackupPath()) {
return $this->getBackupPath();
}
return $this->getTempDirectory()
. '/'
. sprintf('%s%s', $this->getLocalPharFileBasename(), $this->getBackupExtension());
}

protected function getRestorePharFile()
{
if (null !== $this->getRestorePath()) {
return $this->getRestorePath();
}
return $this->getTempDirectory()
. '/'
. sprintf('%s%s', $this->getLocalPharFileBasename(), $this->getBackupExtension()
);
}

protected function getTempPubKeyFile()
{
return $this->getTempDirectory()
. '/'
. sprintf('%s.phar.temp.pubkey', $this->getLocalPharFileBasename());
}

protected function setLocalPharFile($localPharFile)
{
if (!is_null($localPharFile)) {
$localPharFile = realpath($localPharFile);
} else {
$localPharFile = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0];
}
if (!file_exists($localPharFile)) {
throw new RuntimeException(sprintf(
'The set phar file does not exist: %s.', $localPharFile
));
}
if (!is_writable($localPharFile)) {
throw new FilesystemException(sprintf(
'The current phar file is not writeable and cannot be replaced: %s.',
$localPharFile
));
}
$this->localPharFile = $localPharFile;
$this->localPharFileBasename = basename($localPharFile, '.phar');
}

protected function setLocalPubKeyFile()
{
$localPubKeyFile = $this->getLocalPharFile() . '.pubkey';
if (!file_exists($localPubKeyFile)) {
throw new RuntimeException(sprintf(
'The phar pubkey file does not exist: %s.', $localPubKeyFile
));
}
$this->localPubKeyFile = $localPubKeyFile;
}

protected function setTempDirectory()
{
$tempDirectory = dirname($this->getLocalPharFile());
if (!is_writable($tempDirectory)) {
throw new FilesystemException(sprintf(
'The directory is not writeable: %s.', $tempDirectory
));
}
$this->tempDirectory = $tempDirectory;
}

protected function validatePhar($phar)
{
$phar = realpath($phar);
if ($this->hasPubKey()) {
copy($this->getLocalPubKeyFile(), $phar . '.pubkey');
}
chmod($phar, fileperms($this->getLocalPharFile()));

set_error_handler(array($this, 'throwRuntimeException'));
$phar = new \Phar($phar);
$signature = $phar->getSignature();
if ($this->hasPubKey() && strtolower($signature['hash_type']) !== 'openssl') {
throw new NoSignatureException(
'The downloaded phar file has no OpenSSL signature.'
);
}
restore_error_handler();
if ($this->hasPubKey()) {
@unlink($phar . '.pubkey');
}
unset($phar);
}

protected function cleanupAfterError()
{

 @unlink($this->getTempPharFile());
@unlink($this->getTempPubKeyFile());
}
}
<?php











namespace Humbug\SelfUpdate\Strategy;

use Humbug\SelfUpdate\Updater;

interface StrategyInterface
{







public function download(Updater $updater);







public function getCurrentRemoteVersion(Updater $updater);







public function getCurrentLocalVersion(Updater $updater);
}
<?php











namespace Humbug\SelfUpdate\Strategy;

use Humbug\SelfUpdate\Updater;
use Humbug\SelfUpdate\Exception\HttpRequestException;
use Humbug\SelfUpdate\Exception\InvalidArgumentException;

class ShaStrategy implements StrategyInterface
{




protected $versionUrl;




protected $pharUrl;







public function download(Updater $updater)
{

set_error_handler(array($updater, 'throwHttpRequestException'));
$result = humbug_get_contents($this->getPharUrl());
restore_error_handler();
if (false === $result) {
throw new HttpRequestException(sprintf(
'Request to URL failed: %s', $this->getPharUrl()
));
}

file_put_contents($updater->getTempPharFile(), $result);
}







public function getCurrentRemoteVersion(Updater $updater)
{

set_error_handler(array($updater, 'throwHttpRequestException'));
$version = humbug_get_contents($this->getVersionUrl());
restore_error_handler();
if (false === $version) {
throw new HttpRequestException(sprintf(
'Request to URL failed: %s', $this->getVersionUrl()
));
}
if (empty($version)) {
throw new HttpRequestException(
'Version request returned empty response.'
);
}
if (!preg_match('%^[a-z0-9]{40}%', $version, $matches)) {
throw new HttpRequestException(
'Version request returned incorrectly formatted response.'
);
}

return $matches[0];
}







public function getCurrentLocalVersion(Updater $updater)
{
return sha1_file($updater->getLocalPharFile());
}






public function setPharUrl($url)
{
if (!$this->validateAllowedUrl($url)) {
throw new InvalidArgumentException(
sprintf('Invalid url passed as argument: %s.', $url)
);
}
$this->pharUrl = $url;
}






public function getPharUrl()
{
return $this->pharUrl;
}






public function setVersionUrl($url)
{
if (!$this->validateAllowedUrl($url)) {
throw new InvalidArgumentException(
sprintf('Invalid url passed as argument: %s.', $url)
);
}
$this->versionUrl = $url;
}






public function getVersionUrl()
{
return $this->versionUrl;
}

protected function validateAllowedUrl($url)
{
if (filter_var($url, FILTER_VALIDATE_URL)
&& in_array(parse_url($url, PHP_URL_SCHEME), array('http', 'https', 'file'))) {
return true;
}
return false;
}
}
<?php











namespace Humbug\SelfUpdate\Strategy;

use Humbug\SelfUpdate\Updater;
use Humbug\SelfUpdate\VersionParser;
use Humbug\SelfUpdate\Exception\HttpRequestException;
use Humbug\SelfUpdate\Exception\InvalidArgumentException;
use Humbug\SelfUpdate\Exception\JsonParsingException;

class GithubStrategy implements StrategyInterface
{
const API_URL = 'https://packagist.org/p/%s.json';

const STABLE = 'stable';

const UNSTABLE = 'unstable';

const ANY = 'any';




private $localVersion;




private $remoteVersion;




private $remoteUrl;




private $pharName;




private $packageName;




private $stability = self::STABLE;







public function download(Updater $updater)
{

set_error_handler(array($updater, 'throwHttpRequestException'));
$result = humbug_get_contents($this->remoteUrl);
restore_error_handler();
if (false === $result) {
throw new HttpRequestException(sprintf(
'Request to URL failed: %s', $this->remoteUrl
));
}

file_put_contents($updater->getTempPharFile(), $result);
}







public function getCurrentRemoteVersion(Updater $updater)
{

set_error_handler(array($updater, 'throwHttpRequestException'));
$packageUrl = $this->getApiUrl();
$package = json_decode(humbug_get_contents($packageUrl), true);
restore_error_handler();

if (null === $package || json_last_error() !== JSON_ERROR_NONE) {
throw new JsonParsingException(
'Error parsing JSON package data'
. (function_exists('json_last_error_msg') ? ': ' . json_last_error_msg() : '')
);
}

$versions = array_keys($package['packages'][$this->getPackageName()]);
$versionParser = new VersionParser($versions);
if ($this->getStability() === self::STABLE) {
$this->remoteVersion = $versionParser->getMostRecentStable();
} elseif ($this->getStability() === self::UNSTABLE) {
$this->remoteVersion = $versionParser->getMostRecentUnstable();
} else {
$this->remoteVersion = $versionParser->getMostRecentAll();
}




if (!empty($this->remoteVersion)) {
$this->remoteUrl = $this->getDownloadUrl($package);
}

return $this->remoteVersion;
}







public function getCurrentLocalVersion(Updater $updater)
{
return $this->localVersion;
}






public function setCurrentLocalVersion($version)
{
$this->localVersion = $version;
}






public function setPackageName($name)
{
$this->packageName = $name;
}






public function getPackageName()
{
return $this->packageName;
}






public function setPharName($name)
{
$this->pharName = $name;
}






public function getPharName()
{
return $this->pharName;
}






public function setStability($stability)
{
if ($stability !== self::STABLE && $stability !== self::UNSTABLE && $stability !== self::ANY) {
throw new InvalidArgumentException(
'Invalid stability value. Must be one of "stable", "unstable" or "any".'
);
}
$this->stability = $stability;
}






public function getStability()
{
return $this->stability;
}

protected function getApiUrl()
{
return sprintf(self::API_URL, $this->getPackageName());
}

protected function getDownloadUrl(array $package)
{
$baseUrl = preg_replace(
'{\.git$}',
'',
$package['packages'][$this->getPackageName()][$this->remoteVersion]['source']['url']
);
$downloadUrl = sprintf(
'%s/releases/download/%s/%s',
$baseUrl,
$this->remoteVersion,
$this->getPharName()
);
return $downloadUrl;
}
}
<?php











namespace Humbug\SelfUpdate;

class VersionParser
{




private $versions;




private $modifier = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)(?:[.-]?(\d+))?)?([.-]?dev)?';




public function __construct(array $versions = array())
{
$this->versions = $versions;
}







public function getMostRecentStable()
{
return $this->selectRecentStable();
}







public function getMostRecentUnStable()
{
return $this->selectRecentUnstable();
}







public function getMostRecentAll()
{
return $this->selectRecentAll();
}







public function isStable($version)
{
return $this->stable($version);
}








public function isPreRelease($version)
{
return !$this->stable($version) && !$this->development($version);
}








public function isUnstable($version)
{
return !$this->stable($version);
}







public function isDevelopment($version)
{
return $this->development($version);
}

private function selectRecentStable()
{
$candidates = array();
foreach ($this->versions as $version) {
if (!$this->stable($version)) {
continue;
}
$candidates[] = $version;
}
if (empty($candidates)) {
return false;
}
return $this->findMostRecent($candidates);
}

private function selectRecentUnstable()
{
$candidates = array();
foreach ($this->versions as $version) {
if ($this->stable($version) || $this->development($version)) {
continue;
}
$candidates[] = $version;
}
if (empty($candidates)) {
return false;
}
return $this->findMostRecent($candidates);
}

private function selectRecentAll()
{
$candidates = array();
foreach ($this->versions as $version) {
if ($this->development($version)) {
continue;
}
$candidates[] = $version;
}
if (empty($candidates)) {
return false;
}
return $this->findMostRecent($candidates);
}

private function findMostRecent(array $candidates)
{
$candidate = null;
$tracker = null;
foreach ($candidates as $version) {
if (version_compare($candidate, $version, '<')) {
$candidate = $version;
}
}
return $candidate;
}

private function stable($version)
{
$version = preg_replace('{#.+$}i', '', $version);
if ($this->development($version)) {
return false;
}
preg_match('{'.$this->modifier.'$}i', strtolower($version), $match);
if (!empty($match[3])) {
return false;
}
if (!empty($match[1])) {
if ('beta' === $match[1] || 'b' === $match[1]
|| 'alpha' === $match[1] || 'a' === $match[1]
|| 'rc' === $match[1]) {
return false;
}
}
return true;
}

private function development($version)
{
if ('dev-' === substr($version, 0, 4) || '-dev' === substr($version, -4)) {
return true;
}
if (1 == preg_match("/-\d+-[a-z0-9]{8,}$/", $version)) {
return true;
}
return false;
}
}
<?php









namespace Humbug\SelfUpdate\Exception;

class HttpRequestException extends RuntimeException
{
}
<?php









namespace Humbug\SelfUpdate\Exception;

class FilesystemException extends RuntimeException
{
}
<?php









namespace Humbug\SelfUpdate\Exception;

class JsonParsingException extends RuntimeException
{
}
<?php









namespace Humbug\SelfUpdate\Exception;

class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
<?php









namespace Humbug\SelfUpdate\Exception;

class NoSignatureException extends RuntimeException
{
}
<?php









namespace Humbug\SelfUpdate\Exception;

class InvalidArgumentException extends \RuntimeException implements ExceptionInterface
{
}
<?php









namespace Humbug\SelfUpdate\Exception;

interface ExceptionInterface
{
}
<?php










namespace Humbug;

use Composer\CaBundle\CaBundle;
use RuntimeException;




class FileGetContents
{





protected static $lastResponseHeaders;






protected static $nextRequestHeaders;

protected $options = array('http' => array());

public function __construct()
{
$options = $this->getTlsStreamContextDefaults(null);
$this->options = array_replace_recursive($this->options, $options);
}








public function get($filename, $context = null)
{
$context = $this->getStreamContext($filename);
$context = self::setHttpHeaders($context);

$result = file_get_contents($filename, null, $context);

self::setLastResponseHeaders($http_response_header);

return $result;
}






public static function setLastResponseHeaders($headers)
{
self::$lastResponseHeaders = $headers;
}






public static function getLastResponseHeaders()
{
return self::$lastResponseHeaders;
}






public static function setNextRequestHeaders(array $headers)
{
self::$nextRequestHeaders = $headers;
}






public static function hasNextRequestHeaders()
{
return null !== self::$nextRequestHeaders;
}




public static function getNextRequestHeaders()
{
$return = self::$nextRequestHeaders;
self::$nextRequestHeaders = null;

return $return;
}











public static function setHttpHeaders($context)
{
$headers = self::getNextRequestHeaders();

if (empty($headers)) {
return $context;
}

$options = stream_context_get_options($context);
if (!isset($options['http'])) {
$options['http'] = array('header' => array());
} elseif (!isset($options['http']['header'])) {
$options['http']['header'] = array();
} elseif (is_string($options['http']['header'])) {
$options['http']['header'] = explode("\r\n", $options['http']['header']);
}

$headers = empty($options['http']['headers']) ? $headers : array_merge($options['http']['headers'], $headers);

stream_context_set_option(
$context,
'http',
'header',
$headers
);

return $context;
}








protected function getStreamContext($url)
{
$host = parse_url($url, PHP_URL_HOST);

if (PHP_VERSION_ID < 50600) {
$this->options['ssl']['CN_match'] = $host;
$this->options['ssl']['SNI_server_name'] = $host;
}

return $this->getMergedStreamContext($url);
}











protected function getTlsStreamContextDefaults($cafile)
{
$ciphers = implode(':', array(
'ECDHE-RSA-AES128-GCM-SHA256',
'ECDHE-ECDSA-AES128-GCM-SHA256',
'ECDHE-RSA-AES256-GCM-SHA384',
'ECDHE-ECDSA-AES256-GCM-SHA384',
'DHE-RSA-AES128-GCM-SHA256',
'DHE-DSS-AES128-GCM-SHA256',
'kEDH+AESGCM',
'ECDHE-RSA-AES128-SHA256',
'ECDHE-ECDSA-AES128-SHA256',
'ECDHE-RSA-AES128-SHA',
'ECDHE-ECDSA-AES128-SHA',
'ECDHE-RSA-AES256-SHA384',
'ECDHE-ECDSA-AES256-SHA384',
'ECDHE-RSA-AES256-SHA',
'ECDHE-ECDSA-AES256-SHA',
'DHE-RSA-AES128-SHA256',
'DHE-RSA-AES128-SHA',
'DHE-DSS-AES128-SHA256',
'DHE-RSA-AES256-SHA256',
'DHE-DSS-AES256-SHA',
'DHE-RSA-AES256-SHA',
'AES128-GCM-SHA256',
'AES256-GCM-SHA384',
'AES128-SHA256',
'AES256-SHA256',
'AES128-SHA',
'AES256-SHA',
'AES',
'CAMELLIA',
'DES-CBC3-SHA',
'!aNULL',
'!eNULL',
'!EXPORT',
'!DES',
'!RC4',
'!MD5',
'!PSK',
'!aECDH',
'!EDH-DSS-DES-CBC3-SHA',
'!EDH-RSA-DES-CBC3-SHA',
'!KRB5-DES-CBC3-SHA',
'!ADH'
));

$options = array(
'ssl' => array(
'ciphers' => $ciphers,
'verify_peer' => true,
'verify_depth' => 7,
'SNI_enabled' => true,
)
);

if (!$cafile) {
$cafile = CaBundle::getSystemCaRootBundlePath();
}
if (is_dir($cafile)) {
$options['ssl']['capath'] = $cafile;
} elseif ($cafile) {
$options['ssl']['cafile'] = $cafile;
} else {
throw new RuntimeException('A valid cafile could not be located locally.');
}

if (version_compare(PHP_VERSION, '5.4.13') >= 0) {
$options['ssl']['disable_compression'] = true;
}

return $options;
}

















protected function getMergedStreamContext($url)
{
$options = $this->options;


 
 
 if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {

 if (!empty($_SERVER['HTTP_PROXY']) || !empty($_SERVER['http_proxy'])) {

 $proxy = parse_url(!empty($_SERVER['http_proxy']) ? $_SERVER['http_proxy'] : $_SERVER['HTTP_PROXY']);
}
}

if (!empty($proxy)) {
$proxyURL = isset($proxy['scheme']) ? $proxy['scheme'].'://' : '';
$proxyURL .= isset($proxy['host']) ? $proxy['host'] : '';

if (isset($proxy['port'])) {
$proxyURL .= ':'.$proxy['port'];
} elseif ('http://' == substr($proxyURL, 0, 7)) {
$proxyURL .= ':80';
} elseif ('https://' == substr($proxyURL, 0, 8)) {
$proxyURL .= ':443';
}


 $proxyURL = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $proxyURL);

if (0 === strpos($proxyURL, 'ssl:') && !extension_loaded('openssl')) {
throw new RuntimeException('You must enable the openssl extension to use a proxy over https');
}

$options['http'] = array(
'proxy' => $proxyURL,
);


 switch (parse_url($url, PHP_URL_SCHEME)) {
case 'http': 
 $reqFullUriEnv = getenv('HTTP_PROXY_REQUEST_FULLURI');
if ($reqFullUriEnv === false || $reqFullUriEnv === '' || (strtolower($reqFullUriEnv) !== 'false' && (bool) $reqFullUriEnv)) {
$options['http']['request_fulluri'] = true;
}
break;
case 'https': 
 $reqFullUriEnv = getenv('HTTPS_PROXY_REQUEST_FULLURI');
if ($reqFullUriEnv === false || $reqFullUriEnv === '' || (strtolower($reqFullUriEnv) !== 'false' && (bool) $reqFullUriEnv)) {
$options['http']['request_fulluri'] = true;
}
break;
}


if (isset($proxy['user'])) {
$auth = urldecode($proxy['user']);
if (isset($proxy['pass'])) {
$auth .= ':'.urldecode($proxy['pass']);
}
$auth = base64_encode($auth);

$options['http']['header'] = "Proxy-Authorization: Basic {$auth}\r\n";
}
}

return stream_context_create($options);
}




public static function getSystemCaRootBundlePath()
{
@trigger_error(
'Deprecated since 1.1.0. Use `Composer\CaBundle\CaBundle::getSystemCaRootBundlePath()` instead.',
E_USER_DEPRECATED
);

return CaBundle::getSystemCaRootBundlePath();
}




protected static function validateCaFile($contents)
{

 
 if (!CaBundle::isOpensslParseSafe()) {
return !empty($contents);
}

return (bool) openssl_x509_parse($contents);
}
}
<?php










namespace Humbug;











function get_contents($filename, $use_include_path = false, $context = null)
{
static $fileGetContents = null;

if ('https' == parse_url($filename, PHP_URL_SCHEME) && PHP_VERSION_ID < 50600) {
if (!isset($fileGetContents)) {
$fileGetContents = new FileGetContents();
}

return $fileGetContents->get($filename, $context);
} elseif (FileGetContents::hasNextRequestHeaders()) {
if ($context === null) {
$context = stream_context_create();
}

$context = FileGetContents::setHttpHeaders($context);
}

$return = file_get_contents($filename, $use_include_path, $context);

if (isset($http_response_header)) {
FileGetContents::setLastResponseHeaders($http_response_header);
}

return $return;
}







function get_headers()
{
return FileGetContents::getLastResponseHeaders();
}




function set_headers(array $headers)
{
FileGetContents::setNextRequestHeaders($headers);
}
<?php










if (!function_exists('humbug_get_contents')) {
function humbug_get_contents($filename, $use_include_path = false, $context = null)
{
@trigger_error(
'humbug_get_contents() is deprecated since 1.1.0 and will be removed in 2.0.0. Use '
.'Humbug/get_contents() instead.',
E_USER_DEPRECATED
);

return Humbug\get_contents($filename, $use_include_path, $context);
}
}

if (!function_exists('humbug_get_headers')) {
function humbug_get_headers()
{
@trigger_error(
'humbug_get_headers() is deprecated since 1.1.0 and will be removed in 2.0.0. Use '
.'Humbug/get_headers() instead.',
E_USER_DEPRECATED
);

return Humbug\get_headers();
}
}

if (!function_exists('humbug_set_headers')) {
function humbug_set_headers(array $headers)
{
@trigger_error(
'humbug_set_headers() is deprecated since 1.1.0 and will be removed in 2.0.0. Use '
.'Humbug/get_headers() instead.',
E_USER_DEPRECATED
);

Humbug\set_headers($headers);
}
}
<?php









namespace Behat\Gherkin\Cache;

use Behat\Gherkin\Node\FeatureNode;







class MemoryCache implements CacheInterface
{
private $features = array();
private $timestamps = array();









public function isFresh($path, $timestamp)
{
if (!isset($this->features[$path])) {
return false;
}

return $this->timestamps[$path] > $timestamp;
}








public function read($path)
{
return $this->features[$path];
}







public function write($path, FeatureNode $feature)
{
$this->features[$path] = $feature;
$this->timestamps[$path] = time();
}
}
<?php









namespace Behat\Gherkin\Cache;

use Behat\Gherkin\Node\FeatureNode;






interface CacheInterface
{








public function isFresh($path, $timestamp);








public function read($path);







public function write($path, FeatureNode $feature);
}
<?php









namespace Behat\Gherkin\Cache;

use Behat\Gherkin\Exception\CacheException;
use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Gherkin;







class FileCache implements CacheInterface
{
private $path;








public function __construct($path)
{
$this->path = rtrim($path, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.'v'.Gherkin::VERSION;

if (!is_dir($this->path)) {
@mkdir($this->path, 0777, true);
}

if (!is_writeable($this->path)) {
throw new CacheException(sprintf('Cache path "%s" is not writeable. Check your filesystem permissions or disable Gherkin file cache.', $this->path));
}
}









public function isFresh($path, $timestamp)
{
$cachePath = $this->getCachePathFor($path);

if (!file_exists($cachePath)) {
return false;
}

return filemtime($cachePath) > $timestamp;
}










public function read($path)
{
$cachePath = $this->getCachePathFor($path);
$feature = unserialize(file_get_contents($cachePath));

if (!$feature instanceof FeatureNode) {
throw new CacheException(sprintf('Can not load cache for a feature "%s" from "%s".', $path, $cachePath ));
}

return $feature;
}







public function write($path, FeatureNode $feature)
{
file_put_contents($this->getCachePathFor($path), serialize($feature));
}








protected function getCachePathFor($path)
{
return $this->path.'/'.md5($path).'.feature.cache';
}
}
<?php









namespace Behat\Gherkin\Loader;

use Behat\Gherkin\Node\FeatureNode;






interface LoaderInterface
{







public function supports($resource);








public function load($resource);
}
<?php









namespace Behat\Gherkin\Loader;

use Behat\Gherkin\Node\FeatureNode;
use Symfony\Component\Yaml\Yaml;






class YamlFileLoader extends AbstractFileLoader
{
private $loader;

public function __construct()
{
$this->loader = new ArrayLoader();
}








public function supports($path)
{
return is_string($path)
&& is_file($absolute = $this->findAbsolutePath($path))
&& 'yml' === pathinfo($absolute, PATHINFO_EXTENSION);
}








public function load($path)
{
$path = $this->findAbsolutePath($path);
$hash = Yaml::parse(file_get_contents($path));

$features = $this->loader->load($hash);

return array_map(function (FeatureNode $feature) use ($path) {
return new FeatureNode(
$feature->getTitle(),
$feature->getDescription(),
$feature->getTags(),
$feature->getBackground(),
$feature->getScenarios(),
$feature->getKeyword(),
$feature->getLanguage(),
$path,
$feature->getLine()
);
}, $features);
}
}
<?php









namespace Behat\Gherkin\Loader;

use Behat\Gherkin\Node\BackgroundNode;
use Behat\Gherkin\Node\ExampleTableNode;
use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\OutlineNode;
use Behat\Gherkin\Node\PyStringNode;
use Behat\Gherkin\Node\ScenarioNode;
use Behat\Gherkin\Node\StepNode;
use Behat\Gherkin\Node\TableNode;






class ArrayLoader implements LoaderInterface
{







public function supports($resource)
{
return is_array($resource) && (isset($resource['features']) || isset($resource['feature']));
}








public function load($resource)
{
$features = array();

if (isset($resource['features'])) {
foreach ($resource['features'] as $iterator => $hash) {
$feature = $this->loadFeatureHash($hash, $iterator);
$features[] = $feature;
}
} elseif (isset($resource['feature'])) {
$feature = $this->loadFeatureHash($resource['feature']);
$features[] = $feature;
}

return $features;
}









protected function loadFeatureHash(array $hash, $line = 0)
{
$hash = array_merge(
array(
'title' => null,
'description' => null,
'tags' => array(),
'keyword' => 'Feature',
'language' => 'en',
'line' => $line,
'scenarios' => array(),
),
$hash
);
$background = isset($hash['background']) ? $this->loadBackgroundHash($hash['background']) : null;

$scenarios = array();
foreach ((array) $hash['scenarios'] as $scenarioIterator => $scenarioHash) {
if (isset($scenarioHash['type']) && 'outline' === $scenarioHash['type']) {
$scenarios[] = $this->loadOutlineHash($scenarioHash, $scenarioIterator);
} else {
$scenarios[] = $this->loadScenarioHash($scenarioHash, $scenarioIterator);
}
}

return new FeatureNode($hash['title'], $hash['description'], $hash['tags'], $background, $scenarios, $hash['keyword'], $hash['language'], null, $hash['line']);
}








protected function loadBackgroundHash(array $hash)
{
$hash = array_merge(
array(
'title' => null,
'keyword' => 'Background',
'line' => 0,
'steps' => array(),
),
$hash
);

$steps = $this->loadStepsHash($hash['steps']);

return new BackgroundNode($hash['title'], $steps, $hash['keyword'], $hash['line']);
}









protected function loadScenarioHash(array $hash, $line = 0)
{
$hash = array_merge(
array(
'title' => null,
'tags' => array(),
'keyword' => 'Scenario',
'line' => $line,
'steps' => array(),
),
$hash
);

$steps = $this->loadStepsHash($hash['steps']);

return new ScenarioNode($hash['title'], $hash['tags'], $steps, $hash['keyword'], $hash['line']);
}









protected function loadOutlineHash(array $hash, $line = 0)
{
$hash = array_merge(
array(
'title' => null,
'tags' => array(),
'keyword' => 'Scenario Outline',
'line' => $line,
'steps' => array(),
'examples' => array(),
),
$hash
);

$steps = $this->loadStepsHash($hash['steps']);

if (isset($hash['examples']['keyword'])) {
$examplesKeyword = $hash['examples']['keyword'];
unset($hash['examples']['keyword']);
} else {
$examplesKeyword = 'Examples';
}

$exHash = $hash['examples'];
$examples = array();

if ($this->examplesAreInArray($exHash)) {
$examples = $this->processExamplesArray($exHash, $examplesKeyword, $examples);
} else {

 $examples[] = new ExampleTableNode($exHash, $examplesKeyword);;
}

return new OutlineNode($hash['title'], $hash['tags'], $steps, $examples, $hash['keyword'], $hash['line']);
}








private function loadStepsHash(array $hash)
{
$steps = array();
foreach ($hash as $stepIterator => $stepHash) {
$steps[] = $this->loadStepHash($stepHash, $stepIterator);
}

return $steps;
}









protected function loadStepHash(array $hash, $line = 0)
{
$hash = array_merge(
array(
'keyword_type' => 'Given',
'type' => 'Given',
'text' => null,
'keyword' => 'Scenario',
'line' => $line,
'arguments' => array(),
),
$hash
);

$arguments = array();
foreach ($hash['arguments'] as $argumentHash) {
if ('table' === $argumentHash['type']) {
$arguments[] = $this->loadTableHash($argumentHash['rows']);
} elseif ('pystring' === $argumentHash['type']) {
$arguments[] = $this->loadPyStringHash($argumentHash, $hash['line'] + 1);
}
}

return new StepNode($hash['type'], $hash['text'], $arguments, $hash['line'], $hash['keyword_type']);
}








protected function loadTableHash(array $hash)
{
return new TableNode($hash);
}









protected function loadPyStringHash(array $hash, $line = 0)
{
$line = isset($hash['line']) ? $hash['line'] : $line;

$strings = array();
foreach (explode("\n", $hash['text']) as $string) {
$strings[] = $string;
}

return new PyStringNode($strings, $line);
}






private function examplesAreInArray($exHash)
{
return isset($exHash[0]);
}










private function processExamplesArray($exHash, $examplesKeyword, $examples)
{
for ($i = 0; $i < count($exHash); $i++) {
if (isset($exHash[$i]['table'])) {

 $exHashTags = isset($exHash[$i]['tags']) ? $exHash[$i]['tags'] : array();
$examples[] = new ExampleTableNode($exHash[$i]['table'], $examplesKeyword, $exHashTags);
} else {

 $examples[] = new ExampleTableNode($exHash[$i], $examplesKeyword);
}
}

return $examples;
}
}
<?php









namespace Behat\Gherkin\Loader;

use Behat\Gherkin\Cache\CacheInterface;
use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Parser;






class GherkinFileLoader extends AbstractFileLoader
{
protected $parser;
protected $cache;







public function __construct(Parser $parser, CacheInterface $cache = null)
{
$this->parser = $parser;
$this->cache = $cache;
}






public function setCache(CacheInterface $cache)
{
$this->cache = $cache;
}








public function supports($path)
{
return is_string($path)
&& is_file($absolute = $this->findAbsolutePath($path))
&& 'feature' === pathinfo($absolute, PATHINFO_EXTENSION);
}








public function load($path)
{
$path = $this->findAbsolutePath($path);

if ($this->cache) {
if ($this->cache->isFresh($path, filemtime($path))) {
$feature = $this->cache->read($path);
} elseif (null !== $feature = $this->parseFeature($path)) {
$this->cache->write($path, $feature);
}
} else {
$feature = $this->parseFeature($path);
}

return null !== $feature ? array($feature) : array();
}








protected function parseFeature($path)
{
$content = file_get_contents($path);
$feature = $this->parser->parse($content, $path);

return $feature;
}
}
<?php









namespace Behat\Gherkin\Loader;






abstract class AbstractFileLoader implements FileLoaderInterface
{
protected $basePath;






public function setBasePath($path)
{
$this->basePath = realpath($path);
}








protected function findRelativePath($path)
{
if (null !== $this->basePath) {
return strtr($path, array($this->basePath . DIRECTORY_SEPARATOR => ''));
}

return $path;
}








protected function findAbsolutePath($path)
{
if (is_file($path) || is_dir($path)) {
return realpath($path);
}

if (null === $this->basePath) {
return false;
}

if (is_file($this->basePath . DIRECTORY_SEPARATOR . $path)
|| is_dir($this->basePath . DIRECTORY_SEPARATOR . $path)) {
return realpath($this->basePath . DIRECTORY_SEPARATOR . $path);
}

return false;
}
}
<?php

namespace Behat\Gherkin\Loader;

use Behat\Gherkin\Node\BackgroundNode;
use Behat\Gherkin\Node\ExampleTableNode;
use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\OutlineNode;
use Behat\Gherkin\Node\ScenarioInterface;
use Behat\Gherkin\Node\ScenarioNode;
use Behat\Gherkin\Node\StepNode;




class CucumberNDJsonAstLoader implements LoaderInterface
{

public function supports($resource)
{
return is_string($resource);
}

public function load($resource)
{
return array_values(array_filter(array_map(
static function ($line) use ($resource) {
return self::getFeature(json_decode($line, true), $resource);
},
file($resource)
)));
}




private static function getFeature(array $json, $filePath)
{
if (!isset($json['gherkinDocument']['feature'])) {
return null;
}

$featureJson = $json['gherkinDocument']['feature'];

$feature = new FeatureNode(
isset($featureJson['name']) ? $featureJson['name'] : null,
$featureJson['description'] ? trim($featureJson['description']) : null,
self::getTags($featureJson),
self::getBackground($featureJson),
self::getScenarios($featureJson),
$featureJson['keyword'],
$featureJson['language'],
preg_replace('/(?<=\\.feature).*$/', '', $filePath),
$featureJson['location']['line']
);

return $feature;
}




private static function getTags(array $json)
{
return array_map(
static function(array $tag) { return preg_replace('/^@/', '', $tag['name']); },
isset($json['tags']) ? $json['tags'] : []
);
}




private static function getScenarios(array $json)
{

return array_values(
array_map(
static function ($child) {

if ($child['scenario']['examples']) {
return new OutlineNode(
isset($child['scenario']['name']) ? $child['scenario']['name'] : null,
self::getTags($child['scenario']),
self::getSteps(isset($child['scenario']['steps']) ? $child['scenario']['steps'] : []),
self::getTables($child['scenario']['examples']),
$child['scenario']['keyword'],
$child['scenario']['location']['line']
);
}
else {
return new ScenarioNode(
$child['scenario']['name'],
self::getTags($child['scenario']),
self::getSteps(isset($child['scenario']['steps']) ? $child['scenario']['steps'] : []),
$child['scenario']['keyword'],
$child['scenario']['location']['line']
);
}

},
array_filter(
isset($json['children']) ? $json['children'] : [],
static function ($child) {
return isset($child['scenario']);
}
)
)
);
}




private static function getBackground(array $json)
{
$backgrounds = array_values(
array_map(
static function ($child) {
return new BackgroundNode(
$child['background']['name'],
self::getSteps(isset($child['background']['steps']) ? $child['background']['steps'] : []),
$child['background']['keyword'],
$child['background']['location']['line']
);
},
array_filter(
isset($json['children']) ? $json['children'] : [],
static function ($child) {
return isset($child['background']);
}
)
)
);

return count($backgrounds) == 1 ? $backgrounds[0] : null;
}




private static function getSteps(array $json)
{
return array_map(
static function(array $json) {
return new StepNode(
trim($json['keyword']),
$json['text'],
[],
$json['location']['line'],
trim($json['keyword'])
);
},
$json
);
}




private static function getTables(array $json)
{
return array_map(
static function($tableJson) {

$table = [];

$table[$tableJson['tableHeader']['location']['line']] = array_map(
static function($cell) {
return $cell['value'];
},
$tableJson['tableHeader']['cells']
);

foreach ($tableJson['tableBody'] as $bodyRow) {
$table[$bodyRow['location']['line']] = array_map(
static function($cell) {
return $cell['value'];
},
$bodyRow['cells']
);
}

return new ExampleTableNode(
$table,
$tableJson['keyword'],
self::getTags($tableJson)
);
},
$json
);
}
}
<?php









namespace Behat\Gherkin\Loader;






interface FileLoaderInterface extends LoaderInterface
{





public function setBasePath($path);
}
<?php









namespace Behat\Gherkin\Loader;

use Behat\Gherkin\Gherkin;
use Behat\Gherkin\Node\FeatureNode;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;






class DirectoryLoader extends AbstractFileLoader
{
protected $gherkin;






public function __construct(Gherkin $gherkin)
{
$this->gherkin = $gherkin;
}








public function supports($path)
{
return is_string($path)
&& is_dir($this->findAbsolutePath($path));
}








public function load($path)
{
$path = $this->findAbsolutePath($path);

$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS)
);
$paths = array_map('strval', iterator_to_array($iterator));
uasort($paths, 'strnatcasecmp');

$features = array();

foreach ($paths as $path) {
$path = (string) $path;
$loader = $this->gherkin->resolveLoader($path);

if (null !== $loader) {
$features = array_merge($features, $loader->load($path));
}
}

return $features;
}
}
<?php









namespace Behat\Gherkin\Node;






class ExampleTableNode extends TableNode
{



private $tags;




private $keyword;








public function __construct(array $table, $keyword, array $tags = array())
{
$this->keyword = $keyword;
$this->tags = $tags;

parent::__construct($table);
}






public function getNodeType()
{
return 'ExampleTable';
}





public function getTags()
{
return $this->tags;
}






public function getKeyword()
{
return $this->keyword;
}
}
<?php









namespace Behat\Gherkin\Node;

use Behat\Gherkin\Exception\NodeException;






class StepNode implements NodeInterface
{



private $keyword;



private $keywordType;



private $text;



private $arguments = array();



private $line;










public function __construct($keyword, $text, array $arguments, $line, $keywordType = null)
{
if (count($arguments) > 1) {
throw new NodeException(sprintf(
'Steps could have only one argument, but `%s %s` have %d.',
$keyword,
$text,
count($arguments)
));
}

$this->keyword = $keyword;
$this->text = $text;
$this->arguments = $arguments;
$this->line = $line;
$this->keywordType = $keywordType ?: 'Given';
}






public function getNodeType()
{
return 'Step';
}








public function getType()
{
return $this->getKeyword();
}







public function getKeyword()
{
return $this->keyword;
}






public function getKeywordType()
{
return $this->keywordType;
}






public function getText()
{
return $this->text;
}






public function hasArguments()
{
return 0 < count($this->arguments);
}






public function getArguments()
{
return $this->arguments;
}






public function getLine()
{
return $this->line;
}
}
<?php









namespace Behat\Gherkin\Node;






interface ScenarioInterface extends ScenarioLikeInterface, TaggedNodeInterface
{
}
<?php









namespace Behat\Gherkin\Node;






class FeatureNode implements KeywordNodeInterface, TaggedNodeInterface
{



private $title;



private $description;



private $tags = array();



private $background;



private $scenarios = array();



private $keyword;



private $language;



private $file;



private $line;














public function __construct(
$title,
$description,
array $tags,
BackgroundNode $background = null,
array $scenarios,
$keyword,
$language,
$file,
$line
) {

 if (!empty($file) && !$this->isAbsolutePath($file)) {
throw new \InvalidArgumentException('The file should be an absolute path.');
}
$this->title = $title;
$this->description = $description;
$this->tags = $tags;
$this->background = $background;
$this->scenarios = $scenarios;
$this->keyword = $keyword;
$this->language = $language;
$this->file = $file;
$this->line = $line;
}






public function getNodeType()
{
return 'Feature';
}






public function getTitle()
{
return $this->title;
}






public function hasDescription()
{
return !empty($this->description);
}






public function getDescription()
{
return $this->description;
}








public function hasTag($tag)
{
return in_array($tag, $this->tags);
}






public function hasTags()
{
return 0 < count($this->tags);
}






public function getTags()
{
return $this->tags;
}






public function hasBackground()
{
return null !== $this->background;
}






public function getBackground()
{
return $this->background;
}






public function hasScenarios()
{
return 0 < count($this->scenarios);
}






public function getScenarios()
{
return $this->scenarios;
}






public function getKeyword()
{
return $this->keyword;
}






public function getLanguage()
{
return $this->language;
}






public function getFile()
{
return $this->file;
}






public function getLine()
{
return $this->line;
}










protected function isAbsolutePath($file)
{
if (null === $file) {
@trigger_error(sprintf('Calling "%s()" with a null in the $file argument is deprecated since Symfony 4.4.', __METHOD__), E_USER_DEPRECATED);
}

return strspn($file, '/\\', 0, 1)
|| (\strlen($file) > 3 && ctype_alpha($file[0])
&& ':' === $file[1]
&& strspn($file, '/\\', 2, 1)
)
|| null !== parse_url($file, PHP_URL_SCHEME)
;
}
}
<?php









namespace Behat\Gherkin\Node;






class ScenarioNode implements ScenarioInterface
{



private $title;



private $tags = array();



private $steps = array();



private $keyword;



private $line;










public function __construct($title, array $tags, array $steps, $keyword, $line)
{
$this->title = $title;
$this->tags = $tags;
$this->steps = $steps;
$this->keyword = $keyword;
$this->line = $line;
}






public function getNodeType()
{
return 'Scenario';
}






public function getTitle()
{
return $this->title;
}








public function hasTag($tag)
{
return in_array($tag, $this->getTags());
}






public function hasTags()
{
return 0 < count($this->getTags());
}






public function getTags()
{
return $this->tags;
}






public function hasSteps()
{
return 0 < count($this->steps);
}






public function getSteps()
{
return $this->steps;
}






public function getKeyword()
{
return $this->keyword;
}






public function getLine()
{
return $this->line;
}
}
<?php









namespace Behat\Gherkin\Node;






class PyStringNode implements ArgumentInterface
{



private $strings = array();



private $line;







public function __construct(array $strings, $line)
{
$this->strings = $strings;
$this->line = $line;
}






public function getNodeType()
{
return 'PyString';
}






public function getStrings()
{
return $this->strings;
}






public function getRaw()
{
return implode("\n", $this->strings);
}






public function __toString()
{
return $this->getRaw();
}






public function getLine()
{
return $this->line;
}
}
<?php









namespace Behat\Gherkin\Node;






interface StepContainerInterface extends NodeInterface
{





public function hasSteps();






public function getSteps();
}
<?php









namespace Behat\Gherkin\Node;






interface NodeInterface
{





public function getNodeType();






public function getLine();
}
<?php









namespace Behat\Gherkin\Node;






class BackgroundNode implements ScenarioLikeInterface
{



private $title;



private $steps = array();



private $keyword;



private $line;









public function __construct($title, array $steps, $keyword, $line)
{
$this->title = $title;
$this->steps = $steps;
$this->keyword = $keyword;
$this->line = $line;
}






public function getNodeType()
{
return 'Background';
}






public function getTitle()
{
return $this->title;
}






public function hasSteps()
{
return 0 < count($this->steps);
}






public function getSteps()
{
return $this->steps;
}






public function getKeyword()
{
return $this->keyword;
}






public function getLine()
{
return $this->line;
}
}
<?php









namespace Behat\Gherkin\Node;






interface TaggedNodeInterface extends NodeInterface
{







public function hasTag($tag);






public function hasTags();






public function getTags();
}
<?php









namespace Behat\Gherkin\Node;






interface ArgumentInterface extends NodeInterface
{
}
<?php









namespace Behat\Gherkin\Node;






interface ScenarioLikeInterface extends KeywordNodeInterface, StepContainerInterface
{
}
<?php









namespace Behat\Gherkin\Node;






interface KeywordNodeInterface extends NodeInterface
{





public function getKeyword();






public function getTitle();
}
<?php









namespace Behat\Gherkin\Node;

use ArrayIterator;
use Behat\Gherkin\Exception\NodeException;
use Iterator;
use IteratorAggregate;
use ReturnTypeWillChange;






class TableNode implements ArgumentInterface, IteratorAggregate
{



private $table;



private $maxLineLength = array();








public function __construct(array $table)
{
$this->table = $table;
$columnCount = null;

foreach ($this->getRows() as $ridx => $row) {

if (!is_array($row)) {
throw new NodeException(sprintf(
"Table row '%s' is expected to be array, got %s",
$ridx,
gettype($row)
));
}

if ($columnCount === null) {
$columnCount = count($row);
}

if (count($row) !== $columnCount) {
throw new NodeException(sprintf(
"Table row '%s' is expected to have %s columns, got %s",
$ridx,
$columnCount,
count($row)
));
}

foreach ($row as $column => $string) {
if (!isset($this->maxLineLength[$column])) {
$this->maxLineLength[$column] = 0;
}

if (!is_scalar($string)) {
throw new NodeException(sprintf(
"Table cell at row '%s', col '%s' is expected to be scalar, got %s",
$ridx,
$column,
gettype($string)
));
}

$this->maxLineLength[$column] = max($this->maxLineLength[$column], mb_strlen($string, 'utf8'));
}
}
}










public static function fromList(array $list)
{
if (count($list) !== count($list, COUNT_RECURSIVE)) {
throw new NodeException('List is not a one-dimensional array.');
}

array_walk($list, function (&$item) {
$item = array($item);
});
return new self($list);
}






public function getNodeType()
{
return 'Table';
}






public function getHash()
{
return $this->getColumnsHash();
}






public function getColumnsHash()
{
$rows = $this->getRows();
$keys = array_shift($rows);

$hash = array();
foreach ($rows as $row) {
$hash[] = array_combine($keys, $row);
}

return $hash;
}






public function getRowsHash()
{
$hash = array();

foreach ($this->getRows() as $row) {
$hash[array_shift($row)] = (1 == count($row)) ? $row[0] : $row;
}

return $hash;
}







public function getTable()
{
return $this->table;
}






public function getRows()
{
return array_values($this->table);
}






public function getLines()
{
return array_keys($this->table);
}










public function getRow($index)
{
$rows = $this->getRows();

if (!isset($rows[$index])) {
throw new NodeException(sprintf('Rows #%d does not exist in table.', $index));
}

return $rows[$index];
}










public function getColumn($index)
{
if ($index >= count($this->getRow(0))) {
throw new NodeException(sprintf('Column #%d does not exist in table.', $index));
}

$rows = $this->getRows();
$column = array();

foreach ($rows as $row) {
$column[] = $row[$index];
}

return $column;
}










public function getRowLine($index)
{
$lines = array_keys($this->table);

if (!isset($lines[$index])) {
throw new NodeException(sprintf('Rows #%d does not exist in table.', $index));
}

return $lines[$index];
}








public function getRowAsString($rowNum)
{
$values = array();
foreach ($this->getRow($rowNum) as $column => $value) {
$values[] = $this->padRight(' ' . $value . ' ', $this->maxLineLength[$column] + 2);
}

return sprintf('|%s|', implode('|', $values));
}









public function getRowAsStringWithWrappedValues($rowNum, $wrapper)
{
$values = array();
foreach ($this->getRow($rowNum) as $column => $value) {
$value = $this->padRight(' ' . $value . ' ', $this->maxLineLength[$column] + 2);

$values[] = call_user_func($wrapper, $value, $column);
}

return sprintf('|%s|', implode('|', $values));
}






public function getTableAsString()
{
$lines = array();
for ($i = 0; $i < count($this->getRows()); $i++) {
$lines[] = $this->getRowAsString($i);
}

return implode("\n", $lines);
}






public function getLine()
{
return $this->getRowLine(0);
}






public function __toString()
{
return $this->getTableAsString();
}







 public function getIterator()
{
return new ArrayIterator($this->getHash());
}








public function mergeRowsFromTable(TableNode $node)
{

 if ($this->getRow(0) !== $node->getRow(0)) {
throw new NodeException("Tables have different structure. Cannot merge one into another");
}

$firstLine = $node->getLine();
foreach ($node->getTable() as $line => $value) {
if ($line === $firstLine) {
continue;
}

$this->table[$line] = $value;
}
}









protected function padRight($text, $length)
{
while ($length > mb_strlen($text, 'utf8')) {
$text = $text . ' ';
}

return $text;
}
}
<?php









namespace Behat\Gherkin\Node;






class OutlineNode implements ScenarioInterface
{



private $title;



private $tags;



private $steps;



private $tables;



private $keyword;



private $line;



private $examples;











public function __construct(
$title,
array $tags,
array $steps,
$tables,
$keyword,
$line
) {
$this->title = $title;
$this->tags = $tags;
$this->steps = $steps;
$this->keyword = $keyword;
$this->line = $line;
if (!is_array($tables)) {
$this->tables = array($tables);
} else {
$this->tables = $tables;
}
}






public function getNodeType()
{
return 'Outline';
}






public function getTitle()
{
return $this->title;
}








public function hasTag($tag)
{
return in_array($tag, $this->getTags());
}






public function hasTags()
{
return 0 < count($this->getTags());
}






public function getTags()
{
return $this->tags;
}






public function hasSteps()
{
return 0 < count($this->steps);
}






public function getSteps()
{
return $this->steps;
}






public function hasExamples()
{
return 0 < count($this->tables);
}









public function getExampleTable()
{
$table = array();
foreach ($this->tables[0]->getTable() as $k => $v) {
$table[$k] = $v;
}


$exampleTableNode = new ExampleTableNode($table, $this->tables[0]->getKeyword());
for ($i = 1; $i < count($this->tables); $i++) {
$exampleTableNode->mergeRowsFromTable($this->tables[$i]);
}
return $exampleTableNode;
}





public function getExamples()
{
return $this->examples = $this->examples ?: $this->createExamples();
}





public function getExampleTables()
{
return $this->tables;
}






public function getKeyword()
{
return $this->keyword;
}






public function getLine()
{
return $this->line;
}






protected function createExamples()
{
$examples = array();

foreach ($this->getExampleTables() as $exampleTable) {
foreach ($exampleTable->getColumnsHash() as $rowNum => $row) {
$examples[] = new ExampleNode(
$exampleTable->getRowAsString($rowNum + 1),
array_merge($this->tags, $exampleTable->getTags()),
$this->getSteps(),
$row,
$exampleTable->getRowLine($rowNum + 1),
$this->getTitle()
);
}
}

return $examples;
}
}
<?php









namespace Behat\Gherkin\Node;






class ExampleNode implements ScenarioInterface
{



private $title;



private $tags;



private $outlineSteps;



private $tokens;



private $line;



private $steps;



private $outlineTitle;











public function __construct($title, array $tags, $outlineSteps, array $tokens, $line, $outlineTitle = null)
{
$this->title = $title;
$this->tags = $tags;
$this->outlineSteps = $outlineSteps;
$this->tokens = $tokens;
$this->line = $line;
$this->outlineTitle = $outlineTitle;
}






public function getNodeType()
{
return 'Example';
}






public function getKeyword()
{
return $this->getNodeType();
}






public function getTitle()
{
return $this->title;
}








public function hasTag($tag)
{
return in_array($tag, $this->getTags());
}






public function hasTags()
{
return 0 < count($this->getTags());
}






public function getTags()
{
return $this->tags;
}






public function hasSteps()
{
return 0 < count($this->outlineSteps);
}






public function getSteps()
{
return $this->steps = $this->steps ? : $this->createExampleSteps();
}






public function getTokens()
{
return $this->tokens;
}






public function getLine()
{
return $this->line;
}






public function getOutlineTitle()
{
return $this->outlineTitle;
}






protected function createExampleSteps()
{
$steps = array();
foreach ($this->outlineSteps as $outlineStep) {
$keyword = $outlineStep->getKeyword();
$keywordType = $outlineStep->getKeywordType();
$text = $this->replaceTextTokens($outlineStep->getText());
$args = $this->replaceArgumentsTokens($outlineStep->getArguments());
$line = $outlineStep->getLine();

$steps[] = new StepNode($keyword, $text, $args, $line, $keywordType);
}

return $steps;
}








protected function replaceArgumentsTokens(array $arguments)
{
foreach ($arguments as $num => $argument) {
if ($argument instanceof TableNode) {
$arguments[$num] = $this->replaceTableArgumentTokens($argument);
}
if ($argument instanceof PyStringNode) {
$arguments[$num] = $this->replacePyStringArgumentTokens($argument);
}
}

return $arguments;
}








protected function replaceTableArgumentTokens(TableNode $argument)
{
$table = $argument->getTable();
foreach ($table as $line => $row) {
foreach (array_keys($row) as $col) {
$table[$line][$col] = $this->replaceTextTokens($table[$line][$col]);
}
}

return new TableNode($table);
}








protected function replacePyStringArgumentTokens(PyStringNode $argument)
{
$strings = $argument->getStrings();
foreach ($strings as $line => $string) {
$strings[$line] = $this->replaceTextTokens($strings[$line]);
}

return new PyStringNode($strings, $argument->getLine());
}








protected function replaceTextTokens($text)
{
foreach ($this->tokens as $key => $val) {
$text = str_replace('<' . $key . '>', $val, $text);
}

return $text;
}
}
<?php









namespace Behat\Gherkin;

use Behat\Gherkin\Filter\FeatureFilterInterface;
use Behat\Gherkin\Filter\LineFilter;
use Behat\Gherkin\Filter\LineRangeFilter;
use Behat\Gherkin\Loader\FileLoaderInterface;
use Behat\Gherkin\Loader\LoaderInterface;






class Gherkin
{
const VERSION = '4.8.0';




protected $loaders = array();



protected $filters = array();






public function addLoader(LoaderInterface $loader)
{
$this->loaders[] = $loader;
}






public function addFilter(FeatureFilterInterface $filter)
{
$this->filters[] = $filter;
}






public function setFilters(array $filters)
{
$this->filters = array();
array_map(array($this, 'addFilter'), $filters);
}






public function setBasePath($path)
{
foreach ($this->loaders as $loader) {
if ($loader instanceof FileLoaderInterface) {
$loader->setBasePath($path);
}
}
}









public function load($resource, array $filters = array())
{
$filters = array_merge($this->filters, $filters);

$matches = array();
if (preg_match('/^(.*)\:(\d+)-(\d+|\*)$/', $resource, $matches)) {
$resource = $matches[1];
$filters[] = new LineRangeFilter($matches[2], $matches[3]);
} elseif (preg_match('/^(.*)\:(\d+)$/', $resource, $matches)) {
$resource = $matches[1];
$filters[] = new LineFilter($matches[2]);
}

$loader = $this->resolveLoader($resource);

if (null === $loader) {
return array();
}

$features = array();
foreach ($loader->load($resource) as $feature) {
foreach ($filters as $filter) {
$feature = $filter->filterFeature($feature);

if (!$feature->hasScenarios() && !$filter->isFeatureMatch($feature)) {
continue 2;
}
}

$features[] = $feature;
}

return $features;
}








public function resolveLoader($resource)
{
foreach ($this->loaders as $loader) {
if ($loader->supports($resource)) {
return $loader;
}
}

return null;
}
}
<?php









namespace Behat\Gherkin\Filter;

use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\ScenarioInterface;






class RoleFilter extends SimpleFilter
{
protected $pattern;






public function __construct($role)
{
$this->pattern = '/as an? ' . strtr(preg_quote($role, '/'), array(
'\*' => '.*',
'\?' => '.',
'\[' => '[',
'\]' => ']'
)) . '[$\n]/i';
}








public function isFeatureMatch(FeatureNode $feature)
{
return 1 === preg_match($this->pattern, $feature->getDescription() ?? '');
}








public function isScenarioMatch(ScenarioInterface $scenario)
{
return false;
}
}
<?php









namespace Behat\Gherkin\Filter;

use Behat\Gherkin\Node\ScenarioInterface;
use Behat\Gherkin\Node\FeatureNode;






class NarrativeFilter extends SimpleFilter
{



private $regex;






public function __construct($regex)
{
$this->regex = $regex;
}








public function isFeatureMatch(FeatureNode $feature)
{
return 1 === preg_match($this->regex, $feature->getDescription() ?? '');
}








public function isScenarioMatch(ScenarioInterface $scenario)
{
return false;
}
}
<?php









namespace Behat\Gherkin\Filter;

use Behat\Gherkin\Node\FeatureNode;






abstract class SimpleFilter implements FilterInterface
{







public function filterFeature(FeatureNode $feature)
{
if ($this->isFeatureMatch($feature)) {
return $feature;
}

$scenarios = array();
foreach ($feature->getScenarios() as $scenario) {
if (!$this->isScenarioMatch($scenario)) {
continue;
}

$scenarios[] = $scenario;
}

return new FeatureNode(
$feature->getTitle(),
$feature->getDescription(),
$feature->getTags(),
$feature->getBackground(),
$scenarios,
$feature->getKeyword(),
$feature->getLanguage(),
$feature->getFile(),
$feature->getLine()
);
}
}
<?php









namespace Behat\Gherkin\Filter;

use Behat\Gherkin\Node\ExampleTableNode;
use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\OutlineNode;
use Behat\Gherkin\Node\ScenarioInterface;






class LineRangeFilter implements FilterInterface
{
protected $filterMinLine;
protected $filterMaxLine;







public function __construct($filterMinLine, $filterMaxLine)
{
$this->filterMinLine = intval($filterMinLine);
if ($filterMaxLine == '*') {
$this->filterMaxLine = PHP_INT_MAX;
} else {
$this->filterMaxLine = intval($filterMaxLine);
}
}








public function isFeatureMatch(FeatureNode $feature)
{
return $this->filterMinLine <= $feature->getLine()
&& $this->filterMaxLine >= $feature->getLine();
}








public function isScenarioMatch(ScenarioInterface $scenario)
{
if ($this->filterMinLine <= $scenario->getLine() && $this->filterMaxLine >= $scenario->getLine()) {
return true;
}

if ($scenario instanceof OutlineNode && $scenario->hasExamples()) {
foreach ($scenario->getExampleTable()->getLines() as $line) {
if ($this->filterMinLine <= $line && $this->filterMaxLine >= $line) {
return true;
}
}
}

return false;
}








public function filterFeature(FeatureNode $feature)
{
$scenarios = array();
foreach ($feature->getScenarios() as $scenario) {
if (!$this->isScenarioMatch($scenario)) {
continue;
}

if ($scenario instanceof OutlineNode && $scenario->hasExamples()) {

 $exampleTableNodes = array();

foreach ($scenario->getExampleTables() as $exampleTable) {
$table = $exampleTable->getTable();
$lines = array_keys($table);

$filteredTable = array($lines[0] => $table[$lines[0]]);
unset($table[$lines[0]]);

foreach ($table as $line => $row) {
if ($this->filterMinLine <= $line && $this->filterMaxLine >= $line) {
$filteredTable[$line] = $row;
}
}

if (count($filteredTable) > 1) {
$exampleTableNodes[] = new ExampleTableNode($filteredTable, $exampleTable->getKeyword(), $exampleTable->getTags());
}
}

$scenario = new OutlineNode(
$scenario->getTitle(),
$scenario->getTags(),
$scenario->getSteps(),
$exampleTableNodes,
$scenario->getKeyword(),
$scenario->getLine()
);
}

$scenarios[] = $scenario;
}

return new FeatureNode(
$feature->getTitle(),
$feature->getDescription(),
$feature->getTags(),
$feature->getBackground(),
$scenarios,
$feature->getKeyword(),
$feature->getLanguage(),
$feature->getFile(),
$feature->getLine()
);
}
}
<?php









namespace Behat\Gherkin\Filter;

use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\OutlineNode;
use Behat\Gherkin\Node\ScenarioInterface;






class TagFilter extends ComplexFilter
{
protected $filterString;






public function __construct($filterString)
{
$this->filterString = trim($filterString);

if(preg_match('/\s/u', $this->filterString)) {
trigger_error(
"Tags with whitespace are deprecated and may be removed in a future version",
E_USER_DEPRECATED
);
}
}








public function filterFeature(FeatureNode $feature)
{
$scenarios = array();
foreach ($feature->getScenarios() as $scenario) {
if (!$this->isScenarioMatch($feature, $scenario)) {
continue;
}

if ($scenario instanceof OutlineNode && $scenario->hasExamples()) {

$exampleTables = array();

foreach ($scenario->getExampleTables() as $exampleTable) {
if ($this->isTagsMatchCondition(array_merge($feature->getTags(), $scenario->getTags(), $exampleTable->getTags()))) {
$exampleTables[] = $exampleTable;
}
}

$scenario = new OutlineNode(
$scenario->getTitle(),
$scenario->getTags(),
$scenario->getSteps(),
$exampleTables,
$scenario->getKeyword(),
$scenario->getLine()
);
}

$scenarios[] = $scenario;
}

return new FeatureNode(
$feature->getTitle(),
$feature->getDescription(),
$feature->getTags(),
$feature->getBackground(),
$scenarios,
$feature->getKeyword(),
$feature->getLanguage(),
$feature->getFile(),
$feature->getLine()
);
}








public function isFeatureMatch(FeatureNode $feature)
{
return $this->isTagsMatchCondition($feature->getTags());
}









public function isScenarioMatch(FeatureNode $feature, ScenarioInterface $scenario)
{
if ($scenario instanceof OutlineNode && $scenario->hasExamples()) {
foreach ($scenario->getExampleTables() as $example) {
if ($this->isTagsMatchCondition(array_merge($feature->getTags(), $scenario->getTags(), $example->getTags()))) {
return true;
}
}

return false;
}

return $this->isTagsMatchCondition(array_merge($feature->getTags(), $scenario->getTags()));
}








protected function isTagsMatchCondition($tags)
{
$satisfies = true;

foreach (explode('&&', $this->filterString) as $andTags) {
$satisfiesComma = false;

foreach (explode(',', $andTags) as $tag) {
$tag = str_replace('@', '', trim($tag));

if ('~' === $tag[0]) {
$tag = mb_substr($tag, 1, mb_strlen($tag, 'utf8') - 1, 'utf8');
$satisfiesComma = !in_array($tag, $tags) || $satisfiesComma;
} else {
$satisfiesComma = in_array($tag, $tags) || $satisfiesComma;
}
}

$satisfies = $satisfiesComma && $satisfies;
}

return $satisfies;
}
}
<?php









namespace Behat\Gherkin\Filter;

use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\ScenarioInterface;






class NameFilter extends SimpleFilter
{
protected $filterString;






public function __construct($filterString)
{
$this->filterString = trim($filterString);
}








public function isFeatureMatch(FeatureNode $feature)
{
if (null === $feature->getTitle()) {
return false;
}

if ('/' === $this->filterString[0]) {
return 1 === preg_match($this->filterString, $feature->getTitle());
}

return false !== mb_strpos($feature->getTitle(), $this->filterString, 0, 'utf8');
}








public function isScenarioMatch(ScenarioInterface $scenario)
{
if (null === $scenario->getTitle()) {
return false;
}

if ('/' === $this->filterString[0] && 1 === preg_match($this->filterString, $scenario->getTitle())) {
return true;
} elseif (false !== mb_strpos($scenario->getTitle(), $this->filterString, 0, 'utf8')) {
return true;
}

return false;
}
}
<?php









namespace Behat\Gherkin\Filter;

use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\ScenarioInterface;






interface ComplexFilterInterface extends FeatureFilterInterface
{








public function isScenarioMatch(FeatureNode $feature, ScenarioInterface $scenario);
}
<?php









namespace Behat\Gherkin\Filter;

use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\ScenarioInterface;






class PathsFilter extends SimpleFilter
{
protected $filterPaths = array();






public function __construct(array $paths)
{
$this->filterPaths = array_map(
function ($realpath) {
return rtrim($realpath, DIRECTORY_SEPARATOR) .
(is_dir($realpath) ? DIRECTORY_SEPARATOR : '');
},
array_filter(
array_map('realpath', $paths)
)
);
}








public function isFeatureMatch(FeatureNode $feature)
{
foreach ($this->filterPaths as $path) {
if (0 === strpos(realpath($feature->getFile()), $path)) {
return true;
}
}

return false;
}








public function isScenarioMatch(ScenarioInterface $scenario)
{
return false;
}
}
<?php









namespace Behat\Gherkin\Filter;

use Behat\Gherkin\Node\ExampleTableNode;
use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\OutlineNode;
use Behat\Gherkin\Node\ScenarioInterface;






class LineFilter implements FilterInterface
{
protected $filterLine;






public function __construct($filterLine)
{
$this->filterLine = intval($filterLine);
}








public function isFeatureMatch(FeatureNode $feature)
{
return $this->filterLine === $feature->getLine();
}








public function isScenarioMatch(ScenarioInterface $scenario)
{
if ($this->filterLine === $scenario->getLine()) {
return true;
}

if ($scenario instanceof OutlineNode && $scenario->hasExamples()) {
return $this->filterLine === $scenario->getLine()
|| in_array($this->filterLine, $scenario->getExampleTable()->getLines());
}

return false;
}








public function filterFeature(FeatureNode $feature)
{
$scenarios = array();
foreach ($feature->getScenarios() as $scenario) {
if (!$this->isScenarioMatch($scenario)) {
continue;
}

if ($scenario instanceof OutlineNode && $scenario->hasExamples()) {
foreach ($scenario->getExampleTables() as $exampleTable) {
$table = $exampleTable->getTable();
$lines = array_keys($table);

if (in_array($this->filterLine, $lines)) {
$filteredTable = array($lines[0] => $table[$lines[0]]);

if ($lines[0] !== $this->filterLine) {
$filteredTable[$this->filterLine] = $table[$this->filterLine];
}

$scenario = new OutlineNode(
$scenario->getTitle(),
$scenario->getTags(),
$scenario->getSteps(),
array(new ExampleTableNode($filteredTable, $exampleTable->getKeyword(), $exampleTable->getTags())),
$scenario->getKeyword(),
$scenario->getLine()
);
}
}
}

$scenarios[] = $scenario;
}

return new FeatureNode(
$feature->getTitle(),
$feature->getDescription(),
$feature->getTags(),
$feature->getBackground(),
$scenarios,
$feature->getKeyword(),
$feature->getLanguage(),
$feature->getFile(),
$feature->getLine()
);
}
}
<?php









namespace Behat\Gherkin\Filter;

use Behat\Gherkin\Node\FeatureNode;






interface FeatureFilterInterface
{







public function isFeatureMatch(FeatureNode $feature);








public function filterFeature(FeatureNode $feature);
}
<?php









namespace Behat\Gherkin\Filter;

use Behat\Gherkin\Node\ScenarioInterface;






interface FilterInterface extends FeatureFilterInterface
{







public function isScenarioMatch(ScenarioInterface $scenario);
}
<?php









namespace Behat\Gherkin\Filter;

use Behat\Gherkin\Node\FeatureNode;






abstract class ComplexFilter implements ComplexFilterInterface
{







public function filterFeature(FeatureNode $feature)
{
$scenarios = array();
foreach ($feature->getScenarios() as $scenario) {
if (!$this->isScenarioMatch($feature, $scenario)) {
continue;
}

$scenarios[] = $scenario;
}

return new FeatureNode(
$feature->getTitle(),
$feature->getDescription(),
$feature->getTags(),
$feature->getBackground(),
$scenarios,
$feature->getKeyword(),
$feature->getLanguage(),
$feature->getFile(),
$feature->getLine()
);
}
}
<?php









namespace Behat\Gherkin\Exception;

use RuntimeException;

class NodeException extends RuntimeException implements Exception
{
}
<?php









namespace Behat\Gherkin\Exception;

interface Exception
{
}
<?php









namespace Behat\Gherkin\Exception;

use RuntimeException;

class ParserException extends RuntimeException implements Exception
{
}
<?php









namespace Behat\Gherkin\Exception;

use RuntimeException;

class LexerException extends RuntimeException implements Exception
{
}
<?php









namespace Behat\Gherkin\Exception;

use RuntimeException;






class CacheException extends RuntimeException implements Exception
{
}
<?php









namespace Behat\Gherkin;

use Behat\Gherkin\Exception\LexerException;
use Behat\Gherkin\Keywords\KeywordsInterface;






class Lexer
{
private $language;
private $lines;
private $linesCount;
private $line;
private $trimmedLine;
private $lineNumber;
private $eos;
private $keywords;
private $keywordsCache = array();
private $stepKeywordTypesCache = array();
private $deferredObjects = array();
private $deferredObjectsCount = 0;
private $stashedToken;
private $inPyString = false;
private $pyStringSwallow = 0;
private $featureStarted = false;
private $allowMultilineArguments = false;
private $allowSteps = false;
private $pyStringDelimiter = null;






public function __construct(KeywordsInterface $keywords)
{
$this->keywords = $keywords;
}









public function analyse($input, $language = 'en')
{

 if ('UTF-8' !== mb_detect_encoding($input, 'UTF-8', true)) {
throw new LexerException('Feature file is not in UTF8 encoding');
}

$input = strtr($input, array("\r\n" => "\n", "\r" => "\n"));

$this->lines = explode("\n", $input);
$this->linesCount = count($this->lines);
$this->line = $this->lines[0];
$this->lineNumber = 1;
$this->trimmedLine = null;
$this->eos = false;

$this->deferredObjects = array();
$this->deferredObjectsCount = 0;
$this->stashedToken = null;
$this->inPyString = false;
$this->pyStringSwallow = 0;

$this->featureStarted = false;
$this->allowMultilineArguments = false;
$this->allowSteps = false;

$this->keywords->setLanguage($this->language = $language);
$this->keywordsCache = array();
$this->stepKeywordTypesCache = array();
}






public function getLanguage()
{
return $this->language;
}






public function getAdvancedToken()
{
return $this->getStashedToken() ?: $this->getNextToken();
}






public function deferToken(array $token)
{
$token['deferred'] = true;
$this->deferredObjects[] = $token;
++$this->deferredObjectsCount;
}






public function predictToken()
{
if (null === $this->stashedToken) {
$this->stashedToken = $this->getNextToken();
}

return $this->stashedToken;
}






public function skipPredictedToken()
{
$this->stashedToken = null;
}









public function takeToken($type, $value = null)
{
return array(
'type' => $type,
'line' => $this->lineNumber,
'value' => $value ?: null,
'deferred' => false
);
}




protected function consumeLine()
{
++$this->lineNumber;

if (($this->lineNumber - 1) === $this->linesCount) {
$this->eos = true;

return;
}

$this->line = $this->lines[$this->lineNumber - 1];
$this->trimmedLine = null;
}




protected function consumeLineUntil(int $trimmedOffset)
{
$this->line = mb_substr(ltrim($this->line), $trimmedOffset, null, 'utf-8');
$this->trimmedLine = null;
}






protected function getTrimmedLine()
{
return null !== $this->trimmedLine ? $this->trimmedLine : $this->trimmedLine = trim($this->line);
}






protected function getStashedToken()
{
$stashedToken = $this->stashedToken;
$this->stashedToken = null;

return $stashedToken;
}






protected function getDeferredToken()
{
if (!$this->deferredObjectsCount) {
return null;
}

--$this->deferredObjectsCount;

return array_shift($this->deferredObjects);
}






protected function getNextToken()
{
return $this->getDeferredToken()
?: $this->scanEOS()
?: $this->scanLanguage()
?: $this->scanComment()
?: $this->scanPyStringOp()
?: $this->scanPyStringContent()
?: $this->scanStep()
?: $this->scanScenario()
?: $this->scanBackground()
?: $this->scanOutline()
?: $this->scanExamples()
?: $this->scanFeature()
?: $this->scanTags()
?: $this->scanTableRow()
?: $this->scanNewline()
?: $this->scanText();
}









protected function scanInput($regex, $type)
{
if (!preg_match($regex, $this->line, $matches)) {
return null;
}

$token = $this->takeToken($type, $matches[1]);
$this->consumeLine();

return $token;
}









protected function scanInputForKeywords($keywords, $type)
{
if (!preg_match('/^(\s*)(' . $keywords . '):\s*(.*)/u', $this->line, $matches)) {
return null;
}

$token = $this->takeToken($type, $matches[3]);
$token['keyword'] = $matches[2];
$token['indent'] = mb_strlen($matches[1], 'utf8');

$this->consumeLine();


 if ('Feature' === $type) {
$this->featureStarted = true;
}


 if ('Feature' === $type || 'Scenario' === $type || 'Outline' === $type) {
$this->allowMultilineArguments = false;
} elseif ('Examples' === $type) {
$this->allowMultilineArguments = true;
}


 if ('Scenario' === $type || 'Background' === $type || 'Outline' === $type) {
$this->allowSteps = true;
}

return $token;
}






protected function scanEOS()
{
if (!$this->eos) {
return null;
}

return $this->takeToken('EOS');
}








protected function getKeywords($type)
{
if (!isset($this->keywordsCache[$type])) {
$getter = 'get' . $type . 'Keywords';
$keywords = $this->keywords->$getter();

if ('Step' === $type) {
$padded = array();
foreach (explode('|', $keywords) as $keyword) {
$padded[] = false !== mb_strpos($keyword, '<', 0, 'utf8')
? preg_quote(mb_substr($keyword, 0, -1, 'utf8'), '/') . '\s*'
: preg_quote($keyword, '/') . '\s+';
}

$keywords = implode('|', $padded);
}

$this->keywordsCache[$type] = $keywords;
}

return $this->keywordsCache[$type];
}






protected function scanFeature()
{
return $this->scanInputForKeywords($this->getKeywords('Feature'), 'Feature');
}






protected function scanBackground()
{
return $this->scanInputForKeywords($this->getKeywords('Background'), 'Background');
}






protected function scanScenario()
{
return $this->scanInputForKeywords($this->getKeywords('Scenario'), 'Scenario');
}






protected function scanOutline()
{
return $this->scanInputForKeywords($this->getKeywords('Outline'), 'Outline');
}






protected function scanExamples()
{
return $this->scanInputForKeywords($this->getKeywords('Examples'), 'Examples');
}






protected function scanStep()
{
if (!$this->allowSteps) {
return null;
}

$keywords = $this->getKeywords('Step');
if (!preg_match('/^\s*(' . $keywords . ')([^\s].*)/u', $this->line, $matches)) {
return null;
}

$keyword = trim($matches[1]);
$token = $this->takeToken('Step', $keyword);
$token['keyword_type'] = $this->getStepKeywordType($keyword);
$token['text'] = $matches[2];

$this->consumeLine();
$this->allowMultilineArguments = true;

return $token;
}






protected function scanPyStringOp()
{
if (!$this->allowMultilineArguments) {
return null;
}

if(!preg_match('/^\s*(?<delimiter>"""|```)/u', $this->line, $matches, PREG_OFFSET_CAPTURE)) {
return null;
}

['delimiter' => [0 => $delimiter, 1 => $indent]] = $matches;

if ($this->inPyString) {
if ($this->pyStringDelimiter !== $delimiter) {
return null;
}
$this->pyStringDelimiter = null;
}
else {
$this->pyStringDelimiter= $delimiter;
}

$this->inPyString = !$this->inPyString;
$token = $this->takeToken('PyStringOp');
$this->pyStringSwallow = $indent;

$this->consumeLine();

return $token;
}






protected function scanPyStringContent()
{
if (!$this->inPyString) {
return null;
}

$token = $this->scanText();

 $token['value'] = preg_replace('/^\s{0,' . $this->pyStringSwallow . '}/u', '', $token['value'] ?? '');

return $token;
}






protected function scanTableRow()
{
if (!$this->allowMultilineArguments) {
return null;
}

$line = $this->getTrimmedLine();
if (!isset($line[0]) || '|' !== $line[0] || '|' !== substr($line, -1)) {
return null;
}

$token = $this->takeToken('TableRow');
$line = mb_substr($line, 1, mb_strlen($line, 'utf8') - 2, 'utf8');
$columns = array_map(function ($column) {
return trim(str_replace('\\|', '|', $column));
}, preg_split('/(?<!\\\)\|/u', $line));
$token['columns'] = $columns;

$this->consumeLine();

return $token;
}






protected function scanTags()
{
$line = $this->getTrimmedLine();

if (!isset($line[0]) || '@' !== $line[0]) {
return null;
}

if(preg_match('/^(?<line>.*)\s+#.*$/', $line, $matches)) {
['line' => $line] = $matches;
$this->consumeLineUntil(mb_strlen($line, 'utf-8'));
} else {
$this->consumeLine();
}

$token = $this->takeToken('Tag');
$tags = explode('@', mb_substr($line, 1, mb_strlen($line, 'utf8') - 1, 'utf8'));
$tags = array_map('trim', $tags);
$token['tags'] = $tags;


return $token;
}






protected function scanLanguage()
{
if ($this->featureStarted) {
return null;
}

if ($this->inPyString) {
return null;
}

if (0 !== mb_strpos(ltrim($this->line), '#', 0, 'utf8')) {
return null;
}

return $this->scanInput('/^\s*\#\s*language:\s*([\w_\-]+)\s*$/', 'Language');
}






protected function scanComment()
{
if ($this->inPyString) {
return null;
}

$line = $this->getTrimmedLine();
if (0 !== mb_strpos($line, '#', 0, 'utf8')) {
return null;
}

$token = $this->takeToken('Comment', $line);
$this->consumeLine();

return $token;
}






protected function scanNewline()
{
if ('' !== $this->getTrimmedLine()) {
return null;
}

$token = $this->takeToken('Newline', mb_strlen($this->line, 'utf8'));
$this->consumeLine();

return $token;
}






protected function scanText()
{
$token = $this->takeToken('Text', $this->line);
$this->consumeLine();

return $token;
}







private function getStepKeywordType($native)
{

 if ('*' === $native) {
return 'And';
}

if (empty($this->stepKeywordTypesCache)) {
$this->stepKeywordTypesCache = array(
'Given' => explode('|', $this->keywords->getGivenKeywords()),
'When' => explode('|', $this->keywords->getWhenKeywords()),
'Then' => explode('|', $this->keywords->getThenKeywords()),
'And' => explode('|', $this->keywords->getAndKeywords()),
'But' => explode('|', $this->keywords->getButKeywords())
);
}

foreach ($this->stepKeywordTypesCache as $type => $keywords) {
if (in_array($native, $keywords) || in_array($native . '<', $keywords)) {
return $type;
}
}

return 'Given';
}
}
<?php









namespace Behat\Gherkin;

use Behat\Gherkin\Exception\LexerException;
use Behat\Gherkin\Exception\NodeException;
use Behat\Gherkin\Exception\ParserException;
use Behat\Gherkin\Node\BackgroundNode;
use Behat\Gherkin\Node\ExampleTableNode;
use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\OutlineNode;
use Behat\Gherkin\Node\PyStringNode;
use Behat\Gherkin\Node\ScenarioInterface;
use Behat\Gherkin\Node\ScenarioNode;
use Behat\Gherkin\Node\StepNode;
use Behat\Gherkin\Node\TableNode;










class Parser
{
private $lexer;
private $input;
private $file;
private $tags = array();
private $languageSpecifierLine;

private $passedNodesStack = array();






public function __construct(Lexer $lexer)
{
$this->lexer = $lexer;
}











public function parse($input, $file = null)
{
$this->languageSpecifierLine = null;
$this->input = $input;
$this->file = $file;
$this->tags = array();

try {
$this->lexer->analyse($this->input, 'en');
} catch (LexerException $e) {
throw new ParserException(
sprintf('Lexer exception "%s" thrown for file %s', $e->getMessage(), $file),
0,
$e
);
}

$feature = null;
while ('EOS' !== ($predicted = $this->predictTokenType())) {
$node = $this->parseExpression();

if (null === $node || "\n" === $node) {
continue;
}

if (!$feature && $node instanceof FeatureNode) {
$feature = $node;
continue;
}

if ($feature && $node instanceof FeatureNode) {
throw new ParserException(sprintf(
'Only one feature is allowed per feature file. But %s got multiple.',
$this->file
));
}

if (is_string($node)) {
throw new ParserException(sprintf(
'Expected Feature, but got text: "%s"%s',
$node,
$this->file ? ' in file: ' . $this->file : ''
));
}

if (!$node instanceof FeatureNode) {
throw new ParserException(sprintf(
'Expected Feature, but got %s on line: %d%s',
$node->getKeyword(),
$node->getLine(),
$this->file ? ' in file: ' . $this->file : ''
));
}
}

return $feature;
}










protected function expectTokenType($type)
{
$types = (array) $type;
if (in_array($this->predictTokenType(), $types)) {
return $this->lexer->getAdvancedToken();
}

$token = $this->lexer->predictToken();

throw new ParserException(sprintf(
'Expected %s token, but got %s on line: %d%s',
implode(' or ', $types),
$this->predictTokenType(),
$token['line'],
$this->file ? ' in file: ' . $this->file : ''
));
}








protected function acceptTokenType($type)
{
if ($type !== $this->predictTokenType()) {
return null;
}

return $this->lexer->getAdvancedToken();
}






protected function predictTokenType()
{
$token = $this->lexer->predictToken();

return $token['type'];
}








protected function parseExpression()
{
$type = $this->predictTokenType();

while ($type === 'Comment') {
$this->expectTokenType('Comment');

$type = $this->predictTokenType();
}

switch ($type) {
case 'Feature':
return $this->parseFeature();
case 'Background':
return $this->parseBackground();
case 'Scenario':
return $this->parseScenario();
case 'Outline':
return $this->parseOutline();
case 'Examples':
return $this->parseExamples();
case 'TableRow':
return $this->parseTable();
case 'PyStringOp':
return $this->parsePyString();
case 'Step':
return $this->parseStep();
case 'Text':
return $this->parseText();
case 'Newline':
return $this->parseNewline();
case 'Tag':
return $this->parseTags();
case 'Language':
return $this->parseLanguage();
case 'EOS':
return '';
}

throw new ParserException(sprintf('Unknown token type: %s', $type));
}








protected function parseFeature()
{
$token = $this->expectTokenType('Feature');

$title = trim($token['value'] ?? '');
$description = null;
$tags = $this->popTags();
$background = null;
$scenarios = array();
$keyword = $token['keyword'];
$language = $this->lexer->getLanguage();
$file = $this->file;
$line = $token['line'];

array_push($this->passedNodesStack, 'Feature');


 while ('EOS' !== $this->predictTokenType()) {
$node = $this->parseExpression();

if (is_string($node)) {
$text = preg_replace('/^\s{0,' . ($token['indent'] + 2) . '}|\s*$/', '', $node);
$description .= (null !== $description ? "\n" : '') . $text;
continue;
}

if (!$background && $node instanceof BackgroundNode) {
$background = $node;
continue;
}

if ($node instanceof ScenarioInterface) {
$scenarios[] = $node;
continue;
}

if ($background instanceof BackgroundNode && $node instanceof BackgroundNode) {
throw new ParserException(sprintf(
'Each Feature could have only one Background, but found multiple on lines %d and %d%s',
$background->getLine(),
$node->getLine(),
$this->file ? ' in file: ' . $this->file : ''
));
}

if (!$node instanceof ScenarioNode) {
throw new ParserException(sprintf(
'Expected Scenario, Outline or Background, but got %s on line: %d%s',
$node->getNodeType(),
$node->getLine(),
$this->file ? ' in file: ' . $this->file : ''
));
}
}

return new FeatureNode(
rtrim($title) ?: null,
rtrim($description ?? '') ?: null,
$tags,
$background,
$scenarios,
$keyword,
$language,
$file,
$line
);
}








protected function parseBackground()
{
$token = $this->expectTokenType('Background');

$title = trim($token['value'] ?? '');
$keyword = $token['keyword'];
$line = $token['line'];

if (count($this->popTags())) {
throw new ParserException(sprintf(
'Background can not be tagged, but it is on line: %d%s',
$line,
$this->file ? ' in file: ' . $this->file : ''
));
}


 $steps = array();
$allowedTokenTypes = array('Step', 'Newline', 'Text', 'Comment');
while (in_array($this->predictTokenType(), $allowedTokenTypes)) {
$node = $this->parseExpression();

if ($node instanceof StepNode) {
$steps[] = $this->normalizeStepNodeKeywordType($node, $steps);
continue;
}

if (!count($steps) && is_string($node)) {
$text = preg_replace('/^\s{0,' . ($token['indent'] + 2) . '}|\s*$/', '', $node);
$title .= "\n" . $text;
continue;
}

if ("\n" === $node) {
continue;
}

if (is_string($node)) {
throw new ParserException(sprintf(
'Expected Step, but got text: "%s"%s',
$node,
$this->file ? ' in file: ' . $this->file : ''
));
}

if (!$node instanceof StepNode) {
throw new ParserException(sprintf(
'Expected Step, but got %s on line: %d%s',
$node->getNodeType(),
$node->getLine(),
$this->file ? ' in file: ' . $this->file : ''
));
}
}

return new BackgroundNode(rtrim($title) ?: null, $steps, $keyword, $line);
}








protected function parseScenario()
{
$token = $this->expectTokenType('Scenario');

$title = trim($token['value'] ?? '');
$tags = $this->popTags();
$keyword = $token['keyword'];
$line = $token['line'];

array_push($this->passedNodesStack, 'Scenario');


 $steps = array();
while (in_array($this->predictTokenType(), array('Step', 'Newline', 'Text', 'Comment'))) {
$node = $this->parseExpression();

if ($node instanceof StepNode) {
$steps[] = $this->normalizeStepNodeKeywordType($node, $steps);
continue;
}

if (!count($steps) && is_string($node)) {
$text = preg_replace('/^\s{0,' . ($token['indent'] + 2) . '}|\s*$/', '', $node);
$title .= "\n" . $text;
continue;
}

if ("\n" === $node) {
continue;
}

if (is_string($node)) {
throw new ParserException(sprintf(
'Expected Step, but got text: "%s"%s',
$node,
$this->file ? ' in file: ' . $this->file : ''
));
}

if (!$node instanceof StepNode) {
throw new ParserException(sprintf(
'Expected Step, but got %s on line: %d%s',
$node->getNodeType(),
$node->getLine(),
$this->file ? ' in file: ' . $this->file : ''
));
}
}

array_pop($this->passedNodesStack);

return new ScenarioNode(rtrim($title) ?: null, $tags, $steps, $keyword, $line);
}








protected function parseOutline()
{
$token = $this->expectTokenType('Outline');

$title = trim($token['value'] ?? '');
$tags = $this->popTags();
$keyword = $token['keyword'];


$examples = array();
$line = $token['line'];


 $steps = array();

array_push($this->passedNodesStack, 'Outline');

while (in_array($nextTokenType = $this->predictTokenType(), array('Step', 'Examples', 'Newline', 'Text', 'Comment', 'Tag'))) {
if ($nextTokenType === 'Comment') {
$this->lexer->skipPredictedToken();
continue;
}

$node = $this->parseExpression();

if ($node instanceof StepNode) {
$steps[] = $this->normalizeStepNodeKeywordType($node, $steps);
continue;
}

if ($node instanceof ExampleTableNode) {
$examples[] = $node;

continue;
}

if (!count($steps) && is_string($node)) {
$text = preg_replace('/^\s{0,' . ($token['indent'] + 2) . '}|\s*$/', '', $node);
$title .= "\n" . $text;
continue;
}

if ("\n" === $node) {
continue;
}

if (is_string($node)) {
throw new ParserException(sprintf(
'Expected Step or Examples table, but got text: "%s"%s',
$node,
$this->file ? ' in file: ' . $this->file : ''
));
}

if (!$node instanceof StepNode) {
throw new ParserException(sprintf(
'Expected Step or Examples table, but got %s on line: %d%s',
$node->getNodeType(),
$node->getLine(),
$this->file ? ' in file: ' . $this->file : ''
));
}
}

if (empty($examples)) {
throw new ParserException(sprintf(
'Outline should have examples table, but got none for outline "%s" on line: %d%s',
rtrim($title),
$line,
$this->file ? ' in file: ' . $this->file : ''
));
}

return new OutlineNode(rtrim($title) ?: null, $tags, $steps, $examples, $keyword, $line);
}






protected function parseStep()
{
$token = $this->expectTokenType('Step');

$keyword = $token['value'];
$keywordType = $token['keyword_type'];
$text = trim($token['text']);
$line = $token['line'];

array_push($this->passedNodesStack, 'Step');

$arguments = array();
while (in_array($predicted = $this->predictTokenType(), array('PyStringOp', 'TableRow', 'Newline', 'Comment'))) {
if ('Comment' === $predicted || 'Newline' === $predicted) {
$this->acceptTokenType($predicted);
continue;
}

$node = $this->parseExpression();

if ($node instanceof PyStringNode || $node instanceof TableNode) {
$arguments[] = $node;
}
}

array_pop($this->passedNodesStack);

return new StepNode($keyword, $text, $arguments, $line, $keywordType);
}






protected function parseExamples()
{
$keyword = ($this->expectTokenType('Examples'))['keyword'];
$tags = empty($this->tags) ? array() : $this->popTags();
$table = $this->parseTableRows();

try {
return new ExampleTableNode($table, $keyword, $tags);
} catch(NodeException $e) {
$this->rethrowNodeException($e);
}
}






protected function parseTable()
{
$table = $this->parseTableRows();

try {
return new TableNode($table);
} catch(NodeException $e) {
$this->rethrowNodeException($e);
}
}






protected function parsePyString()
{
$token = $this->expectTokenType('PyStringOp');

$line = $token['line'];

$strings = array();
while ('PyStringOp' !== ($predicted = $this->predictTokenType()) && 'Text' === $predicted) {
$token = $this->expectTokenType('Text');

$strings[] = $token['value'];
}

$this->expectTokenType('PyStringOp');

return new PyStringNode($strings, $line);
}






protected function parseTags()
{
$token = $this->expectTokenType('Tag');

$this->guardTags($token['tags']);

$this->tags = array_merge($this->tags, $token['tags']);

$possibleTransitions = array(
'Outline' => array(
'Examples',
'Step'
)
);

$currentType = '-1';

 if (!empty($this->passedNodesStack)) {
$currentType = $this->passedNodesStack[count($this->passedNodesStack) - 1];
}

$nextType = $this->predictTokenType();
if (!isset($possibleTransitions[$currentType]) || in_array($nextType, $possibleTransitions[$currentType])) {
return $this->parseExpression();
}

return "\n";
}






protected function popTags()
{
$tags = $this->tags;
$this->tags = array();

return $tags;
}






protected function guardTags(array $tags)
{
foreach ($tags as $tag) {
if (preg_match('/\s/', $tag)) {
trigger_error('Whitespace in tags is deprecated, found "$tag"', E_USER_DEPRECATED);
}
}
}






protected function parseText()
{
$token = $this->expectTokenType('Text');

return $token['value'];
}






protected function parseNewline()
{
$this->expectTokenType('Newline');

return "\n";
}








protected function parseLanguage()
{
$token = $this->expectTokenType('Language');

if (null === $this->languageSpecifierLine) {
$this->lexer->analyse($this->input, $token['value']);
$this->languageSpecifierLine = $token['line'];
} elseif ($token['line'] !== $this->languageSpecifierLine) {
throw new ParserException(sprintf(
'Ambiguous language specifiers on lines: %d and %d%s',
$this->languageSpecifierLine,
$token['line'],
$this->file ? ' in file: ' . $this->file : ''
));
}

return $this->parseExpression();
}






private function parseTableRows()
{
$table = array();
while (in_array($predicted = $this->predictTokenType(), array('TableRow', 'Newline', 'Comment'))) {
if ('Comment' === $predicted || 'Newline' === $predicted) {
$this->acceptTokenType($predicted);
continue;
}

$token = $this->expectTokenType('TableRow');

$table[$token['line']] = $token['columns'];
}

return $table;
}








private function normalizeStepNodeKeywordType(StepNode $node, array $steps = array())
{
if (in_array($node->getKeywordType(), array('And', 'But'))) {
if (($prev = end($steps))) {
$keywordType = $prev->getKeywordType();
} else {
$keywordType = 'Given';
}

$node = new StepNode(
$node->getKeyword(),
$node->getText(),
$node->getArguments(),
$node->getLine(),
$keywordType
);
}
return $node;
}

private function rethrowNodeException(NodeException $e): void
{
throw new ParserException(
$e->getMessage() . ($this->file ? ' in file ' . $this->file : ''),
0,
$e
);
}
}
<?php









namespace Behat\Gherkin\Keywords;

use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;








class CucumberKeywords extends ArrayKeywords
{





public function __construct($yaml)
{

 $file = null;
if (strpos($yaml, "\n") === false && is_file($yaml)) {
if (false === is_readable($yaml)) {
throw new ParseException(sprintf('Unable to parse "%s" as the file is not readable.', $yaml));
}

$file = $yaml;
$yaml = file_get_contents($file);
}

try {
$content = Yaml::parse($yaml);
} catch (ParseException $e) {
if ($file) {
$e->setParsedFile($file);
}

throw $e;
}

parent::__construct($content);
}






public function getGivenKeywords()
{
return $this->prepareStepString(parent::getGivenKeywords());
}






public function getWhenKeywords()
{
return $this->prepareStepString(parent::getWhenKeywords());
}






public function getThenKeywords()
{
return $this->prepareStepString(parent::getThenKeywords());
}






public function getAndKeywords()
{
return $this->prepareStepString(parent::getAndKeywords());
}






public function getButKeywords()
{
return $this->prepareStepString(parent::getButKeywords());
}








private function prepareStepString($keywordsString)
{
if (0 === mb_strpos($keywordsString, '*|', 0, 'UTF-8')) {
$keywordsString = mb_substr($keywordsString, 2, mb_strlen($keywordsString, 'utf8') - 2, 'utf8');
}

return $keywordsString;
}
}
<?php









namespace Behat\Gherkin\Keywords;

































class ArrayKeywords implements KeywordsInterface
{
private $keywords = array();
private $keywordString = array();
private $language;






public function __construct(array $keywords)
{
$this->keywords = $keywords;
}






public function setLanguage($language)
{
if (!isset($this->keywords[$language])) {
$this->language = 'en';
} else {
$this->language = $language;
}
}






public function getFeatureKeywords()
{
return $this->keywords[$this->language]['feature'];
}






public function getBackgroundKeywords()
{
return $this->keywords[$this->language]['background'];
}






public function getScenarioKeywords()
{
return $this->keywords[$this->language]['scenario'];
}






public function getOutlineKeywords()
{
return $this->keywords[$this->language]['scenario_outline'];
}






public function getExamplesKeywords()
{
return $this->keywords[$this->language]['examples'];
}






public function getGivenKeywords()
{
return $this->keywords[$this->language]['given'];
}






public function getWhenKeywords()
{
return $this->keywords[$this->language]['when'];
}






public function getThenKeywords()
{
return $this->keywords[$this->language]['then'];
}






public function getAndKeywords()
{
return $this->keywords[$this->language]['and'];
}






public function getButKeywords()
{
return $this->keywords[$this->language]['but'];
}






public function getStepKeywords()
{
if (!isset($this->keywordString[$this->language])) {
$keywords = array_merge(
explode('|', $this->getGivenKeywords()),
explode('|', $this->getWhenKeywords()),
explode('|', $this->getThenKeywords()),
explode('|', $this->getAndKeywords()),
explode('|', $this->getButKeywords())
);

usort($keywords, function ($keyword1, $keyword2) {
return mb_strlen($keyword2, 'utf8') - mb_strlen($keyword1, 'utf8');
});

$this->keywordString[$this->language] = implode('|', $keywords);
}

return $this->keywordString[$this->language];
}
}
<?php









namespace Behat\Gherkin\Keywords;








class CachedArrayKeywords extends ArrayKeywords
{





public function __construct($file)
{
parent::__construct(include($file));
}
}
<?php









namespace Behat\Gherkin\Keywords;






interface KeywordsInterface
{





public function setLanguage($language);






public function getFeatureKeywords();






public function getBackgroundKeywords();






public function getScenarioKeywords();






public function getOutlineKeywords();






public function getExamplesKeywords();






public function getGivenKeywords();






public function getWhenKeywords();






public function getThenKeywords();






public function getAndKeywords();






public function getButKeywords();






public function getStepKeywords();
}
<?php









namespace Behat\Gherkin\Keywords;






class KeywordsDumper
{
private $keywords;
private $keywordsDumper;






public function __construct(KeywordsInterface $keywords)
{
$this->keywords = $keywords;
$this->keywordsDumper = array($this, 'dumpKeywords');
}








public function setKeywordsDumperFunction($mapper)
{
$this->keywordsDumper = $mapper;
}









public function dumpKeywords(array $keywords, $isShort)
{
if ($isShort) {
return 1 < count($keywords) ? '(' . implode('|', $keywords) . ')' : $keywords[0];
}

return $keywords[0];
}










public function dump($language, $short = true, $excludeAsterisk = false)
{
$this->keywords->setLanguage($language);
$languageComment = '';
if ('en' !== $language) {
$languageComment = "# language: $language\n";
}

$keywords = explode('|', $this->keywords->getFeatureKeywords());

if ($short) {
$keywords = call_user_func($this->keywordsDumper, $keywords, $short);

return trim($languageComment . $this->dumpFeature($keywords, $short, $excludeAsterisk));
}

$features = array();
foreach ($keywords as $keyword) {
$keyword = call_user_func($this->keywordsDumper, array($keyword), $short);
$features[] = trim($languageComment . $this->dumpFeature($keyword, $short, $excludeAsterisk));
}

return $features;
}









protected function dumpFeature($keyword, $short = true, $excludeAsterisk = false)
{
$dump = <<<GHERKIN
{$keyword}: Internal operations
  In order to stay secret
  As a secret organization
  We need to be able to erase past agents' memory


GHERKIN;


 $keywords = explode('|', $this->keywords->getBackgroundKeywords());
if ($short) {
$keywords = call_user_func($this->keywordsDumper, $keywords, $short);
$dump .= $this->dumpBackground($keywords, $short, $excludeAsterisk);
} else {
$keyword = call_user_func($this->keywordsDumper, array($keywords[0]), $short);
$dump .= $this->dumpBackground($keyword, $short, $excludeAsterisk);
}


 $keywords = explode('|', $this->keywords->getScenarioKeywords());
if ($short) {
$keywords = call_user_func($this->keywordsDumper, $keywords, $short);
$dump .= $this->dumpScenario($keywords, $short, $excludeAsterisk);
} else {
foreach ($keywords as $keyword) {
$keyword = call_user_func($this->keywordsDumper, array($keyword), $short);
$dump .= $this->dumpScenario($keyword, $short, $excludeAsterisk);
}
}


 $keywords = explode('|', $this->keywords->getOutlineKeywords());
if ($short) {
$keywords = call_user_func($this->keywordsDumper, $keywords, $short);
$dump .= $this->dumpOutline($keywords, $short, $excludeAsterisk);
} else {
foreach ($keywords as $keyword) {
$keyword = call_user_func($this->keywordsDumper, array($keyword), $short);
$dump .= $this->dumpOutline($keyword, $short, $excludeAsterisk);
}
}

return $dump;
}









protected function dumpBackground($keyword, $short = true, $excludeAsterisk = false)
{
$dump = <<<GHERKIN
  {$keyword}:

GHERKIN;


 $dump .= $this->dumpStep(
$this->keywords->getGivenKeywords(),
'there is agent A',
$short,
$excludeAsterisk
);


 $dump .= $this->dumpStep(
$this->keywords->getAndKeywords(),
'there is agent B',
$short,
$excludeAsterisk
);

return $dump . "\n";
}









protected function dumpScenario($keyword, $short = true, $excludeAsterisk = false)
{
$dump = <<<GHERKIN
  {$keyword}: Erasing agent memory

GHERKIN;


 $dump .= $this->dumpStep(
$this->keywords->getGivenKeywords(),
'there is agent J',
$short,
$excludeAsterisk
);


 $dump .= $this->dumpStep(
$this->keywords->getAndKeywords(),
'there is agent K',
$short,
$excludeAsterisk
);


 $dump .= $this->dumpStep(
$this->keywords->getWhenKeywords(),
'I erase agent K\'s memory',
$short,
$excludeAsterisk
);


 $dump .= $this->dumpStep(
$this->keywords->getThenKeywords(),
'there should be agent J',
$short,
$excludeAsterisk
);


 $dump .= $this->dumpStep(
$this->keywords->getButKeywords(),
'there should not be agent K',
$short,
$excludeAsterisk
);

return $dump . "\n";
}









protected function dumpOutline($keyword, $short = true, $excludeAsterisk = false)
{
$dump = <<<GHERKIN
  {$keyword}: Erasing other agents' memory

GHERKIN;


 $dump .= $this->dumpStep(
$this->keywords->getGivenKeywords(),
'there is agent <agent1>',
$short,
$excludeAsterisk
);


 $dump .= $this->dumpStep(
$this->keywords->getAndKeywords(),
'there is agent <agent2>',
$short,
$excludeAsterisk
);


 $dump .= $this->dumpStep(
$this->keywords->getWhenKeywords(),
'I erase agent <agent2>\'s memory',
$short,
$excludeAsterisk
);


 $dump .= $this->dumpStep(
$this->keywords->getThenKeywords(),
'there should be agent <agent1>',
$short,
$excludeAsterisk
);


 $dump .= $this->dumpStep(
$this->keywords->getButKeywords(),
'there should not be agent <agent2>',
$short,
$excludeAsterisk
);

$keywords = explode('|', $this->keywords->getExamplesKeywords());
if ($short) {
$keyword = call_user_func($this->keywordsDumper, $keywords, $short);
} else {
$keyword = call_user_func($this->keywordsDumper, array($keywords[0]), $short);
}

$dump .= <<<GHERKIN

    {$keyword}:
      | agent1 | agent2 |
      | D      | M      |

GHERKIN;

return $dump . "\n";
}










protected function dumpStep($keywords, $text, $short = true, $excludeAsterisk = false)
{
$dump = '';

$keywords = explode('|', $keywords);
if ($short) {
$keywords = array_map(
function ($keyword) {
return str_replace('<', '', $keyword);
},
$keywords
);
$keywords = call_user_func($this->keywordsDumper, $keywords, $short);
$dump .= <<<GHERKIN
    {$keywords} {$text}

GHERKIN;
} else {
foreach ($keywords as $keyword) {
if ($excludeAsterisk && '*' === $keyword) {
continue;
}

$indent = ' ';
if (false !== mb_strpos($keyword, '<', 0, 'utf8')) {
$keyword = mb_substr($keyword, 0, -1, 'utf8');
$indent = '';
}
$keyword = call_user_func($this->keywordsDumper, array($keyword), $short);
$dump .= <<<GHERKIN
    {$keyword}{$indent}{$text}

GHERKIN;
}
}

return $dump;
}
}
<?php

return __DIR__;<?php










return array (
'en' => 
array (
'and' => 'And|*',
'background' => 'Background',
'but' => 'But|*',
'examples' => 'Scenarios|Examples',
'feature' => 'Business Need|Ability|Feature',
'given' => 'Given|*',
'name' => 'English',
'native' => 'English',
'rule' => 'Rule',
'scenario' => 'Scenario|Example',
'scenario_outline' => 'Scenario Template|Scenario Outline',
'then' => 'Then|*',
'when' => 'When|*',
),
'af' => 
array (
'and' => 'En|*',
'background' => 'Agtergrond',
'but' => 'Maar|*',
'examples' => 'Voorbeelde',
'feature' => 'Besigheid Behoefte|Funksie|Vermoë',
'given' => 'Gegewe|*',
'name' => 'Afrikaans',
'native' => 'Afrikaans',
'rule' => 'Regel',
'scenario' => 'Voorbeeld|Situasie',
'scenario_outline' => 'Situasie Uiteensetting',
'then' => 'Dan|*',
'when' => 'Wanneer|*',
),
'am' => 
array (
'and' => 'Եվ|*',
'background' => 'Կոնտեքստ',
'but' => 'Բայց|*',
'examples' => 'Օրինակներ',
'feature' => 'Ֆունկցիոնալություն|Հատկություն',
'given' => 'Դիցուք|*',
'name' => 'Armenian',
'native' => 'հայերեն',
'rule' => 'Rule',
'scenario' => 'Սցենար|Օրինակ',
'scenario_outline' => 'Սցենարի կառուցվացքը',
'then' => 'Ապա|*',
'when' => 'Եթե|Երբ|*',
),
'an' => 
array (
'and' => '*|E|Y',
'background' => 'Antecedents',
'but' => 'Pero|*',
'examples' => 'Eixemplos',
'feature' => 'Caracteristica',
'given' => 'Dadas|Dada|Daus|Dau|*',
'name' => 'Aragonese',
'native' => 'Aragonés',
'rule' => 'Rule',
'scenario' => 'Eixemplo|Caso',
'scenario_outline' => 'Esquema del caso',
'then' => 'Antonces|Alavez|Allora|*',
'when' => 'Cuan|*',
),
'ar' => 
array (
'and' => '*|و',
'background' => 'الخلفية',
'but' => 'لكن|*',
'examples' => 'امثلة',
'feature' => 'خاصية',
'given' => 'بفرض|*',
'name' => 'Arabic',
'native' => 'العربية',
'rule' => 'Rule',
'scenario' => 'سيناريو|مثال',
'scenario_outline' => 'سيناريو مخطط',
'then' => 'اذاً|ثم|*',
'when' => 'عندما|متى|*',
),
'ast' => 
array (
'and' => 'Ya|*|Y',
'background' => 'Antecedentes',
'but' => 'Peru|*',
'examples' => 'Exemplos',
'feature' => 'Carauterística',
'given' => 'Dada|Daes|Daos|Dáu|*',
'name' => 'Asturian',
'native' => 'asturianu',
'rule' => 'Rule',
'scenario' => 'Exemplo|Casu',
'scenario_outline' => 'Esbozu del casu',
'then' => 'Entós|*',
'when' => 'Cuando|*',
),
'az' => 
array (
'and' => 'Həm|Və|*',
'background' => 'Kontekst|Keçmiş',
'but' => 'Ancaq|Amma|*',
'examples' => 'Nümunələr',
'feature' => 'Özəllik',
'given' => 'Tutaq ki|Verilir|*',
'name' => 'Azerbaijani',
'native' => 'Azərbaycanca',
'rule' => 'Rule',
'scenario' => 'Ssenari|Nümunə',
'scenario_outline' => 'Ssenarinin strukturu',
'then' => 'O halda|*',
'when' => 'Nə vaxt ki|Əgər|*',
),
'bg' => 
array (
'and' => '*|И',
'background' => 'Предистория',
'but' => 'Но|*',
'examples' => 'Примери',
'feature' => 'Функционалност',
'given' => 'Дадено|*',
'name' => 'Bulgarian',
'native' => 'български',
'rule' => 'Rule',
'scenario' => 'Сценарий|Пример',
'scenario_outline' => 'Рамка на сценарий',
'then' => 'То|*',
'when' => 'Когато|*',
),
'bm' => 
array (
'and' => 'Dan|*',
'background' => 'Latar Belakang',
'but' => 'Tetapi|Tapi|*',
'examples' => 'Contoh',
'feature' => 'Fungsi',
'given' => 'Diberi|Bagi|*',
'name' => 'Malay',
'native' => 'Bahasa Melayu',
'rule' => 'Rule',
'scenario' => 'Keadaan|Senario|Situasi',
'scenario_outline' => 'Garis Panduan Senario|Kerangka Keadaan|Kerangka Senario|Kerangka Situasi',
'then' => 'Kemudian|Maka|*',
'when' => 'Apabila|*',
),
'bs' => 
array (
'and' => '*|A|I',
'background' => 'Pozadina',
'but' => 'Ali|*',
'examples' => 'Primjeri',
'feature' => 'Karakteristika',
'given' => 'Dato|*',
'name' => 'Bosnian',
'native' => 'Bosanski',
'rule' => 'Rule',
'scenario' => 'Scenariju|Scenario|Primjer',
'scenario_outline' => 'Scenario-outline|Scenariju-obris',
'then' => 'Zatim|*',
'when' => 'Kada|*',
),
'ca' => 
array (
'and' => '*|I',
'background' => 'Antecedents|Rerefons',
'but' => 'Però|*',
'examples' => 'Exemples',
'feature' => 'Característica|Funcionalitat',
'given' => 'Donada|Atesa|Donat|Atès|*',
'name' => 'Catalan',
'native' => 'català',
'rule' => 'Rule',
'scenario' => 'Escenari|Exemple',
'scenario_outline' => 'Esquema de l\'escenari',
'then' => 'Aleshores|Cal|*',
'when' => 'Quan|*',
),
'cs' => 
array (
'and' => 'A také|*|A',
'background' => 'Kontext|Pozadí',
'but' => 'Ale|*',
'examples' => 'Příklady',
'feature' => 'Požadavek',
'given' => 'Za předpokladu|Pokud|*',
'name' => 'Czech',
'native' => 'Česky',
'rule' => 'Pravidlo',
'scenario' => 'Příklad|Scénář',
'scenario_outline' => 'Osnova scénáře|Náčrt Scénáře',
'then' => 'Pak|*',
'when' => 'Když|*',
),
'cy-GB' => 
array (
'and' => '*|A',
'background' => 'Cefndir',
'but' => 'Ond|*',
'examples' => 'Enghreifftiau',
'feature' => 'Arwedd',
'given' => 'Anrhegedig a|*',
'name' => 'Welsh',
'native' => 'Cymraeg',
'rule' => 'Rule',
'scenario' => 'Enghraifft|Scenario',
'scenario_outline' => 'Scenario Amlinellol',
'then' => 'Yna|*',
'when' => 'Pryd|*',
),
'da' => 
array (
'and' => 'Og|*',
'background' => 'Baggrund',
'but' => 'Men|*',
'examples' => 'Eksempler',
'feature' => 'Egenskab',
'given' => 'Givet|*',
'name' => 'Danish',
'native' => 'dansk',
'rule' => 'Rule',
'scenario' => 'Eksempel|Scenarie',
'scenario_outline' => 'Abstrakt Scenario',
'then' => 'Så|*',
'when' => 'Når|*',
),
'de' => 
array (
'and' => 'Und|*',
'background' => 'Voraussetzungen|Vorbedingungen|Hintergrund|Grundlage',
'but' => 'Aber|*',
'examples' => 'Beispiele',
'feature' => 'Funktionalität|Funktion',
'given' => 'Gegeben seien|Gegeben sei|Angenommen|*',
'name' => 'German',
'native' => 'Deutsch',
'rule' => 'Regel|Rule',
'scenario' => 'Beispiel|Szenario',
'scenario_outline' => 'Szenariogrundriss|Szenarien',
'then' => 'Dann|*',
'when' => 'Wenn|*',
),
'el' => 
array (
'and' => 'Και|*',
'background' => 'Υπόβαθρο',
'but' => 'Αλλά|*',
'examples' => 'Παραδείγματα|Σενάρια',
'feature' => 'Δυνατότητα|Λειτουργία',
'given' => 'Δεδομένου|*',
'name' => 'Greek',
'native' => 'Ελληνικά',
'rule' => 'Rule',
'scenario' => 'Παράδειγμα|Σενάριο',
'scenario_outline' => 'Περίγραμμα Σεναρίου|Περιγραφή Σεναρίου',
'then' => 'Τότε|*',
'when' => 'Όταν|*',
),
'em' => 
array (
'and' => '😂<|*',
'background' => '💤',
'but' => '😔<|*',
'examples' => '📓',
'feature' => '📚',
'given' => '😐<|*',
'name' => 'Emoji',
'native' => '😀',
'rule' => 'Rule',
'scenario' => '📕|🥒',
'scenario_outline' => '📖',
'then' => '🙏<|*',
'when' => '🎬<|*',
),
'en-Scouse' => 
array (
'and' => 'An|*',
'background' => 'Dis is what went down',
'but' => 'Buh|*',
'examples' => 'Examples',
'feature' => 'Feature',
'given' => 'Youse know when youse got|Givun|*',
'name' => 'Scouse',
'native' => 'Scouse',
'rule' => 'Rule',
'scenario' => 'The thing of it is',
'scenario_outline' => 'Wharrimean is',
'then' => 'Den youse gotta|Dun|*',
'when' => 'Youse know like when|Wun|*',
),
'en-au' => 
array (
'and' => 'Too right|*',
'background' => 'First off',
'but' => 'Yeah nah|*',
'examples' => 'You\'ll wanna',
'feature' => 'Pretty much',
'given' => 'Y\'know|*',
'name' => 'Australian',
'native' => 'Australian',
'rule' => 'Rule',
'scenario' => 'Awww, look mate',
'scenario_outline' => 'Reckon it\'s like',
'then' => 'But at the end of the day I reckon|*',
'when' => 'It\'s just unbelievable|*',
),
'en-lol' => 
array (
'and' => 'AN|*',
'background' => 'B4',
'but' => 'BUT|*',
'examples' => 'EXAMPLZ',
'feature' => 'OH HAI',
'given' => 'I CAN HAZ|*',
'name' => 'LOLCAT',
'native' => 'LOLCAT',
'rule' => 'Rule',
'scenario' => 'MISHUN',
'scenario_outline' => 'MISHUN SRSLY',
'then' => 'DEN|*',
'when' => 'WEN|*',
),
'en-old' => 
array (
'and' => 'Ond|*|7',
'background' => 'Aer|Ær',
'but' => 'Ac|*',
'examples' => 'Se the|Se ðe|Se þe',
'feature' => 'Hwaet|Hwæt',
'given' => 'Thurh|Ðurh|Þurh|*',
'name' => 'Old English',
'native' => 'Englisc',
'rule' => 'Rule',
'scenario' => 'Swa',
'scenario_outline' => 'Swa hwaer swa|Swa hwær swa',
'then' => 'Tha the|Ða ðe|Þa þe|Tha|Ða|Þa|*',
'when' => 'Tha|Ða|Þa|*',
),
'en-pirate' => 
array (
'and' => 'Aye|*',
'background' => 'Yo-ho-ho',
'but' => 'Avast!|*',
'examples' => 'Dead men tell no tales',
'feature' => 'Ahoy matey!',
'given' => 'Gangway!|*',
'name' => 'Pirate',
'native' => 'Pirate',
'rule' => 'Rule',
'scenario' => 'Heave to',
'scenario_outline' => 'Shiver me timbers',
'then' => 'Let go and haul|*',
'when' => 'Blimey!|*',
),
'en-tx' => 
array (
'and' => 'Come hell or high water',
'background' => 'Lemme tell y\'all a story',
'but' => 'Well now hold on, I\'ll you what',
'examples' => 'Now that\'s a story longer than a cattle drive in July',
'feature' => 'This ain’t my first rodeo|All gussied up',
'given' => 'All git out|Fixin\' to',
'name' => 'Texas',
'native' => 'Texas',
'rule' => 'Rule ',
'scenario' => 'All hat and no cattle',
'scenario_outline' => 'Busy as a hound in flea season|Serious as a snake bite',
'then' => 'There’s no tree but bears some fruit',
'when' => 'Quick out of the chute',
),
'eo' => 
array (
'and' => 'Kaj|*',
'background' => 'Fono',
'but' => 'Sed|*',
'examples' => 'Ekzemploj',
'feature' => 'Trajto',
'given' => 'Donitaĵo|Komence|*',
'name' => 'Esperanto',
'native' => 'Esperanto',
'rule' => 'Rule',
'scenario' => 'Ekzemplo|Scenaro|Kazo',
'scenario_outline' => 'Konturo de la scenaro|Kazo-skizo|Skizo',
'then' => 'Do|*',
'when' => 'Se|*',
),
'es' => 
array (
'and' => '*|E|Y',
'background' => 'Antecedentes',
'but' => 'Pero|*',
'examples' => 'Ejemplos',
'feature' => 'Necesidad del negocio|Característica|Requisito',
'given' => 'Dadas|Dados|Dada|Dado|*',
'name' => 'Spanish',
'native' => 'español',
'rule' => 'Regla de negocio|Regla',
'scenario' => 'Escenario|Ejemplo',
'scenario_outline' => 'Esquema del escenario',
'then' => 'Entonces|*',
'when' => 'Cuando|*',
),
'et' => 
array (
'and' => 'Ja|*',
'background' => 'Taust',
'but' => 'Kuid|*',
'examples' => 'Juhtumid',
'feature' => 'Omadus',
'given' => 'Eeldades|*',
'name' => 'Estonian',
'native' => 'eesti keel',
'rule' => 'Reegel',
'scenario' => 'Stsenaarium|Juhtum',
'scenario_outline' => 'Raamstsenaarium|Raamjuhtum',
'then' => 'Siis|*',
'when' => 'Kui|*',
),
'fa' => 
array (
'and' => '*|و',
'background' => 'زمینه',
'but' => 'اما|*',
'examples' => 'نمونه ها',
'feature' => 'وِیژگی',
'given' => 'با فرض|*',
'name' => 'Persian',
'native' => 'فارسی',
'rule' => 'Rule',
'scenario' => 'سناریو|مثال',
'scenario_outline' => 'الگوی سناریو',
'then' => 'آنگاه|*',
'when' => 'هنگامی|*',
),
'fi' => 
array (
'and' => 'Ja|*',
'background' => 'Tausta',
'but' => 'Mutta|*',
'examples' => 'Tapaukset',
'feature' => 'Ominaisuus',
'given' => 'Oletetaan|*',
'name' => 'Finnish',
'native' => 'suomi',
'rule' => 'Rule',
'scenario' => 'Tapaus',
'scenario_outline' => 'Tapausaihio',
'then' => 'Niin|*',
'when' => 'Kun|*',
),
'fr' => 
array (
'and' => 'Et qu\'<|Et que|Et|*',
'background' => 'Contexte',
'but' => 'Mais qu\'<|Mais que|Mais|*',
'examples' => 'Exemples',
'feature' => 'Fonctionnalité',
'given' => 'Etant donné qu\'<|Étant donné qu\'<|Etant donné que|Étant donné que|Etant données|Étant données|Etant donnée|Etant donnés|Sachant qu\'<|Étant donnée|Étant donnés|Etant donné|Sachant que|Étant donné|Sachant|Soit|*',
'name' => 'French',
'native' => 'français',
'rule' => 'Règle',
'scenario' => 'Scénario|Exemple',
'scenario_outline' => 'Plan du Scénario|Plan du scénario',
'then' => 'Alors|Donc|*',
'when' => 'Lorsqu\'<|Lorsque|Quand|*',
),
'ga' => 
array (
'and' => 'Agus<|*',
'background' => 'Cúlra',
'but' => 'Ach<|*',
'examples' => 'Samplaí',
'feature' => 'Gné',
'given' => 'Cuir i gcás nach<|Cuir i gcás gur<|Cuir i gcás nár<|Cuir i gcás go<|*',
'name' => 'Irish',
'native' => 'Gaeilge',
'rule' => 'Rule',
'scenario' => 'Sampla|Cás',
'scenario_outline' => 'Cás Achomair',
'then' => 'Ansin<|*',
'when' => 'Nuair nach<|Nuair nár<|Nuair ba<|Nuair a<|*',
),
'gj' => 
array (
'and' => 'અને|*',
'background' => 'બેકગ્રાઉન્ડ',
'but' => 'પણ|*',
'examples' => 'ઉદાહરણો',
'feature' => 'વ્યાપાર જરૂર|ક્ષમતા|લક્ષણ',
'given' => 'આપેલ છે|*',
'name' => 'Gujarati',
'native' => 'ગુજરાતી',
'rule' => 'Rule',
'scenario' => 'ઉદાહરણ|સ્થિતિ',
'scenario_outline' => 'પરિદ્દશ્ય રૂપરેખા|પરિદ્દશ્ય ઢાંચો',
'then' => 'પછી|*',
'when' => 'ક્યારે|*',
),
'gl' => 
array (
'and' => '*|E',
'background' => 'Contexto',
'but' => 'Mais|Pero|*',
'examples' => 'Exemplos',
'feature' => 'Característica',
'given' => 'Dadas|Dados|Dada|Dado|*',
'name' => 'Galician',
'native' => 'galego',
'rule' => 'Rule',
'scenario' => 'Escenario|Exemplo',
'scenario_outline' => 'Esbozo do escenario',
'then' => 'Entón|Logo|*',
'when' => 'Cando|*',
),
'he' => 
array (
'and' => 'וגם|*',
'background' => 'רקע',
'but' => 'אבל|*',
'examples' => 'דוגמאות',
'feature' => 'תכונה',
'given' => 'בהינתן|*',
'name' => 'Hebrew',
'native' => 'עברית',
'rule' => 'כלל',
'scenario' => 'דוגמא|תרחיש',
'scenario_outline' => 'תבנית תרחיש',
'then' => 'אזי|אז|*',
'when' => 'כאשר|*',
),
'hi' => 
array (
'and' => 'तथा|और|*',
'background' => 'पृष्ठभूमि',
'but' => 'किन्तु|परन्तु|पर|*',
'examples' => 'उदाहरण',
'feature' => 'रूप लेख',
'given' => 'चूंकि|अगर|यदि|*',
'name' => 'Hindi',
'native' => 'हिंदी',
'rule' => 'नियम',
'scenario' => 'परिदृश्य',
'scenario_outline' => 'परिदृश्य रूपरेखा',
'then' => 'तदा|तब|*',
'when' => 'कदा|जब|*',
),
'hr' => 
array (
'and' => '*|I',
'background' => 'Pozadina',
'but' => 'Ali|*',
'examples' => 'Scenariji|Primjeri',
'feature' => 'Mogucnost|Mogućnost|Osobina',
'given' => 'Ukoliko|Zadani|Zadano|Zadan|*',
'name' => 'Croatian',
'native' => 'hrvatski',
'rule' => 'Rule',
'scenario' => 'Scenarij|Primjer',
'scenario_outline' => 'Koncept|Skica',
'then' => 'Onda|*',
'when' => 'Kada|Kad|*',
),
'ht' => 
array (
'and' => 'Epi|Ak|*|E',
'background' => 'Istorik|Kontèks',
'but' => 'Men|*',
'examples' => 'Egzanp',
'feature' => 'Fonksyonalite|Karakteristik|Mak',
'given' => 'Sipoze Ke|Sipoze ke|Sipoze|*',
'name' => 'Creole',
'native' => 'kreyòl',
'rule' => 'Rule',
'scenario' => 'Senaryo',
'scenario_outline' => 'Senaryo Deskripsyon|Senaryo deskripsyon|Dyagram Senaryo|Dyagram senaryo|Plan Senaryo|Plan senaryo',
'then' => 'Le sa a|Lè sa a|*',
'when' => 'Le|Lè|*',
),
'hu' => 
array (
'and' => 'És|*',
'background' => 'Háttér',
'but' => 'De|*',
'examples' => 'Példák',
'feature' => 'Jellemző',
'given' => 'Amennyiben|Adott|*',
'name' => 'Hungarian',
'native' => 'magyar',
'rule' => 'Szabály',
'scenario' => 'Forgatókönyv|Példa',
'scenario_outline' => 'Forgatókönyv vázlat',
'then' => 'Akkor|*',
'when' => 'Amikor|Majd|Ha|*',
),
'id' => 
array (
'and' => 'Dan|*',
'background' => 'Latar Belakang|Dasar',
'but' => 'Tetapi|Tapi|*',
'examples' => 'Contoh|Misal',
'feature' => 'Fitur',
'given' => 'Diasumsikan|Diketahui|Dengan|Bila|Jika|*',
'name' => 'Indonesian',
'native' => 'Bahasa Indonesia',
'rule' => 'Aturan|Rule',
'scenario' => 'Skenario',
'scenario_outline' => 'Garis-Besar Skenario|Skenario konsep',
'then' => 'Kemudian|Maka|*',
'when' => 'Ketika|*',
),
'is' => 
array (
'and' => 'Og|*',
'background' => 'Bakgrunnur',
'but' => 'En|*',
'examples' => 'Atburðarásir|Dæmi',
'feature' => 'Eiginleiki',
'given' => 'Ef|*',
'name' => 'Icelandic',
'native' => 'Íslenska',
'rule' => 'Rule',
'scenario' => 'Atburðarás',
'scenario_outline' => 'Lýsing Atburðarásar|Lýsing Dæma',
'then' => 'Þá|*',
'when' => 'Þegar|*',
),
'it' => 
array (
'and' => '*|E',
'background' => 'Contesto',
'but' => 'Ma|*',
'examples' => 'Esempi',
'feature' => 'Esigenza di Business|Funzionalità|Abilità',
'given' => 'Data|Date|Dati|Dato|*',
'name' => 'Italian',
'native' => 'italiano',
'rule' => 'Regola',
'scenario' => 'Scenario|Esempio',
'scenario_outline' => 'Schema dello scenario',
'then' => 'Allora|*',
'when' => 'Quando|*',
),
'ja' => 
array (
'and' => 'かつ<|*',
'background' => '背景',
'but' => 'しかし<|ただし<|但し<|*',
'examples' => 'サンプル|例',
'feature' => 'フィーチャ|機能',
'given' => '前提<|*',
'name' => 'Japanese',
'native' => '日本語',
'rule' => 'Rule',
'scenario' => 'シナリオ',
'scenario_outline' => 'シナリオアウトライン|シナリオテンプレート|シナリオテンプレ|テンプレ',
'then' => 'ならば<|*',
'when' => 'もし<|*',
),
'jv' => 
array (
'and' => 'Lan|*',
'background' => 'Dasar',
'but' => 'Ananging|Nanging|Tapi|*',
'examples' => 'Contone|Conto',
'feature' => 'Fitur',
'given' => 'Nalikaning|Nalika|*',
'name' => 'Javanese',
'native' => 'Basa Jawa',
'rule' => 'Rule',
'scenario' => 'Skenario',
'scenario_outline' => 'Konsep skenario',
'then' => 'Banjur|Njuk|*',
'when' => 'Manawa|Menawa|*',
),
'ka' => 
array (
'and' => 'და<|*',
'background' => 'კონტექსტი',
'but' => 'მაგ­რამ<|*',
'examples' => 'მაგალითები',
'feature' => 'თვისება',
'given' => 'მოცემული<|*',
'name' => 'Georgian',
'native' => 'ქართველი',
'rule' => 'Rule',
'scenario' => 'მაგალითად|სცენარის',
'scenario_outline' => 'სცენარის ნიმუში',
'then' => 'მაშინ<|*',
'when' => 'როდესაც<|*',
),
'kn' => 
array (
'and' => 'ಮತ್ತು|*',
'background' => 'ಹಿನ್ನೆಲೆ',
'but' => 'ಆದರೆ|*',
'examples' => 'ಉದಾಹರಣೆಗಳು',
'feature' => 'ಹೆಚ್ಚಳ',
'given' => 'ನೀಡಿದ|*',
'name' => 'Kannada',
'native' => 'ಕನ್ನಡ',
'rule' => 'Rule',
'scenario' => 'ಕಥಾಸಾರಾಂಶ|ಉದಾಹರಣೆ',
'scenario_outline' => 'ವಿವರಣೆ',
'then' => 'ನಂತರ|*',
'when' => 'ಸ್ಥಿತಿಯನ್ನು|*',
),
'ko' => 
array (
'and' => '그리고<|*',
'background' => '배경',
'but' => '하지만<|단<|*',
'examples' => '예',
'feature' => '기능',
'given' => '먼저<|조건<|*',
'name' => 'Korean',
'native' => '한국어',
'rule' => 'Rule',
'scenario' => '시나리오',
'scenario_outline' => '시나리오 개요',
'then' => '그러면<|*',
'when' => '만약<|만일<|*',
),
'lt' => 
array (
'and' => 'Ir|*',
'background' => 'Kontekstas',
'but' => 'Bet|*',
'examples' => 'Pavyzdžiai|Scenarijai|Variantai',
'feature' => 'Savybė',
'given' => 'Duota|*',
'name' => 'Lithuanian',
'native' => 'lietuvių kalba',
'rule' => 'Rule',
'scenario' => 'Scenarijus|Pavyzdys',
'scenario_outline' => 'Scenarijaus šablonas',
'then' => 'Tada|*',
'when' => 'Kai|*',
),
'lu' => 
array (
'and' => 'an|*|a',
'background' => 'Hannergrond',
'but' => 'awer|mä|*',
'examples' => 'Beispiller',
'feature' => 'Funktionalitéit',
'given' => 'ugeholl|*',
'name' => 'Luxemburgish',
'native' => 'Lëtzebuergesch',
'rule' => 'Rule',
'scenario' => 'Beispill|Szenario',
'scenario_outline' => 'Plang vum Szenario',
'then' => 'dann|*',
'when' => 'wann|*',
),
'lv' => 
array (
'and' => 'Un|*',
'background' => 'Konteksts|Situācija',
'but' => 'Bet|*',
'examples' => 'Paraugs|Piemēri',
'feature' => 'Funkcionalitāte|Fīča',
'given' => 'Kad|*',
'name' => 'Latvian',
'native' => 'latviešu',
'rule' => 'Rule',
'scenario' => 'Scenārijs|Piemērs',
'scenario_outline' => 'Scenārijs pēc parauga',
'then' => 'Tad|*',
'when' => 'Ja|*',
),
'mk-Cyrl' => 
array (
'and' => '*|И',
'background' => 'Контекст|Содржина',
'but' => 'Но|*',
'examples' => 'Сценарија|Примери',
'feature' => 'Бизнис потреба|Функционалност|Можност',
'given' => 'Дадена|Дадено|*',
'name' => 'Macedonian',
'native' => 'Македонски',
'rule' => 'Rule',
'scenario' => 'На пример|Сценарио|Пример',
'scenario_outline' => 'Преглед на сценарија|Концепт|Скица',
'then' => 'Тогаш|*',
'when' => 'Кога|*',
),
'mk-Latn' => 
array (
'and' => '*|I',
'background' => 'Sodrzhina|Kontekst',
'but' => 'No|*',
'examples' => 'Scenaria|Primeri',
'feature' => 'Biznis potreba|Funkcionalnost|Mozhnost',
'given' => 'Dadena|Dadeno|*',
'name' => 'Macedonian (Latin)',
'native' => 'Makedonski (Latinica)',
'rule' => 'Rule',
'scenario' => 'Na primer|Scenario',
'scenario_outline' => 'Pregled na scenarija|Koncept|Skica',
'then' => 'Togash|*',
'when' => 'Koga|*',
),
'mn' => 
array (
'and' => 'Тэгээд|Мөн|*',
'background' => 'Агуулга',
'but' => 'Гэхдээ|Харин|*',
'examples' => 'Тухайлбал',
'feature' => 'Функционал|Функц',
'given' => 'Өгөгдсөн нь|Анх|*',
'name' => 'Mongolian',
'native' => 'монгол',
'rule' => 'Rule',
'scenario' => 'Сценар',
'scenario_outline' => 'Сценарын төлөвлөгөө',
'then' => 'Үүний дараа|Тэгэхэд|*',
'when' => 'Хэрэв|*',
),
'mr' => 
array (
'and' => 'तसेच|आणि|*',
'background' => 'पार्श्वभूमी',
'but' => 'परंतु|पण|*',
'examples' => 'उदाहरण',
'feature' => 'वैशिष्ट्य|सुविधा',
'given' => 'दिलेल्या प्रमाणे|जर<|*',
'name' => 'Marathi',
'native' => 'मराठी',
'rule' => 'नियम',
'scenario' => 'परिदृश्य',
'scenario_outline' => 'परिदृश्य रूपरेखा',
'then' => 'तेव्हा|मग|*',
'when' => 'जेव्हा|*',
),
'ne' => 
array (
'and' => 'अनी|*|र',
'background' => 'पृष्ठभूमी',
'but' => 'तर|*',
'examples' => 'उदाहरणहरु|उदाहरण',
'feature' => 'विशेषता|सुविधा',
'given' => 'दिइएको|दिएको|यदि|*',
'name' => 'Nepali',
'native' => 'नेपाली',
'rule' => 'नियम',
'scenario' => 'परिदृश्य',
'scenario_outline' => 'परिदृश्य रूपरेखा',
'then' => 'त्यसपछि|अनी|*',
'when' => 'जब|*',
),
'nl' => 
array (
'and' => 'En|*',
'background' => 'Achtergrond',
'but' => 'Maar|*',
'examples' => 'Voorbeelden',
'feature' => 'Functionaliteit',
'given' => 'Gegeven|Stel|*',
'name' => 'Dutch',
'native' => 'Nederlands',
'rule' => 'Rule',
'scenario' => 'Voorbeeld|Scenario',
'scenario_outline' => 'Abstract Scenario',
'then' => 'Dan|*',
'when' => 'Wanneer|Als|*',
),
'no' => 
array (
'and' => 'Og|*',
'background' => 'Bakgrunn',
'but' => 'Men|*',
'examples' => 'Eksempler',
'feature' => 'Egenskap',
'given' => 'Gitt|*',
'name' => 'Norwegian',
'native' => 'norsk',
'rule' => 'Regel',
'scenario' => 'Eksempel|Scenario',
'scenario_outline' => 'Abstrakt Scenario|Scenariomal',
'then' => 'Så|*',
'when' => 'Når|*',
),
'pa' => 
array (
'and' => 'ਅਤੇ|*',
'background' => 'ਪਿਛੋਕੜ',
'but' => 'ਪਰ|*',
'examples' => 'ਉਦਾਹਰਨਾਂ',
'feature' => 'ਨਕਸ਼ ਨੁਹਾਰ|ਮੁਹਾਂਦਰਾ|ਖਾਸੀਅਤ',
'given' => 'ਜਿਵੇਂ ਕਿ|ਜੇਕਰ|*',
'name' => 'Panjabi',
'native' => 'ਪੰਜਾਬੀ',
'rule' => 'Rule',
'scenario' => 'ਉਦਾਹਰਨ|ਪਟਕਥਾ',
'scenario_outline' => 'ਪਟਕਥਾ ਰੂਪ ਰੇਖਾ|ਪਟਕਥਾ ਢਾਂਚਾ',
'then' => 'ਤਦ|*',
'when' => 'ਜਦੋਂ|*',
),
'pl' => 
array (
'and' => 'Oraz|*|I',
'background' => 'Założenia',
'but' => 'Ale|*',
'examples' => 'Przykłady',
'feature' => 'Potrzeba biznesowa|Właściwość|Funkcja|Aspekt',
'given' => 'Zakładając, że|Zakładając|Mając|*',
'name' => 'Polish',
'native' => 'polski',
'rule' => 'Reguła|Zasada',
'scenario' => 'Scenariusz|Przykład',
'scenario_outline' => 'Szablon scenariusza',
'then' => 'Wtedy|*',
'when' => 'Jeżeli|Jeśli|Kiedy|Gdy|*',
),
'pt' => 
array (
'and' => '*|E',
'background' => 'Cenario de Fundo|Cenário de Fundo|Contexto|Fundo',
'but' => 'Mas|*',
'examples' => 'Cenarios|Cenários|Exemplos',
'feature' => 'Caracteristica|Característica|Funcionalidade',
'given' => 'Dadas|Dados|Dada|Dado|*',
'name' => 'Portuguese',
'native' => 'português',
'rule' => 'Regra',
'scenario' => 'Cenario|Cenário|Exemplo',
'scenario_outline' => 'Delineacao do Cenario|Delineação do Cenário|Esquema do Cenario|Esquema do Cenário',
'then' => 'Entao|Então|*',
'when' => 'Quando|*',
),
'ro' => 
array (
'and' => 'Si|Şi|Și|*',
'background' => 'Context',
'but' => 'Dar|*',
'examples' => 'Exemple',
'feature' => 'Functionalitate|Funcţionalitate|Funcționalitate',
'given' => 'Dată fiind<|Date fiind|Dati fiind|Daţi fiind|Dați fiind|Dat fiind|*',
'name' => 'Romanian',
'native' => 'română',
'rule' => 'Rule',
'scenario' => 'Scenariu|Exemplu',
'scenario_outline' => 'Structura scenariu|Structură scenariu',
'then' => 'Atunci|*',
'when' => 'Cand|Când|*',
),
'ru' => 
array (
'and' => 'К тому же|Также|*|И',
'background' => 'Предыстория|Контекст',
'but' => 'Иначе|Но|*|А',
'examples' => 'Примеры',
'feature' => 'Функциональность|Функционал|Свойство|Функция',
'given' => 'Допустим|Пусть|Дано|*',
'name' => 'Russian',
'native' => 'русский',
'rule' => 'Правило',
'scenario' => 'Сценарий|Пример',
'scenario_outline' => 'Структура сценария|Шаблон сценария',
'then' => 'Затем|Тогда|То|*',
'when' => 'Когда|Если|*',
),
'sk' => 
array (
'and' => 'A taktiež|A zároveň|A tiež|*|A',
'background' => 'Pozadie',
'but' => 'Ale|*',
'examples' => 'Príklady',
'feature' => 'Požiadavka|Vlastnosť|Funkcia',
'given' => 'Za predpokladu|Pokiaľ|*',
'name' => 'Slovak',
'native' => 'Slovensky',
'rule' => 'Rule',
'scenario' => 'Príklad|Scenár',
'scenario_outline' => 'Osnova Scenára|Náčrt Scenára|Náčrt Scenáru',
'then' => 'Potom|Tak|*',
'when' => 'Keď|Ak|*',
),
'sl' => 
array (
'and' => 'Ter|In',
'background' => 'Kontekst|Osnova|Ozadje',
'but' => 'Vendar|Ampak|Toda',
'examples' => 'Scenariji|Primeri',
'feature' => 'Funkcionalnost|Značilnost|Funkcija|Lastnost|Moznosti|Možnosti',
'given' => 'Privzeto|Podano|Zaradi|Dano',
'name' => 'Slovenian',
'native' => 'Slovenski',
'rule' => 'Rule',
'scenario' => 'Scenarij|Primer',
'scenario_outline' => 'Struktura scenarija|Oris scenarija|Koncept|Osnutek|Skica',
'then' => 'Takrat|Potem|Nato',
'when' => 'Kadar|Ce|Ko|Če',
),
'sr-Cyrl' => 
array (
'and' => '*|И',
'background' => 'Контекст|Позадина|Основа',
'but' => 'Али|*',
'examples' => 'Сценарији|Примери',
'feature' => 'Функционалност|Могућност|Особина',
'given' => 'За дате|За дати|За дато|*',
'name' => 'Serbian',
'native' => 'Српски',
'rule' => 'Правило',
'scenario' => 'Сценарио|Пример|Пример',
'scenario_outline' => 'Структура сценарија|Концепт|Скица',
'then' => 'Онда|*',
'when' => 'Када|Кад|*',
),
'sr-Latn' => 
array (
'and' => '*|I',
'background' => 'Kontekst|Pozadina|Osnova',
'but' => 'Ali|*',
'examples' => 'Scenariji|Primeri',
'feature' => 'Funkcionalnost|Mogucnost|Mogućnost|Osobina',
'given' => 'Za date|Za dati|Za dato|*',
'name' => 'Serbian (Latin)',
'native' => 'Srpski (Latinica)',
'rule' => 'Pravilo',
'scenario' => 'Scenario|Primer',
'scenario_outline' => 'Struktura scenarija|Koncept|Skica',
'then' => 'Onda|*',
'when' => 'Kada|Kad|*',
),
'sv' => 
array (
'and' => 'Och|*',
'background' => 'Bakgrund',
'but' => 'Men|*',
'examples' => 'Exempel',
'feature' => 'Egenskap',
'given' => 'Givet|*',
'name' => 'Swedish',
'native' => 'Svenska',
'rule' => 'Regel',
'scenario' => 'Scenario',
'scenario_outline' => 'Abstrakt Scenario|Scenariomall',
'then' => 'Så|*',
'when' => 'När|*',
),
'ta' => 
array (
'and' => 'மற்றும்|மேலும்|*',
'background' => 'பின்னணி',
'but' => 'ஆனால்|*',
'examples' => 'எடுத்துக்காட்டுகள்|நிலைமைகளில்|காட்சிகள்',
'feature' => 'வணிக தேவை|அம்சம்|திறன்',
'given' => 'கொடுக்கப்பட்ட|*',
'name' => 'Tamil',
'native' => 'தமிழ்',
'rule' => 'Rule',
'scenario' => 'உதாரணமாக|காட்சி',
'scenario_outline' => 'காட்சி வார்ப்புரு|காட்சி சுருக்கம்',
'then' => 'அப்பொழுது|*',
'when' => 'எப்போது|*',
),
'te' => 
array (
'and' => 'మరియు|*',
'background' => 'నేపథ్యం',
'but' => 'కాని|*',
'examples' => 'ఉదాహరణలు',
'feature' => 'గుణము',
'given' => 'చెప్పబడినది|*',
'name' => 'Telugu',
'native' => 'తెలుగు',
'rule' => 'Rule',
'scenario' => 'సన్నివేశం|ఉదాహరణ',
'scenario_outline' => 'కథనం',
'then' => 'అప్పుడు|*',
'when' => 'ఈ పరిస్థితిలో|*',
),
'th' => 
array (
'and' => 'และ|*',
'background' => 'แนวคิด',
'but' => 'แต่|*',
'examples' => 'ชุดของเหตุการณ์|ชุดของตัวอย่าง',
'feature' => 'ความต้องการทางธุรกิจ|ความสามารถ|โครงหลัก',
'given' => 'กำหนดให้|*',
'name' => 'Thai',
'native' => 'ไทย',
'rule' => 'Rule',
'scenario' => 'เหตุการณ์',
'scenario_outline' => 'โครงสร้างของเหตุการณ์|สรุปเหตุการณ์',
'then' => 'ดังนั้น|*',
'when' => 'เมื่อ|*',
),
'tlh' => 
array (
'and' => 'latlh|\'ej|*',
'background' => 'mo\'',
'but' => '\'ach|\'a|*',
'examples' => 'ghantoH|lutmey',
'feature' => 'poQbogh malja\'|Qu\'meH \'ut|perbogh|Qap|laH',
'given' => 'DaH ghu\' bejlu\'|ghu\' noblu\'|*',
'name' => 'Klingon',
'native' => 'tlhIngan',
'rule' => 'Rule',
'scenario' => 'lut',
'scenario_outline' => 'lut chovnatlh',
'then' => 'vaj|*',
'when' => 'qaSDI\'|*',
),
'tr' => 
array (
'and' => 'Ve|*',
'background' => 'Geçmiş',
'but' => 'Fakat|Ama|*',
'examples' => 'Örnekler',
'feature' => 'Özellik',
'given' => 'Diyelim ki|*',
'name' => 'Turkish',
'native' => 'Türkçe',
'rule' => 'Kural',
'scenario' => 'Senaryo|Örnek',
'scenario_outline' => 'Senaryo taslağı',
'then' => 'O zaman|*',
'when' => 'Eğer ki|*',
),
'tt' => 
array (
'and' => 'Һәм|Вә|*',
'background' => 'Кереш',
'but' => 'Ләкин|Әмма|*',
'examples' => 'Мисаллар|Үрнәкләр',
'feature' => 'Үзенчәлеклелек|Мөмкинлек',
'given' => 'Әйтик|*',
'name' => 'Tatar',
'native' => 'Татарча',
'rule' => 'Rule',
'scenario' => 'Сценарий',
'scenario_outline' => 'Сценарийның төзелеше',
'then' => 'Нәтиҗәдә|*',
'when' => 'Әгәр|*',
),
'uk' => 
array (
'and' => 'А також|Та|*|І',
'background' => 'Передумова',
'but' => 'Але|*',
'examples' => 'Приклади',
'feature' => 'Функціонал',
'given' => 'Припустимо, що|Припустимо|Нехай|Дано|*',
'name' => 'Ukrainian',
'native' => 'Українська',
'rule' => 'Rule',
'scenario' => 'Сценарій|Приклад',
'scenario_outline' => 'Структура сценарію',
'then' => 'Тоді|То|*',
'when' => 'Коли|Якщо|*',
),
'ur' => 
array (
'and' => 'اور|*',
'background' => 'پس منظر',
'but' => 'لیکن|*',
'examples' => 'مثالیں',
'feature' => 'کاروبار کی ضرورت|خصوصیت|صلاحیت',
'given' => 'فرض کیا|بالفرض|اگر|*',
'name' => 'Urdu',
'native' => 'اردو',
'rule' => 'Rule',
'scenario' => 'منظرنامہ',
'scenario_outline' => 'منظر نامے کا خاکہ',
'then' => 'پھر|تب|*',
'when' => 'جب|*',
),
'uz' => 
array (
'and' => 'Ва|*',
'background' => 'Тарих',
'but' => 'Бирок|Лекин|Аммо|*',
'examples' => 'Мисоллар',
'feature' => 'Функционал',
'given' => 'Агар|*',
'name' => 'Uzbek',
'native' => 'Узбекча',
'rule' => 'Rule',
'scenario' => 'Сценарий',
'scenario_outline' => 'Сценарий структураси',
'then' => 'Унда|*',
'when' => 'Агар|*',
),
'vi' => 
array (
'and' => 'Và|*',
'background' => 'Bối cảnh',
'but' => 'Nhưng|*',
'examples' => 'Dữ liệu',
'feature' => 'Tính năng',
'given' => 'Biết|Cho|*',
'name' => 'Vietnamese',
'native' => 'Tiếng Việt',
'rule' => 'Rule',
'scenario' => 'Tình huống|Kịch bản',
'scenario_outline' => 'Khung tình huống|Khung kịch bản',
'then' => 'Thì|*',
'when' => 'Khi|*',
),
'zh-CN' => 
array (
'and' => '同时<|并且<|而且<|*',
'background' => '背景',
'but' => '但是<|*',
'examples' => '例子',
'feature' => '功能',
'given' => '假如<|假定<|假设<|*',
'name' => 'Chinese simplified',
'native' => '简体中文',
'rule' => 'Rule',
'scenario' => '剧本|场景',
'scenario_outline' => '剧本大纲|场景大纲',
'then' => '那么<|*',
'when' => '当<|*',
),
'zh-TW' => 
array (
'and' => '並且<|同時<|而且<|*',
'background' => '背景',
'but' => '但是<|*',
'examples' => '例子',
'feature' => '功能',
'given' => '假如<|假定<|假設<|*',
'name' => 'Chinese traditional',
'native' => '繁體中文',
'rule' => 'Rule',
'scenario' => '劇本|場景',
'scenario_outline' => '劇本大綱|場景大綱',
'then' => '那麼<|*',
'when' => '當<|*',
),
);<?php declare(strict_types=1);








namespace SebastianBergmann\Exporter;

use SebastianBergmann\RecursionContext\Context;












class Exporter
{

















public function export($value, $indentation = 0)
{
return $this->recursiveExport($value, $indentation);
}







public function shortenedRecursiveExport(&$data, Context $context = null)
{
$result = [];
$exporter = new self();

if (!$context) {
$context = new Context;
}

$array = $data;
$context->add($data);

foreach ($array as $key => $value) {
if (\is_array($value)) {
if ($context->contains($data[$key]) !== false) {
$result[] = '*RECURSION*';
} else {
$result[] = \sprintf(
'array(%s)',
$this->shortenedRecursiveExport($data[$key], $context)
);
}
} else {
$result[] = $exporter->shortenedExport($value);
}
}

return \implode(', ', $result);
}














public function shortenedExport($value)
{
if (\is_string($value)) {
$string = \str_replace("\n", '', $this->export($value));

if (\function_exists('mb_strlen')) {
if (\mb_strlen($string) > 40) {
$string = \mb_substr($string, 0, 30) . '...' . \mb_substr($string, -7);
}
} else {
if (\strlen($string) > 40) {
$string = \substr($string, 0, 30) . '...' . \substr($string, -7);
}
}

return $string;
}

if (\is_object($value)) {
return \sprintf(
'%s Object (%s)',
\get_class($value),
\count($this->toArray($value)) > 0 ? '...' : ''
);
}

if (\is_array($value)) {
return \sprintf(
'Array (%s)',
\count($value) > 0 ? '...' : ''
);
}

return $this->export($value);
}







public function toArray($value)
{
if (!\is_object($value)) {
return (array) $value;
}

$array = [];

foreach ((array) $value as $key => $val) {

 
 
 if ("\0Error\0trace" === $key || "\0Exception\0trace" === $key) {
continue;
}


 
 
 
 if (\preg_match('/^\0.+\0(.+)$/', (string) $key, $matches)) {
$key = $matches[1];
}


 if ($key === "\0gcdata") {
continue;
}

$array[$key] = $val;
}


 
 
 if ($value instanceof \SplObjectStorage) {
foreach ($value as $key => $val) {
$array[\spl_object_hash($val)] = [
'obj' => $val,
'inf' => $value->getInfo(),
];
}
}

return $array;
}












protected function recursiveExport(&$value, $indentation, $processed = null)
{
if ($value === null) {
return 'null';
}

if ($value === true) {
return 'true';
}

if ($value === false) {
return 'false';
}

if (\is_float($value) && (float) ((int) $value) === $value) {
return "$value.0";
}

if ($this->isClosedResource($value)) {
return 'resource (closed)';
}

if (\is_resource($value)) {
return \sprintf(
'resource(%d) of type (%s)',
$value,
\get_resource_type($value)
);
}

if (\is_string($value)) {

 if (\preg_match('/[^\x09-\x0d\x1b\x20-\xff]/', $value)) {
return 'Binary String: 0x' . \bin2hex($value);
}

return "'" .
\str_replace(
'<lf>',
"\n",
\str_replace(
["\r\n", "\n\r", "\r", "\n"],
['\r\n<lf>', '\n\r<lf>', '\r<lf>', '\n<lf>'],
$value
)
) .
"'";
}

$whitespace = \str_repeat(' ', (int)(4 * $indentation));

if (!$processed) {
$processed = new Context;
}

if (\is_array($value)) {
if (($key = $processed->contains($value)) !== false) {
return 'Array &' . $key;
}

$array = $value;
$key = $processed->add($value);
$values = '';

if (\count($array) > 0) {
foreach ($array as $k => $v) {
$values .= \sprintf(
'%s    %s => %s' . "\n",
$whitespace,
$this->recursiveExport($k, $indentation),
$this->recursiveExport($value[$k], $indentation + 1, $processed)
);
}

$values = "\n" . $values . $whitespace;
}

return \sprintf('Array &%s (%s)', $key, $values);
}

if (\is_object($value)) {
$class = \get_class($value);

if ($hash = $processed->contains($value)) {
return \sprintf('%s Object &%s', $class, $hash);
}

$hash = $processed->add($value);
$values = '';
$array = $this->toArray($value);

if (\count($array) > 0) {
foreach ($array as $k => $v) {
$values .= \sprintf(
'%s    %s => %s' . "\n",
$whitespace,
$this->recursiveExport($k, $indentation),
$this->recursiveExport($v, $indentation + 1, $processed)
);
}

$values = "\n" . $values . $whitespace;
}

return \sprintf('%s Object &%s (%s)', $class, $hash, $values);
}

return \var_export($value, true);
}








private function isResource($value)
{
return $value !== null
&& \is_scalar($value) === false
&& \is_array($value) === false
&& \is_object($value) === false;
}








private function isClosedResource($value)
{



if (\gettype($value) === 'resource (closed)') {
return true;
}





$isResource = \is_resource($value);
$isNotNonResource = $this->isResource($value);

if ($isResource === false && $isNotNonResource === true) {
return true;
}

if ($isNotNonResource === true) {
try {
$resourceType = @\get_resource_type($value);

if ($resourceType === 'Unknown') {
return true;
}
} catch (TypeError $e) {

 } catch (Exception $e) {

 }
}

return false;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\GlobalState;

interface Exception
{
}
<?php declare(strict_types=1);








namespace SebastianBergmann\GlobalState;

final class RuntimeException extends \RuntimeException implements Exception
{
}
<?php declare(strict_types=1);








namespace SebastianBergmann\GlobalState;




final class Blacklist
{



private $globalVariables = [];




private $classes = [];




private $classNamePrefixes = [];




private $parentClasses = [];




private $interfaces = [];




private $staticAttributes = [];

public function addGlobalVariable(string $variableName): void
{
$this->globalVariables[$variableName] = true;
}

public function addClass(string $className): void
{
$this->classes[] = $className;
}

public function addSubclassesOf(string $className): void
{
$this->parentClasses[] = $className;
}

public function addImplementorsOf(string $interfaceName): void
{
$this->interfaces[] = $interfaceName;
}

public function addClassNamePrefix(string $classNamePrefix): void
{
$this->classNamePrefixes[] = $classNamePrefix;
}

public function addStaticAttribute(string $className, string $attributeName): void
{
if (!isset($this->staticAttributes[$className])) {
$this->staticAttributes[$className] = [];
}

$this->staticAttributes[$className][$attributeName] = true;
}

public function isGlobalVariableBlacklisted(string $variableName): bool
{
return isset($this->globalVariables[$variableName]);
}

public function isStaticAttributeBlacklisted(string $className, string $attributeName): bool
{
if (\in_array($className, $this->classes)) {
return true;
}

foreach ($this->classNamePrefixes as $prefix) {
if (\strpos($className, $prefix) === 0) {
return true;
}
}

$class = new \ReflectionClass($className);

foreach ($this->parentClasses as $type) {
if ($class->isSubclassOf($type)) {
return true;
}
}

foreach ($this->interfaces as $type) {
if ($class->implementsInterface($type)) {
return true;
}
}

if (isset($this->staticAttributes[$className][$attributeName])) {
return true;
}

return false;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\GlobalState;




final class CodeExporter
{
public function constants(Snapshot $snapshot): string
{
$result = '';

foreach ($snapshot->constants() as $name => $value) {
$result .= \sprintf(
'if (!defined(\'%s\')) define(\'%s\', %s);' . "\n",
$name,
$name,
$this->exportVariable($value)
);
}

return $result;
}

public function globalVariables(Snapshot $snapshot): string
{
$result = '$GLOBALS = [];' . \PHP_EOL;

foreach ($snapshot->globalVariables() as $name => $value) {
$result .= \sprintf(
'$GLOBALS[%s] = %s;' . \PHP_EOL,
$this->exportVariable($name),
$this->exportVariable($value)
);
}

return $result;
}

public function iniSettings(Snapshot $snapshot): string
{
$result = '';

foreach ($snapshot->iniSettings() as $key => $value) {
$result .= \sprintf(
'@ini_set(%s, %s);' . "\n",
$this->exportVariable($key),
$this->exportVariable($value)
);
}

return $result;
}

private function exportVariable($variable): string
{
if (\is_scalar($variable) || null === $variable ||
(\is_array($variable) && $this->arrayOnlyContainsScalars($variable))) {
return \var_export($variable, true);
}

return 'unserialize(' . \var_export(\serialize($variable), true) . ')';
}

private function arrayOnlyContainsScalars(array $array): bool
{
$result = true;

foreach ($array as $element) {
if (\is_array($element)) {
$result = $this->arrayOnlyContainsScalars($element);
} elseif (!\is_scalar($element) && null !== $element) {
$result = false;
}

if ($result === false) {
break;
}
}

return $result;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\GlobalState;




class Restorer
{







public function restoreFunctions(Snapshot $snapshot): void
{
if (!\function_exists('uopz_delete')) {
throw new RuntimeException('The uopz_delete() function is required for this operation');
}

$functions = \get_defined_functions();

foreach (\array_diff($functions['user'], $snapshot->functions()) as $function) {
uopz_delete($function);
}
}




public function restoreGlobalVariables(Snapshot $snapshot): void
{
$superGlobalArrays = $snapshot->superGlobalArrays();

foreach ($superGlobalArrays as $superGlobalArray) {
$this->restoreSuperGlobalArray($snapshot, $superGlobalArray);
}

$globalVariables = $snapshot->globalVariables();

foreach (\array_keys($GLOBALS) as $key) {
if ($key !== 'GLOBALS' &&
!\in_array($key, $superGlobalArrays) &&
!$snapshot->blacklist()->isGlobalVariableBlacklisted($key)) {
if (\array_key_exists($key, $globalVariables)) {
$GLOBALS[$key] = $globalVariables[$key];
} else {
unset($GLOBALS[$key]);
}
}
}
}




public function restoreStaticAttributes(Snapshot $snapshot): void
{
$current = new Snapshot($snapshot->blacklist(), false, false, false, false, true, false, false, false, false);
$newClasses = \array_diff($current->classes(), $snapshot->classes());

unset($current);

foreach ($snapshot->staticAttributes() as $className => $staticAttributes) {
foreach ($staticAttributes as $name => $value) {
$reflector = new \ReflectionProperty($className, $name);
$reflector->setAccessible(true);
$reflector->setValue($value);
}
}

foreach ($newClasses as $className) {
$class = new \ReflectionClass($className);
$defaults = $class->getDefaultProperties();

foreach ($class->getProperties() as $attribute) {
if (!$attribute->isStatic()) {
continue;
}

$name = $attribute->getName();

if ($snapshot->blacklist()->isStaticAttributeBlacklisted($className, $name)) {
continue;
}

if (!isset($defaults[$name])) {
continue;
}

$attribute->setAccessible(true);
$attribute->setValue($defaults[$name]);
}
}
}




private function restoreSuperGlobalArray(Snapshot $snapshot, string $superGlobalArray): void
{
$superGlobalVariables = $snapshot->superGlobalVariables();

if (isset($GLOBALS[$superGlobalArray]) &&
\is_array($GLOBALS[$superGlobalArray]) &&
isset($superGlobalVariables[$superGlobalArray])) {
$keys = \array_keys(
\array_merge(
$GLOBALS[$superGlobalArray],
$superGlobalVariables[$superGlobalArray]
)
);

foreach ($keys as $key) {
if (isset($superGlobalVariables[$superGlobalArray][$key])) {
$GLOBALS[$superGlobalArray][$key] = $superGlobalVariables[$superGlobalArray][$key];
} else {
unset($GLOBALS[$superGlobalArray][$key]);
}
}
}
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\GlobalState;

use SebastianBergmann\ObjectReflector\ObjectReflector;
use SebastianBergmann\RecursionContext\Context;




class Snapshot
{



private $blacklist;




private $globalVariables = [];




private $superGlobalArrays = [];




private $superGlobalVariables = [];




private $staticAttributes = [];




private $iniSettings = [];




private $includedFiles = [];




private $constants = [];




private $functions = [];




private $interfaces = [];




private $classes = [];




private $traits = [];




public function __construct(Blacklist $blacklist = null, bool $includeGlobalVariables = true, bool $includeStaticAttributes = true, bool $includeConstants = true, bool $includeFunctions = true, bool $includeClasses = true, bool $includeInterfaces = true, bool $includeTraits = true, bool $includeIniSettings = true, bool $includeIncludedFiles = true)
{
if ($blacklist === null) {
$blacklist = new Blacklist;
}

$this->blacklist = $blacklist;

if ($includeConstants) {
$this->snapshotConstants();
}

if ($includeFunctions) {
$this->snapshotFunctions();
}

if ($includeClasses || $includeStaticAttributes) {
$this->snapshotClasses();
}

if ($includeInterfaces) {
$this->snapshotInterfaces();
}

if ($includeGlobalVariables) {
$this->setupSuperGlobalArrays();
$this->snapshotGlobals();
}

if ($includeStaticAttributes) {
$this->snapshotStaticAttributes();
}

if ($includeIniSettings) {
$this->iniSettings = \ini_get_all(null, false);
}

if ($includeIncludedFiles) {
$this->includedFiles = \get_included_files();
}

$this->traits = \get_declared_traits();
}

public function blacklist(): Blacklist
{
return $this->blacklist;
}

public function globalVariables(): array
{
return $this->globalVariables;
}

public function superGlobalVariables(): array
{
return $this->superGlobalVariables;
}

public function superGlobalArrays(): array
{
return $this->superGlobalArrays;
}

public function staticAttributes(): array
{
return $this->staticAttributes;
}

public function iniSettings(): array
{
return $this->iniSettings;
}

public function includedFiles(): array
{
return $this->includedFiles;
}

public function constants(): array
{
return $this->constants;
}

public function functions(): array
{
return $this->functions;
}

public function interfaces(): array
{
return $this->interfaces;
}

public function classes(): array
{
return $this->classes;
}

public function traits(): array
{
return $this->traits;
}




private function snapshotConstants(): void
{
$constants = \get_defined_constants(true);

if (isset($constants['user'])) {
$this->constants = $constants['user'];
}
}




private function snapshotFunctions(): void
{
$functions = \get_defined_functions();

$this->functions = $functions['user'];
}




private function snapshotClasses(): void
{
foreach (\array_reverse(\get_declared_classes()) as $className) {
$class = new \ReflectionClass($className);

if (!$class->isUserDefined()) {
break;
}

$this->classes[] = $className;
}

$this->classes = \array_reverse($this->classes);
}




private function snapshotInterfaces(): void
{
foreach (\array_reverse(\get_declared_interfaces()) as $interfaceName) {
$class = new \ReflectionClass($interfaceName);

if (!$class->isUserDefined()) {
break;
}

$this->interfaces[] = $interfaceName;
}

$this->interfaces = \array_reverse($this->interfaces);
}




private function snapshotGlobals(): void
{
$superGlobalArrays = $this->superGlobalArrays();

foreach ($superGlobalArrays as $superGlobalArray) {
$this->snapshotSuperGlobalArray($superGlobalArray);
}

foreach (\array_keys($GLOBALS) as $key) {
if ($key !== 'GLOBALS' &&
!\in_array($key, $superGlobalArrays) &&
$this->canBeSerialized($GLOBALS[$key]) &&
!$this->blacklist->isGlobalVariableBlacklisted($key)) {

$this->globalVariables[$key] = \unserialize(\serialize($GLOBALS[$key]));
}
}
}




private function snapshotSuperGlobalArray(string $superGlobalArray): void
{
$this->superGlobalVariables[$superGlobalArray] = [];

if (isset($GLOBALS[$superGlobalArray]) && \is_array($GLOBALS[$superGlobalArray])) {
foreach ($GLOBALS[$superGlobalArray] as $key => $value) {

$this->superGlobalVariables[$superGlobalArray][$key] = \unserialize(\serialize($value));
}
}
}




private function snapshotStaticAttributes(): void
{
foreach ($this->classes as $className) {
$class = new \ReflectionClass($className);
$snapshot = [];

foreach ($class->getProperties() as $attribute) {
if ($attribute->isStatic()) {
$name = $attribute->getName();

if ($this->blacklist->isStaticAttributeBlacklisted($className, $name)) {
continue;
}

$attribute->setAccessible(true);
$value = $attribute->getValue();

if ($this->canBeSerialized($value)) {

$snapshot[$name] = \unserialize(\serialize($value));
}
}
}

if (!empty($snapshot)) {
$this->staticAttributes[$className] = $snapshot;
}
}
}




private function setupSuperGlobalArrays(): void
{
$this->superGlobalArrays = [
'_ENV',
'_POST',
'_GET',
'_COOKIE',
'_SERVER',
'_FILES',
'_REQUEST',
];
}

private function canBeSerialized($variable): bool
{
if (\is_scalar($variable) || $variable === null) {
return true;
}

if (\is_resource($variable)) {
return false;
}

foreach ($this->enumerateObjectsAndResources($variable) as $value) {
if (\is_resource($value)) {
return false;
}

if (\is_object($value)) {
$class = new \ReflectionClass($value);

if ($class->isAnonymous()) {
return false;
}

try {
@\serialize($value);
} catch (\Throwable $t) {
return false;
}
}
}

return true;
}

private function enumerateObjectsAndResources($variable): array
{
if (isset(\func_get_args()[1])) {
$processed = \func_get_args()[1];
} else {
$processed = new Context;
}

$result = [];

if ($processed->contains($variable)) {
return $result;
}

$array = $variable;
$processed->add($variable);

if (\is_array($variable)) {
foreach ($array as $element) {
if (!\is_array($element) && !\is_object($element) && !\is_resource($element)) {
continue;
}

if (!\is_resource($element)) {

$result = \array_merge(
$result,
$this->enumerateObjectsAndResources($element, $processed)
);
} else {
$result[] = $element;
}
}
} else {
$result[] = $variable;

foreach ((new ObjectReflector)->getAttributes($variable) as $value) {
if (!\is_array($value) && !\is_object($value) && !\is_resource($value)) {
continue;
}

if (!\is_resource($value)) {

$result = \array_merge(
$result,
$this->enumerateObjectsAndResources($value, $processed)
);
} else {
$result[] = $value;
}
}
}

return $result;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Type;

final class VoidType extends Type
{
public function isAssignable(Type $other): bool
{
return $other instanceof self;
}

public function getReturnTypeDeclaration(): string
{
return ': void';
}

public function allowsNull(): bool
{
return false;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Type;

final class NullType extends Type
{
public function isAssignable(Type $other): bool
{
return !($other instanceof VoidType);
}

public function getReturnTypeDeclaration(): string
{
return '';
}

public function allowsNull(): bool
{
return true;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Type;

final class CallableType extends Type
{



private $allowsNull;

public function __construct(bool $nullable)
{
$this->allowsNull = $nullable;
}




public function isAssignable(Type $other): bool
{
if ($this->allowsNull && $other instanceof NullType) {
return true;
}

if ($other instanceof self) {
return true;
}

if ($other instanceof ObjectType) {
if ($this->isClosure($other)) {
return true;
}

if ($this->hasInvokeMethod($other)) {
return true;
}
}

if ($other instanceof SimpleType) {
if ($this->isFunction($other)) {
return true;
}

if ($this->isClassCallback($other)) {
return true;
}

if ($this->isObjectCallback($other)) {
return true;
}
}

return false;
}

public function getReturnTypeDeclaration(): string
{
return ': ' . ($this->allowsNull ? '?' : '') . 'callable';
}

public function allowsNull(): bool
{
return $this->allowsNull;
}

private function isClosure(ObjectType $type): bool
{
return !$type->className()->isNamespaced() && $type->className()->getSimpleName() === \Closure::class;
}




private function hasInvokeMethod(ObjectType $type): bool
{
try {
$class = new \ReflectionClass($type->className()->getQualifiedName());

 } catch (\ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);

 }

if ($class->hasMethod('__invoke')) {
return true;
}

return false;
}

private function isFunction(SimpleType $type): bool
{
if (!\is_string($type->value())) {
return false;
}

return \function_exists($type->value());
}

private function isObjectCallback(SimpleType $type): bool
{
if (!\is_array($type->value())) {
return false;
}

if (\count($type->value()) !== 2) {
return false;
}

if (!\is_object($type->value()[0]) || !\is_string($type->value()[1])) {
return false;
}

[$object, $methodName] = $type->value();

$reflector = new \ReflectionObject($object);

return $reflector->hasMethod($methodName);
}

private function isClassCallback(SimpleType $type): bool
{
if (!\is_string($type->value()) && !\is_array($type->value())) {
return false;
}

if (\is_string($type->value())) {
if (\strpos($type->value(), '::') === false) {
return false;
}

[$className, $methodName] = \explode('::', $type->value());
}

if (\is_array($type->value())) {
if (\count($type->value()) !== 2) {
return false;
}

if (!\is_string($type->value()[0]) || !\is_string($type->value()[1])) {
return false;
}

[$className, $methodName] = $type->value();
}

\assert(isset($className) && \is_string($className));
\assert(isset($methodName) && \is_string($methodName));

try {
$class = new \ReflectionClass($className);

if ($class->hasMethod($methodName)) {
$method = $class->getMethod($methodName);

return $method->isPublic() && $method->isStatic();
}

 } catch (\ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);

 }

return false;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Type;

final class GenericObjectType extends Type
{



private $allowsNull;

public function __construct(bool $nullable)
{
$this->allowsNull = $nullable;
}

public function isAssignable(Type $other): bool
{
if ($this->allowsNull && $other instanceof NullType) {
return true;
}

if (!$other instanceof ObjectType) {
return false;
}

return true;
}

public function getReturnTypeDeclaration(): string
{
return ': ' . ($this->allowsNull ? '?' : '') . 'object';
}

public function allowsNull(): bool
{
return $this->allowsNull;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Type;

final class IterableType extends Type
{



private $allowsNull;

public function __construct(bool $nullable)
{
$this->allowsNull = $nullable;
}




public function isAssignable(Type $other): bool
{
if ($this->allowsNull && $other instanceof NullType) {
return true;
}

if ($other instanceof self) {
return true;
}

if ($other instanceof SimpleType) {
return \is_iterable($other->value());
}

if ($other instanceof ObjectType) {
try {
return (new \ReflectionClass($other->className()->getQualifiedName()))->isIterable();

 } catch (\ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);

 }
}

return false;
}

public function getReturnTypeDeclaration(): string
{
return ': ' . ($this->allowsNull ? '?' : '') . 'iterable';
}

public function allowsNull(): bool
{
return $this->allowsNull;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Type;

interface Exception
{
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Type;

final class RuntimeException extends \RuntimeException implements Exception
{
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Type;

final class UnknownType extends Type
{
public function isAssignable(Type $other): bool
{
return true;
}

public function getReturnTypeDeclaration(): string
{
return '';
}

public function allowsNull(): bool
{
return true;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Type;

abstract class Type
{
public static function fromValue($value, bool $allowsNull): self
{
$typeName = \gettype($value);

if ($typeName === 'object') {
return new ObjectType(TypeName::fromQualifiedName(\get_class($value)), $allowsNull);
}

$type = self::fromName($typeName, $allowsNull);

if ($type instanceof SimpleType) {
$type = new SimpleType($typeName, $allowsNull, $value);
}

return $type;
}

public static function fromName(string $typeName, bool $allowsNull): self
{
switch (\strtolower($typeName)) {
case 'callable':
return new CallableType($allowsNull);

case 'iterable':
return new IterableType($allowsNull);

case 'null':
return new NullType;

case 'object':
return new GenericObjectType($allowsNull);

case 'unknown type':
return new UnknownType;

case 'void':
return new VoidType;

case 'array':
case 'bool':
case 'boolean':
case 'double':
case 'float':
case 'int':
case 'integer':
case 'real':
case 'resource':
case 'resource (closed)':
case 'string':
return new SimpleType($typeName, $allowsNull);

default:
return new ObjectType(TypeName::fromQualifiedName($typeName), $allowsNull);
}
}

abstract public function isAssignable(Type $other): bool;

abstract public function getReturnTypeDeclaration(): string;

abstract public function allowsNull(): bool;
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Type;

final class SimpleType extends Type
{



private $name;




private $allowsNull;




private $value;

public function __construct(string $name, bool $nullable, $value = null)
{
$this->name = $this->normalize($name);
$this->allowsNull = $nullable;
$this->value = $value;
}

public function isAssignable(Type $other): bool
{
if ($this->allowsNull && $other instanceof NullType) {
return true;
}

if ($other instanceof self) {
return $this->name === $other->name;
}

return false;
}

public function getReturnTypeDeclaration(): string
{
return ': ' . ($this->allowsNull ? '?' : '') . $this->name;
}

public function allowsNull(): bool
{
return $this->allowsNull;
}

public function value()
{
return $this->value;
}

private function normalize(string $name): string
{
$name = \strtolower($name);

switch ($name) {
case 'boolean':
return 'bool';

case 'real':
case 'double':
return 'float';

case 'integer':
return 'int';

case '[]':
return 'array';

default:
return $name;
}
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Type;

final class TypeName
{



private $namespaceName;




private $simpleName;

public static function fromQualifiedName(string $fullClassName): self
{
if ($fullClassName[0] === '\\') {
$fullClassName = \substr($fullClassName, 1);
}

$classNameParts = \explode('\\', $fullClassName);

$simpleName = \array_pop($classNameParts);
$namespaceName = \implode('\\', $classNameParts);

return new self($namespaceName, $simpleName);
}

public static function fromReflection(\ReflectionClass $type): self
{
return new self(
$type->getNamespaceName(),
$type->getShortName()
);
}

public function __construct(?string $namespaceName, string $simpleName)
{
if ($namespaceName === '') {
$namespaceName = null;
}

$this->namespaceName = $namespaceName;
$this->simpleName = $simpleName;
}

public function getNamespaceName(): ?string
{
return $this->namespaceName;
}

public function getSimpleName(): string
{
return $this->simpleName;
}

public function getQualifiedName(): string
{
return $this->namespaceName === null
? $this->simpleName
: $this->namespaceName . '\\' . $this->simpleName;
}

public function isNamespaced(): bool
{
return $this->namespaceName !== null;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Type;

final class ObjectType extends Type
{



private $className;




private $allowsNull;

public function __construct(TypeName $className, bool $allowsNull)
{
$this->className = $className;
$this->allowsNull = $allowsNull;
}

public function isAssignable(Type $other): bool
{
if ($this->allowsNull && $other instanceof NullType) {
return true;
}

if ($other instanceof self) {
if (0 === \strcasecmp($this->className->getQualifiedName(), $other->className->getQualifiedName())) {
return true;
}

if (\is_subclass_of($other->className->getQualifiedName(), $this->className->getQualifiedName(), true)) {
return true;
}
}

return false;
}

public function getReturnTypeDeclaration(): string
{
return ': ' . ($this->allowsNull ? '?' : '') . $this->className->getQualifiedName();
}

public function allowsNull(): bool
{
return $this->allowsNull;
}

public function className(): TypeName
{
return $this->className;
}
}
<?php declare(strict_types=1);









namespace SebastianBergmann\Diff\Output;

use SebastianBergmann\Diff\Differ;





final class DiffOnlyOutputBuilder implements DiffOutputBuilderInterface
{



private $header;

public function __construct(string $header = "--- Original\n+++ New\n")
{
$this->header = $header;
}

public function getDiff(array $diff): string
{
$buffer = \fopen('php://memory', 'r+b');

if ('' !== $this->header) {
\fwrite($buffer, $this->header);

if ("\n" !== \substr($this->header, -1, 1)) {
\fwrite($buffer, "\n");
}
}

foreach ($diff as $diffEntry) {
if ($diffEntry[1] === Differ::ADDED) {
\fwrite($buffer, '+' . $diffEntry[0]);
} elseif ($diffEntry[1] === Differ::REMOVED) {
\fwrite($buffer, '-' . $diffEntry[0]);
} elseif ($diffEntry[1] === Differ::DIFF_LINE_END_WARNING) {
\fwrite($buffer, ' ' . $diffEntry[0]);

continue; 
 } else { 
continue; 
 }

$lc = \substr($diffEntry[0], -1);

if ($lc !== "\n" && $lc !== "\r") {
\fwrite($buffer, "\n"); 
 }
}

$diff = \stream_get_contents($buffer, -1, 0);
\fclose($buffer);

return $diff;
}
}
<?php declare(strict_types=1);









namespace SebastianBergmann\Diff\Output;





interface DiffOutputBuilderInterface
{
public function getDiff(array $diff): string;
}
<?php declare(strict_types=1);









namespace SebastianBergmann\Diff\Output;

use SebastianBergmann\Diff\Differ;




final class UnifiedDiffOutputBuilder extends AbstractChunkOutputBuilder
{



private $collapseRanges = true;




private $commonLineThreshold = 6;




private $contextLines = 3;




private $header;




private $addLineNumbers;

public function __construct(string $header = "--- Original\n+++ New\n", bool $addLineNumbers = false)
{
$this->header = $header;
$this->addLineNumbers = $addLineNumbers;
}

public function getDiff(array $diff): string
{
$buffer = \fopen('php://memory', 'r+b');

if ('' !== $this->header) {
\fwrite($buffer, $this->header);

if ("\n" !== \substr($this->header, -1, 1)) {
\fwrite($buffer, "\n");
}
}

if (0 !== \count($diff)) {
$this->writeDiffHunks($buffer, $diff);
}

$diff = \stream_get_contents($buffer, -1, 0);

\fclose($buffer);


 
 $last = \substr($diff, -1);

return "\n" !== $last && "\r" !== $last
? $diff . "\n"
: $diff
;
}

private function writeDiffHunks($output, array $diff): void
{


$upperLimit = \count($diff);

if (0 === $diff[$upperLimit - 1][1]) {
$lc = \substr($diff[$upperLimit - 1][0], -1);

if ("\n" !== $lc) {
\array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]);
}
} else {

 
 $toFind = [1 => true, 2 => true];

for ($i = $upperLimit - 1; $i >= 0; --$i) {
if (isset($toFind[$diff[$i][1]])) {
unset($toFind[$diff[$i][1]]);
$lc = \substr($diff[$i][0], -1);

if ("\n" !== $lc) {
\array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]);
}

if (!\count($toFind)) {
break;
}
}
}
}



$cutOff = \max($this->commonLineThreshold, $this->contextLines);
$hunkCapture = false;
$sameCount = $toRange = $fromRange = 0;
$toStart = $fromStart = 1;

foreach ($diff as $i => $entry) {
if (0 === $entry[1]) { 
 if (false === $hunkCapture) {
++$fromStart;
++$toStart;

continue;
}

++$sameCount;
++$toRange;
++$fromRange;

if ($sameCount === $cutOff) {
$contextStartOffset = ($hunkCapture - $this->contextLines) < 0
? $hunkCapture
: $this->contextLines
;


 
 
 
 
 
 
 
 
 

$this->writeHunk(
$diff,
$hunkCapture - $contextStartOffset,
$i - $cutOff + $this->contextLines + 1,
$fromStart - $contextStartOffset,
$fromRange - $cutOff + $contextStartOffset + $this->contextLines,
$toStart - $contextStartOffset,
$toRange - $cutOff + $contextStartOffset + $this->contextLines,
$output
);

$fromStart += $fromRange;
$toStart += $toRange;

$hunkCapture = false;
$sameCount = $toRange = $fromRange = 0;
}

continue;
}

$sameCount = 0;

if ($entry[1] === Differ::NO_LINE_END_EOF_WARNING) {
continue;
}

if (false === $hunkCapture) {
$hunkCapture = $i;
}

if (Differ::ADDED === $entry[1]) {
++$toRange;
}

if (Differ::REMOVED === $entry[1]) {
++$fromRange;
}
}

if (false === $hunkCapture) {
return;
}


 

$contextStartOffset = $hunkCapture - $this->contextLines < 0
? $hunkCapture
: $this->contextLines
;


 
 $contextEndOffset = \min($sameCount, $this->contextLines);

$fromRange -= $sameCount;
$toRange -= $sameCount;

$this->writeHunk(
$diff,
$hunkCapture - $contextStartOffset,
$i - $sameCount + $contextEndOffset + 1,
$fromStart - $contextStartOffset,
$fromRange + $contextStartOffset + $contextEndOffset,
$toStart - $contextStartOffset,
$toRange + $contextStartOffset + $contextEndOffset,
$output
);
}

private function writeHunk(
array $diff,
int $diffStartIndex,
int $diffEndIndex,
int $fromStart,
int $fromRange,
int $toStart,
int $toRange,
$output
): void {
if ($this->addLineNumbers) {
\fwrite($output, '@@ -' . $fromStart);

if (!$this->collapseRanges || 1 !== $fromRange) {
\fwrite($output, ',' . $fromRange);
}

\fwrite($output, ' +' . $toStart);

if (!$this->collapseRanges || 1 !== $toRange) {
\fwrite($output, ',' . $toRange);
}

\fwrite($output, " @@\n");
} else {
\fwrite($output, "@@ @@\n");
}

for ($i = $diffStartIndex; $i < $diffEndIndex; ++$i) {
if ($diff[$i][1] === Differ::ADDED) {
\fwrite($output, '+' . $diff[$i][0]);
} elseif ($diff[$i][1] === Differ::REMOVED) {
\fwrite($output, '-' . $diff[$i][0]);
} elseif ($diff[$i][1] === Differ::OLD) {
\fwrite($output, ' ' . $diff[$i][0]);
} elseif ($diff[$i][1] === Differ::NO_LINE_END_EOF_WARNING) {
\fwrite($output, "\n"); 
 } else { 
\fwrite($output, ' ' . $diff[$i][0]);
}
}
}
}
<?php declare(strict_types=1);









namespace SebastianBergmann\Diff\Output;

use SebastianBergmann\Diff\ConfigurationException;
use SebastianBergmann\Diff\Differ;






final class StrictUnifiedDiffOutputBuilder implements DiffOutputBuilderInterface
{
private static $default = [
'collapseRanges' => true, 
 'commonLineThreshold' => 6, 
 'contextLines' => 3, 
 'fromFile' => null,
'fromFileDate' => null,
'toFile' => null,
'toFileDate' => null,
];



private $changed;




private $collapseRanges;




private $commonLineThreshold;




private $header;




private $contextLines;

public function __construct(array $options = [])
{
$options = \array_merge(self::$default, $options);

if (!\is_bool($options['collapseRanges'])) {
throw new ConfigurationException('collapseRanges', 'a bool', $options['collapseRanges']);
}

if (!\is_int($options['contextLines']) || $options['contextLines'] < 0) {
throw new ConfigurationException('contextLines', 'an int >= 0', $options['contextLines']);
}

if (!\is_int($options['commonLineThreshold']) || $options['commonLineThreshold'] <= 0) {
throw new ConfigurationException('commonLineThreshold', 'an int > 0', $options['commonLineThreshold']);
}

foreach (['fromFile', 'toFile'] as $option) {
if (!\is_string($options[$option])) {
throw new ConfigurationException($option, 'a string', $options[$option]);
}
}

foreach (['fromFileDate', 'toFileDate'] as $option) {
if (null !== $options[$option] && !\is_string($options[$option])) {
throw new ConfigurationException($option, 'a string or <null>', $options[$option]);
}
}

$this->header = \sprintf(
"--- %s%s\n+++ %s%s\n",
$options['fromFile'],
null === $options['fromFileDate'] ? '' : "\t" . $options['fromFileDate'],
$options['toFile'],
null === $options['toFileDate'] ? '' : "\t" . $options['toFileDate']
);

$this->collapseRanges = $options['collapseRanges'];
$this->commonLineThreshold = $options['commonLineThreshold'];
$this->contextLines = $options['contextLines'];
}

public function getDiff(array $diff): string
{
if (0 === \count($diff)) {
return '';
}

$this->changed = false;

$buffer = \fopen('php://memory', 'r+b');
\fwrite($buffer, $this->header);

$this->writeDiffHunks($buffer, $diff);

if (!$this->changed) {
\fclose($buffer);

return '';
}

$diff = \stream_get_contents($buffer, -1, 0);

\fclose($buffer);


 
 $last = \substr($diff, -1);

return "\n" !== $last && "\r" !== $last
? $diff . "\n"
: $diff
;
}

private function writeDiffHunks($output, array $diff): void
{


$upperLimit = \count($diff);

if (0 === $diff[$upperLimit - 1][1]) {
$lc = \substr($diff[$upperLimit - 1][0], -1);

if ("\n" !== $lc) {
\array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]);
}
} else {

 
 $toFind = [1 => true, 2 => true];

for ($i = $upperLimit - 1; $i >= 0; --$i) {
if (isset($toFind[$diff[$i][1]])) {
unset($toFind[$diff[$i][1]]);
$lc = \substr($diff[$i][0], -1);

if ("\n" !== $lc) {
\array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]);
}

if (!\count($toFind)) {
break;
}
}
}
}



$cutOff = \max($this->commonLineThreshold, $this->contextLines);
$hunkCapture = false;
$sameCount = $toRange = $fromRange = 0;
$toStart = $fromStart = 1;

foreach ($diff as $i => $entry) {
if (0 === $entry[1]) { 
 if (false === $hunkCapture) {
++$fromStart;
++$toStart;

continue;
}

++$sameCount;
++$toRange;
++$fromRange;

if ($sameCount === $cutOff) {
$contextStartOffset = ($hunkCapture - $this->contextLines) < 0
? $hunkCapture
: $this->contextLines
;


 
 
 
 
 
 
 
 
 

$this->writeHunk(
$diff,
$hunkCapture - $contextStartOffset,
$i - $cutOff + $this->contextLines + 1,
$fromStart - $contextStartOffset,
$fromRange - $cutOff + $contextStartOffset + $this->contextLines,
$toStart - $contextStartOffset,
$toRange - $cutOff + $contextStartOffset + $this->contextLines,
$output
);

$fromStart += $fromRange;
$toStart += $toRange;

$hunkCapture = false;
$sameCount = $toRange = $fromRange = 0;
}

continue;
}

$sameCount = 0;

if ($entry[1] === Differ::NO_LINE_END_EOF_WARNING) {
continue;
}

$this->changed = true;

if (false === $hunkCapture) {
$hunkCapture = $i;
}

if (Differ::ADDED === $entry[1]) { 
 ++$toRange;
}

if (Differ::REMOVED === $entry[1]) { 
 ++$fromRange;
}
}

if (false === $hunkCapture) {
return;
}


 

$contextStartOffset = $hunkCapture - $this->contextLines < 0
? $hunkCapture
: $this->contextLines
;


 
 $contextEndOffset = \min($sameCount, $this->contextLines);

$fromRange -= $sameCount;
$toRange -= $sameCount;

$this->writeHunk(
$diff,
$hunkCapture - $contextStartOffset,
$i - $sameCount + $contextEndOffset + 1,
$fromStart - $contextStartOffset,
$fromRange + $contextStartOffset + $contextEndOffset,
$toStart - $contextStartOffset,
$toRange + $contextStartOffset + $contextEndOffset,
$output
);
}

private function writeHunk(
array $diff,
int $diffStartIndex,
int $diffEndIndex,
int $fromStart,
int $fromRange,
int $toStart,
int $toRange,
$output
): void {
\fwrite($output, '@@ -' . $fromStart);

if (!$this->collapseRanges || 1 !== $fromRange) {
\fwrite($output, ',' . $fromRange);
}

\fwrite($output, ' +' . $toStart);

if (!$this->collapseRanges || 1 !== $toRange) {
\fwrite($output, ',' . $toRange);
}

\fwrite($output, " @@\n");

for ($i = $diffStartIndex; $i < $diffEndIndex; ++$i) {
if ($diff[$i][1] === Differ::ADDED) {
$this->changed = true;
\fwrite($output, '+' . $diff[$i][0]);
} elseif ($diff[$i][1] === Differ::REMOVED) {
$this->changed = true;
\fwrite($output, '-' . $diff[$i][0]);
} elseif ($diff[$i][1] === Differ::OLD) {
\fwrite($output, ' ' . $diff[$i][0]);
} elseif ($diff[$i][1] === Differ::NO_LINE_END_EOF_WARNING) {
$this->changed = true;
\fwrite($output, $diff[$i][0]);
}

 
 
 
 
 }
}
}
<?php declare(strict_types=1);









namespace SebastianBergmann\Diff\Output;

abstract class AbstractChunkOutputBuilder implements DiffOutputBuilderInterface
{









protected function getCommonChunks(array $diff, int $lineThreshold = 5): array
{
$diffSize = \count($diff);
$capturing = false;
$chunkStart = 0;
$chunkSize = 0;
$commonChunks = [];

for ($i = 0; $i < $diffSize; ++$i) {
if ($diff[$i][1] === 0 ) {
if ($capturing === false) {
$capturing = true;
$chunkStart = $i;
$chunkSize = 0;
} else {
++$chunkSize;
}
} elseif ($capturing !== false) {
if ($chunkSize >= $lineThreshold) {
$commonChunks[$chunkStart] = $chunkStart + $chunkSize;
}

$capturing = false;
}
}

if ($capturing !== false && $chunkSize >= $lineThreshold) {
$commonChunks[$chunkStart] = $chunkStart + $chunkSize;
}

return $commonChunks;
}
}
<?php declare(strict_types=1);









namespace SebastianBergmann\Diff;

use SebastianBergmann\Diff\Output\DiffOutputBuilderInterface;
use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;




final class Differ
{
public const OLD = 0;
public const ADDED = 1;
public const REMOVED = 2;
public const DIFF_LINE_END_WARNING = 3;
public const NO_LINE_END_EOF_WARNING = 4;




private $outputBuilder;






public function __construct($outputBuilder = null)
{
if ($outputBuilder instanceof DiffOutputBuilderInterface) {
$this->outputBuilder = $outputBuilder;
} elseif (null === $outputBuilder) {
$this->outputBuilder = new UnifiedDiffOutputBuilder;
} elseif (\is_string($outputBuilder)) {

 
 
 $this->outputBuilder = new UnifiedDiffOutputBuilder($outputBuilder);
} else {
throw new InvalidArgumentException(
\sprintf(
'Expected builder to be an instance of DiffOutputBuilderInterface, <null> or a string, got %s.',
\is_object($outputBuilder) ? 'instance of "' . \get_class($outputBuilder) . '"' : \gettype($outputBuilder) . ' "' . $outputBuilder . '"'
)
);
}
}










public function diff($from, $to, LongestCommonSubsequenceCalculator $lcs = null): string
{
$diff = $this->diffToArray(
$this->normalizeDiffInput($from),
$this->normalizeDiffInput($to),
$lcs
);

return $this->outputBuilder->getDiff($diff);
}


















public function diffToArray($from, $to, LongestCommonSubsequenceCalculator $lcs = null): array
{
if (\is_string($from)) {
$from = $this->splitStringByLines($from);
} elseif (!\is_array($from)) {
throw new InvalidArgumentException('"from" must be an array or string.');
}

if (\is_string($to)) {
$to = $this->splitStringByLines($to);
} elseif (!\is_array($to)) {
throw new InvalidArgumentException('"to" must be an array or string.');
}

[$from, $to, $start, $end] = self::getArrayDiffParted($from, $to);

if ($lcs === null) {
$lcs = $this->selectLcsImplementation($from, $to);
}

$common = $lcs->calculate(\array_values($from), \array_values($to));
$diff = [];

foreach ($start as $token) {
$diff[] = [$token, self::OLD];
}

\reset($from);
\reset($to);

foreach ($common as $token) {
while (($fromToken = \reset($from)) !== $token) {
$diff[] = [\array_shift($from), self::REMOVED];
}

while (($toToken = \reset($to)) !== $token) {
$diff[] = [\array_shift($to), self::ADDED];
}

$diff[] = [$token, self::OLD];

\array_shift($from);
\array_shift($to);
}

while (($token = \array_shift($from)) !== null) {
$diff[] = [$token, self::REMOVED];
}

while (($token = \array_shift($to)) !== null) {
$diff[] = [$token, self::ADDED];
}

foreach ($end as $token) {
$diff[] = [$token, self::OLD];
}

if ($this->detectUnmatchedLineEndings($diff)) {
\array_unshift($diff, ["#Warning: Strings contain different line endings!\n", self::DIFF_LINE_END_WARNING]);
}

return $diff;
}








private function normalizeDiffInput($input)
{
if (!\is_array($input) && !\is_string($input)) {
return (string) $input;
}

return $input;
}








private function splitStringByLines(string $input): array
{
return \preg_split('/(.*\R)/', $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
}







private function selectLcsImplementation(array $from, array $to): LongestCommonSubsequenceCalculator
{

 
 
 
 $memoryLimit = 100 * 1024 * 1024;

if ($this->calculateEstimatedFootprint($from, $to) > $memoryLimit) {
return new MemoryEfficientLongestCommonSubsequenceCalculator;
}

return new TimeEfficientLongestCommonSubsequenceCalculator;
}









private function calculateEstimatedFootprint(array $from, array $to)
{
$itemSize = PHP_INT_SIZE === 4 ? 76 : 144;

return $itemSize * \min(\count($from), \count($to)) ** 2;
}








private function detectUnmatchedLineEndings(array $diff): bool
{
$newLineBreaks = ['' => true];
$oldLineBreaks = ['' => true];

foreach ($diff as $entry) {
if (self::OLD === $entry[1]) {
$ln = $this->getLinebreak($entry[0]);
$oldLineBreaks[$ln] = true;
$newLineBreaks[$ln] = true;
} elseif (self::ADDED === $entry[1]) {
$newLineBreaks[$this->getLinebreak($entry[0])] = true;
} elseif (self::REMOVED === $entry[1]) {
$oldLineBreaks[$this->getLinebreak($entry[0])] = true;
}
}


 if (['' => true] === $newLineBreaks || ['' => true] === $oldLineBreaks) {
return false;
}


 foreach ($newLineBreaks as $break => $set) {
if (!isset($oldLineBreaks[$break])) {
return true;
}
}

foreach ($oldLineBreaks as $break => $set) {
if (!isset($newLineBreaks[$break])) {
return true;
}
}

return false;
}

private function getLinebreak($line): string
{
if (!\is_string($line)) {
return '';
}

$lc = \substr($line, -1);

if ("\r" === $lc) {
return "\r";
}

if ("\n" !== $lc) {
return '';
}

if ("\r\n" === \substr($line, -2)) {
return "\r\n";
}

return "\n";
}

private static function getArrayDiffParted(array &$from, array &$to): array
{
$start = [];
$end = [];

\reset($to);

foreach ($from as $k => $v) {
$toK = \key($to);

if ($toK === $k && $v === $to[$k]) {
$start[$k] = $v;

unset($from[$k], $to[$k]);
} else {
break;
}
}

\end($from);
\end($to);

do {
$fromK = \key($from);
$toK = \key($to);

if (null === $fromK || null === $toK || \current($from) !== \current($to)) {
break;
}

\prev($from);
\prev($to);

$end = [$fromK => $from[$fromK]] + $end;
unset($from[$fromK], $to[$toK]);
} while (true);

return [$from, $to, $start, $end];
}
}
<?php declare(strict_types=1);









namespace SebastianBergmann\Diff;

final class MemoryEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator
{



public function calculate(array $from, array $to): array
{
$cFrom = \count($from);
$cTo = \count($to);

if ($cFrom === 0) {
return [];
}

if ($cFrom === 1) {
if (\in_array($from[0], $to, true)) {
return [$from[0]];
}

return [];
}

$i = (int) ($cFrom / 2);
$fromStart = \array_slice($from, 0, $i);
$fromEnd = \array_slice($from, $i);
$llB = $this->length($fromStart, $to);
$llE = $this->length(\array_reverse($fromEnd), \array_reverse($to));
$jMax = 0;
$max = 0;

for ($j = 0; $j <= $cTo; $j++) {
$m = $llB[$j] + $llE[$cTo - $j];

if ($m >= $max) {
$max = $m;
$jMax = $j;
}
}

$toStart = \array_slice($to, 0, $jMax);
$toEnd = \array_slice($to, $jMax);

return \array_merge(
$this->calculate($fromStart, $toStart),
$this->calculate($fromEnd, $toEnd)
);
}

private function length(array $from, array $to): array
{
$current = \array_fill(0, \count($to) + 1, 0);
$cFrom = \count($from);
$cTo = \count($to);

for ($i = 0; $i < $cFrom; $i++) {
$prev = $current;

for ($j = 0; $j < $cTo; $j++) {
if ($from[$i] === $to[$j]) {
$current[$j + 1] = $prev[$j] + 1;
} else {
$current[$j + 1] = \max($current[$j], $prev[$j + 1]);
}
}
}

return $current;
}
}
<?php declare(strict_types=1);









namespace SebastianBergmann\Diff;

final class Chunk
{



private $start;




private $startRange;




private $end;




private $endRange;




private $lines;

public function __construct(int $start = 0, int $startRange = 1, int $end = 0, int $endRange = 1, array $lines = [])
{
$this->start = $start;
$this->startRange = $startRange;
$this->end = $end;
$this->endRange = $endRange;
$this->lines = $lines;
}

public function getStart(): int
{
return $this->start;
}

public function getStartRange(): int
{
return $this->startRange;
}

public function getEnd(): int
{
return $this->end;
}

public function getEndRange(): int
{
return $this->endRange;
}




public function getLines(): array
{
return $this->lines;
}




public function setLines(array $lines): void
{
foreach ($lines as $line) {
if (!$line instanceof Line) {
throw new InvalidArgumentException;
}
}

$this->lines = $lines;
}
}
<?php declare(strict_types=1);









namespace SebastianBergmann\Diff;

final class TimeEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator
{



public function calculate(array $from, array $to): array
{
$common = [];
$fromLength = \count($from);
$toLength = \count($to);
$width = $fromLength + 1;
$matrix = new \SplFixedArray($width * ($toLength + 1));

for ($i = 0; $i <= $fromLength; ++$i) {
$matrix[$i] = 0;
}

for ($j = 0; $j <= $toLength; ++$j) {
$matrix[$j * $width] = 0;
}

for ($i = 1; $i <= $fromLength; ++$i) {
for ($j = 1; $j <= $toLength; ++$j) {
$o = ($j * $width) + $i;
$matrix[$o] = \max(
$matrix[$o - 1],
$matrix[$o - $width],
$from[$i - 1] === $to[$j - 1] ? $matrix[$o - $width - 1] + 1 : 0
);
}
}

$i = $fromLength;
$j = $toLength;

while ($i > 0 && $j > 0) {
if ($from[$i - 1] === $to[$j - 1]) {
$common[] = $from[$i - 1];
--$i;
--$j;
} else {
$o = ($j * $width) + $i;

if ($matrix[$o - $width] > $matrix[$o - 1]) {
--$j;
} else {
--$i;
}
}
}

return \array_reverse($common);
}
}
<?php declare(strict_types=1);









namespace SebastianBergmann\Diff;

interface LongestCommonSubsequenceCalculator
{








public function calculate(array $from, array $to): array;
}
<?php declare(strict_types=1);









namespace SebastianBergmann\Diff;

final class Line
{
public const ADDED = 1;
public const REMOVED = 2;
public const UNCHANGED = 3;




private $type;




private $content;

public function __construct(int $type = self::UNCHANGED, string $content = '')
{
$this->type = $type;
$this->content = $content;
}

public function getContent(): string
{
return $this->content;
}

public function getType(): int
{
return $this->type;
}
}
<?php declare(strict_types=1);









namespace SebastianBergmann\Diff;

final class Diff
{



private $from;




private $to;




private $chunks;






public function __construct(string $from, string $to, array $chunks = [])
{
$this->from = $from;
$this->to = $to;
$this->chunks = $chunks;
}

public function getFrom(): string
{
return $this->from;
}

public function getTo(): string
{
return $this->to;
}




public function getChunks(): array
{
return $this->chunks;
}




public function setChunks(array $chunks): void
{
$this->chunks = $chunks;
}
}
<?php declare(strict_types=1);









namespace SebastianBergmann\Diff;

interface Exception
{
}
<?php declare(strict_types=1);









namespace SebastianBergmann\Diff;

final class ConfigurationException extends InvalidArgumentException
{







public function __construct(
string $option,
string $expected,
$value,
int $code = 0,
\Exception $previous = null
) {
parent::__construct(
\sprintf(
'Option "%s" must be %s, got "%s".',
$option,
$expected,
\is_object($value) ? \get_class($value) : (null === $value ? '<null>' : \gettype($value) . '#' . $value)
),
$code,
$previous
);
}
}
<?php declare(strict_types=1);









namespace SebastianBergmann\Diff;

class InvalidArgumentException extends \InvalidArgumentException implements Exception
{
}
<?php declare(strict_types=1);









namespace SebastianBergmann\Diff;




final class Parser
{





public function parse(string $string): array
{
$lines = \preg_split('(\r\n|\r|\n)', $string);

if (!empty($lines) && $lines[\count($lines) - 1] === '') {
\array_pop($lines);
}

$lineCount = \count($lines);
$diffs = [];
$diff = null;
$collected = [];

for ($i = 0; $i < $lineCount; ++$i) {
if (\preg_match('(^---\\s+(?P<file>\\S+))', $lines[$i], $fromMatch) &&
\preg_match('(^\\+\\+\\+\\s+(?P<file>\\S+))', $lines[$i + 1], $toMatch)) {
if ($diff !== null) {
$this->parseFileDiff($diff, $collected);

$diffs[] = $diff;
$collected = [];
}

$diff = new Diff($fromMatch['file'], $toMatch['file']);

++$i;
} else {
if (\preg_match('/^(?:diff --git |index [\da-f\.]+|[+-]{3} [ab])/', $lines[$i])) {
continue;
}

$collected[] = $lines[$i];
}
}

if ($diff !== null && \count($collected)) {
$this->parseFileDiff($diff, $collected);

$diffs[] = $diff;
}

return $diffs;
}

private function parseFileDiff(Diff $diff, array $lines): void
{
$chunks = [];
$chunk = null;

foreach ($lines as $line) {
if (\preg_match('/^@@\s+-(?P<start>\d+)(?:,\s*(?P<startrange>\d+))?\s+\+(?P<end>\d+)(?:,\s*(?P<endrange>\d+))?\s+@@/', $line, $match)) {
$chunk = new Chunk(
(int) $match['start'],
isset($match['startrange']) ? \max(1, (int) $match['startrange']) : 1,
(int) $match['end'],
isset($match['endrange']) ? \max(1, (int) $match['endrange']) : 1
);

$chunks[] = $chunk;
$diffLines = [];

continue;
}

if (\preg_match('/^(?P<type>[+ -])?(?P<line>.*)/', $line, $match)) {
$type = Line::UNCHANGED;

if ($match['type'] === '+') {
$type = Line::ADDED;
} elseif ($match['type'] === '-') {
$type = Line::REMOVED;
}

$diffLines[] = new Line($type, $match['line']);

if (null !== $chunk) {
$chunk->setLines($diffLines);
}
}
}

$diff->setChunks($chunks);
}
}
<?php









namespace SebastianBergmann;




class Version
{



private $path;




private $release;




private $version;





public function __construct($release, $path)
{
$this->release = $release;
$this->path = $path;
}




public function getVersion()
{
if ($this->version === null) {
if (count(explode('.', $this->release)) == 3) {
$this->version = $this->release;
} else {
$this->version = $this->release . '-dev';
}

$git = $this->getGitInformation($this->path);

if ($git) {
if (count(explode('.', $this->release)) == 3) {
$this->version = $git;
} else {
$git = explode('-', $git);

$this->version = $this->release . '-' . end($git);
}
}
}

return $this->version;
}






private function getGitInformation($path)
{
if (!is_dir($path . DIRECTORY_SEPARATOR . '.git')) {
return false;
}

$process = proc_open(
'git describe --tags',
[
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
],
$pipes,
$path
);

if (!is_resource($process)) {
return false;
}

$result = trim(stream_get_contents($pipes[1]));

fclose($pipes[1]);
fclose($pipes[2]);

$returnCode = proc_close($process);

if ($returnCode !== 0) {
return false;
}

return $result;
}
}
<?php









namespace SebastianBergmann\RecursionContext;



interface Exception
{
}
<?php









namespace SebastianBergmann\RecursionContext;





final class Context
{



private $arrays;




private $objects;




public function __construct()
{
$this->arrays = array();
$this->objects = new \SplObjectStorage;
}










public function add(&$value)
{
if (is_array($value)) {
return $this->addArray($value);
} elseif (is_object($value)) {
return $this->addObject($value);
}

throw new InvalidArgumentException(
'Only arrays and objects are supported'
);
}










public function contains(&$value)
{
if (is_array($value)) {
return $this->containsArray($value);
} elseif (is_object($value)) {
return $this->containsObject($value);
}

throw new InvalidArgumentException(
'Only arrays and objects are supported'
);
}






private function addArray(array &$array)
{
$key = $this->containsArray($array);

if ($key !== false) {
return $key;
}

$key = count($this->arrays);
$this->arrays[] = &$array;

if (!isset($array[PHP_INT_MAX]) && !isset($array[PHP_INT_MAX - 1])) {
$array[] = $key;
$array[] = $this->objects;
} else { 
do {
$key = random_int(PHP_INT_MIN, PHP_INT_MAX);
} while (isset($array[$key]));

$array[$key] = $key;

do {
$key = random_int(PHP_INT_MIN, PHP_INT_MAX);
} while (isset($array[$key]));

$array[$key] = $this->objects;
}

return $key;
}






private function addObject($object)
{
if (!$this->objects->contains($object)) {
$this->objects->attach($object);
}

return spl_object_hash($object);
}






private function containsArray(array &$array)
{
$end = array_slice($array, -2);

return isset($end[1]) && $end[1] === $this->objects ? $end[0] : false;
}






private function containsObject($value)
{
if ($this->objects->contains($value)) {
return spl_object_hash($value);
}

return false;
}

public function __destruct()
{
foreach ($this->arrays as &$array) {
if (is_array($array)) {
array_pop($array);
array_pop($array);
}
}
}
}
<?php









namespace SebastianBergmann\RecursionContext;



final class InvalidArgumentException extends \InvalidArgumentException implements Exception
{
}
<?php declare(strict_types=1);








namespace SebastianBergmann\ResourceOperations;

final class ResourceOperations
{



public static function getFunctions(): array
{
return [
'Directory::close',
'Directory::read',
'Directory::rewind',
'DirectoryIterator::openFile',
'FilesystemIterator::openFile',
'Gmagick::readimagefile',
'HttpResponse::getRequestBodyStream',
'HttpResponse::getStream',
'HttpResponse::setStream',
'Imagick::pingImageFile',
'Imagick::readImageFile',
'Imagick::writeImageFile',
'Imagick::writeImagesFile',
'MongoGridFSCursor::__construct',
'MongoGridFSFile::getResource',
'MysqlndUhConnection::stmtInit',
'MysqlndUhConnection::storeResult',
'MysqlndUhConnection::useResult',
'PDF_activate_item',
'PDF_add_launchlink',
'PDF_add_locallink',
'PDF_add_nameddest',
'PDF_add_note',
'PDF_add_pdflink',
'PDF_add_table_cell',
'PDF_add_textflow',
'PDF_add_thumbnail',
'PDF_add_weblink',
'PDF_arc',
'PDF_arcn',
'PDF_attach_file',
'PDF_begin_document',
'PDF_begin_font',
'PDF_begin_glyph',
'PDF_begin_item',
'PDF_begin_layer',
'PDF_begin_page',
'PDF_begin_page_ext',
'PDF_begin_pattern',
'PDF_begin_template',
'PDF_begin_template_ext',
'PDF_circle',
'PDF_clip',
'PDF_close',
'PDF_close_image',
'PDF_close_pdi',
'PDF_close_pdi_page',
'PDF_closepath',
'PDF_closepath_fill_stroke',
'PDF_closepath_stroke',
'PDF_concat',
'PDF_continue_text',
'PDF_create_3dview',
'PDF_create_action',
'PDF_create_annotation',
'PDF_create_bookmark',
'PDF_create_field',
'PDF_create_fieldgroup',
'PDF_create_gstate',
'PDF_create_pvf',
'PDF_create_textflow',
'PDF_curveto',
'PDF_define_layer',
'PDF_delete',
'PDF_delete_pvf',
'PDF_delete_table',
'PDF_delete_textflow',
'PDF_encoding_set_char',
'PDF_end_document',
'PDF_end_font',
'PDF_end_glyph',
'PDF_end_item',
'PDF_end_layer',
'PDF_end_page',
'PDF_end_page_ext',
'PDF_end_pattern',
'PDF_end_template',
'PDF_endpath',
'PDF_fill',
'PDF_fill_imageblock',
'PDF_fill_pdfblock',
'PDF_fill_stroke',
'PDF_fill_textblock',
'PDF_findfont',
'PDF_fit_image',
'PDF_fit_pdi_page',
'PDF_fit_table',
'PDF_fit_textflow',
'PDF_fit_textline',
'PDF_get_apiname',
'PDF_get_buffer',
'PDF_get_errmsg',
'PDF_get_errnum',
'PDF_get_parameter',
'PDF_get_pdi_parameter',
'PDF_get_pdi_value',
'PDF_get_value',
'PDF_info_font',
'PDF_info_matchbox',
'PDF_info_table',
'PDF_info_textflow',
'PDF_info_textline',
'PDF_initgraphics',
'PDF_lineto',
'PDF_load_3ddata',
'PDF_load_font',
'PDF_load_iccprofile',
'PDF_load_image',
'PDF_makespotcolor',
'PDF_moveto',
'PDF_new',
'PDF_open_ccitt',
'PDF_open_file',
'PDF_open_image',
'PDF_open_image_file',
'PDF_open_memory_image',
'PDF_open_pdi',
'PDF_open_pdi_document',
'PDF_open_pdi_page',
'PDF_pcos_get_number',
'PDF_pcos_get_stream',
'PDF_pcos_get_string',
'PDF_place_image',
'PDF_place_pdi_page',
'PDF_process_pdi',
'PDF_rect',
'PDF_restore',
'PDF_resume_page',
'PDF_rotate',
'PDF_save',
'PDF_scale',
'PDF_set_border_color',
'PDF_set_border_dash',
'PDF_set_border_style',
'PDF_set_gstate',
'PDF_set_info',
'PDF_set_layer_dependency',
'PDF_set_parameter',
'PDF_set_text_pos',
'PDF_set_value',
'PDF_setcolor',
'PDF_setdash',
'PDF_setdashpattern',
'PDF_setflat',
'PDF_setfont',
'PDF_setgray',
'PDF_setgray_fill',
'PDF_setgray_stroke',
'PDF_setlinecap',
'PDF_setlinejoin',
'PDF_setlinewidth',
'PDF_setmatrix',
'PDF_setmiterlimit',
'PDF_setrgbcolor',
'PDF_setrgbcolor_fill',
'PDF_setrgbcolor_stroke',
'PDF_shading',
'PDF_shading_pattern',
'PDF_shfill',
'PDF_show',
'PDF_show_boxed',
'PDF_show_xy',
'PDF_skew',
'PDF_stringwidth',
'PDF_stroke',
'PDF_suspend_page',
'PDF_translate',
'PDF_utf16_to_utf8',
'PDF_utf32_to_utf16',
'PDF_utf8_to_utf16',
'PDO::pgsqlLOBOpen',
'RarEntry::getStream',
'SQLite3::openBlob',
'SWFMovie::saveToFile',
'SplFileInfo::openFile',
'SplFileObject::openFile',
'SplTempFileObject::openFile',
'V8Js::compileString',
'V8Js::executeScript',
'Vtiful\Kernel\Excel::setColumn',
'Vtiful\Kernel\Excel::setRow',
'Vtiful\Kernel\Format::align',
'Vtiful\Kernel\Format::bold',
'Vtiful\Kernel\Format::italic',
'Vtiful\Kernel\Format::underline',
'XMLWriter::openMemory',
'XMLWriter::openURI',
'ZipArchive::getStream',
'Zookeeper::setLogStream',
'apc_bin_dumpfile',
'apc_bin_loadfile',
'bbcode_add_element',
'bbcode_add_smiley',
'bbcode_create',
'bbcode_destroy',
'bbcode_parse',
'bbcode_set_arg_parser',
'bbcode_set_flags',
'bcompiler_read',
'bcompiler_write_class',
'bcompiler_write_constant',
'bcompiler_write_exe_footer',
'bcompiler_write_file',
'bcompiler_write_footer',
'bcompiler_write_function',
'bcompiler_write_functions_from_file',
'bcompiler_write_header',
'bcompiler_write_included_filename',
'bzclose',
'bzerrno',
'bzerror',
'bzerrstr',
'bzflush',
'bzopen',
'bzread',
'bzwrite',
'cairo_surface_write_to_png',
'closedir',
'copy',
'crack_closedict',
'crack_opendict',
'cubrid_bind',
'cubrid_close_prepare',
'cubrid_close_request',
'cubrid_col_get',
'cubrid_col_size',
'cubrid_column_names',
'cubrid_column_types',
'cubrid_commit',
'cubrid_connect',
'cubrid_connect_with_url',
'cubrid_current_oid',
'cubrid_db_parameter',
'cubrid_disconnect',
'cubrid_drop',
'cubrid_fetch',
'cubrid_free_result',
'cubrid_get',
'cubrid_get_autocommit',
'cubrid_get_charset',
'cubrid_get_class_name',
'cubrid_get_db_parameter',
'cubrid_get_query_timeout',
'cubrid_get_server_info',
'cubrid_insert_id',
'cubrid_is_instance',
'cubrid_lob2_bind',
'cubrid_lob2_close',
'cubrid_lob2_export',
'cubrid_lob2_import',
'cubrid_lob2_new',
'cubrid_lob2_read',
'cubrid_lob2_seek',
'cubrid_lob2_seek64',
'cubrid_lob2_size',
'cubrid_lob2_size64',
'cubrid_lob2_tell',
'cubrid_lob2_tell64',
'cubrid_lob2_write',
'cubrid_lob_export',
'cubrid_lob_get',
'cubrid_lob_send',
'cubrid_lob_size',
'cubrid_lock_read',
'cubrid_lock_write',
'cubrid_move_cursor',
'cubrid_next_result',
'cubrid_num_cols',
'cubrid_num_rows',
'cubrid_pconnect',
'cubrid_pconnect_with_url',
'cubrid_prepare',
'cubrid_put',
'cubrid_query',
'cubrid_rollback',
'cubrid_schema',
'cubrid_seq_add',
'cubrid_seq_drop',
'cubrid_seq_insert',
'cubrid_seq_put',
'cubrid_set_add',
'cubrid_set_autocommit',
'cubrid_set_db_parameter',
'cubrid_set_drop',
'cubrid_set_query_timeout',
'cubrid_unbuffered_query',
'curl_close',
'curl_copy_handle',
'curl_errno',
'curl_error',
'curl_escape',
'curl_exec',
'curl_getinfo',
'curl_multi_add_handle',
'curl_multi_close',
'curl_multi_errno',
'curl_multi_exec',
'curl_multi_getcontent',
'curl_multi_info_read',
'curl_multi_remove_handle',
'curl_multi_select',
'curl_multi_setopt',
'curl_pause',
'curl_reset',
'curl_setopt',
'curl_setopt_array',
'curl_share_close',
'curl_share_errno',
'curl_share_init',
'curl_share_setopt',
'curl_unescape',
'cyrus_authenticate',
'cyrus_bind',
'cyrus_close',
'cyrus_connect',
'cyrus_query',
'cyrus_unbind',
'db2_autocommit',
'db2_bind_param',
'db2_client_info',
'db2_close',
'db2_column_privileges',
'db2_columns',
'db2_commit',
'db2_conn_error',
'db2_conn_errormsg',
'db2_connect',
'db2_cursor_type',
'db2_exec',
'db2_execute',
'db2_fetch_array',
'db2_fetch_assoc',
'db2_fetch_both',
'db2_fetch_object',
'db2_fetch_row',
'db2_field_display_size',
'db2_field_name',
'db2_field_num',
'db2_field_precision',
'db2_field_scale',
'db2_field_type',
'db2_field_width',
'db2_foreign_keys',
'db2_free_result',
'db2_free_stmt',
'db2_get_option',
'db2_last_insert_id',
'db2_lob_read',
'db2_next_result',
'db2_num_fields',
'db2_num_rows',
'db2_pclose',
'db2_pconnect',
'db2_prepare',
'db2_primary_keys',
'db2_procedure_columns',
'db2_procedures',
'db2_result',
'db2_rollback',
'db2_server_info',
'db2_set_option',
'db2_special_columns',
'db2_statistics',
'db2_stmt_error',
'db2_stmt_errormsg',
'db2_table_privileges',
'db2_tables',
'dba_close',
'dba_delete',
'dba_exists',
'dba_fetch',
'dba_firstkey',
'dba_insert',
'dba_nextkey',
'dba_open',
'dba_optimize',
'dba_popen',
'dba_replace',
'dba_sync',
'dbplus_add',
'dbplus_aql',
'dbplus_close',
'dbplus_curr',
'dbplus_find',
'dbplus_first',
'dbplus_flush',
'dbplus_freelock',
'dbplus_freerlocks',
'dbplus_getlock',
'dbplus_getunique',
'dbplus_info',
'dbplus_last',
'dbplus_lockrel',
'dbplus_next',
'dbplus_open',
'dbplus_prev',
'dbplus_rchperm',
'dbplus_rcreate',
'dbplus_rcrtexact',
'dbplus_rcrtlike',
'dbplus_restorepos',
'dbplus_rkeys',
'dbplus_ropen',
'dbplus_rquery',
'dbplus_rrename',
'dbplus_rsecindex',
'dbplus_runlink',
'dbplus_rzap',
'dbplus_savepos',
'dbplus_setindex',
'dbplus_setindexbynumber',
'dbplus_sql',
'dbplus_tremove',
'dbplus_undo',
'dbplus_undoprepare',
'dbplus_unlockrel',
'dbplus_unselect',
'dbplus_update',
'dbplus_xlockrel',
'dbplus_xunlockrel',
'deflate_add',
'dio_close',
'dio_fcntl',
'dio_open',
'dio_read',
'dio_seek',
'dio_stat',
'dio_tcsetattr',
'dio_truncate',
'dio_write',
'dir',
'eio_busy',
'eio_cancel',
'eio_chmod',
'eio_chown',
'eio_close',
'eio_custom',
'eio_dup2',
'eio_fallocate',
'eio_fchmod',
'eio_fchown',
'eio_fdatasync',
'eio_fstat',
'eio_fstatvfs',
'eio_fsync',
'eio_ftruncate',
'eio_futime',
'eio_get_last_error',
'eio_grp',
'eio_grp_add',
'eio_grp_cancel',
'eio_grp_limit',
'eio_link',
'eio_lstat',
'eio_mkdir',
'eio_mknod',
'eio_nop',
'eio_open',
'eio_read',
'eio_readahead',
'eio_readdir',
'eio_readlink',
'eio_realpath',
'eio_rename',
'eio_rmdir',
'eio_seek',
'eio_sendfile',
'eio_stat',
'eio_statvfs',
'eio_symlink',
'eio_sync',
'eio_sync_file_range',
'eio_syncfs',
'eio_truncate',
'eio_unlink',
'eio_utime',
'eio_write',
'enchant_broker_describe',
'enchant_broker_dict_exists',
'enchant_broker_free',
'enchant_broker_free_dict',
'enchant_broker_get_dict_path',
'enchant_broker_get_error',
'enchant_broker_init',
'enchant_broker_list_dicts',
'enchant_broker_request_dict',
'enchant_broker_request_pwl_dict',
'enchant_broker_set_dict_path',
'enchant_broker_set_ordering',
'enchant_dict_add_to_personal',
'enchant_dict_add_to_session',
'enchant_dict_check',
'enchant_dict_describe',
'enchant_dict_get_error',
'enchant_dict_is_in_session',
'enchant_dict_quick_check',
'enchant_dict_store_replacement',
'enchant_dict_suggest',
'event_add',
'event_base_free',
'event_base_loop',
'event_base_loopbreak',
'event_base_loopexit',
'event_base_new',
'event_base_priority_init',
'event_base_reinit',
'event_base_set',
'event_buffer_base_set',
'event_buffer_disable',
'event_buffer_enable',
'event_buffer_fd_set',
'event_buffer_free',
'event_buffer_new',
'event_buffer_priority_set',
'event_buffer_read',
'event_buffer_set_callback',
'event_buffer_timeout_set',
'event_buffer_watermark_set',
'event_buffer_write',
'event_del',
'event_free',
'event_new',
'event_priority_set',
'event_set',
'event_timer_add',
'event_timer_del',
'event_timer_pending',
'event_timer_set',
'expect_expectl',
'expect_popen',
'fam_cancel_monitor',
'fam_close',
'fam_monitor_collection',
'fam_monitor_directory',
'fam_monitor_file',
'fam_next_event',
'fam_open',
'fam_pending',
'fam_resume_monitor',
'fam_suspend_monitor',
'fann_cascadetrain_on_data',
'fann_cascadetrain_on_file',
'fann_clear_scaling_params',
'fann_copy',
'fann_create_from_file',
'fann_create_shortcut_array',
'fann_create_standard',
'fann_create_standard_array',
'fann_create_train',
'fann_create_train_from_callback',
'fann_descale_input',
'fann_descale_output',
'fann_descale_train',
'fann_destroy',
'fann_destroy_train',
'fann_duplicate_train_data',
'fann_get_MSE',
'fann_get_activation_function',
'fann_get_activation_steepness',
'fann_get_bias_array',
'fann_get_bit_fail',
'fann_get_bit_fail_limit',
'fann_get_cascade_activation_functions',
'fann_get_cascade_activation_functions_count',
'fann_get_cascade_activation_steepnesses',
'fann_get_cascade_activation_steepnesses_count',
'fann_get_cascade_candidate_change_fraction',
'fann_get_cascade_candidate_limit',
'fann_get_cascade_candidate_stagnation_epochs',
'fann_get_cascade_max_cand_epochs',
'fann_get_cascade_max_out_epochs',
'fann_get_cascade_min_cand_epochs',
'fann_get_cascade_min_out_epochs',
'fann_get_cascade_num_candidate_groups',
'fann_get_cascade_num_candidates',
'fann_get_cascade_output_change_fraction',
'fann_get_cascade_output_stagnation_epochs',
'fann_get_cascade_weight_multiplier',
'fann_get_connection_array',
'fann_get_connection_rate',
'fann_get_errno',
'fann_get_errstr',
'fann_get_layer_array',
'fann_get_learning_momentum',
'fann_get_learning_rate',
'fann_get_network_type',
'fann_get_num_input',
'fann_get_num_layers',
'fann_get_num_output',
'fann_get_quickprop_decay',
'fann_get_quickprop_mu',
'fann_get_rprop_decrease_factor',
'fann_get_rprop_delta_max',
'fann_get_rprop_delta_min',
'fann_get_rprop_delta_zero',
'fann_get_rprop_increase_factor',
'fann_get_sarprop_step_error_shift',
'fann_get_sarprop_step_error_threshold_factor',
'fann_get_sarprop_temperature',
'fann_get_sarprop_weight_decay_shift',
'fann_get_total_connections',
'fann_get_total_neurons',
'fann_get_train_error_function',
'fann_get_train_stop_function',
'fann_get_training_algorithm',
'fann_init_weights',
'fann_length_train_data',
'fann_merge_train_data',
'fann_num_input_train_data',
'fann_num_output_train_data',
'fann_randomize_weights',
'fann_read_train_from_file',
'fann_reset_errno',
'fann_reset_errstr',
'fann_run',
'fann_save',
'fann_save_train',
'fann_scale_input',
'fann_scale_input_train_data',
'fann_scale_output',
'fann_scale_output_train_data',
'fann_scale_train',
'fann_scale_train_data',
'fann_set_activation_function',
'fann_set_activation_function_hidden',
'fann_set_activation_function_layer',
'fann_set_activation_function_output',
'fann_set_activation_steepness',
'fann_set_activation_steepness_hidden',
'fann_set_activation_steepness_layer',
'fann_set_activation_steepness_output',
'fann_set_bit_fail_limit',
'fann_set_callback',
'fann_set_cascade_activation_functions',
'fann_set_cascade_activation_steepnesses',
'fann_set_cascade_candidate_change_fraction',
'fann_set_cascade_candidate_limit',
'fann_set_cascade_candidate_stagnation_epochs',
'fann_set_cascade_max_cand_epochs',
'fann_set_cascade_max_out_epochs',
'fann_set_cascade_min_cand_epochs',
'fann_set_cascade_min_out_epochs',
'fann_set_cascade_num_candidate_groups',
'fann_set_cascade_output_change_fraction',
'fann_set_cascade_output_stagnation_epochs',
'fann_set_cascade_weight_multiplier',
'fann_set_error_log',
'fann_set_input_scaling_params',
'fann_set_learning_momentum',
'fann_set_learning_rate',
'fann_set_output_scaling_params',
'fann_set_quickprop_decay',
'fann_set_quickprop_mu',
'fann_set_rprop_decrease_factor',
'fann_set_rprop_delta_max',
'fann_set_rprop_delta_min',
'fann_set_rprop_delta_zero',
'fann_set_rprop_increase_factor',
'fann_set_sarprop_step_error_shift',
'fann_set_sarprop_step_error_threshold_factor',
'fann_set_sarprop_temperature',
'fann_set_sarprop_weight_decay_shift',
'fann_set_scaling_params',
'fann_set_train_error_function',
'fann_set_train_stop_function',
'fann_set_training_algorithm',
'fann_set_weight',
'fann_set_weight_array',
'fann_shuffle_train_data',
'fann_subset_train_data',
'fann_test',
'fann_test_data',
'fann_train',
'fann_train_epoch',
'fann_train_on_data',
'fann_train_on_file',
'fbsql_affected_rows',
'fbsql_autocommit',
'fbsql_blob_size',
'fbsql_change_user',
'fbsql_clob_size',
'fbsql_close',
'fbsql_commit',
'fbsql_connect',
'fbsql_create_blob',
'fbsql_create_clob',
'fbsql_create_db',
'fbsql_data_seek',
'fbsql_database',
'fbsql_database_password',
'fbsql_db_query',
'fbsql_db_status',
'fbsql_drop_db',
'fbsql_errno',
'fbsql_error',
'fbsql_fetch_array',
'fbsql_fetch_assoc',
'fbsql_fetch_field',
'fbsql_fetch_lengths',
'fbsql_fetch_object',
'fbsql_fetch_row',
'fbsql_field_flags',
'fbsql_field_len',
'fbsql_field_name',
'fbsql_field_seek',
'fbsql_field_table',
'fbsql_field_type',
'fbsql_free_result',
'fbsql_get_autostart_info',
'fbsql_hostname',
'fbsql_insert_id',
'fbsql_list_dbs',
'fbsql_list_fields',
'fbsql_list_tables',
'fbsql_next_result',
'fbsql_num_fields',
'fbsql_num_rows',
'fbsql_password',
'fbsql_pconnect',
'fbsql_query',
'fbsql_read_blob',
'fbsql_read_clob',
'fbsql_result',
'fbsql_rollback',
'fbsql_rows_fetched',
'fbsql_select_db',
'fbsql_set_characterset',
'fbsql_set_lob_mode',
'fbsql_set_password',
'fbsql_set_transaction',
'fbsql_start_db',
'fbsql_stop_db',
'fbsql_table_name',
'fbsql_username',
'fclose',
'fdf_add_doc_javascript',
'fdf_add_template',
'fdf_close',
'fdf_create',
'fdf_enum_values',
'fdf_get_ap',
'fdf_get_attachment',
'fdf_get_encoding',
'fdf_get_file',
'fdf_get_flags',
'fdf_get_opt',
'fdf_get_status',
'fdf_get_value',
'fdf_get_version',
'fdf_next_field_name',
'fdf_open',
'fdf_open_string',
'fdf_remove_item',
'fdf_save',
'fdf_save_string',
'fdf_set_ap',
'fdf_set_encoding',
'fdf_set_file',
'fdf_set_flags',
'fdf_set_javascript_action',
'fdf_set_on_import_javascript',
'fdf_set_opt',
'fdf_set_status',
'fdf_set_submit_form_action',
'fdf_set_target_frame',
'fdf_set_value',
'fdf_set_version',
'feof',
'fflush',
'ffmpeg_frame::__construct',
'ffmpeg_frame::toGDImage',
'fgetc',
'fgetcsv',
'fgets',
'fgetss',
'file',
'file_get_contents',
'file_put_contents',
'finfo::buffer',
'finfo::file',
'finfo_buffer',
'finfo_close',
'finfo_file',
'finfo_open',
'finfo_set_flags',
'flock',
'fopen',
'fpassthru',
'fprintf',
'fputcsv',
'fputs',
'fread',
'fscanf',
'fseek',
'fstat',
'ftell',
'ftp_alloc',
'ftp_append',
'ftp_cdup',
'ftp_chdir',
'ftp_chmod',
'ftp_close',
'ftp_delete',
'ftp_exec',
'ftp_fget',
'ftp_fput',
'ftp_get',
'ftp_get_option',
'ftp_login',
'ftp_mdtm',
'ftp_mkdir',
'ftp_mlsd',
'ftp_nb_continue',
'ftp_nb_fget',
'ftp_nb_fput',
'ftp_nb_get',
'ftp_nb_put',
'ftp_nlist',
'ftp_pasv',
'ftp_put',
'ftp_pwd',
'ftp_quit',
'ftp_raw',
'ftp_rawlist',
'ftp_rename',
'ftp_rmdir',
'ftp_set_option',
'ftp_site',
'ftp_size',
'ftp_systype',
'ftruncate',
'fwrite',
'get_resource_type',
'gmp_div',
'gnupg::init',
'gnupg_adddecryptkey',
'gnupg_addencryptkey',
'gnupg_addsignkey',
'gnupg_cleardecryptkeys',
'gnupg_clearencryptkeys',
'gnupg_clearsignkeys',
'gnupg_decrypt',
'gnupg_decryptverify',
'gnupg_encrypt',
'gnupg_encryptsign',
'gnupg_export',
'gnupg_geterror',
'gnupg_getprotocol',
'gnupg_import',
'gnupg_init',
'gnupg_keyinfo',
'gnupg_setarmor',
'gnupg_seterrormode',
'gnupg_setsignmode',
'gnupg_sign',
'gnupg_verify',
'gupnp_context_get_host_ip',
'gupnp_context_get_port',
'gupnp_context_get_subscription_timeout',
'gupnp_context_host_path',
'gupnp_context_new',
'gupnp_context_set_subscription_timeout',
'gupnp_context_timeout_add',
'gupnp_context_unhost_path',
'gupnp_control_point_browse_start',
'gupnp_control_point_browse_stop',
'gupnp_control_point_callback_set',
'gupnp_control_point_new',
'gupnp_device_action_callback_set',
'gupnp_device_info_get',
'gupnp_device_info_get_service',
'gupnp_root_device_get_available',
'gupnp_root_device_get_relative_location',
'gupnp_root_device_new',
'gupnp_root_device_set_available',
'gupnp_root_device_start',
'gupnp_root_device_stop',
'gupnp_service_action_get',
'gupnp_service_action_return',
'gupnp_service_action_return_error',
'gupnp_service_action_set',
'gupnp_service_freeze_notify',
'gupnp_service_info_get',
'gupnp_service_info_get_introspection',
'gupnp_service_introspection_get_state_variable',
'gupnp_service_notify',
'gupnp_service_proxy_action_get',
'gupnp_service_proxy_action_set',
'gupnp_service_proxy_add_notify',
'gupnp_service_proxy_callback_set',
'gupnp_service_proxy_get_subscribed',
'gupnp_service_proxy_remove_notify',
'gupnp_service_proxy_send_action',
'gupnp_service_proxy_set_subscribed',
'gupnp_service_thaw_notify',
'gzclose',
'gzeof',
'gzgetc',
'gzgets',
'gzgetss',
'gzpassthru',
'gzputs',
'gzread',
'gzrewind',
'gzseek',
'gztell',
'gzwrite',
'hash_update_stream',
'http\Env\Response::send',
'http_get_request_body_stream',
'ibase_add_user',
'ibase_affected_rows',
'ibase_backup',
'ibase_blob_add',
'ibase_blob_cancel',
'ibase_blob_close',
'ibase_blob_create',
'ibase_blob_get',
'ibase_blob_open',
'ibase_close',
'ibase_commit',
'ibase_commit_ret',
'ibase_connect',
'ibase_db_info',
'ibase_delete_user',
'ibase_drop_db',
'ibase_execute',
'ibase_fetch_assoc',
'ibase_fetch_object',
'ibase_fetch_row',
'ibase_field_info',
'ibase_free_event_handler',
'ibase_free_query',
'ibase_free_result',
'ibase_gen_id',
'ibase_maintain_db',
'ibase_modify_user',
'ibase_name_result',
'ibase_num_fields',
'ibase_num_params',
'ibase_param_info',
'ibase_pconnect',
'ibase_prepare',
'ibase_query',
'ibase_restore',
'ibase_rollback',
'ibase_rollback_ret',
'ibase_server_info',
'ibase_service_attach',
'ibase_service_detach',
'ibase_set_event_handler',
'ibase_trans',
'ifx_affected_rows',
'ifx_close',
'ifx_connect',
'ifx_do',
'ifx_error',
'ifx_fetch_row',
'ifx_fieldproperties',
'ifx_fieldtypes',
'ifx_free_result',
'ifx_getsqlca',
'ifx_htmltbl_result',
'ifx_num_fields',
'ifx_num_rows',
'ifx_pconnect',
'ifx_prepare',
'ifx_query',
'image2wbmp',
'imageaffine',
'imagealphablending',
'imageantialias',
'imagearc',
'imagebmp',
'imagechar',
'imagecharup',
'imagecolorallocate',
'imagecolorallocatealpha',
'imagecolorat',
'imagecolorclosest',
'imagecolorclosestalpha',
'imagecolorclosesthwb',
'imagecolordeallocate',
'imagecolorexact',
'imagecolorexactalpha',
'imagecolormatch',
'imagecolorresolve',
'imagecolorresolvealpha',
'imagecolorset',
'imagecolorsforindex',
'imagecolorstotal',
'imagecolortransparent',
'imageconvolution',
'imagecopy',
'imagecopymerge',
'imagecopymergegray',
'imagecopyresampled',
'imagecopyresized',
'imagecrop',
'imagecropauto',
'imagedashedline',
'imagedestroy',
'imageellipse',
'imagefill',
'imagefilledarc',
'imagefilledellipse',
'imagefilledpolygon',
'imagefilledrectangle',
'imagefilltoborder',
'imagefilter',
'imageflip',
'imagefttext',
'imagegammacorrect',
'imagegd',
'imagegd2',
'imagegetclip',
'imagegif',
'imagegrabscreen',
'imagegrabwindow',
'imageinterlace',
'imageistruecolor',
'imagejpeg',
'imagelayereffect',
'imageline',
'imageopenpolygon',
'imagepalettecopy',
'imagepalettetotruecolor',
'imagepng',
'imagepolygon',
'imagepsencodefont',
'imagepsextendfont',
'imagepsfreefont',
'imagepsloadfont',
'imagepsslantfont',
'imagepstext',
'imagerectangle',
'imageresolution',
'imagerotate',
'imagesavealpha',
'imagescale',
'imagesetbrush',
'imagesetclip',
'imagesetinterpolation',
'imagesetpixel',
'imagesetstyle',
'imagesetthickness',
'imagesettile',
'imagestring',
'imagestringup',
'imagesx',
'imagesy',
'imagetruecolortopalette',
'imagettftext',
'imagewbmp',
'imagewebp',
'imagexbm',
'imap_append',
'imap_body',
'imap_bodystruct',
'imap_check',
'imap_clearflag_full',
'imap_close',
'imap_create',
'imap_createmailbox',
'imap_delete',
'imap_deletemailbox',
'imap_expunge',
'imap_fetch_overview',
'imap_fetchbody',
'imap_fetchheader',
'imap_fetchmime',
'imap_fetchstructure',
'imap_fetchtext',
'imap_gc',
'imap_get_quota',
'imap_get_quotaroot',
'imap_getacl',
'imap_getmailboxes',
'imap_getsubscribed',
'imap_header',
'imap_headerinfo',
'imap_headers',
'imap_list',
'imap_listmailbox',
'imap_listscan',
'imap_listsubscribed',
'imap_lsub',
'imap_mail_copy',
'imap_mail_move',
'imap_mailboxmsginfo',
'imap_msgno',
'imap_num_msg',
'imap_num_recent',
'imap_ping',
'imap_rename',
'imap_renamemailbox',
'imap_reopen',
'imap_savebody',
'imap_scan',
'imap_scanmailbox',
'imap_search',
'imap_set_quota',
'imap_setacl',
'imap_setflag_full',
'imap_sort',
'imap_status',
'imap_subscribe',
'imap_thread',
'imap_uid',
'imap_undelete',
'imap_unsubscribe',
'inflate_add',
'inflate_get_read_len',
'inflate_get_status',
'ingres_autocommit',
'ingres_autocommit_state',
'ingres_charset',
'ingres_close',
'ingres_commit',
'ingres_connect',
'ingres_cursor',
'ingres_errno',
'ingres_error',
'ingres_errsqlstate',
'ingres_escape_string',
'ingres_execute',
'ingres_fetch_array',
'ingres_fetch_assoc',
'ingres_fetch_object',
'ingres_fetch_proc_return',
'ingres_fetch_row',
'ingres_field_length',
'ingres_field_name',
'ingres_field_nullable',
'ingres_field_precision',
'ingres_field_scale',
'ingres_field_type',
'ingres_free_result',
'ingres_next_error',
'ingres_num_fields',
'ingres_num_rows',
'ingres_pconnect',
'ingres_prepare',
'ingres_query',
'ingres_result_seek',
'ingres_rollback',
'ingres_set_environment',
'ingres_unbuffered_query',
'inotify_add_watch',
'inotify_init',
'inotify_queue_len',
'inotify_read',
'inotify_rm_watch',
'kadm5_chpass_principal',
'kadm5_create_principal',
'kadm5_delete_principal',
'kadm5_destroy',
'kadm5_flush',
'kadm5_get_policies',
'kadm5_get_principal',
'kadm5_get_principals',
'kadm5_init_with_password',
'kadm5_modify_principal',
'ldap_add',
'ldap_bind',
'ldap_close',
'ldap_compare',
'ldap_control_paged_result',
'ldap_control_paged_result_response',
'ldap_count_entries',
'ldap_delete',
'ldap_errno',
'ldap_error',
'ldap_exop',
'ldap_exop_passwd',
'ldap_exop_refresh',
'ldap_exop_whoami',
'ldap_first_attribute',
'ldap_first_entry',
'ldap_first_reference',
'ldap_free_result',
'ldap_get_attributes',
'ldap_get_dn',
'ldap_get_entries',
'ldap_get_option',
'ldap_get_values',
'ldap_get_values_len',
'ldap_mod_add',
'ldap_mod_del',
'ldap_mod_replace',
'ldap_modify',
'ldap_modify_batch',
'ldap_next_attribute',
'ldap_next_entry',
'ldap_next_reference',
'ldap_parse_exop',
'ldap_parse_reference',
'ldap_parse_result',
'ldap_rename',
'ldap_sasl_bind',
'ldap_set_option',
'ldap_set_rebind_proc',
'ldap_sort',
'ldap_start_tls',
'ldap_unbind',
'libxml_set_streams_context',
'm_checkstatus',
'm_completeauthorizations',
'm_connect',
'm_connectionerror',
'm_deletetrans',
'm_destroyconn',
'm_getcell',
'm_getcellbynum',
'm_getcommadelimited',
'm_getheader',
'm_initconn',
'm_iscommadelimited',
'm_maxconntimeout',
'm_monitor',
'm_numcolumns',
'm_numrows',
'm_parsecommadelimited',
'm_responsekeys',
'm_responseparam',
'm_returnstatus',
'm_setblocking',
'm_setdropfile',
'm_setip',
'm_setssl',
'm_setssl_cafile',
'm_setssl_files',
'm_settimeout',
'm_transactionssent',
'm_transinqueue',
'm_transkeyval',
'm_transnew',
'm_transsend',
'm_validateidentifier',
'm_verifyconnection',
'm_verifysslcert',
'mailparse_determine_best_xfer_encoding',
'mailparse_msg_create',
'mailparse_msg_extract_part',
'mailparse_msg_extract_part_file',
'mailparse_msg_extract_whole_part_file',
'mailparse_msg_free',
'mailparse_msg_get_part',
'mailparse_msg_get_part_data',
'mailparse_msg_get_structure',
'mailparse_msg_parse',
'mailparse_msg_parse_file',
'mailparse_stream_encode',
'mailparse_uudecode_all',
'maxdb::use_result',
'maxdb_affected_rows',
'maxdb_connect',
'maxdb_disable_rpl_parse',
'maxdb_dump_debug_info',
'maxdb_embedded_connect',
'maxdb_enable_reads_from_master',
'maxdb_enable_rpl_parse',
'maxdb_errno',
'maxdb_error',
'maxdb_fetch_lengths',
'maxdb_field_tell',
'maxdb_get_host_info',
'maxdb_get_proto_info',
'maxdb_get_server_info',
'maxdb_get_server_version',
'maxdb_info',
'maxdb_init',
'maxdb_insert_id',
'maxdb_master_query',
'maxdb_more_results',
'maxdb_next_result',
'maxdb_num_fields',
'maxdb_num_rows',
'maxdb_rpl_parse_enabled',
'maxdb_rpl_probe',
'maxdb_select_db',
'maxdb_sqlstate',
'maxdb_stmt::result_metadata',
'maxdb_stmt_affected_rows',
'maxdb_stmt_errno',
'maxdb_stmt_error',
'maxdb_stmt_num_rows',
'maxdb_stmt_param_count',
'maxdb_stmt_result_metadata',
'maxdb_stmt_sqlstate',
'maxdb_thread_id',
'maxdb_use_result',
'maxdb_warning_count',
'mcrypt_enc_get_algorithms_name',
'mcrypt_enc_get_block_size',
'mcrypt_enc_get_iv_size',
'mcrypt_enc_get_key_size',
'mcrypt_enc_get_modes_name',
'mcrypt_enc_get_supported_key_sizes',
'mcrypt_enc_is_block_algorithm',
'mcrypt_enc_is_block_algorithm_mode',
'mcrypt_enc_is_block_mode',
'mcrypt_enc_self_test',
'mcrypt_generic',
'mcrypt_generic_deinit',
'mcrypt_generic_end',
'mcrypt_generic_init',
'mcrypt_module_close',
'mcrypt_module_open',
'mdecrypt_generic',
'mkdir',
'mqseries_back',
'mqseries_begin',
'mqseries_close',
'mqseries_cmit',
'mqseries_conn',
'mqseries_connx',
'mqseries_disc',
'mqseries_get',
'mqseries_inq',
'mqseries_open',
'mqseries_put',
'mqseries_put1',
'mqseries_set',
'msg_get_queue',
'msg_receive',
'msg_remove_queue',
'msg_send',
'msg_set_queue',
'msg_stat_queue',
'msql_affected_rows',
'msql_close',
'msql_connect',
'msql_create_db',
'msql_data_seek',
'msql_db_query',
'msql_drop_db',
'msql_fetch_array',
'msql_fetch_field',
'msql_fetch_object',
'msql_fetch_row',
'msql_field_flags',
'msql_field_len',
'msql_field_name',
'msql_field_seek',
'msql_field_table',
'msql_field_type',
'msql_free_result',
'msql_list_dbs',
'msql_list_fields',
'msql_list_tables',
'msql_num_fields',
'msql_num_rows',
'msql_pconnect',
'msql_query',
'msql_result',
'msql_select_db',
'mssql_bind',
'mssql_close',
'mssql_connect',
'mssql_data_seek',
'mssql_execute',
'mssql_fetch_array',
'mssql_fetch_assoc',
'mssql_fetch_batch',
'mssql_fetch_field',
'mssql_fetch_object',
'mssql_fetch_row',
'mssql_field_length',
'mssql_field_name',
'mssql_field_seek',
'mssql_field_type',
'mssql_free_result',
'mssql_free_statement',
'mssql_init',
'mssql_next_result',
'mssql_num_fields',
'mssql_num_rows',
'mssql_pconnect',
'mssql_query',
'mssql_result',
'mssql_rows_affected',
'mssql_select_db',
'mysql_affected_rows',
'mysql_client_encoding',
'mysql_close',
'mysql_connect',
'mysql_create_db',
'mysql_data_seek',
'mysql_db_name',
'mysql_db_query',
'mysql_drop_db',
'mysql_errno',
'mysql_error',
'mysql_fetch_array',
'mysql_fetch_assoc',
'mysql_fetch_field',
'mysql_fetch_lengths',
'mysql_fetch_object',
'mysql_fetch_row',
'mysql_field_flags',
'mysql_field_len',
'mysql_field_name',
'mysql_field_seek',
'mysql_field_table',
'mysql_field_type',
'mysql_free_result',
'mysql_get_host_info',
'mysql_get_proto_info',
'mysql_get_server_info',
'mysql_info',
'mysql_insert_id',
'mysql_list_dbs',
'mysql_list_fields',
'mysql_list_processes',
'mysql_list_tables',
'mysql_num_fields',
'mysql_num_rows',
'mysql_pconnect',
'mysql_ping',
'mysql_query',
'mysql_real_escape_string',
'mysql_result',
'mysql_select_db',
'mysql_set_charset',
'mysql_stat',
'mysql_tablename',
'mysql_thread_id',
'mysql_unbuffered_query',
'mysqlnd_uh_convert_to_mysqlnd',
'ncurses_bottom_panel',
'ncurses_del_panel',
'ncurses_delwin',
'ncurses_getmaxyx',
'ncurses_getyx',
'ncurses_hide_panel',
'ncurses_keypad',
'ncurses_meta',
'ncurses_move_panel',
'ncurses_mvwaddstr',
'ncurses_new_panel',
'ncurses_newpad',
'ncurses_newwin',
'ncurses_panel_above',
'ncurses_panel_below',
'ncurses_panel_window',
'ncurses_pnoutrefresh',
'ncurses_prefresh',
'ncurses_replace_panel',
'ncurses_show_panel',
'ncurses_top_panel',
'ncurses_waddch',
'ncurses_waddstr',
'ncurses_wattroff',
'ncurses_wattron',
'ncurses_wattrset',
'ncurses_wborder',
'ncurses_wclear',
'ncurses_wcolor_set',
'ncurses_werase',
'ncurses_wgetch',
'ncurses_whline',
'ncurses_wmouse_trafo',
'ncurses_wmove',
'ncurses_wnoutrefresh',
'ncurses_wrefresh',
'ncurses_wstandend',
'ncurses_wstandout',
'ncurses_wvline',
'newt_button',
'newt_button_bar',
'newt_checkbox',
'newt_checkbox_get_value',
'newt_checkbox_set_flags',
'newt_checkbox_set_value',
'newt_checkbox_tree',
'newt_checkbox_tree_add_item',
'newt_checkbox_tree_find_item',
'newt_checkbox_tree_get_current',
'newt_checkbox_tree_get_entry_value',
'newt_checkbox_tree_get_multi_selection',
'newt_checkbox_tree_get_selection',
'newt_checkbox_tree_multi',
'newt_checkbox_tree_set_current',
'newt_checkbox_tree_set_entry',
'newt_checkbox_tree_set_entry_value',
'newt_checkbox_tree_set_width',
'newt_compact_button',
'newt_component_add_callback',
'newt_component_takes_focus',
'newt_create_grid',
'newt_draw_form',
'newt_entry',
'newt_entry_get_value',
'newt_entry_set',
'newt_entry_set_filter',
'newt_entry_set_flags',
'newt_form',
'newt_form_add_component',
'newt_form_add_components',
'newt_form_add_hot_key',
'newt_form_destroy',
'newt_form_get_current',
'newt_form_run',
'newt_form_set_background',
'newt_form_set_height',
'newt_form_set_size',
'newt_form_set_timer',
'newt_form_set_width',
'newt_form_watch_fd',
'newt_grid_add_components_to_form',
'newt_grid_basic_window',
'newt_grid_free',
'newt_grid_get_size',
'newt_grid_h_close_stacked',
'newt_grid_h_stacked',
'newt_grid_place',
'newt_grid_set_field',
'newt_grid_simple_window',
'newt_grid_v_close_stacked',
'newt_grid_v_stacked',
'newt_grid_wrapped_window',
'newt_grid_wrapped_window_at',
'newt_label',
'newt_label_set_text',
'newt_listbox',
'newt_listbox_append_entry',
'newt_listbox_clear',
'newt_listbox_clear_selection',
'newt_listbox_delete_entry',
'newt_listbox_get_current',
'newt_listbox_get_selection',
'newt_listbox_insert_entry',
'newt_listbox_item_count',
'newt_listbox_select_item',
'newt_listbox_set_current',
'newt_listbox_set_current_by_key',
'newt_listbox_set_data',
'newt_listbox_set_entry',
'newt_listbox_set_width',
'newt_listitem',
'newt_listitem_get_data',
'newt_listitem_set',
'newt_radio_get_current',
'newt_radiobutton',
'newt_run_form',
'newt_scale',
'newt_scale_set',
'newt_scrollbar_set',
'newt_textbox',
'newt_textbox_get_num_lines',
'newt_textbox_reflowed',
'newt_textbox_set_height',
'newt_textbox_set_text',
'newt_vertical_scrollbar',
'oci_bind_array_by_name',
'oci_bind_by_name',
'oci_cancel',
'oci_close',
'oci_commit',
'oci_connect',
'oci_define_by_name',
'oci_error',
'oci_execute',
'oci_fetch',
'oci_fetch_all',
'oci_fetch_array',
'oci_fetch_assoc',
'oci_fetch_object',
'oci_fetch_row',
'oci_field_is_null',
'oci_field_name',
'oci_field_precision',
'oci_field_scale',
'oci_field_size',
'oci_field_type',
'oci_field_type_raw',
'oci_free_cursor',
'oci_free_statement',
'oci_get_implicit_resultset',
'oci_new_collection',
'oci_new_connect',
'oci_new_cursor',
'oci_new_descriptor',
'oci_num_fields',
'oci_num_rows',
'oci_parse',
'oci_pconnect',
'oci_register_taf_callback',
'oci_result',
'oci_rollback',
'oci_server_version',
'oci_set_action',
'oci_set_client_identifier',
'oci_set_client_info',
'oci_set_module_name',
'oci_set_prefetch',
'oci_statement_type',
'oci_unregister_taf_callback',
'odbc_autocommit',
'odbc_close',
'odbc_columnprivileges',
'odbc_columns',
'odbc_commit',
'odbc_connect',
'odbc_cursor',
'odbc_data_source',
'odbc_do',
'odbc_error',
'odbc_errormsg',
'odbc_exec',
'odbc_execute',
'odbc_fetch_array',
'odbc_fetch_into',
'odbc_fetch_row',
'odbc_field_len',
'odbc_field_name',
'odbc_field_num',
'odbc_field_precision',
'odbc_field_scale',
'odbc_field_type',
'odbc_foreignkeys',
'odbc_free_result',
'odbc_gettypeinfo',
'odbc_next_result',
'odbc_num_fields',
'odbc_num_rows',
'odbc_pconnect',
'odbc_prepare',
'odbc_primarykeys',
'odbc_procedurecolumns',
'odbc_procedures',
'odbc_result',
'odbc_result_all',
'odbc_rollback',
'odbc_setoption',
'odbc_specialcolumns',
'odbc_statistics',
'odbc_tableprivileges',
'odbc_tables',
'openal_buffer_create',
'openal_buffer_data',
'openal_buffer_destroy',
'openal_buffer_get',
'openal_buffer_loadwav',
'openal_context_create',
'openal_context_current',
'openal_context_destroy',
'openal_context_process',
'openal_context_suspend',
'openal_device_close',
'openal_device_open',
'openal_source_create',
'openal_source_destroy',
'openal_source_get',
'openal_source_pause',
'openal_source_play',
'openal_source_rewind',
'openal_source_set',
'openal_source_stop',
'openal_stream',
'opendir',
'openssl_csr_new',
'openssl_dh_compute_key',
'openssl_free_key',
'openssl_pkey_export',
'openssl_pkey_free',
'openssl_pkey_get_details',
'openssl_spki_new',
'openssl_x509_free',
'pclose',
'pfsockopen',
'pg_affected_rows',
'pg_cancel_query',
'pg_client_encoding',
'pg_close',
'pg_connect_poll',
'pg_connection_busy',
'pg_connection_reset',
'pg_connection_status',
'pg_consume_input',
'pg_convert',
'pg_copy_from',
'pg_copy_to',
'pg_dbname',
'pg_delete',
'pg_end_copy',
'pg_escape_bytea',
'pg_escape_identifier',
'pg_escape_literal',
'pg_escape_string',
'pg_execute',
'pg_fetch_all',
'pg_fetch_all_columns',
'pg_fetch_array',
'pg_fetch_assoc',
'pg_fetch_row',
'pg_field_name',
'pg_field_num',
'pg_field_size',
'pg_field_table',
'pg_field_type',
'pg_field_type_oid',
'pg_flush',
'pg_free_result',
'pg_get_notify',
'pg_get_pid',
'pg_get_result',
'pg_host',
'pg_insert',
'pg_last_error',
'pg_last_notice',
'pg_last_oid',
'pg_lo_close',
'pg_lo_create',
'pg_lo_export',
'pg_lo_import',
'pg_lo_open',
'pg_lo_read',
'pg_lo_read_all',
'pg_lo_seek',
'pg_lo_tell',
'pg_lo_truncate',
'pg_lo_unlink',
'pg_lo_write',
'pg_meta_data',
'pg_num_fields',
'pg_num_rows',
'pg_options',
'pg_parameter_status',
'pg_ping',
'pg_port',
'pg_prepare',
'pg_put_line',
'pg_query',
'pg_query_params',
'pg_result_error',
'pg_result_error_field',
'pg_result_seek',
'pg_result_status',
'pg_select',
'pg_send_execute',
'pg_send_prepare',
'pg_send_query',
'pg_send_query_params',
'pg_set_client_encoding',
'pg_set_error_verbosity',
'pg_socket',
'pg_trace',
'pg_transaction_status',
'pg_tty',
'pg_untrace',
'pg_update',
'pg_version',
'php_user_filter::filter',
'proc_close',
'proc_get_status',
'proc_terminate',
'ps_add_bookmark',
'ps_add_launchlink',
'ps_add_locallink',
'ps_add_note',
'ps_add_pdflink',
'ps_add_weblink',
'ps_arc',
'ps_arcn',
'ps_begin_page',
'ps_begin_pattern',
'ps_begin_template',
'ps_circle',
'ps_clip',
'ps_close',
'ps_close_image',
'ps_closepath',
'ps_closepath_stroke',
'ps_continue_text',
'ps_curveto',
'ps_delete',
'ps_end_page',
'ps_end_pattern',
'ps_end_template',
'ps_fill',
'ps_fill_stroke',
'ps_findfont',
'ps_get_buffer',
'ps_get_parameter',
'ps_get_value',
'ps_hyphenate',
'ps_include_file',
'ps_lineto',
'ps_makespotcolor',
'ps_moveto',
'ps_new',
'ps_open_file',
'ps_open_image',
'ps_open_image_file',
'ps_open_memory_image',
'ps_place_image',
'ps_rect',
'ps_restore',
'ps_rotate',
'ps_save',
'ps_scale',
'ps_set_border_color',
'ps_set_border_dash',
'ps_set_border_style',
'ps_set_info',
'ps_set_parameter',
'ps_set_text_pos',
'ps_set_value',
'ps_setcolor',
'ps_setdash',
'ps_setflat',
'ps_setfont',
'ps_setgray',
'ps_setlinecap',
'ps_setlinejoin',
'ps_setlinewidth',
'ps_setmiterlimit',
'ps_setoverprintmode',
'ps_setpolydash',
'ps_shading',
'ps_shading_pattern',
'ps_shfill',
'ps_show',
'ps_show2',
'ps_show_boxed',
'ps_show_xy',
'ps_show_xy2',
'ps_string_geometry',
'ps_stringwidth',
'ps_stroke',
'ps_symbol',
'ps_symbol_name',
'ps_symbol_width',
'ps_translate',
'px_close',
'px_create_fp',
'px_date2string',
'px_delete',
'px_delete_record',
'px_get_field',
'px_get_info',
'px_get_parameter',
'px_get_record',
'px_get_schema',
'px_get_value',
'px_insert_record',
'px_new',
'px_numfields',
'px_numrecords',
'px_open_fp',
'px_put_record',
'px_retrieve_record',
'px_set_blob_file',
'px_set_parameter',
'px_set_tablename',
'px_set_targetencoding',
'px_set_value',
'px_timestamp2string',
'px_update_record',
'radius_acct_open',
'radius_add_server',
'radius_auth_open',
'radius_close',
'radius_config',
'radius_create_request',
'radius_demangle',
'radius_demangle_mppe_key',
'radius_get_attr',
'radius_put_addr',
'radius_put_attr',
'radius_put_int',
'radius_put_string',
'radius_put_vendor_addr',
'radius_put_vendor_attr',
'radius_put_vendor_int',
'radius_put_vendor_string',
'radius_request_authenticator',
'radius_salt_encrypt_attr',
'radius_send_request',
'radius_server_secret',
'radius_strerror',
'readdir',
'readfile',
'recode_file',
'rename',
'rewind',
'rewinddir',
'rmdir',
'rpm_close',
'rpm_get_tag',
'rpm_open',
'sapi_windows_vt100_support',
'scandir',
'sem_acquire',
'sem_get',
'sem_release',
'sem_remove',
'set_file_buffer',
'shm_attach',
'shm_detach',
'shm_get_var',
'shm_has_var',
'shm_put_var',
'shm_remove',
'shm_remove_var',
'shmop_close',
'shmop_delete',
'shmop_open',
'shmop_read',
'shmop_size',
'shmop_write',
'socket_accept',
'socket_addrinfo_bind',
'socket_addrinfo_connect',
'socket_addrinfo_explain',
'socket_bind',
'socket_clear_error',
'socket_close',
'socket_connect',
'socket_export_stream',
'socket_get_option',
'socket_get_status',
'socket_getopt',
'socket_getpeername',
'socket_getsockname',
'socket_import_stream',
'socket_last_error',
'socket_listen',
'socket_read',
'socket_recv',
'socket_recvfrom',
'socket_recvmsg',
'socket_send',
'socket_sendmsg',
'socket_sendto',
'socket_set_block',
'socket_set_blocking',
'socket_set_nonblock',
'socket_set_option',
'socket_set_timeout',
'socket_shutdown',
'socket_write',
'sqlite_close',
'sqlite_fetch_string',
'sqlite_has_more',
'sqlite_open',
'sqlite_popen',
'sqlsrv_begin_transaction',
'sqlsrv_cancel',
'sqlsrv_client_info',
'sqlsrv_close',
'sqlsrv_commit',
'sqlsrv_connect',
'sqlsrv_execute',
'sqlsrv_fetch',
'sqlsrv_fetch_array',
'sqlsrv_fetch_object',
'sqlsrv_field_metadata',
'sqlsrv_free_stmt',
'sqlsrv_get_field',
'sqlsrv_has_rows',
'sqlsrv_next_result',
'sqlsrv_num_fields',
'sqlsrv_num_rows',
'sqlsrv_prepare',
'sqlsrv_query',
'sqlsrv_rollback',
'sqlsrv_rows_affected',
'sqlsrv_send_stream_data',
'sqlsrv_server_info',
'ssh2_auth_agent',
'ssh2_auth_hostbased_file',
'ssh2_auth_none',
'ssh2_auth_password',
'ssh2_auth_pubkey_file',
'ssh2_disconnect',
'ssh2_exec',
'ssh2_fetch_stream',
'ssh2_fingerprint',
'ssh2_methods_negotiated',
'ssh2_publickey_add',
'ssh2_publickey_init',
'ssh2_publickey_list',
'ssh2_publickey_remove',
'ssh2_scp_recv',
'ssh2_scp_send',
'ssh2_sftp',
'ssh2_sftp_chmod',
'ssh2_sftp_lstat',
'ssh2_sftp_mkdir',
'ssh2_sftp_readlink',
'ssh2_sftp_realpath',
'ssh2_sftp_rename',
'ssh2_sftp_rmdir',
'ssh2_sftp_stat',
'ssh2_sftp_symlink',
'ssh2_sftp_unlink',
'ssh2_shell',
'ssh2_tunnel',
'stomp_connect',
'streamWrapper::stream_cast',
'stream_bucket_append',
'stream_bucket_make_writeable',
'stream_bucket_new',
'stream_bucket_prepend',
'stream_context_create',
'stream_context_get_default',
'stream_context_get_options',
'stream_context_get_params',
'stream_context_set_default',
'stream_context_set_params',
'stream_copy_to_stream',
'stream_encoding',
'stream_filter_append',
'stream_filter_prepend',
'stream_filter_remove',
'stream_get_contents',
'stream_get_line',
'stream_get_meta_data',
'stream_isatty',
'stream_set_blocking',
'stream_set_chunk_size',
'stream_set_read_buffer',
'stream_set_timeout',
'stream_set_write_buffer',
'stream_socket_accept',
'stream_socket_client',
'stream_socket_enable_crypto',
'stream_socket_get_name',
'stream_socket_recvfrom',
'stream_socket_sendto',
'stream_socket_server',
'stream_socket_shutdown',
'stream_supports_lock',
'svn_fs_abort_txn',
'svn_fs_apply_text',
'svn_fs_begin_txn2',
'svn_fs_change_node_prop',
'svn_fs_check_path',
'svn_fs_contents_changed',
'svn_fs_copy',
'svn_fs_delete',
'svn_fs_dir_entries',
'svn_fs_file_contents',
'svn_fs_file_length',
'svn_fs_is_dir',
'svn_fs_is_file',
'svn_fs_make_dir',
'svn_fs_make_file',
'svn_fs_node_created_rev',
'svn_fs_node_prop',
'svn_fs_props_changed',
'svn_fs_revision_prop',
'svn_fs_revision_root',
'svn_fs_txn_root',
'svn_fs_youngest_rev',
'svn_repos_create',
'svn_repos_fs',
'svn_repos_fs_begin_txn_for_commit',
'svn_repos_fs_commit_txn',
'svn_repos_open',
'sybase_affected_rows',
'sybase_close',
'sybase_connect',
'sybase_data_seek',
'sybase_fetch_array',
'sybase_fetch_assoc',
'sybase_fetch_field',
'sybase_fetch_object',
'sybase_fetch_row',
'sybase_field_seek',
'sybase_free_result',
'sybase_num_fields',
'sybase_num_rows',
'sybase_pconnect',
'sybase_query',
'sybase_result',
'sybase_select_db',
'sybase_set_message_handler',
'sybase_unbuffered_query',
'tmpfile',
'udm_add_search_limit',
'udm_alloc_agent',
'udm_alloc_agent_array',
'udm_cat_list',
'udm_cat_path',
'udm_check_charset',
'udm_clear_search_limits',
'udm_crc32',
'udm_errno',
'udm_error',
'udm_find',
'udm_free_agent',
'udm_free_res',
'udm_get_doc_count',
'udm_get_res_field',
'udm_get_res_param',
'udm_hash32',
'udm_load_ispell_data',
'udm_set_agent_param',
'unlink',
'vfprintf',
'w32api_init_dtype',
'wddx_add_vars',
'wddx_packet_end',
'wddx_packet_start',
'xml_get_current_byte_index',
'xml_get_current_column_number',
'xml_get_current_line_number',
'xml_get_error_code',
'xml_parse',
'xml_parse_into_struct',
'xml_parser_create',
'xml_parser_create_ns',
'xml_parser_free',
'xml_parser_get_option',
'xml_parser_set_option',
'xml_set_character_data_handler',
'xml_set_default_handler',
'xml_set_element_handler',
'xml_set_end_namespace_decl_handler',
'xml_set_external_entity_ref_handler',
'xml_set_notation_decl_handler',
'xml_set_object',
'xml_set_processing_instruction_handler',
'xml_set_start_namespace_decl_handler',
'xml_set_unparsed_entity_decl_handler',
'xmlrpc_server_add_introspection_data',
'xmlrpc_server_call_method',
'xmlrpc_server_create',
'xmlrpc_server_destroy',
'xmlrpc_server_register_introspection_callback',
'xmlrpc_server_register_method',
'xmlwriter_end_attribute',
'xmlwriter_end_cdata',
'xmlwriter_end_comment',
'xmlwriter_end_document',
'xmlwriter_end_dtd',
'xmlwriter_end_dtd_attlist',
'xmlwriter_end_dtd_element',
'xmlwriter_end_dtd_entity',
'xmlwriter_end_element',
'xmlwriter_end_pi',
'xmlwriter_flush',
'xmlwriter_full_end_element',
'xmlwriter_open_memory',
'xmlwriter_open_uri',
'xmlwriter_output_memory',
'xmlwriter_set_indent',
'xmlwriter_set_indent_string',
'xmlwriter_start_attribute',
'xmlwriter_start_attribute_ns',
'xmlwriter_start_cdata',
'xmlwriter_start_comment',
'xmlwriter_start_document',
'xmlwriter_start_dtd',
'xmlwriter_start_dtd_attlist',
'xmlwriter_start_dtd_element',
'xmlwriter_start_dtd_entity',
'xmlwriter_start_element',
'xmlwriter_start_element_ns',
'xmlwriter_start_pi',
'xmlwriter_text',
'xmlwriter_write_attribute',
'xmlwriter_write_attribute_ns',
'xmlwriter_write_cdata',
'xmlwriter_write_comment',
'xmlwriter_write_dtd',
'xmlwriter_write_dtd_attlist',
'xmlwriter_write_dtd_element',
'xmlwriter_write_dtd_entity',
'xmlwriter_write_element',
'xmlwriter_write_element_ns',
'xmlwriter_write_pi',
'xmlwriter_write_raw',
'xslt_create',
'yaz_addinfo',
'yaz_ccl_conf',
'yaz_ccl_parse',
'yaz_close',
'yaz_database',
'yaz_element',
'yaz_errno',
'yaz_error',
'yaz_es',
'yaz_es_result',
'yaz_get_option',
'yaz_hits',
'yaz_itemorder',
'yaz_present',
'yaz_range',
'yaz_record',
'yaz_scan',
'yaz_scan_result',
'yaz_schema',
'yaz_search',
'yaz_sort',
'yaz_syntax',
'zip_close',
'zip_entry_close',
'zip_entry_compressedsize',
'zip_entry_compressionmethod',
'zip_entry_filesize',
'zip_entry_name',
'zip_entry_open',
'zip_entry_read',
'zip_open',
'zip_read',
];
}
}
#!/usr/bin/env php
<?php declare(strict_types=1);









$functions = require __DIR__ . '/FunctionSignatureMap.php';
$resourceFunctions = [];

foreach ($functions as $function => $arguments) {
foreach ($arguments as $argument) {
if (strpos($argument, '?') === 0) {
$argument = substr($argument, 1);
}

if ($argument === 'resource') {
$resourceFunctions[] = explode('\'', $function)[0];
}
}
}

$resourceFunctions = array_unique($resourceFunctions);
sort($resourceFunctions);

$buffer = <<<EOT
<?php declare(strict_types=1);
/*
 * This file is part of resource-operations.
 *
 * (c) Sebastian Bergmann <sebastian@phpunit.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace SebastianBergmann\ResourceOperations;

final class ResourceOperations
{
    /**
     * @return string[]
     */
    public static function getFunctions(): array
    {
        return [

EOT;

foreach ($resourceFunctions as $function) {
$buffer .= sprintf("            '%s',\n", $function);
}

$buffer .= <<< EOT
        ];
    }
}

EOT;

file_put_contents(__DIR__ . '/../src/ResourceOperations.php', $buffer);

<?php









declare(strict_types=1);

namespace SebastianBergmann\ObjectReflector;

interface Exception
{
}
<?php









declare(strict_types=1);

namespace SebastianBergmann\ObjectReflector;

class ObjectReflector
{







public function getAttributes($object): array
{
if (!is_object($object)) {
throw new InvalidArgumentException;
}

$attributes = [];
$className = get_class($object);

foreach ((array) $object as $name => $value) {
$name = explode("\0", (string) $name);

if (count($name) === 1) {
$name = $name[0];
} else {
if ($name[1] !== $className) {
$name = $name[1] . '::' . $name[2];
} else {
$name = $name[2];
}
}

$attributes[$name] = $value;
}

return $attributes;
}
}
<?php









declare(strict_types=1);

namespace SebastianBergmann\ObjectReflector;

class InvalidArgumentException extends \InvalidArgumentException implements Exception
{
}
<?php









namespace SebastianBergmann\ObjectEnumerator;

interface Exception
{
}
<?php









namespace SebastianBergmann\ObjectEnumerator;

use SebastianBergmann\ObjectReflector\ObjectReflector;
use SebastianBergmann\RecursionContext\Context;





class Enumerator
{








public function enumerate($variable)
{
if (!is_array($variable) && !is_object($variable)) {
throw new InvalidArgumentException;
}

if (isset(func_get_args()[1])) {
if (!func_get_args()[1] instanceof Context) {
throw new InvalidArgumentException;
}

$processed = func_get_args()[1];
} else {
$processed = new Context;
}

$objects = [];

if ($processed->contains($variable)) {
return $objects;
}

$array = $variable;
$processed->add($variable);

if (is_array($variable)) {
foreach ($array as $element) {
if (!is_array($element) && !is_object($element)) {
continue;
}

$objects = array_merge(
$objects,
$this->enumerate($element, $processed)
);
}
} else {
$objects[] = $variable;

$reflector = new ObjectReflector;

foreach ($reflector->getAttributes($variable) as $value) {
if (!is_array($value) && !is_object($value)) {
continue;
}

$objects = array_merge(
$objects,
$this->enumerate($value, $processed)
);
}
}

return $objects;
}
}
<?php









namespace SebastianBergmann\ObjectEnumerator;

class InvalidArgumentException extends \InvalidArgumentException implements Exception
{
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Environment;

final class Console
{



public const STDIN = 0;




public const STDOUT = 1;




public const STDERR = 2;







public function hasColorSupport(): bool
{
if ('Hyper' === \getenv('TERM_PROGRAM')) {
return true;
}

if ($this->isWindows()) {

 return (\defined('STDOUT') && \function_exists('sapi_windows_vt100_support') && @\sapi_windows_vt100_support(\STDOUT))
|| false !== \getenv('ANSICON')
|| 'ON' === \getenv('ConEmuANSI')
|| 'xterm' === \getenv('TERM');

 }

if (!\defined('STDOUT')) {

 return false;

 }

return $this->isInteractive(\STDOUT);
}






public function getNumberOfColumns(): int
{
if (!$this->isInteractive(\defined('STDIN') ? \STDIN : self::STDIN)) {
return 80;
}

if ($this->isWindows()) {
return $this->getNumberOfColumnsWindows();
}

return $this->getNumberOfColumnsInteractive();
}









public function isInteractive($fileDescriptor = self::STDOUT): bool
{
if (\is_resource($fileDescriptor)) {

 if (\function_exists('stream_isatty') && @\stream_isatty($fileDescriptor)) {
return true;
}

$stat = @\fstat(\STDOUT);

 return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
}

return \function_exists('posix_isatty') && @\posix_isatty($fileDescriptor);
}

private function isWindows(): bool
{
return \DIRECTORY_SEPARATOR === '\\';
}




private function getNumberOfColumnsInteractive(): int
{
if (\function_exists('shell_exec') && \preg_match('#\d+ (\d+)#', \shell_exec('stty size') ?: '', $match) === 1) {
if ((int) $match[1] > 0) {
return (int) $match[1];
}
}

if (\function_exists('shell_exec') && \preg_match('#columns = (\d+);#', \shell_exec('stty') ?: '', $match) === 1) {
if ((int) $match[1] > 0) {
return (int) $match[1];
}
}

return 80;
}




private function getNumberOfColumnsWindows(): int
{
$ansicon = \getenv('ANSICON');
$columns = 80;

if (\is_string($ansicon) && \preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', \trim($ansicon), $matches)) {
$columns = $matches[1];
} elseif (\function_exists('proc_open')) {
$process = \proc_open(
'mode CON',
[
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
],
$pipes,
null,
null,
['suppress_errors' => true]
);

if (\is_resource($process)) {
$info = \stream_get_contents($pipes[1]);

\fclose($pipes[1]);
\fclose($pipes[2]);
\proc_close($process);

if (\preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
$columns = $matches[2];
}
}
}

return $columns - 1;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Environment;




final class Runtime
{



private static $binary;





public function canCollectCodeCoverage(): bool
{
return $this->hasXdebug() || $this->hasPCOV() || $this->hasPHPDBGCodeCoverage();
}




public function discardsComments(): bool
{
if (!\extension_loaded('Zend OPcache')) {
return false;
}

if (\ini_get('opcache.save_comments') !== '0') {
return false;
}

if ((\PHP_SAPI === 'cli' || \PHP_SAPI === 'phpdbg') && \ini_get('opcache.enable_cli') === '1') {
return true;
}

if (\PHP_SAPI !== 'cli' && \PHP_SAPI !== 'phpdbg' && \ini_get('opcache.enable') === '1') {
return true;
}

return false;
}





public function getBinary(): string
{

 if (self::$binary === null && $this->isHHVM()) {

 if ((self::$binary = \getenv('PHP_BINARY')) === false) {
self::$binary = \PHP_BINARY;
}

self::$binary = \escapeshellarg(self::$binary) . ' --php' .
' -d hhvm.php7.all=1';

 }

if (self::$binary === null && \PHP_BINARY !== '') {
self::$binary = \escapeshellarg(\PHP_BINARY);
}

if (self::$binary === null) {

 $possibleBinaryLocations = [
\PHP_BINDIR . '/php',
\PHP_BINDIR . '/php-cli.exe',
\PHP_BINDIR . '/php.exe',
];

foreach ($possibleBinaryLocations as $binary) {
if (\is_readable($binary)) {
self::$binary = \escapeshellarg($binary);

break;
}
}

 }

if (self::$binary === null) {

 self::$binary = 'php';

 }

return self::$binary;
}

public function getNameWithVersion(): string
{
return $this->getName() . ' ' . $this->getVersion();
}

public function getNameWithVersionAndCodeCoverageDriver(): string
{
if (!$this->canCollectCodeCoverage() || $this->hasPHPDBGCodeCoverage()) {
return $this->getNameWithVersion();
}

if ($this->hasXdebug()) {
return \sprintf(
'%s with Xdebug %s',
$this->getNameWithVersion(),
\phpversion('xdebug')
);
}

if ($this->hasPCOV()) {
return \sprintf(
'%s with PCOV %s',
$this->getNameWithVersion(),
\phpversion('pcov')
);
}
}

public function getName(): string
{
if ($this->isHHVM()) {

 return 'HHVM';

 }

if ($this->isPHPDBG()) {

 return 'PHPDBG';

 }

return 'PHP';
}

public function getVendorUrl(): string
{
if ($this->isHHVM()) {

 return 'http://hhvm.com/';

 }

return 'https://secure.php.net/';
}

public function getVersion(): string
{
if ($this->isHHVM()) {

 return HHVM_VERSION;

 }

return \PHP_VERSION;
}




public function hasXdebug(): bool
{
return ($this->isPHP() || $this->isHHVM()) && \extension_loaded('xdebug');
}




public function isHHVM(): bool
{
return \defined('HHVM_VERSION');
}




public function isPHP(): bool
{
return !$this->isHHVM() && !$this->isPHPDBG();
}




public function isPHPDBG(): bool
{
return \PHP_SAPI === 'phpdbg' && !$this->isHHVM();
}





public function hasPHPDBGCodeCoverage(): bool
{
return $this->isPHPDBG();
}




public function hasPCOV(): bool
{
return $this->isPHP() && \extension_loaded('pcov') && \ini_get('pcov.enabled');
}













public function getCurrentSettings(array $values): array
{
$diff = [];
$files = [];

if ($file = \php_ini_loaded_file()) {
$files[] = $file;
}

if ($scanned = \php_ini_scanned_files()) {
$files = \array_merge(
$files,
\array_map(
'trim',
\explode(",\n", $scanned)
)
);
}

foreach ($files as $ini) {
$config = \parse_ini_file($ini, true);

foreach ($values as $value) {
$set = \ini_get($value);

if (isset($config[$value]) && $set != $config[$value]) {
$diff[] = \sprintf('%s=%s', $value, $set);
}
}
}

return $diff;
}
}
<?php declare(strict_types=1);








namespace SebastianBergmann\Environment;

final class OperatingSystem
{




public function getFamily(): string
{
if (\defined('PHP_OS_FAMILY')) {
return \PHP_OS_FAMILY;
}

if (\DIRECTORY_SEPARATOR === '\\') {
return 'Windows';
}

switch (\PHP_OS) {
case 'Darwin':
return 'Darwin';

case 'DragonFly':
case 'FreeBSD':
case 'NetBSD':
case 'OpenBSD':
return 'BSD';

case 'Linux':
return 'Linux';

case 'SunOS':
return 'Solaris';

default:
return 'Unknown';
}
}
}
<?php








namespace SebastianBergmann\Comparator;




class Factory
{



private static $instance;




private $customComparators = [];




private $defaultComparators = [];




public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new self;
}

return self::$instance;
}




public function __construct()
{
$this->registerDefaultComparators();
}









public function getComparatorFor($expected, $actual)
{
foreach ($this->customComparators as $comparator) {
if ($comparator->accepts($expected, $actual)) {
return $comparator;
}
}

foreach ($this->defaultComparators as $comparator) {
if ($comparator->accepts($expected, $actual)) {
return $comparator;
}
}
}











public function register(Comparator $comparator)
{
\array_unshift($this->customComparators, $comparator);

$comparator->setFactory($this);
}








public function unregister(Comparator $comparator)
{
foreach ($this->customComparators as $key => $_comparator) {
if ($comparator === $_comparator) {
unset($this->customComparators[$key]);
}
}
}




public function reset()
{
$this->customComparators = [];
}

private function registerDefaultComparators()
{
$this->registerDefaultComparator(new MockObjectComparator);
$this->registerDefaultComparator(new DateTimeComparator);
$this->registerDefaultComparator(new DOMNodeComparator);
$this->registerDefaultComparator(new SplObjectStorageComparator);
$this->registerDefaultComparator(new ExceptionComparator);
$this->registerDefaultComparator(new ObjectComparator);
$this->registerDefaultComparator(new ResourceComparator);
$this->registerDefaultComparator(new ArrayComparator);
$this->registerDefaultComparator(new DoubleComparator);
$this->registerDefaultComparator(new NumericComparator);
$this->registerDefaultComparator(new ScalarComparator);
$this->registerDefaultComparator(new TypeComparator);
}

private function registerDefaultComparator(Comparator $comparator)
{
$this->defaultComparators[] = $comparator;

$comparator->setFactory($this);
}
}
<?php








namespace SebastianBergmann\Comparator;




class ArrayComparator extends Comparator
{








public function accepts($expected, $actual)
{
return \is_array($expected) && \is_array($actual);
}













public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false, array &$processed = [])
{
if ($canonicalize) {
\sort($expected);
\sort($actual);
}

$remaining = $actual;
$actualAsString = "Array (\n";
$expectedAsString = "Array (\n";
$equal = true;

foreach ($expected as $key => $value) {
unset($remaining[$key]);

if (!\array_key_exists($key, $actual)) {
$expectedAsString .= \sprintf(
"    %s => %s\n",
$this->exporter->export($key),
$this->exporter->shortenedExport($value)
);

$equal = false;

continue;
}

try {
$comparator = $this->factory->getComparatorFor($value, $actual[$key]);
$comparator->assertEquals($value, $actual[$key], $delta, $canonicalize, $ignoreCase, $processed);

$expectedAsString .= \sprintf(
"    %s => %s\n",
$this->exporter->export($key),
$this->exporter->shortenedExport($value)
);

$actualAsString .= \sprintf(
"    %s => %s\n",
$this->exporter->export($key),
$this->exporter->shortenedExport($actual[$key])
);
} catch (ComparisonFailure $e) {
$expectedAsString .= \sprintf(
"    %s => %s\n",
$this->exporter->export($key),
$e->getExpectedAsString() ? $this->indent($e->getExpectedAsString()) : $this->exporter->shortenedExport($e->getExpected())
);

$actualAsString .= \sprintf(
"    %s => %s\n",
$this->exporter->export($key),
$e->getActualAsString() ? $this->indent($e->getActualAsString()) : $this->exporter->shortenedExport($e->getActual())
);

$equal = false;
}
}

foreach ($remaining as $key => $value) {
$actualAsString .= \sprintf(
"    %s => %s\n",
$this->exporter->export($key),
$this->exporter->shortenedExport($value)
);

$equal = false;
}

$expectedAsString .= ')';
$actualAsString .= ')';

if (!$equal) {
throw new ComparisonFailure(
$expected,
$actual,
$expectedAsString,
$actualAsString,
false,
'Failed asserting that two arrays are equal.'
);
}
}

protected function indent($lines)
{
return \trim(\str_replace("\n", "\n    ", $lines));
}
}
<?php








namespace SebastianBergmann\Comparator;

use SebastianBergmann\Exporter\Exporter;




abstract class Comparator
{



protected $factory;




protected $exporter;

public function __construct()
{
$this->exporter = new Exporter;
}

public function setFactory(Factory $factory)
{
$this->factory = $factory;
}









abstract public function accepts($expected, $actual);












abstract public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false);
}
<?php








namespace SebastianBergmann\Comparator;




class DateTimeComparator extends ObjectComparator
{








public function accepts($expected, $actual)
{
return ($expected instanceof \DateTime || $expected instanceof \DateTimeInterface) &&
($actual instanceof \DateTime || $actual instanceof \DateTimeInterface);
}














public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false, array &$processed = [])
{


$absDelta = \abs($delta);
$delta = new \DateInterval(\sprintf('PT%dS', $absDelta));
$delta->f = $absDelta - \floor($absDelta);

$actualClone = (clone $actual)
->setTimezone(new \DateTimeZone('UTC'));

$expectedLower = (clone $expected)
->setTimezone(new \DateTimeZone('UTC'))
->sub($delta);

$expectedUpper = (clone $expected)
->setTimezone(new \DateTimeZone('UTC'))
->add($delta);

if ($actualClone < $expectedLower || $actualClone > $expectedUpper) {
throw new ComparisonFailure(
$expected,
$actual,
$this->dateTimeToString($expected),
$this->dateTimeToString($actual),
false,
'Failed asserting that two DateTime objects are equal.'
);
}
}






private function dateTimeToString(\DateTimeInterface $datetime): string
{
$string = $datetime->format('Y-m-d\TH:i:s.uO');

return $string ?: 'Invalid DateTimeInterface object';
}
}
<?php








namespace SebastianBergmann\Comparator;




class NumericComparator extends ScalarComparator
{








public function accepts($expected, $actual)
{

 
 return \is_numeric($expected) && \is_numeric($actual) &&
!(\is_float($expected) || \is_float($actual)) &&
!(\is_string($expected) && \is_string($actual));
}












public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false)
{
if (\is_infinite($actual) && \is_infinite($expected)) {
return; 
 }

if ((\is_infinite($actual) xor \is_infinite($expected)) ||
(\is_nan($actual) || \is_nan($expected)) ||
\abs($actual - $expected) > $delta) {
throw new ComparisonFailure(
$expected,
$actual,
'',
'',
false,
\sprintf(
'Failed asserting that %s matches expected %s.',
$this->exporter->export($actual),
$this->exporter->export($expected)
)
);
}
}
}
<?php








namespace SebastianBergmann\Comparator;




class TypeComparator extends Comparator
{








public function accepts($expected, $actual)
{
return true;
}












public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false)
{
if (\gettype($expected) != \gettype($actual)) {
throw new ComparisonFailure(
$expected,
$actual,

 '',
'',
false,
\sprintf(
'%s does not match expected type "%s".',
$this->exporter->shortenedExport($actual),
\gettype($expected)
)
);
}
}
}
<?php








namespace SebastianBergmann\Comparator;

use SebastianBergmann\Diff\Differ;
use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;




class ComparisonFailure extends \RuntimeException
{





protected $expected;






protected $actual;






protected $expectedAsString;






protected $actualAsString;




protected $identical;







protected $message;












public function __construct($expected, $actual, $expectedAsString, $actualAsString, $identical = false, $message = '')
{
$this->expected = $expected;
$this->actual = $actual;
$this->expectedAsString = $expectedAsString;
$this->actualAsString = $actualAsString;
$this->message = $message;
}

public function getActual()
{
return $this->actual;
}

public function getExpected()
{
return $this->expected;
}




public function getActualAsString()
{
return $this->actualAsString;
}




public function getExpectedAsString()
{
return $this->expectedAsString;
}




public function getDiff()
{
if (!$this->actualAsString && !$this->expectedAsString) {
return '';
}

$differ = new Differ(new UnifiedDiffOutputBuilder("\n--- Expected\n+++ Actual\n"));

return $differ->diff($this->expectedAsString, $this->actualAsString);
}




public function toString()
{
return $this->message . $this->getDiff();
}
}
<?php








namespace SebastianBergmann\Comparator;




class MockObjectComparator extends ObjectComparator
{








public function accepts($expected, $actual)
{
return ($expected instanceof \PHPUnit_Framework_MockObject_MockObject || $expected instanceof \PHPUnit\Framework\MockObject\MockObject) &&
($actual instanceof \PHPUnit_Framework_MockObject_MockObject || $actual instanceof \PHPUnit\Framework\MockObject\MockObject);
}









protected function toArray($object)
{
$array = parent::toArray($object);

unset($array['__phpunit_invocationMocker']);

return $array;
}
}
<?php








namespace SebastianBergmann\Comparator;




class ScalarComparator extends Comparator
{










public function accepts($expected, $actual)
{
return ((\is_scalar($expected) xor null === $expected) &&
(\is_scalar($actual) xor null === $actual))

 || (\is_string($expected) && \is_object($actual) && \method_exists($actual, '__toString'))
|| (\is_object($expected) && \method_exists($expected, '__toString') && \is_string($actual));
}












public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false)
{
$expectedToCompare = $expected;
$actualToCompare = $actual;


 
 if (\is_string($expected) || \is_string($actual)) {
$expectedToCompare = (string) $expectedToCompare;
$actualToCompare = (string) $actualToCompare;

if ($ignoreCase) {
$expectedToCompare = \strtolower($expectedToCompare);
$actualToCompare = \strtolower($actualToCompare);
}
}

if ($expectedToCompare !== $actualToCompare && \is_string($expected) && \is_string($actual)) {
throw new ComparisonFailure(
$expected,
$actual,
$this->exporter->export($expected),
$this->exporter->export($actual),
false,
'Failed asserting that two strings are equal.'
);
}

if ($expectedToCompare != $actualToCompare) {
throw new ComparisonFailure(
$expected,
$actual,

 '',
'',
false,
\sprintf(
'Failed asserting that %s matches expected %s.',
$this->exporter->export($actual),
$this->exporter->export($expected)
)
);
}
}
}
<?php








namespace SebastianBergmann\Comparator;

use DOMDocument;
use DOMNode;




class DOMNodeComparator extends ObjectComparator
{








public function accepts($expected, $actual)
{
return $expected instanceof DOMNode && $actual instanceof DOMNode;
}













public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false, array &$processed = [])
{
$expectedAsString = $this->nodeToText($expected, true, $ignoreCase);
$actualAsString = $this->nodeToText($actual, true, $ignoreCase);

if ($expectedAsString !== $actualAsString) {
$type = $expected instanceof DOMDocument ? 'documents' : 'nodes';

throw new ComparisonFailure(
$expected,
$actual,
$expectedAsString,
$actualAsString,
false,
\sprintf("Failed asserting that two DOM %s are equal.\n", $type)
);
}
}





private function nodeToText(DOMNode $node, bool $canonicalize, bool $ignoreCase): string
{
if ($canonicalize) {
$document = new DOMDocument;
@$document->loadXML($node->C14N());

$node = $document;
}

$document = $node instanceof DOMDocument ? $node : $node->ownerDocument;

$document->formatOutput = true;
$document->normalizeDocument();

$text = $node instanceof DOMDocument ? $node->saveXML() : $document->saveXML($node);

return $ignoreCase ? \strtolower($text) : $text;
}
}
<?php








namespace SebastianBergmann\Comparator;




class ExceptionComparator extends ObjectComparator
{








public function accepts($expected, $actual)
{
return $expected instanceof \Exception && $actual instanceof \Exception;
}









protected function toArray($object)
{
$array = parent::toArray($object);

unset(
$array['file'],
$array['line'],
$array['trace'],
$array['string'],
$array['xdebug_message']
);

return $array;
}
}
<?php








namespace SebastianBergmann\Comparator;




class DoubleComparator extends NumericComparator
{





const EPSILON = 0.0000000001;









public function accepts($expected, $actual)
{
return (\is_float($expected) || \is_float($actual)) && \is_numeric($expected) && \is_numeric($actual);
}












public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false)
{
if ($delta == 0) {
$delta = self::EPSILON;
}

parent::assertEquals($expected, $actual, $delta, $canonicalize, $ignoreCase);
}
}
<?php








namespace SebastianBergmann\Comparator;




class ObjectComparator extends ArrayComparator
{








public function accepts($expected, $actual)
{
return \is_object($expected) && \is_object($actual);
}













public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false, array &$processed = [])
{
if (\get_class($actual) !== \get_class($expected)) {
throw new ComparisonFailure(
$expected,
$actual,
$this->exporter->export($expected),
$this->exporter->export($actual),
false,
\sprintf(
'%s is not instance of expected class "%s".',
$this->exporter->export($actual),
\get_class($expected)
)
);
}


 if (\in_array([$actual, $expected], $processed, true) ||
\in_array([$expected, $actual], $processed, true)) {
return;
}

$processed[] = [$actual, $expected];


 
 
 if ($actual !== $expected) {
try {
parent::assertEquals(
$this->toArray($expected),
$this->toArray($actual),
$delta,
$canonicalize,
$ignoreCase,
$processed
);
} catch (ComparisonFailure $e) {
throw new ComparisonFailure(
$expected,
$actual,

 \substr_replace($e->getExpectedAsString(), \get_class($expected) . ' Object', 0, 5),
\substr_replace($e->getActualAsString(), \get_class($actual) . ' Object', 0, 5),
false,
'Failed asserting that two objects are equal.'
);
}
}
}









protected function toArray($object)
{
return $this->exporter->toArray($object);
}
}
<?php








namespace SebastianBergmann\Comparator;




class SplObjectStorageComparator extends Comparator
{








public function accepts($expected, $actual)
{
return $expected instanceof \SplObjectStorage && $actual instanceof \SplObjectStorage;
}












public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false)
{
foreach ($actual as $object) {
if (!$expected->contains($object)) {
throw new ComparisonFailure(
$expected,
$actual,
$this->exporter->export($expected),
$this->exporter->export($actual),
false,
'Failed asserting that two objects are equal.'
);
}
}

foreach ($expected as $object) {
if (!$actual->contains($object)) {
throw new ComparisonFailure(
$expected,
$actual,
$this->exporter->export($expected),
$this->exporter->export($actual),
false,
'Failed asserting that two objects are equal.'
);
}
}
}
}
<?php








namespace SebastianBergmann\Comparator;




class ResourceComparator extends Comparator
{








public function accepts($expected, $actual)
{
return \is_resource($expected) && \is_resource($actual);
}












public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false)
{
if ($actual != $expected) {
throw new ComparisonFailure(
$expected,
$actual,
$this->exporter->export($expected),
$this->exporter->export($actual)
);
}
}
}
<?php









namespace SebastianBergmann\CodeUnitReverseLookup;




class Wizard
{



private $lookupTable = [];




private $processedClasses = [];




private $processedFunctions = [];







public function lookup($filename, $lineNumber)
{
if (!isset($this->lookupTable[$filename][$lineNumber])) {
$this->updateLookupTable();
}

if (isset($this->lookupTable[$filename][$lineNumber])) {
return $this->lookupTable[$filename][$lineNumber];
} else {
return $filename . ':' . $lineNumber;
}
}

private function updateLookupTable()
{
$this->processClassesAndTraits();
$this->processFunctions();
}

private function processClassesAndTraits()
{
foreach (array_merge(get_declared_classes(), get_declared_traits()) as $classOrTrait) {
if (isset($this->processedClasses[$classOrTrait])) {
continue;
}

$reflector = new \ReflectionClass($classOrTrait);

foreach ($reflector->getMethods() as $method) {
$this->processFunctionOrMethod($method);
}

$this->processedClasses[$classOrTrait] = true;
}
}

private function processFunctions()
{
foreach (get_defined_functions()['user'] as $function) {
if (isset($this->processedFunctions[$function])) {
continue;
}

$this->processFunctionOrMethod(new \ReflectionFunction($function));

$this->processedFunctions[$function] = true;
}
}




private function processFunctionOrMethod(\ReflectionFunctionAbstract $functionOrMethod)
{
if ($functionOrMethod->isInternal()) {
return;
}

$name = $functionOrMethod->getName();

if ($functionOrMethod instanceof \ReflectionMethod) {
$name = $functionOrMethod->getDeclaringClass()->getName() . '::' . $name;
}

if (!isset($this->lookupTable[$functionOrMethod->getFileName()])) {
$this->lookupTable[$functionOrMethod->getFileName()] = [];
}

foreach (range($functionOrMethod->getStartLine(), $functionOrMethod->getEndLine()) as $line) {
$this->lookupTable[$functionOrMethod->getFileName()][$line] = $name;
}
}
}
<?php

namespace PhpAmqpLib\Exchange;

final class AMQPExchangeType
{
const DIRECT = 'direct';
const FANOUT = 'fanout';
const TOPIC = 'topic';
const HEADERS = 'headers';
}
<?php

namespace PhpAmqpLib;

final class Package
{
const NAME = 'AMQPLib';
const VERSION = '3.1.0';
}
<?php

namespace PhpAmqpLib\Helper;














final class SocketConstants
{



private $constants;


private static $instance;

public function __construct()
{
$constants = get_defined_constants(true);
if (isset($constants['sockets'])) {
$this->constants = $constants['sockets'];
} else {
trigger_error('Sockets extension is not enabled', E_USER_WARNING);
$this->constants = array();
}
}





public function __get($name)
{
return isset($this->constants[$name]) ? $this->constants[$name] : 0;
}






public function __set($name, $value)
{
}





public function __isset($name)
{
return isset($this->constants[$name]);
}




public static function getInstance()
{
if (!self::$instance) {
self::$instance = new self();
}

return self::$instance;
}
}
<?php

namespace PhpAmqpLib\Helper;

if (class_exists('phpseclib\Math\BigInteger')) {
class BigInteger extends \phpseclib\Math\BigInteger
{
}
} elseif (class_exists('phpseclib3\Math\BigInteger')) {
class BigInteger extends \phpseclib3\Math\BigInteger
{
}
} else {
throw new \RuntimeException('Cannot find supported phpseclib/phpseclib library');
}
<?php

namespace PhpAmqpLib\Helper;

class MiscHelper
{




public static function methodSig($a)
{
if (is_string($a)) {
return $a;
}

return sprintf('%d,%d', $a[0], $a[1]);
}









public static function splitSecondsMicroseconds($number)
{
return array((int)floor($number), (int)(fmod($number, 1) * 1000000));
}



















public static function hexdump($data, $htmloutput = true, $uppercase = false, $return = false)
{

 $hexi = '';
$ascii = '';
$dump = $htmloutput ? '<pre>' : '';
$offset = 0;
$len = mb_strlen($data, 'ASCII');


 $hexFormat = $uppercase ? 'X' : 'x';


 for ($i = $j = 0; $i < $len; $i++) {

 
 
 $hexi .= sprintf('%02' . $hexFormat . ' ', ord($data[$i]));


 if (ord($data[$i]) >= 32) {
$ascii .= $htmloutput ? htmlentities($data[$i]) : $data[$i];
} else {
$ascii .= '.';
}


 if ($j === 7) {
$hexi .= ' ';
$ascii .= ' ';
}


 if (++$j === 16 || $i === $len - 1) {

 
 
 $dump .= sprintf('%04' . $hexFormat . '  %-49s  %s', $offset, $hexi, $ascii);


 $hexi = $ascii = '';
$offset += 16;
$j = 0;


 if ($i !== $len - 1) {
$dump .= PHP_EOL;
}
}
}


 $dump .= $htmloutput ? '</pre>' : '';
$dump .= PHP_EOL;

if ($return) {
return $dump;
}

echo $dump;

return null;
}





public static function dump_table($table)
{
$tokens = array();
foreach ($table as $name => $value) {
switch ($value[0]) {
case 'D':
$val = $value[1]->n . 'E' . $value[1]->e;
break;
case 'F':
$val = '(' . self::dump_table($value[1]) . ')';
break;
case 'T':
$val = date('Y-m-d H:i:s', $value[1]);
break;
default:
$val = $value[1];
}
$tokens[] = $name . '=' . $val;
}

return implode(', ', $tokens);
}
}
<?php

namespace PhpAmqpLib\Helper;

use PhpAmqpLib\Wire\Constants;

class DebugHelper
{



protected $debug;




protected $debug_output;




protected $constants;




public function __construct(Constants $constants)
{
$this->debug = defined('AMQP_DEBUG') ? AMQP_DEBUG : false;
if (defined('AMQP_DEBUG_OUTPUT')) {
$this->debug_output = AMQP_DEBUG_OUTPUT;
} else {
$this->debug_output = fopen('php://output', 'wb');
}
$this->constants = $constants;
}




public function debug_msg($msg)
{
if ($this->debug) {
$this->print_msg($msg);
}
}




public function debug_allowed_methods($allowed_methods)
{
if ($this->debug) {
if ($allowed_methods) {
$msg = 'waiting for ' . implode(', ', $allowed_methods);
} else {
$msg = 'waiting for any method';
}
$this->debug_msg($msg);
}
}




public function debug_method_signature1($method_sig)
{
$this->debug_method_signature('< %s:', $method_sig);
}





public function debug_method_signature($msg, $method_sig)
{
if ($this->debug) {
$constants = $this->constants;
$methods = $constants::$GLOBAL_METHOD_NAMES;
$key = MiscHelper::methodSig($method_sig);
$this->debug_msg(sprintf($msg . ': %s', $key, $methods[$key]));
}
}




public function debug_hexdump($data)
{
if ($this->debug) {
$this->debug_msg(
sprintf(
'< [hex]: %s%s',
PHP_EOL,
MiscHelper::hexdump($data, $htmloutput = false, $uppercase = true, $return = true)
)
);
}
}








public function debug_connection_start($version_major, $version_minor, $server_properties, $mechanisms, $locales)
{
if ($this->debug) {
$this->debug_msg(
sprintf(
'Start from server, version: %d.%d, properties: %s, mechanisms: %s, locales: %s',
$version_major,
$version_minor,
MiscHelper::dump_table($server_properties),
implode(', ', $mechanisms),
implode(', ', $locales)
)
);
}
}




protected function print_msg($s)
{
fwrite($this->debug_output, $s . PHP_EOL);
}
}
<?php



namespace PhpAmqpLib\Helper\Protocol;

class MethodMap080
{



protected $method_map = array(
'10,10' => 'connection_start',
'10,11' => 'connection_start_ok',
'10,20' => 'connection_secure',
'10,21' => 'connection_secure_ok',
'10,30' => 'connection_tune',
'10,31' => 'connection_tune_ok',
'10,40' => 'connection_open',
'10,41' => 'connection_open_ok',
'10,50' => 'connection_redirect',
'10,60' => 'connection_close',
'10,61' => 'connection_close_ok',
'20,10' => 'channel_open',
'20,11' => 'channel_open_ok',
'20,20' => 'channel_flow',
'20,21' => 'channel_flow_ok',
'20,30' => 'channel_alert',
'20,40' => 'channel_close',
'20,41' => 'channel_close_ok',
'30,10' => 'access_request',
'30,11' => 'access_request_ok',
'40,10' => 'exchange_declare',
'40,11' => 'exchange_declare_ok',
'40,20' => 'exchange_delete',
'40,21' => 'exchange_delete_ok',
'50,10' => 'queue_declare',
'50,11' => 'queue_declare_ok',
'50,20' => 'queue_bind',
'50,21' => 'queue_bind_ok',
'50,30' => 'queue_purge',
'50,31' => 'queue_purge_ok',
'50,40' => 'queue_delete',
'50,41' => 'queue_delete_ok',
'50,50' => 'queue_unbind',
'50,51' => 'queue_unbind_ok',
'60,10' => 'basic_qos',
'60,11' => 'basic_qos_ok',
'60,20' => 'basic_consume',
'60,21' => 'basic_consume_ok',
'60,30' => 'basic_cancel',
'60,31' => 'basic_cancel_ok',
'60,40' => 'basic_publish',
'60,50' => 'basic_return',
'60,60' => 'basic_deliver',
'60,70' => 'basic_get',
'60,71' => 'basic_get_ok',
'60,72' => 'basic_get_empty',
'60,80' => 'basic_ack',
'60,90' => 'basic_reject',
'60,100' => 'basic_recover_async',
'60,110' => 'basic_recover',
'60,111' => 'basic_recover_ok',
'70,10' => 'file_qos',
'70,11' => 'file_qos_ok',
'70,20' => 'file_consume',
'70,21' => 'file_consume_ok',
'70,30' => 'file_cancel',
'70,31' => 'file_cancel_ok',
'70,40' => 'file_open',
'70,41' => 'file_open_ok',
'70,50' => 'file_stage',
'70,60' => 'file_publish',
'70,70' => 'file_return',
'70,80' => 'file_deliver',
'70,90' => 'file_ack',
'70,100' => 'file_reject',
'80,10' => 'stream_qos',
'80,11' => 'stream_qos_ok',
'80,20' => 'stream_consume',
'80,21' => 'stream_consume_ok',
'80,30' => 'stream_cancel',
'80,31' => 'stream_cancel_ok',
'80,40' => 'stream_publish',
'80,50' => 'stream_return',
'80,60' => 'stream_deliver',
'90,10' => 'tx_select',
'90,11' => 'tx_select_ok',
'90,20' => 'tx_commit',
'90,21' => 'tx_commit_ok',
'90,30' => 'tx_rollback',
'90,31' => 'tx_rollback_ok',
'100,10' => 'dtx_select',
'100,11' => 'dtx_select_ok',
'100,20' => 'dtx_start',
'100,21' => 'dtx_start_ok',
'110,10' => 'tunnel_request',
'120,10' => 'test_integer',
'120,11' => 'test_integer_ok',
'120,20' => 'test_string',
'120,21' => 'test_string_ok',
'120,30' => 'test_table',
'120,31' => 'test_table_ok',
'120,40' => 'test_content',
'120,41' => 'test_content_ok',
);





public function get_method($method_sig)
{
return $this->method_map[$method_sig];
}





public function valid_method($method_sig)
{
return array_key_exists($method_sig, $this->method_map);
}
}
<?php



namespace PhpAmqpLib\Helper\Protocol;

class Wait091
{



protected $wait = array(
'connection.start' => '10,10',
'connection.start_ok' => '10,11',
'connection.secure' => '10,20',
'connection.secure_ok' => '10,21',
'connection.tune' => '10,30',
'connection.tune_ok' => '10,31',
'connection.open' => '10,40',
'connection.open_ok' => '10,41',
'connection.close' => '10,50',
'connection.close_ok' => '10,51',
'connection.blocked' => '10,60',
'connection.unblocked' => '10,61',
'channel.open' => '20,10',
'channel.open_ok' => '20,11',
'channel.flow' => '20,20',
'channel.flow_ok' => '20,21',
'channel.close' => '20,40',
'channel.close_ok' => '20,41',
'access.request' => '30,10',
'access.request_ok' => '30,11',
'exchange.declare' => '40,10',
'exchange.declare_ok' => '40,11',
'exchange.delete' => '40,20',
'exchange.delete_ok' => '40,21',
'exchange.bind' => '40,30',
'exchange.bind_ok' => '40,31',
'exchange.unbind' => '40,40',
'exchange.unbind_ok' => '40,51',
'queue.declare' => '50,10',
'queue.declare_ok' => '50,11',
'queue.bind' => '50,20',
'queue.bind_ok' => '50,21',
'queue.purge' => '50,30',
'queue.purge_ok' => '50,31',
'queue.delete' => '50,40',
'queue.delete_ok' => '50,41',
'queue.unbind' => '50,50',
'queue.unbind_ok' => '50,51',
'basic.qos' => '60,10',
'basic.qos_ok' => '60,11',
'basic.consume' => '60,20',
'basic.consume_ok' => '60,21',
'basic.cancel' => '60,30',
'basic.cancel_ok' => '60,31',
'basic.publish' => '60,40',
'basic.return' => '60,50',
'basic.deliver' => '60,60',
'basic.get' => '60,70',
'basic.get_ok' => '60,71',
'basic.get_empty' => '60,72',
'basic.ack' => '60,80',
'basic.reject' => '60,90',
'basic.recover_async' => '60,100',
'basic.recover' => '60,110',
'basic.recover_ok' => '60,111',
'basic.nack' => '60,120',
'tx.select' => '90,10',
'tx.select_ok' => '90,11',
'tx.commit' => '90,20',
'tx.commit_ok' => '90,21',
'tx.rollback' => '90,30',
'tx.rollback_ok' => '90,31',
'confirm.select' => '85,10',
'confirm.select_ok' => '85,11',
);





public function get_wait($method)
{
return $this->wait[$method];
}
}
<?php



namespace PhpAmqpLib\Helper\Protocol;

class Wait080
{



protected $wait = array(
'connection.start' => '10,10',
'connection.start_ok' => '10,11',
'connection.secure' => '10,20',
'connection.secure_ok' => '10,21',
'connection.tune' => '10,30',
'connection.tune_ok' => '10,31',
'connection.open' => '10,40',
'connection.open_ok' => '10,41',
'connection.redirect' => '10,50',
'connection.close' => '10,60',
'connection.close_ok' => '10,61',
'channel.open' => '20,10',
'channel.open_ok' => '20,11',
'channel.flow' => '20,20',
'channel.flow_ok' => '20,21',
'channel.alert' => '20,30',
'channel.close' => '20,40',
'channel.close_ok' => '20,41',
'access.request' => '30,10',
'access.request_ok' => '30,11',
'exchange.declare' => '40,10',
'exchange.declare_ok' => '40,11',
'exchange.delete' => '40,20',
'exchange.delete_ok' => '40,21',
'queue.declare' => '50,10',
'queue.declare_ok' => '50,11',
'queue.bind' => '50,20',
'queue.bind_ok' => '50,21',
'queue.purge' => '50,30',
'queue.purge_ok' => '50,31',
'queue.delete' => '50,40',
'queue.delete_ok' => '50,41',
'queue.unbind' => '50,50',
'queue.unbind_ok' => '50,51',
'basic.qos' => '60,10',
'basic.qos_ok' => '60,11',
'basic.consume' => '60,20',
'basic.consume_ok' => '60,21',
'basic.cancel' => '60,30',
'basic.cancel_ok' => '60,31',
'basic.publish' => '60,40',
'basic.return' => '60,50',
'basic.deliver' => '60,60',
'basic.get' => '60,70',
'basic.get_ok' => '60,71',
'basic.get_empty' => '60,72',
'basic.ack' => '60,80',
'basic.reject' => '60,90',
'basic.recover_async' => '60,100',
'basic.recover' => '60,110',
'basic.recover_ok' => '60,111',
'file.qos' => '70,10',
'file.qos_ok' => '70,11',
'file.consume' => '70,20',
'file.consume_ok' => '70,21',
'file.cancel' => '70,30',
'file.cancel_ok' => '70,31',
'file.open' => '70,40',
'file.open_ok' => '70,41',
'file.stage' => '70,50',
'file.publish' => '70,60',
'file.return' => '70,70',
'file.deliver' => '70,80',
'file.ack' => '70,90',
'file.reject' => '70,100',
'stream.qos' => '80,10',
'stream.qos_ok' => '80,11',
'stream.consume' => '80,20',
'stream.consume_ok' => '80,21',
'stream.cancel' => '80,30',
'stream.cancel_ok' => '80,31',
'stream.publish' => '80,40',
'stream.return' => '80,50',
'stream.deliver' => '80,60',
'tx.select' => '90,10',
'tx.select_ok' => '90,11',
'tx.commit' => '90,20',
'tx.commit_ok' => '90,21',
'tx.rollback' => '90,30',
'tx.rollback_ok' => '90,31',
'dtx.select' => '100,10',
'dtx.select_ok' => '100,11',
'dtx.start' => '100,20',
'dtx.start_ok' => '100,21',
'tunnel.request' => '110,10',
'test.integer' => '120,10',
'test.integer_ok' => '120,11',
'test.string' => '120,20',
'test.string_ok' => '120,21',
'test.table' => '120,30',
'test.table_ok' => '120,31',
'test.content' => '120,40',
'test.content_ok' => '120,41',
);





public function get_wait($method)
{
return $this->wait[$method];
}
}
<?php



namespace PhpAmqpLib\Helper\Protocol;

use PhpAmqpLib\Wire\AMQPWriter;
use PhpAmqpLib\Wire\AMQPReader;

class Protocol080
{








public function connectionStart(
$version_major = 0,
$version_minor = 8,
$server_properties = [],
$mechanisms = 'PLAIN',
$locales = 'en_US'
) {
$writer = new AMQPWriter();
$writer->write_octet($version_major);
$writer->write_octet($version_minor);
$writer->write_table(empty($server_properties) ? array() : $server_properties);
$writer->write_longstr($mechanisms);
$writer->write_longstr($locales);
return array(10, 10, $writer);
}





public static function connectionStartOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_table();
$response[] = $reader->read_shortstr();
$response[] = $reader->read_longstr();
$response[] = $reader->read_shortstr();
return $response;
}





public function connectionSecure($challenge)
{
$writer = new AMQPWriter();
$writer->write_longstr($challenge);
return array(10, 20, $writer);
}





public static function connectionSecureOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_longstr();
return $response;
}







public function connectionTune($channel_max = 0, $frame_max = 0, $heartbeat = 0)
{
$writer = new AMQPWriter();
$writer->write_short($channel_max);
$writer->write_long($frame_max);
$writer->write_short($heartbeat);
return array(10, 30, $writer);
}





public static function connectionTuneOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_short();
$response[] = $reader->read_long();
$response[] = $reader->read_short();
return $response;
}







public function connectionOpen($virtual_host = '/', $capabilities = '', $insist = false)
{
$writer = new AMQPWriter();
$writer->write_shortstr($virtual_host);
$writer->write_shortstr($capabilities);
$writer->write_bits(array($insist));
return array(10, 40, $writer);
}





public static function connectionOpenOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_shortstr();
return $response;
}






public function connectionRedirect($host, $known_hosts = '')
{
$writer = new AMQPWriter();
$writer->write_shortstr($host);
$writer->write_shortstr($known_hosts);
return array(10, 50, $writer);
}








public function connectionClose($reply_code, $reply_text, $class_id, $method_id)
{
$writer = new AMQPWriter();
$writer->write_short($reply_code);
$writer->write_shortstr($reply_text);
$writer->write_short($class_id);
$writer->write_short($method_id);
return array(10, 60, $writer);
}





public static function connectionCloseOk(AMQPReader $reader)
{
$response = array();
return $response;
}





public function channelOpen($out_of_band = '')
{
$writer = new AMQPWriter();
$writer->write_shortstr($out_of_band);
return array(20, 10, $writer);
}





public static function channelOpenOk(AMQPReader $reader)
{
$response = array();
return $response;
}





public function channelFlow($active)
{
$writer = new AMQPWriter();
$writer->write_bits(array($active));
return array(20, 20, $writer);
}





public static function channelFlowOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_bit();
return $response;
}







public function channelAlert($reply_code, $reply_text = '', $details = array())
{
$writer = new AMQPWriter();
$writer->write_short($reply_code);
$writer->write_shortstr($reply_text);
$writer->write_table(empty($details) ? array() : $details);
return array(20, 30, $writer);
}








public function channelClose($reply_code, $reply_text, $class_id, $method_id)
{
$writer = new AMQPWriter();
$writer->write_short($reply_code);
$writer->write_shortstr($reply_text);
$writer->write_short($class_id);
$writer->write_short($method_id);
return array(20, 40, $writer);
}





public static function channelCloseOk(AMQPReader $reader)
{
$response = array();
return $response;
}










public function accessRequest(
$realm = '/data',
$exclusive = false,
$passive = true,
$active = true,
$write = true,
$read = true
) {
$writer = new AMQPWriter();
$writer->write_shortstr($realm);
$writer->write_bits(array($exclusive, $passive, $active, $write, $read));
return array(30, 10, $writer);
}





public static function accessRequestOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_short();
return $response;
}













public function exchangeDeclare(
$ticket = 1,
$exchange = '',
$type = 'direct',
$passive = false,
$durable = false,
$auto_delete = false,
$internal = false,
$nowait = false,
$arguments = array()
) {
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($exchange);
$writer->write_shortstr($type);
$writer->write_bits(array($passive, $durable, $auto_delete, $internal, $nowait));
$writer->write_table(empty($arguments) ? array() : $arguments);
return array(40, 10, $writer);
}





public static function exchangeDeclareOk(AMQPReader $reader)
{
$response = array();
return $response;
}








public function exchangeDelete($ticket = 1, $exchange = '', $if_unused = false, $nowait = false)
{
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($exchange);
$writer->write_bits(array($if_unused, $nowait));
return array(40, 20, $writer);
}





public static function exchangeDeleteOk(AMQPReader $reader)
{
$response = array();
return $response;
}












public function queueDeclare(
$ticket = 1,
$queue = '',
$passive = false,
$durable = false,
$exclusive = false,
$auto_delete = false,
$nowait = false,
$arguments = array()
) {
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($queue);
$writer->write_bits(array($passive, $durable, $exclusive, $auto_delete, $nowait));
$writer->write_table(empty($arguments) ? array() : $arguments);
return array(50, 10, $writer);
}





public static function queueDeclareOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_shortstr();
$response[] = $reader->read_long();
$response[] = $reader->read_long();
return $response;
}










public function queueBind(
$ticket = 1,
$queue = '',
$exchange = '',
$routing_key = '',
$nowait = false,
$arguments = array()
) {
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($queue);
$writer->write_shortstr($exchange);
$writer->write_shortstr($routing_key);
$writer->write_bits(array($nowait));
$writer->write_table(empty($arguments) ? array() : $arguments);
return array(50, 20, $writer);
}





public static function queueBindOk(AMQPReader $reader)
{
$response = array();
return $response;
}







public function queuePurge($ticket = 1, $queue = '', $nowait = false)
{
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($queue);
$writer->write_bits(array($nowait));
return array(50, 30, $writer);
}





public static function queuePurgeOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_long();
return $response;
}









public function queueDelete($ticket = 1, $queue = '', $if_unused = false, $if_empty = false, $nowait = false)
{
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($queue);
$writer->write_bits(array($if_unused, $if_empty, $nowait));
return array(50, 40, $writer);
}





public static function queueDeleteOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_long();
return $response;
}









public function queueUnbind($ticket = 1, $queue = '', $exchange = '', $routing_key = '', $arguments = array())
{
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($queue);
$writer->write_shortstr($exchange);
$writer->write_shortstr($routing_key);
$writer->write_table(empty($arguments) ? array() : $arguments);
return array(50, 50, $writer);
}





public static function queueUnbindOk(AMQPReader $reader)
{
$response = array();
return $response;
}







public function basicQos($prefetch_size = 0, $prefetch_count = 0, $global = false)
{
$writer = new AMQPWriter();
$writer->write_long($prefetch_size);
$writer->write_short($prefetch_count);
$writer->write_bits(array($global));
return array(60, 10, $writer);
}





public static function basicQosOk(AMQPReader $reader)
{
$response = array();
return $response;
}











public function basicConsume(
$ticket = 1,
$queue = '',
$consumer_tag = '',
$no_local = false,
$no_ack = false,
$exclusive = false,
$nowait = false
) {
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($queue);
$writer->write_shortstr($consumer_tag);
$writer->write_bits(array($no_local, $no_ack, $exclusive, $nowait));
return array(60, 20, $writer);
}





public static function basicConsumeOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_shortstr();
return $response;
}






public function basicCancel($consumer_tag, $nowait = false)
{
$writer = new AMQPWriter();
$writer->write_shortstr($consumer_tag);
$writer->write_bits(array($nowait));
return array(60, 30, $writer);
}





public static function basicCancelOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_shortstr();
return $response;
}









public function basicPublish($ticket = 1, $exchange = '', $routing_key = '', $mandatory = false, $immediate = false)
{
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($exchange);
$writer->write_shortstr($routing_key);
$writer->write_bits(array($mandatory, $immediate));
return array(60, 40, $writer);
}








public function basicReturn($reply_code, $reply_text, $exchange, $routing_key)
{
$writer = new AMQPWriter();
$writer->write_short($reply_code);
$writer->write_shortstr($reply_text);
$writer->write_shortstr($exchange);
$writer->write_shortstr($routing_key);
return array(60, 50, $writer);
}









public function basicDeliver($consumer_tag, $delivery_tag, $redelivered, $exchange, $routing_key)
{
$writer = new AMQPWriter();
$writer->write_shortstr($consumer_tag);
$writer->write_longlong($delivery_tag);
$writer->write_bits(array($redelivered));
$writer->write_shortstr($exchange);
$writer->write_shortstr($routing_key);
return array(60, 60, $writer);
}







public function basicGet($ticket = 1, $queue = '', $no_ack = false)
{
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($queue);
$writer->write_bits(array($no_ack));
return array(60, 70, $writer);
}





public static function basicGetOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_longlong();
$response[] = $reader->read_bit();
$response[] = $reader->read_shortstr();
$response[] = $reader->read_shortstr();
$response[] = $reader->read_long();
return $response;
}





public static function basicGetEmpty(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_shortstr();
return $response;
}






public function basicAck($delivery_tag = 0, $multiple = false)
{
$writer = new AMQPWriter();
$writer->write_longlong($delivery_tag);
$writer->write_bits(array($multiple));
return array(60, 80, $writer);
}






public function basicReject($delivery_tag, $requeue = true)
{
$writer = new AMQPWriter();
$writer->write_longlong($delivery_tag);
$writer->write_bits(array($requeue));
return array(60, 90, $writer);
}





public function basicRecoverAsync($requeue = false)
{
$writer = new AMQPWriter();
$writer->write_bits(array($requeue));
return array(60, 100, $writer);
}





public function basicRecover($requeue = false)
{
$writer = new AMQPWriter();
$writer->write_bits(array($requeue));
return array(60, 110, $writer);
}





public static function basicRecoverOk(AMQPReader $reader)
{
$response = array();
return $response;
}







public function fileQos($prefetch_size = 0, $prefetch_count = 0, $global = false)
{
$writer = new AMQPWriter();
$writer->write_long($prefetch_size);
$writer->write_short($prefetch_count);
$writer->write_bits(array($global));
return array(70, 10, $writer);
}





public static function fileQosOk(AMQPReader $reader)
{
$response = array();
return $response;
}











public function fileConsume(
$ticket = 1,
$queue = '',
$consumer_tag = '',
$no_local = false,
$no_ack = false,
$exclusive = false,
$nowait = false
) {
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($queue);
$writer->write_shortstr($consumer_tag);
$writer->write_bits(array($no_local, $no_ack, $exclusive, $nowait));
return array(70, 20, $writer);
}





public static function fileConsumeOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_shortstr();
return $response;
}






public function fileCancel($consumer_tag, $nowait = false)
{
$writer = new AMQPWriter();
$writer->write_shortstr($consumer_tag);
$writer->write_bits(array($nowait));
return array(70, 30, $writer);
}





public static function fileCancelOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_shortstr();
return $response;
}






public function fileOpen($identifier, $content_size)
{
$writer = new AMQPWriter();
$writer->write_shortstr($identifier);
$writer->write_longlong($content_size);
return array(70, 40, $writer);
}





public static function fileOpenOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_longlong();
return $response;
}





public function fileStage()
{
$writer = new AMQPWriter();
return array(70, 50, $writer);
}










public function filePublish(
$ticket = 1,
$exchange = '',
$routing_key = '',
$mandatory = false,
$immediate = false,
$identifier = ''
) {
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($exchange);
$writer->write_shortstr($routing_key);
$writer->write_bits(array($mandatory, $immediate));
$writer->write_shortstr($identifier);
return array(70, 60, $writer);
}








public function fileReturn($reply_code = 200, $reply_text = '', $exchange = '', $routing_key = '')
{
$writer = new AMQPWriter();
$writer->write_short($reply_code);
$writer->write_shortstr($reply_text);
$writer->write_shortstr($exchange);
$writer->write_shortstr($routing_key);
return array(70, 70, $writer);
}










public function fileDeliver(
$consumer_tag,
$delivery_tag,
$redelivered,
$exchange,
$routing_key,
$identifier
) {
$writer = new AMQPWriter();
$writer->write_shortstr($consumer_tag);
$writer->write_longlong($delivery_tag);
$writer->write_bits(array($redelivered));
$writer->write_shortstr($exchange);
$writer->write_shortstr($routing_key);
$writer->write_shortstr($identifier);
return array(70, 80, $writer);
}






public function fileAck($delivery_tag = 0, $multiple = false)
{
$writer = new AMQPWriter();
$writer->write_longlong($delivery_tag);
$writer->write_bits(array($multiple));
return array(70, 90, $writer);
}






public function fileReject($delivery_tag, $requeue = true)
{
$writer = new AMQPWriter();
$writer->write_longlong($delivery_tag);
$writer->write_bits(array($requeue));
return array(70, 100, $writer);
}








public function streamQos($prefetch_size = 0, $prefetch_count = 0, $consume_rate = 0, $global = false)
{
$writer = new AMQPWriter();
$writer->write_long($prefetch_size);
$writer->write_short($prefetch_count);
$writer->write_long($consume_rate);
$writer->write_bits(array($global));
return array(80, 10, $writer);
}





public static function streamQosOk(AMQPReader $reader)
{
$response = array();
return $response;
}










public function streamConsume(
$ticket = 1,
$queue = '',
$consumer_tag = '',
$no_local = false,
$exclusive = false,
$nowait = false
) {
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($queue);
$writer->write_shortstr($consumer_tag);
$writer->write_bits(array($no_local, $exclusive, $nowait));
return array(80, 20, $writer);
}





public static function streamConsumeOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_shortstr();
return $response;
}






public function streamCancel($consumer_tag, $nowait = false)
{
$writer = new AMQPWriter();
$writer->write_shortstr($consumer_tag);
$writer->write_bits(array($nowait));
return array(80, 30, $writer);
}





public static function streamCancelOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_shortstr();
return $response;
}









public function streamPublish(
$ticket = 1,
$exchange = '',
$routing_key = '',
$mandatory = false,
$immediate = false
) {
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($exchange);
$writer->write_shortstr($routing_key);
$writer->write_bits(array($mandatory, $immediate));
return array(80, 40, $writer);
}








public function streamReturn($reply_code = 200, $reply_text = '', $exchange = '', $routing_key = '')
{
$writer = new AMQPWriter();
$writer->write_short($reply_code);
$writer->write_shortstr($reply_text);
$writer->write_shortstr($exchange);
$writer->write_shortstr($routing_key);
return array(80, 50, $writer);
}








public function streamDeliver($consumer_tag, $delivery_tag, $exchange, $queue)
{
$writer = new AMQPWriter();
$writer->write_shortstr($consumer_tag);
$writer->write_longlong($delivery_tag);
$writer->write_shortstr($exchange);
$writer->write_shortstr($queue);
return array(80, 60, $writer);
}





public function txSelect()
{
$writer = new AMQPWriter();
return array(90, 10, $writer);
}





public static function txSelectOk(AMQPReader $reader)
{
$response = array();
return $response;
}





public function txCommit()
{
$writer = new AMQPWriter();
return array(90, 20, $writer);
}





public static function txCommitOk(AMQPReader $reader)
{
$response = array();
return $response;
}





public function txRollback()
{
$writer = new AMQPWriter();
return array(90, 30, $writer);
}





public static function txRollbackOk(AMQPReader $reader)
{
$response = array();
return $response;
}





public function dtxSelect()
{
$writer = new AMQPWriter();
return array(100, 10, $writer);
}





public static function dtxSelectOk(AMQPReader $reader)
{
$response = array();
return $response;
}





public function dtxStart($dtx_identifier)
{
$writer = new AMQPWriter();
$writer->write_shortstr($dtx_identifier);
return array(100, 20, $writer);
}





public static function dtxStartOk(AMQPReader $reader)
{
$response = array();
return $response;
}





public function tunnelRequest($meta_data)
{
$writer = new AMQPWriter();
$writer->write_table(empty($meta_data) ? array() : $meta_data);
return array(110, 10, $writer);
}









public function testInteger($integer_1, $integer_2, $integer_3, $integer_4, $operation)
{
$writer = new AMQPWriter();
$writer->write_octet($integer_1);
$writer->write_short($integer_2);
$writer->write_long($integer_3);
$writer->write_longlong($integer_4);
$writer->write_octet($operation);
return array(120, 10, $writer);
}





public static function testIntegerOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_longlong();
return $response;
}







public function testString($string_1, $string_2, $operation)
{
$writer = new AMQPWriter();
$writer->write_shortstr($string_1);
$writer->write_longstr($string_2);
$writer->write_octet($operation);
return array(120, 20, $writer);
}





public static function testStringOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_longstr();
return $response;
}







public function testTable($table, $integer_op, $string_op)
{
$writer = new AMQPWriter();
$writer->write_table(empty($table) ? array() : $table);
$writer->write_octet($integer_op);
$writer->write_octet($string_op);
return array(120, 30, $writer);
}





public static function testTableOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_longlong();
$response[] = $reader->read_longstr();
return $response;
}





public function testContent()
{
$writer = new AMQPWriter();
return array(120, 40, $writer);
}





public static function testContentOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_long();
return $response;
}
}
<?php



namespace PhpAmqpLib\Helper\Protocol;

class MethodMap091
{



protected $method_map = array(
'10,10' => 'connection_start',
'10,11' => 'connection_start_ok',
'10,20' => 'connection_secure',
'10,21' => 'connection_secure_ok',
'10,30' => 'connection_tune',
'10,31' => 'connection_tune_ok',
'10,40' => 'connection_open',
'10,41' => 'connection_open_ok',
'10,50' => 'connection_close',
'10,51' => 'connection_close_ok',
'10,60' => 'connection_blocked',
'10,61' => 'connection_unblocked',
'20,10' => 'channel_open',
'20,11' => 'channel_open_ok',
'20,20' => 'channel_flow',
'20,21' => 'channel_flow_ok',
'20,40' => 'channel_close',
'20,41' => 'channel_close_ok',
'30,10' => 'access_request',
'30,11' => 'access_request_ok',
'40,10' => 'exchange_declare',
'40,11' => 'exchange_declare_ok',
'40,20' => 'exchange_delete',
'40,21' => 'exchange_delete_ok',
'40,30' => 'exchange_bind',
'40,31' => 'exchange_bind_ok',
'40,40' => 'exchange_unbind',
'40,51' => 'exchange_unbind_ok',
'50,10' => 'queue_declare',
'50,11' => 'queue_declare_ok',
'50,20' => 'queue_bind',
'50,21' => 'queue_bind_ok',
'50,30' => 'queue_purge',
'50,31' => 'queue_purge_ok',
'50,40' => 'queue_delete',
'50,41' => 'queue_delete_ok',
'50,50' => 'queue_unbind',
'50,51' => 'queue_unbind_ok',
'60,10' => 'basic_qos',
'60,11' => 'basic_qos_ok',
'60,20' => 'basic_consume',
'60,21' => 'basic_consume_ok',
'60,30' => 'basic_cancel_from_server',
'60,31' => 'basic_cancel_ok',
'60,40' => 'basic_publish',
'60,50' => 'basic_return',
'60,60' => 'basic_deliver',
'60,70' => 'basic_get',
'60,71' => 'basic_get_ok',
'60,72' => 'basic_get_empty',
'60,80' => 'basic_ack_from_server',
'60,90' => 'basic_reject',
'60,100' => 'basic_recover_async',
'60,110' => 'basic_recover',
'60,111' => 'basic_recover_ok',
'60,120' => 'basic_nack_from_server',
'90,10' => 'tx_select',
'90,11' => 'tx_select_ok',
'90,20' => 'tx_commit',
'90,21' => 'tx_commit_ok',
'90,30' => 'tx_rollback',
'90,31' => 'tx_rollback_ok',
'85,10' => 'confirm_select',
'85,11' => 'confirm_select_ok',
);





public function get_method($method_sig)
{
return $this->method_map[$method_sig];
}





public function valid_method($method_sig)
{
return array_key_exists($method_sig, $this->method_map);
}
}
<?php



namespace PhpAmqpLib\Helper\Protocol;

use PhpAmqpLib\Wire\AMQPWriter;
use PhpAmqpLib\Wire\AMQPReader;

class Protocol091
{








public function connectionStart(
$version_major = 0,
$version_minor = 9,
$server_properties = [],
$mechanisms = 'PLAIN',
$locales = 'en_US'
) {
$writer = new AMQPWriter();
$writer->write_octet($version_major);
$writer->write_octet($version_minor);
$writer->write_table(empty($server_properties) ? array() : $server_properties);
$writer->write_longstr($mechanisms);
$writer->write_longstr($locales);
return array(10, 10, $writer);
}





public static function connectionStartOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_table();
$response[] = $reader->read_shortstr();
$response[] = $reader->read_longstr();
$response[] = $reader->read_shortstr();
return $response;
}





public function connectionSecure($challenge)
{
$writer = new AMQPWriter();
$writer->write_longstr($challenge);
return array(10, 20, $writer);
}





public static function connectionSecureOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_longstr();
return $response;
}







public function connectionTune($channel_max = 0, $frame_max = 0, $heartbeat = 0)
{
$writer = new AMQPWriter();
$writer->write_short($channel_max);
$writer->write_long($frame_max);
$writer->write_short($heartbeat);
return array(10, 30, $writer);
}





public static function connectionTuneOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_short();
$response[] = $reader->read_long();
$response[] = $reader->read_short();
return $response;
}







public function connectionOpen($virtual_host = '/', $capabilities = '', $insist = false)
{
$writer = new AMQPWriter();
$writer->write_shortstr($virtual_host);
$writer->write_shortstr($capabilities);
$writer->write_bits(array($insist));
return array(10, 40, $writer);
}





public static function connectionOpenOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_shortstr();
return $response;
}








public function connectionClose($reply_code, $reply_text, $class_id, $method_id)
{
$writer = new AMQPWriter();
$writer->write_short($reply_code);
$writer->write_shortstr($reply_text);
$writer->write_short($class_id);
$writer->write_short($method_id);
return array(10, 50, $writer);
}





public static function connectionCloseOk(AMQPReader $reader)
{
$response = array();
return $response;
}





public function connectionBlocked($reason = '')
{
$writer = new AMQPWriter();
$writer->write_shortstr($reason);
return array(10, 60, $writer);
}





public static function connectionUnblocked(AMQPReader $reader)
{
$response = array();
return $response;
}





public function channelOpen($out_of_band = '')
{
$writer = new AMQPWriter();
$writer->write_shortstr($out_of_band);
return array(20, 10, $writer);
}





public static function channelOpenOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_longstr();
return $response;
}





public function channelFlow($active)
{
$writer = new AMQPWriter();
$writer->write_bits(array($active));
return array(20, 20, $writer);
}





public static function channelFlowOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_bit();
return $response;
}








public function channelClose($reply_code, $reply_text, $class_id, $method_id)
{
$writer = new AMQPWriter();
$writer->write_short($reply_code);
$writer->write_shortstr($reply_text);
$writer->write_short($class_id);
$writer->write_short($method_id);
return array(20, 40, $writer);
}





public static function channelCloseOk(AMQPReader $reader)
{
$response = array();
return $response;
}










public function accessRequest(
$realm = '/data',
$exclusive = false,
$passive = true,
$active = true,
$write = true,
$read = true
) {
$writer = new AMQPWriter();
$writer->write_shortstr($realm);
$writer->write_bits(array($exclusive, $passive, $active, $write, $read));
return array(30, 10, $writer);
}





public static function accessRequestOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_short();
return $response;
}













public function exchangeDeclare(
$ticket = 0,
$exchange = '',
$type = 'direct',
$passive = false,
$durable = false,
$auto_delete = false,
$internal = false,
$nowait = false,
$arguments = array()
) {
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($exchange);
$writer->write_shortstr($type);
$writer->write_bits(array($passive, $durable, $auto_delete, $internal, $nowait));
$writer->write_table(empty($arguments) ? array() : $arguments);
return array(40, 10, $writer);
}





public static function exchangeDeclareOk(AMQPReader $reader)
{
$response = array();
return $response;
}








public function exchangeDelete($ticket = 0, $exchange = '', $if_unused = false, $nowait = false)
{
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($exchange);
$writer->write_bits(array($if_unused, $nowait));
return array(40, 20, $writer);
}





public static function exchangeDeleteOk(AMQPReader $reader)
{
$response = array();
return $response;
}










public function exchangeBind(
$ticket = 0,
$destination = '',
$source = '',
$routing_key = '',
$nowait = false,
$arguments = array()
) {
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($destination);
$writer->write_shortstr($source);
$writer->write_shortstr($routing_key);
$writer->write_bits(array($nowait));
$writer->write_table(empty($arguments) ? array() : $arguments);
return array(40, 30, $writer);
}





public static function exchangeBindOk(AMQPReader $reader)
{
$response = array();
return $response;
}










public function exchangeUnbind(
$ticket = 0,
$destination = '',
$source = '',
$routing_key = '',
$nowait = false,
$arguments = array()
) {
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($destination);
$writer->write_shortstr($source);
$writer->write_shortstr($routing_key);
$writer->write_bits(array($nowait));
$writer->write_table(empty($arguments) ? array() : $arguments);
return array(40, 40, $writer);
}





public static function exchangeUnbindOk(AMQPReader $reader)
{
$response = array();
return $response;
}












public function queueDeclare(
$ticket = 0,
$queue = '',
$passive = false,
$durable = false,
$exclusive = false,
$auto_delete = false,
$nowait = false,
$arguments = array()
) {
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($queue);
$writer->write_bits(array($passive, $durable, $exclusive, $auto_delete, $nowait));
$writer->write_table(empty($arguments) ? array() : $arguments);
return array(50, 10, $writer);
}





public static function queueDeclareOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_shortstr();
$response[] = $reader->read_long();
$response[] = $reader->read_long();
return $response;
}










public function queueBind(
$ticket = 0,
$queue = '',
$exchange = '',
$routing_key = '',
$nowait = false,
$arguments = array()
) {
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($queue);
$writer->write_shortstr($exchange);
$writer->write_shortstr($routing_key);
$writer->write_bits(array($nowait));
$writer->write_table(empty($arguments) ? array() : $arguments);
return array(50, 20, $writer);
}





public static function queueBindOk(AMQPReader $reader)
{
$response = array();
return $response;
}







public function queuePurge($ticket = 0, $queue = '', $nowait = false)
{
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($queue);
$writer->write_bits(array($nowait));
return array(50, 30, $writer);
}





public static function queuePurgeOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_long();
return $response;
}









public function queueDelete($ticket = 0, $queue = '', $if_unused = false, $if_empty = false, $nowait = false)
{
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($queue);
$writer->write_bits(array($if_unused, $if_empty, $nowait));
return array(50, 40, $writer);
}





public static function queueDeleteOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_long();
return $response;
}









public function queueUnbind($ticket = 0, $queue = '', $exchange = '', $routing_key = '', $arguments = array())
{
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($queue);
$writer->write_shortstr($exchange);
$writer->write_shortstr($routing_key);
$writer->write_table(empty($arguments) ? array() : $arguments);
return array(50, 50, $writer);
}





public static function queueUnbindOk(AMQPReader $reader)
{
$response = array();
return $response;
}







public function basicQos($prefetch_size = 0, $prefetch_count = 0, $global = false)
{
$writer = new AMQPWriter();
$writer->write_long($prefetch_size);
$writer->write_short($prefetch_count);
$writer->write_bits(array($global));
return array(60, 10, $writer);
}





public static function basicQosOk(AMQPReader $reader)
{
$response = array();
return $response;
}












public function basicConsume(
$ticket = 0,
$queue = '',
$consumer_tag = '',
$no_local = false,
$no_ack = false,
$exclusive = false,
$nowait = false,
$arguments = array()
) {
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($queue);
$writer->write_shortstr($consumer_tag);
$writer->write_bits(array($no_local, $no_ack, $exclusive, $nowait));
$writer->write_table(empty($arguments) ? array() : $arguments);
return array(60, 20, $writer);
}





public static function basicConsumeOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_shortstr();
return $response;
}






public function basicCancel($consumer_tag, $nowait = false)
{
$writer = new AMQPWriter();
$writer->write_shortstr($consumer_tag);
$writer->write_bits(array($nowait));
return array(60, 30, $writer);
}





public static function basicCancelOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_shortstr();
return $response;
}









public function basicPublish(
$ticket = 0,
$exchange = '',
$routing_key = '',
$mandatory = false,
$immediate = false
) {
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($exchange);
$writer->write_shortstr($routing_key);
$writer->write_bits(array($mandatory, $immediate));
return array(60, 40, $writer);
}








public function basicReturn($reply_code, $reply_text, $exchange, $routing_key)
{
$writer = new AMQPWriter();
$writer->write_short($reply_code);
$writer->write_shortstr($reply_text);
$writer->write_shortstr($exchange);
$writer->write_shortstr($routing_key);
return array(60, 50, $writer);
}









public function basicDeliver($consumer_tag, $delivery_tag, $redelivered, $exchange, $routing_key)
{
$writer = new AMQPWriter();
$writer->write_shortstr($consumer_tag);
$writer->write_longlong($delivery_tag);
$writer->write_bits(array($redelivered));
$writer->write_shortstr($exchange);
$writer->write_shortstr($routing_key);
return array(60, 60, $writer);
}







public function basicGet($ticket = 0, $queue = '', $no_ack = false)
{
$writer = new AMQPWriter();
$writer->write_short($ticket);
$writer->write_shortstr($queue);
$writer->write_bits(array($no_ack));
return array(60, 70, $writer);
}





public static function basicGetOk(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_longlong();
$response[] = $reader->read_bit();
$response[] = $reader->read_shortstr();
$response[] = $reader->read_shortstr();
$response[] = $reader->read_long();
return $response;
}





public static function basicGetEmpty(AMQPReader $reader)
{
$response = array();
$response[] = $reader->read_shortstr();
return $response;
}






public function basicAck($delivery_tag = 0, $multiple = false)
{
$writer = new AMQPWriter();
$writer->write_longlong($delivery_tag);
$writer->write_bits(array($multiple));
return array(60, 80, $writer);
}






public function basicReject($delivery_tag, $requeue = true)
{
$writer = new AMQPWriter();
$writer->write_longlong($delivery_tag);
$writer->write_bits(array($requeue));
return array(60, 90, $writer);
}





public function basicRecoverAsync($requeue = false)
{
$writer = new AMQPWriter();
$writer->write_bits(array($requeue));
return array(60, 100, $writer);
}





public function basicRecover($requeue = false)
{
$writer = new AMQPWriter();
$writer->write_bits(array($requeue));
return array(60, 110, $writer);
}





public static function basicRecoverOk(AMQPReader $reader)
{
$response = array();
return $response;
}







public function basicNack($delivery_tag = 0, $multiple = false, $requeue = true)
{
$writer = new AMQPWriter();
$writer->write_longlong($delivery_tag);
$writer->write_bits(array($multiple, $requeue));
return array(60, 120, $writer);
}





public function txSelect()
{
$writer = new AMQPWriter();
return array(90, 10, $writer);
}





public static function txSelectOk(AMQPReader $reader)
{
$response = array();
return $response;
}





public function txCommit()
{
$writer = new AMQPWriter();
return array(90, 20, $writer);
}





public static function txCommitOk(AMQPReader $reader)
{
$response = array();
return $response;
}





public function txRollback()
{
$writer = new AMQPWriter();
return array(90, 30, $writer);
}





public static function txRollbackOk(AMQPReader $reader)
{
$response = array();
return $response;
}





public function confirmSelect($nowait = false)
{
$writer = new AMQPWriter();
$writer->write_bits(array($nowait));
return array(85, 10, $writer);
}





public static function confirmSelectOk(AMQPReader $reader)
{
$response = array();
return $response;
}
}
<?php

namespace PhpAmqpLib\Helper;

use InvalidArgumentException;

class Assert
{




public static function isCallable($argument)
{
if (!is_callable($argument)) {
throw new InvalidArgumentException(sprintf(
'Given argument "%s" should be callable. %s type was given.',
$argument,
gettype($argument)
));
}
}
}
<?php

namespace PhpAmqpLib\Message;

use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Exception\AMQPEmptyDeliveryTagException;
use PhpAmqpLib\Wire\AMQPReader;
use PhpAmqpLib\Wire\AMQPWriter;




class AMQPMessage
{
const DELIVERY_MODE_NON_PERSISTENT = 1;
const DELIVERY_MODE_PERSISTENT = 2;


public $body;


public $body_size;


public $is_truncated = false;


public $content_encoding;


private $deliveryTag;


private $consumerTag;


private $redelivered;


private $exchange;


private $routingKey;


private $messageCount;


private $channel;


private $responded = false;






public $delivery_info = array();


protected $properties = array();


protected $serialized_properties;


protected static $propertyDefinitions = array(
'content_type' => 'shortstr',
'content_encoding' => 'shortstr',
'application_headers' => 'table_object',
'delivery_mode' => 'octet',
'priority' => 'octet',
'correlation_id' => 'shortstr',
'reply_to' => 'shortstr',
'expiration' => 'shortstr',
'message_id' => 'shortstr',
'timestamp' => 'timestamp',
'type' => 'shortstr',
'user_id' => 'shortstr',
'app_id' => 'shortstr',
'cluster_id' => 'shortstr',
);





public function __construct($body = '', $properties = array())
{
$this->setBody($body);

if (!empty($properties) && is_array($properties)) {
$this->properties = array_intersect_key($properties, self::$propertyDefinitions);
}
}









public function ack($multiple = false)
{
$this->assertUnacked();
$this->channel->basic_ack($this->deliveryTag, $multiple);
$this->onResponse();
}











public function nack($requeue = false, $multiple = false)
{
$this->assertUnacked();
$this->channel->basic_nack($this->deliveryTag, $multiple, $requeue);
$this->onResponse();
}









public function reject($requeue = true)
{
$this->assertUnacked();
$this->channel->basic_reject($this->deliveryTag, $requeue);
$this->onResponse();
}




protected function assertUnacked()
{
if (!$this->channel || $this->responded) {
throw new \LogicException('Message is not published or response was already sent');
}
}

protected function onResponse()
{
$this->responded = true;
}





public function getChannel()
{
return $this->channel;
}







public function setChannel($channel)
{
if ($this->channel) {
throw new \RuntimeException('A message is already assigned to channel');
}
$this->channel = $channel;
$this->delivery_info['channel'] = $channel;

return $this;
}









public function setDeliveryInfo($deliveryTag, $redelivered, $exchange, $routingKey)
{
$this->deliveryTag = $this->delivery_info['delivery_tag'] = $deliveryTag;
$this->redelivered = $this->delivery_info['redelivered'] = $redelivered;
$this->exchange = $this->delivery_info['exchange'] = $exchange;
$this->routingKey = $this->delivery_info['routing_key'] = $routingKey;

return $this;
}





public function isRedelivered()
{
return $this->redelivered;
}





public function getExchange()
{
return $this->exchange;
}





public function getRoutingKey()
{
return $this->routingKey;
}





public function getConsumerTag()
{
return $this->consumerTag;
}






public function setConsumerTag($consumerTag)
{
$this->consumerTag = $consumerTag;
$this->delivery_info['consumer_tag'] = $consumerTag;

return $this;
}





public function getMessageCount()
{
return $this->messageCount;
}






public function setMessageCount($messageCount)
{
$this->messageCount = (int)$messageCount;
$this->delivery_info['message_count'] = $this->messageCount;

return $this;
}




public function getBody()
{
return $this->body;
}







public function setBody($body)
{
$this->body = $body;

return $this;
}




public function getContentEncoding()
{
return $this->content_encoding;
}




public function getBodySize()
{
return $this->body_size;
}





public function setBodySize($body_size)
{
$this->body_size = (int)$body_size;

return $this;
}




public function isTruncated()
{
return $this->is_truncated;
}





public function setIsTruncated($is_truncated)
{
$this->is_truncated = (bool)$is_truncated;

return $this;
}






public function setDeliveryTag($deliveryTag)
{
if (!empty($this->deliveryTag)) {
throw new \LogicException('Delivery tag cannot be changed');
}
$this->deliveryTag = $deliveryTag;
$this->delivery_info['delivery_tag'] = $deliveryTag;

return $this;
}






public function getDeliveryTag()
{
if (empty($this->deliveryTag)) {
throw new AMQPEmptyDeliveryTagException('This message was not delivered yet');
}

return $this->deliveryTag;
}








public function has($name)
{
return isset($this->properties[$name]) || isset($this->delivery_info[$name]);
}









public function get($name)
{
if (isset($this->properties[$name])) {
return $this->properties[$name];
}

if (isset($this->delivery_info[$name])) {
return $this->delivery_info[$name];
}

throw new \OutOfBoundsException(sprintf(
'No "%s" property',
$name
));
}






public function get_properties()
{
return $this->properties;
}








public function set($name, $value)
{
if (!array_key_exists($name, self::$propertyDefinitions)) {
throw new \OutOfBoundsException(sprintf(
'No "%s" property',
$name
));
}

if (isset($this->properties[$name]) && $this->properties[$name] === $value) {

 return;
}

$this->properties[$name] = $value;
$this->serialized_properties = null;
}











public function load_properties(AMQPReader $reader)
{

 $flags = array();

while (true) {
$flag_bits = $reader->read_short();
$flags[] = $flag_bits;

if (($flag_bits & 1) === 0) {
break;
}
}

$shift = 0;
$data = array();

foreach (self::$propertyDefinitions as $key => $proptype) {
if ($shift === 0) {
if (!$flags) {
break;
}
$flag_bits = array_shift($flags);
$shift = 15;
}

if ($flag_bits & (1 << $shift)) {
$data[$key] = $reader->{'read_' . $proptype}();
}

$shift -= 1;
}

$this->properties = $data;

return $this;
}










public function serialize_properties()
{
if (!empty($this->serialized_properties)) {
return $this->serialized_properties;
}

$shift = 15;
$flag_bits = 0;
$flags = array();
$raw_bytes = new AMQPWriter();

foreach (self::$propertyDefinitions as $key => $prototype) {
$val = isset($this->properties[$key]) ? $this->properties[$key] : null;


 
 if ($val === null) {
$shift -= 1;
continue;
}

if ($shift === 0) {
$flags[] = $flag_bits;
$flag_bits = 0;
$shift = 15;
}

$flag_bits |= (1 << $shift);
if ($prototype !== 'bit') {
$raw_bytes->{'write_' . $prototype}($val);
}

$shift -= 1;
}

$flags[] = $flag_bits;
$result = new AMQPWriter();
foreach ($flags as $flag_bits) {
$result->write_short($flag_bits);
}

$result->write($raw_bytes->getvalue());

$this->serialized_properties = $result->getvalue();

return $this->serialized_properties;
}
}
<?php

namespace PhpAmqpLib\Connection;

use PhpAmqpLib\Channel\AbstractChannel;
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Exception\AMQPConnectionClosedException;
use PhpAmqpLib\Exception\AMQPHeartbeatMissedException;
use PhpAmqpLib\Exception\AMQPInvalidFrameException;
use PhpAmqpLib\Exception\AMQPIOException;
use PhpAmqpLib\Exception\AMQPNoDataException;
use PhpAmqpLib\Exception\AMQPRuntimeException;
use PhpAmqpLib\Exception\AMQPSocketException;
use PhpAmqpLib\Exception\AMQPTimeoutException;
use PhpAmqpLib\Helper\Assert;
use PhpAmqpLib\Package;
use PhpAmqpLib\Wire;
use PhpAmqpLib\Wire\AMQPReader;
use PhpAmqpLib\Wire\AMQPTable;
use PhpAmqpLib\Wire\AMQPWriter;
use PhpAmqpLib\Wire\IO\AbstractIO;

abstract class AbstractConnection extends AbstractChannel
{




public static $LIBRARY_PROPERTIES = array(
'product' => array('S', Package::NAME),
'platform' => array('S', 'PHP'),
'version' => array('S', Package::VERSION),
'information' => array('S', ''),
'copyright' => array('S', ''),
'capabilities' => array(
'F',
array(
'authentication_failure_close' => array('t', true),
'publisher_confirms' => array('t', true),
'consumer_cancel_notify' => array('t', true),
'exchange_exchange_bindings' => array('t', true),
'basic.nack' => array('t', true),
'connection.blocked' => array('t', true)
)
)
);





public $channels = array();


protected $version_major;


protected $version_minor;


protected $server_properties;


protected $mechanisms;


protected $locales;


protected $wait_tune_ok;


protected $known_hosts;


protected $input;


protected $vhost;


protected $insist;


protected $login_method;





protected $login_response;


protected $locale;


protected $heartbeat;


protected $last_frame;


protected $channel_max = 65535;


protected $frame_max = 131072;


protected $construct_params;


protected $close_on_destruct = true;


protected $is_connected = false;


protected $io;


protected $wait_frame_reader;


private $connection_block_handler;


private $connection_unblock_handler;


protected $connection_timeout ;








private $prepare_content_cache = array();


private $prepare_content_cache_max_size = 100;





private $channel_rpc_timeout;





protected $blocked = false;





protected $writing = false;















public function __construct(
$user,
$password,
$vhost = '/',
$insist = false,
$login_method = 'AMQPLAIN',
$login_response = null,
$locale = 'en_US',
AbstractIO $io = null,
$heartbeat = 0,
$connection_timeout = 0,
$channel_rpc_timeout = 0.0
) {
if (is_null($io)) {
throw new \InvalidArgumentException('Argument $io cannot be null');
}


 $this->construct_params = func_get_args();

$this->wait_frame_reader = new AMQPReader(null);
$this->vhost = $vhost;
$this->insist = $insist;
$this->login_method = $login_method;
$this->locale = $locale;
$this->io = $io;
$this->heartbeat = $heartbeat;
$this->connection_timeout = $connection_timeout;
$this->channel_rpc_timeout = $channel_rpc_timeout;

if ($user && $password) {
if ($login_method === 'PLAIN') {
$this->login_response = sprintf("\0%s\0%s", $user, $password);
} elseif ($login_method === 'AMQPLAIN') {
$login_response = new AMQPWriter();
$login_response->write_table(array(
'LOGIN' => array('S', $user),
'PASSWORD' => array('S', $password)
));


 $responseValue = $login_response->getvalue();
$this->login_response = mb_substr($responseValue, 4, mb_strlen($responseValue, 'ASCII') - 4, 'ASCII');
} else {
throw new \InvalidArgumentException('Unknown login method: ' . $login_method);
}
} else {
$this->login_response = null;
}


 if ($this->connectOnConstruct()) {
$this->connect();
}
}




protected function connect()
{
$this->blocked = false;
try {

 while (!$this->isConnected()) {

 $this->setIsConnected(true);


 $this->io->connect();

$this->channels = array();

 parent::__construct($this, 0);

$this->input = new AMQPReader(null, $this->io);

$this->write($this->constants->getHeader());

 $this->last_frame = microtime(true);
$this->wait(array($this->waitHelper->get_wait('connection.start')), false, $this->connection_timeout);
$this->x_start_ok(
$this->getLibraryProperties(),
$this->login_method,
$this->login_response,
$this->locale
);

$this->wait_tune_ok = true;
while ($this->wait_tune_ok) {
$this->wait(array(
$this->waitHelper->get_wait('connection.secure'),
$this->waitHelper->get_wait('connection.tune')
), false, $this->connection_timeout);
}

$host = $this->x_open($this->vhost, '', $this->insist);
if (!$host) {

 $this->io->reenableHeartbeat();
return null; 
 }

$this->setIsConnected(false);
$this->closeChannels();


 $this->close_socket();
}
} catch (\Exception $e) {

 $this->setIsConnected(false);
$this->closeChannels();
$this->close_input();
$this->close_socket();
throw $e; 
 }
}





public function reconnect()
{

 $this->safeClose();

 $this->io->close();

 $this->setIsConnected(false);
$this->connect();
}




public function __clone()
{
call_user_func_array(array($this, '__construct'), $this->construct_params);
}

public function __destruct()
{
if ($this->close_on_destruct) {
$this->safeClose();
}
}




protected function safeClose()
{
try {
if (null !== $this->input) {
$this->close();
}
} catch (\Exception $e) {

 }
}










public function select(?int $sec, int $usec = 0): int
{
try {
return $this->io->select($sec, $usec);
} catch (AMQPConnectionClosedException $e) {
$this->do_close();
throw $e;
} catch (AMQPRuntimeException $e) {
$this->setIsConnected(false);
throw $e;
}
}







public function set_close_on_destruct($close = true)
{
$this->close_on_destruct = (bool) $close;
}

protected function close_input()
{
$this->debug && $this->debug->debug_msg('closing input');

if (null !== $this->input) {
$this->input->close();
$this->input = null;
}
}

protected function close_socket()
{
$this->debug && $this->debug->debug_msg('closing socket');
$this->io->close();
}




public function write($data)
{
$this->debug->debug_hexdump($data);

try {
$this->writing = true;
$this->io->write($data);
} catch (AMQPConnectionClosedException $e) {
$this->do_close();
throw $e;
} catch (AMQPRuntimeException $e) {
$this->setIsConnected(false);
throw $e;
} finally {
$this->writing = false;
}
}

protected function do_close()
{
$this->frame_queue = [];
$this->method_queue = [];
$this->setIsConnected(false);
$this->close_input();
$this->close_socket();
}





public function get_free_channel_id()
{
for ($i = 1; $i <= $this->channel_max; $i++) {
if (!isset($this->channels[$i])) {
return $i;
}
}

throw new AMQPRuntimeException('No free channel ids');
}










public function send_content($channel, $class_id, $weight, $body_size, $packed_properties, $body, $pkt)
{
$this->prepare_content($channel, $class_id, $weight, $body_size, $packed_properties, $body, $pkt);
$this->write($pkt->getvalue());
}













public function prepare_content($channel, $class_id, $weight, $body_size, $packed_properties, $body, $pkt)
{
$pkt = $pkt ?: new AMQPWriter();


 $key_cache = sprintf(
'%s|%s|%s|%s',
$channel,
$packed_properties,
$class_id,
$weight
);

if (!isset($this->prepare_content_cache[$key_cache])) {
$w = new AMQPWriter();
$w->write_octet(2);
$w->write_short($channel);
$w->write_long(mb_strlen($packed_properties, 'ASCII') + 12);
$w->write_short($class_id);
$w->write_short($weight);
$this->prepare_content_cache[$key_cache] = $w->getvalue();
if (count($this->prepare_content_cache) > $this->prepare_content_cache_max_size) {
reset($this->prepare_content_cache);
$old_key = key($this->prepare_content_cache);
unset($this->prepare_content_cache[$old_key]);
}
}
$pkt->write($this->prepare_content_cache[$key_cache]);

$pkt->write_longlong($body_size);
$pkt->write($packed_properties);

$pkt->write_octet(0xCE);



 
 
 $position = 0;
$bodyLength = mb_strlen($body, 'ASCII');
while ($position < $bodyLength) {
$payload = mb_substr($body, $position, $this->frame_max - 8, 'ASCII');
$position += $this->frame_max - 8;

$pkt->write_octet(3);
$pkt->write_short($channel);
$pkt->write_long(mb_strlen($payload, 'ASCII'));

$pkt->write($payload);

$pkt->write_octet(0xCE);
}

return $pkt;
}







protected function send_channel_method_frame($channel, $method_sig, $args = '', $pkt = null)
{
$pkt = $this->prepare_channel_method_frame($channel, $method_sig, $args, $pkt);
$this->write($pkt->getvalue());
$this->debug->debug_method_signature1($method_sig);
}










protected function prepare_channel_method_frame($channel, $method_sig, $args = '', $pkt = null)
{
if ($args instanceof AMQPWriter) {
$args = $args->getvalue();
}

$pkt = $pkt ?: new AMQPWriter();

$pkt->write_octet(1);
$pkt->write_short($channel);
$pkt->write_long(mb_strlen($args, 'ASCII') + 4); 
 

$pkt->write_short($method_sig[0]); 
 $pkt->write_short($method_sig[1]); 
 $pkt->write($args);

$pkt->write_octet(0xCE);

$this->debug->debug_method_signature1($method_sig);

return $pkt;
}










protected function wait_frame($timeout = 0)
{
if (null === $this->input) {
$this->setIsConnected(false);
throw new AMQPConnectionClosedException('Broken pipe or closed connection');
}

$currentTimeout = $this->input->getTimeout();
$this->input->setTimeout($timeout);

try {

 $this->wait_frame_reader->reuse(
$this->input->read(AMQPReader::OCTET + AMQPReader::SHORT + AMQPReader::LONG)
);

$frame_type = $this->wait_frame_reader->read_octet();
if (!$this->constants->isFrameType($frame_type)) {
throw new AMQPInvalidFrameException('Invalid frame type ' . $frame_type);
}
$channel = $this->wait_frame_reader->read_short();
$size = $this->wait_frame_reader->read_long();


 $this->wait_frame_reader->reuse($this->input->read(AMQPReader::OCTET + (int) $size));

$payload = $this->wait_frame_reader->read($size);
$ch = $this->wait_frame_reader->read_octet();
} catch (AMQPTimeoutException $e) {
if ($this->input) {
$this->input->setTimeout($currentTimeout);
}
throw $e;
} catch (AMQPNoDataException $e) {
if ($this->input) {
$this->input->setTimeout($currentTimeout);
}
throw $e;
} catch (AMQPConnectionClosedException $exception) {
$this->do_close();
throw $exception;
}

$this->input->setTimeout($currentTimeout);

if ($ch !== 0xCE) {
throw new AMQPInvalidFrameException(sprintf(
'Framing error, unexpected byte: %x',
$ch
));
}

return array($frame_type, $channel, $payload);
}








protected function wait_channel($channel_id, $timeout = 0)
{

 $_timeout = $timeout;
while (true) {
$start = microtime(true);
try {
list($frame_type, $frame_channel, $payload) = $this->wait_frame($_timeout);
} catch (AMQPTimeoutException $e) {
if (
$this->heartbeat && $this->last_frame
&& microtime(true) - ($this->heartbeat * 2) > $this->last_frame
) {
$this->debug->debug_msg('missed server heartbeat (at threshold * 2)');
$this->setIsConnected(false);
throw new AMQPHeartbeatMissedException('Missed server heartbeat');
}

throw $e;
}

$this->last_frame = microtime(true);

if ($frame_channel === 0 && $frame_type === 8) {

 $this->debug->debug_msg('received server heartbeat');
if ($_timeout > 0) {
$_timeout -= $this->last_frame - $start;
if ($_timeout <= 0) {

 throw new AMQPTimeoutException('Timeout waiting on channel');
}
}
continue;
}

if ($frame_channel === $channel_id) {
return array($frame_type, $payload);
}


 
 
 
 if (isset($this->channels[$frame_channel])) {
$this->channels[$frame_channel]->frame_queue[] = [$frame_type, $payload];
}


 
 
 if ($frame_type === 1 && $frame_channel === 0) {
$this->wait();
}
}
}








public function channel($channel_id = null)
{
if (isset($this->channels[$channel_id])) {
return $this->channels[$channel_id];
}

$channel_id = $channel_id ?: $this->get_free_channel_id();
$ch = new AMQPChannel($this, $channel_id, true, $this->channel_rpc_timeout);
$this->channels[$channel_id] = $ch;

return $ch;
}









public function close($reply_code = 0, $reply_text = '', $method_sig = array(0, 0))
{
$this->io->disableHeartbeat();
if (empty($this->protocolWriter) || !$this->isConnected()) {
return null;
}

$result = null;
try {
$this->closeChannels();
list($class_id, $method_id, $args) = $this->protocolWriter->connectionClose(
$reply_code,
$reply_text,
$method_sig[0],
$method_sig[1]
);
$this->send_method_frame(array($class_id, $method_id), $args);
$result = $this->wait(
array($this->waitHelper->get_wait('connection.close_ok')),
false,
$this->connection_timeout
);
} catch (\Exception $exception) {
$this->do_close();
throw $exception;
}

$this->setIsConnected(false);

return $result;
}





protected function connection_close(AMQPReader $reader)
{
$code = (int)$reader->read_short();
$reason = $reader->read_shortstr();
$class = $reader->read_short();
$method = $reader->read_short();
$reason .= sprintf('(%s, %s)', $class, $method);

$this->x_close_ok();

throw new AMQPConnectionClosedException($reason, $code);
}




protected function x_close_ok()
{
$this->send_method_frame(
explode(',', $this->waitHelper->get_wait('connection.close_ok'))
);
$this->do_close();
}




protected function connection_close_ok()
{
$this->do_close();
}







protected function x_open($virtual_host, $capabilities = '', $insist = false)
{
$args = new AMQPWriter();
$args->write_shortstr($virtual_host);
$args->write_shortstr($capabilities);
$args->write_bits(array($insist));
$this->send_method_frame(array(10, 40), $args);

$wait = array(
$this->waitHelper->get_wait('connection.open_ok')
);

if ($this->protocolVersion === Wire\Constants080::VERSION) {
$wait[] = $this->waitHelper->get_wait('connection.redirect');
}

return $this->wait($wait, false, $this->connection_timeout);
}






protected function connection_open_ok($args)
{
$this->known_hosts = $args->read_shortstr();
$this->debug->debug_msg('Open OK! known_hosts: ' . $this->known_hosts);
}







protected function connection_redirect($args)
{
$host = $args->read_shortstr();
$this->known_hosts = $args->read_shortstr();
$this->debug->debug_msg(sprintf(
'Redirected to [%s], known_hosts [%s]',
$host,
$this->known_hosts
));

return $host;
}






protected function connection_secure($args)
{
$args->read_longstr();
}






protected function x_secure_ok($response)
{
$args = new AMQPWriter();
$args->write_longstr($response);
$this->send_method_frame(array(10, 21), $args);
}






protected function connection_start($args)
{
$this->version_major = $args->read_octet();
$this->version_minor = $args->read_octet();
$this->server_properties = $args->read_table();
$this->mechanisms = explode(' ', $args->read_longstr());
$this->locales = explode(' ', $args->read_longstr());

$this->debug->debug_connection_start(
$this->version_major,
$this->version_minor,
$this->server_properties,
$this->mechanisms,
$this->locales
);
}







protected function x_start_ok($clientProperties, $mechanism, $response, $locale)
{
$args = new AMQPWriter();
$args->write_table($clientProperties);
$args->write_shortstr($mechanism);
$args->write_longstr($response);
$args->write_shortstr($locale);
$this->send_method_frame(array(10, 11), $args);
}






protected function connection_tune($args)
{
$v = $args->read_short();
if ($v) {
$this->channel_max = $v;
}

$v = $args->read_long();
if ($v) {
$this->frame_max = (int)$v;
}


 if ($this->heartbeat === null) {
$this->heartbeat = $args->read_short();
}

$this->x_tune_ok($this->channel_max, $this->frame_max, $this->heartbeat);
}








protected function x_tune_ok($channel_max, $frame_max, $heartbeat)
{
$args = new AMQPWriter();
$args->write_short($channel_max);
$args->write_long($frame_max);
$args->write_short($heartbeat);
$this->send_method_frame(array(10, 31), $args);
$this->wait_tune_ok = false;
}





public function getIO()
{
return $this->io;
}









public function checkHeartBeat()
{
$this->io->check_heartbeat();
}




public function getLastActivity()
{
return $this->io->getLastActivity();
}






protected function connection_blocked(AMQPReader $args)
{
$this->blocked = true;

 $this->dispatch_to_handler($this->connection_block_handler, array($args->read_shortstr()));
}




protected function connection_unblocked()
{
$this->blocked = false;

 $this->dispatch_to_handler($this->connection_unblock_handler);
}







public function set_connection_block_handler($callback)
{
Assert::isCallable($callback);
$this->connection_block_handler = $callback;
}







public function set_connection_unblock_handler($callback)
{
Assert::isCallable($callback);
$this->connection_unblock_handler = $callback;
}






public function isConnected()
{
return $this->is_connected;
}






public function isBlocked()
{
return $this->blocked;
}





public function isWriting()
{
return $this->writing;
}






protected function setIsConnected($is_connected)
{
$this->is_connected = (bool) $is_connected;
}




protected function closeChannels()
{
foreach ($this->channels as $key => $channel) {

 if ($key === 0) {
continue;
}
try {
$channel->close();
} catch (\Exception $e) {

}
}
}






public function connectOnConstruct()
{
return true;
}




public function getServerProperties()
{
return $this->server_properties;
}




public function getHeartbeat()
{
return $this->heartbeat;
}






public function getLibraryProperties()
{
return self::$LIBRARY_PROPERTIES;
}








public static function create_connection($hosts, $options = array())
{
if (!is_array($hosts) || count($hosts) < 1) {
throw new \InvalidArgumentException(
'An array of hosts are required when attempting to create a connection'
);
}

foreach ($hosts as $hostdef) {
self::validate_host($hostdef);
$host = $hostdef['host'];
$port = $hostdef['port'];
$user = $hostdef['user'];
$password = $hostdef['password'];
$vhost = isset($hostdef['vhost']) ? $hostdef['vhost'] : '/';
try {
$conn = static::try_create_connection($host, $port, $user, $password, $vhost, $options);
return $conn;
} catch (\Exception $e) {
$latest_exception = $e;
}
}
throw $latest_exception;
}

public static function validate_host($host)
{
if (!isset($host['host'])) {
throw new \InvalidArgumentException("'host' key is required.");
}
if (!isset($host['port'])) {
throw new \InvalidArgumentException("'port' key is required.");
}
if (!isset($host['user'])) {
throw new \InvalidArgumentException("'user' key is required.");
}
if (!isset($host['password'])) {
throw new \InvalidArgumentException("'password' key is required.");
}
}
}
<?php

namespace PhpAmqpLib\Connection;

use PhpAmqpLib\Wire\IO\StreamIO;

class AMQPStreamConnection extends AbstractConnection
{


















public function __construct(
$host,
$port,
$user,
$password,
$vhost = '/',
$insist = false,
$login_method = 'AMQPLAIN',
$login_response = null,
$locale = 'en_US',
$connection_timeout = 3.0,
$read_write_timeout = 3.0,
$context = null,
$keepalive = false,
$heartbeat = 0,
$channel_rpc_timeout = 0.0,
$ssl_protocol = null
) {
if ($channel_rpc_timeout > $read_write_timeout) {
throw new \InvalidArgumentException('channel RPC timeout must not be greater than I/O read-write timeout');
}

$io = new StreamIO(
$host,
$port,
$connection_timeout,
$read_write_timeout,
$context,
$keepalive,
$heartbeat,
$ssl_protocol
);

parent::__construct(
$user,
$password,
$vhost,
$insist,
$login_method,
$login_response,
$locale,
$io,
$heartbeat,
$connection_timeout,
$channel_rpc_timeout
);


 $this->construct_params = func_get_args();
}

protected static function try_create_connection($host, $port, $user, $password, $vhost, $options)
{
$insist = isset($options['insist']) ?
$options['insist'] : false;
$login_method = isset($options['login_method']) ?
$options['login_method'] : 'AMQPLAIN';
$login_response = isset($options['login_response']) ?
$options['login_response'] : null;
$locale = isset($options['locale']) ?
$options['locale'] : 'en_US';
$connection_timeout = isset($options['connection_timeout']) ?
$options['connection_timeout'] : 3.0;
$read_write_timeout = isset($options['read_write_timeout']) ?
$options['read_write_timeout'] : 3.0;
$context = isset($options['context']) ?
$options['context'] : null;
$keepalive = isset($options['keepalive']) ?
$options['keepalive'] : false;
$heartbeat = isset($options['heartbeat']) ?
$options['heartbeat'] : 60;
return new static(
$host,
$port,
$user,
$password,
$vhost,
$insist,
$login_method,
$login_response,
$locale,
$connection_timeout,
$read_write_timeout,
$context,
$keepalive,
$heartbeat
);
}
}
<?php

namespace PhpAmqpLib\Connection\Heartbeat;

use PhpAmqpLib\Connection\AbstractConnection;
use PhpAmqpLib\Exception\AMQPRuntimeException;




final class PCNTLHeartbeatSender
{



private $connection;





public function __construct(AbstractConnection $connection)
{
if (!$this->isSupported()) {
throw new AMQPRuntimeException('Signal-based heartbeat sender is unsupported');
}

$this->connection = $connection;
}

public function __destruct()
{
$this->unregister();
}




private function isSupported()
{
return extension_loaded('pcntl')
&& function_exists('pcntl_async_signals')
&& (defined('AMQP_WITHOUT_SIGNALS') ? !AMQP_WITHOUT_SIGNALS : true);
}

public function register()
{
if (!$this->connection) {
throw new AMQPRuntimeException('Unable to re-register heartbeat sender');
}

if (!$this->connection->isConnected()) {
throw new AMQPRuntimeException('Unable to register heartbeat sender, connection is not active');
}

$timeout = $this->connection->getHeartbeat();

if ($timeout > 0) {
$interval = ceil($timeout / 2);
pcntl_async_signals(true);
$this->registerListener($interval);
pcntl_alarm($interval);
}
}

public function unregister()
{
$this->connection = null;

 pcntl_signal(SIGALRM, SIG_IGN);
}




private function registerListener($interval)
{
pcntl_signal(SIGALRM, function () use ($interval) {
if (!$this->connection) {
return;
}

if (!$this->connection->isConnected()) {
$this->unregister();
return;
}

if ($this->connection->isWriting()) {
pcntl_alarm($interval);
return;
}

if (time() > ($this->connection->getLastActivity() + $interval)) {
$this->connection->checkHeartBeat();
}

pcntl_alarm($interval);
});
}
}
<?php

namespace PhpAmqpLib\Connection;

use PhpAmqpLib\Wire\IO\SocketIO;

class AMQPSocketConnection extends AbstractConnection
{

















public function __construct(
$host,
$port,
$user,
$password,
$vhost = '/',
$insist = false,
$login_method = 'AMQPLAIN',
$login_response = null,
$locale = 'en_US',
$read_timeout = 3,
$keepalive = false,
$write_timeout = 3,
$heartbeat = 0,
$channel_rpc_timeout = 0.0
) {
if ($channel_rpc_timeout > $read_timeout) {
throw new \InvalidArgumentException('channel RPC timeout must not be greater than I/O read timeout');
}

$io = new SocketIO($host, $port, $read_timeout, $keepalive, $write_timeout, $heartbeat);

parent::__construct(
$user,
$password,
$vhost,
$insist,
$login_method,
$login_response,
$locale,
$io,
$heartbeat,
max($read_timeout, $write_timeout),
$channel_rpc_timeout
);
}

protected static function try_create_connection($host, $port, $user, $password, $vhost, $options)
{
$insist = isset($options['insist']) ?
$options['insist'] : false;
$login_method = isset($options['login_method']) ?
$options['login_method'] : 'AMQPLAIN';
$login_response = isset($options['login_response']) ?
$options['login_response'] : null;
$locale = isset($options['locale']) ?
$options['locale'] : 'en_US';
$read_timeout = isset($options['read_timeout']) ?
$options['read_timeout'] : 3;
$keepalive = isset($options['keepalive']) ?
$options['keepalive'] : false;
$write_timeout = isset($options['write_timeout']) ?
$options['write_timeout'] : 3;
$heartbeat = isset($options['heartbeat']) ?
$options['heartbeat'] : 0;
return new static(
$host,
$port,
$user,
$password,
$vhost,
$insist,
$login_method,
$login_response,
$locale,
$read_timeout,
$keepalive,
$write_timeout,
$heartbeat
);
}
}
<?php

namespace PhpAmqpLib\Connection;

class AMQPLazySSLConnection extends AMQPSSLConnection
{



public function channel($channel_id = null)
{
$this->connect();

return parent::channel($channel_id);
}




public function getIO()
{
if (empty($this->io)) {
$this->connect();
}

return $this->io;
}






public function connectOnConstruct()
{
return false;
}







public static function create_connection($hosts, $options = array())
{
if (count($hosts) > 1) {
throw new \RuntimeException('Lazy connection does not support multiple hosts');
}

return parent::create_connection($hosts, $options);
}
}
<?php

namespace PhpAmqpLib\Connection;




class AMQPLazySocketConnection extends AMQPSocketConnection
{



public function channel($channel_id = null)
{
$this->connect();

return parent::channel($channel_id);
}




public function getIO()
{
if (empty($this->io)) {
$this->connect();
}

return $this->io;
}






public function connectOnConstruct()
{
return false;
}







public static function create_connection($hosts, $options = array())
{
if (count($hosts) > 1) {
throw new \RuntimeException('Lazy connection does not support multiple hosts');
}

return parent::create_connection($hosts, $options);
}
}
<?php

namespace PhpAmqpLib\Connection;

class AMQPSSLConnection extends AMQPStreamConnection
{










public function __construct(
$host,
$port,
$user,
$password,
$vhost = '/',
$ssl_options = array(),
$options = array(),
$ssl_protocol = 'ssl'
) {
$ssl_context = empty($ssl_options) ? null : $this->createSslContext($ssl_options);
parent::__construct(
$host,
$port,
$user,
$password,
$vhost,
isset($options['insist']) ? $options['insist'] : false,
isset($options['login_method']) ? $options['login_method'] : 'AMQPLAIN',
isset($options['login_response']) ? $options['login_response'] : null,
isset($options['locale']) ? $options['locale'] : 'en_US',
isset($options['connection_timeout']) ? $options['connection_timeout'] : 3,
isset($options['read_write_timeout']) ? $options['read_write_timeout'] : 130,
$ssl_context,
isset($options['keepalive']) ? $options['keepalive'] : false,
isset($options['heartbeat']) ? $options['heartbeat'] : 0,
isset($options['channel_rpc_timeout']) ? $options['channel_rpc_timeout'] : 0.0,
$ssl_protocol
);
}

public static function try_create_connection($host, $port, $user, $password, $vhost, $options)
{
$ssl_options = isset($options['ssl_options']) ? $options['ssl_options'] : [];
return new static($host, $port, $user, $password, $vhost, $ssl_options, $options);
}





private function createSslContext($options)
{
$ssl_context = stream_context_create();
foreach ($options as $k => $v) {
stream_context_set_option($ssl_context, 'ssl', $k, $v);
}

return $ssl_context;
}
}
<?php

namespace PhpAmqpLib\Connection;

class AMQPLazyConnection extends AMQPStreamConnection
{



public function channel($channel_id = null)
{
$this->connect();

return parent::channel($channel_id);
}




public function getIO()
{
if (empty($this->io)) {
$this->connect();
}

return $this->io;
}






public function connectOnConstruct()
{
return false;
}







public static function create_connection($hosts, $options = array())
{
if (count($hosts) > 1) {
throw new \RuntimeException('Lazy connection does not support multiple hosts');
}

return parent::create_connection($hosts, $options);
}
}
<?php

namespace PhpAmqpLib\Wire;

use PhpAmqpLib\Helper\BigInteger;

class AbstractClient
{

const PLATFORM_64BIT = PHP_INT_SIZE === 8;


protected static $bigIntegers = array();




protected static $isLittleEndian;







protected function correctEndianness($bytes)
{
return self::isLittleEndian() ? $this->convertByteOrder($bytes) : $bytes;
}





protected function convertByteOrder($bytes)
{
return strrev($bytes);
}





protected function getLongMSB($longInt)
{
return (bool) ($longInt & 0x80000000);
}





protected function getMSB($bytes)
{
return ord($bytes[0]) > 127;
}




protected static function isLittleEndian()
{
if (self::$isLittleEndian === null) {
$tmp = unpack('S', "\x01\x00"); 
 self::$isLittleEndian = $tmp[1] === 1;
}

return self::$isLittleEndian;
}






protected static function getBigInteger($value, $base = 10)
{
if (!isset(self::$bigIntegers[$base])) {
self::$bigIntegers[$base] = array();
}
if (isset(self::$bigIntegers[$base][$value])) {
return self::$bigIntegers[$base][$value];
}

$integer = new BigInteger($value, $base);
self::$bigIntegers[$base][$value] = $integer;

return $integer;
}
}
<?php

namespace PhpAmqpLib\Wire;

class AMQPArray extends AMQPAbstractCollection
{




public function __construct(array $data = null)
{
parent::__construct(empty($data) ? null : array_values($data));
}




final public function getType()
{
return self::T_ARRAY;
}






public function push($val, $type = null)
{
$this->setValue($val, $type);

return $this;
}
}
<?php



namespace PhpAmqpLib\Wire;

final class Constants080 extends Constants
{
const VERSION = '8.0';
const AMQP_HEADER = "AMQP\x01\x01\x08\x00";




public static $FRAME_TYPES = array(
1 => 'FRAME-METHOD',
2 => 'FRAME-HEADER',
3 => 'FRAME-BODY',
4 => 'FRAME-OOB-METHOD',
5 => 'FRAME-OOB-HEADER',
6 => 'FRAME-OOB-BODY',
7 => 'FRAME-TRACE',
8 => 'FRAME-HEARTBEAT',
4096 => 'FRAME-MIN-SIZE',
206 => 'FRAME-END',
501 => 'FRAME-ERROR',
);




public static $CONTENT_METHODS = array(
0 => '60,40',
1 => '60,50',
2 => '60,60',
3 => '60,71',
4 => '70,50',
5 => '70,70',
6 => '80,40',
7 => '80,50',
8 => '80,60',
9 => '110,10',
10 => '120,40',
11 => '120,41',
);




public static $CLOSE_METHODS = array(
0 => '10,60',
1 => '20,40',
);




public static $GLOBAL_METHOD_NAMES = array(
'10,10' => 'Connection.start',
'10,11' => 'Connection.start_ok',
'10,20' => 'Connection.secure',
'10,21' => 'Connection.secure_ok',
'10,30' => 'Connection.tune',
'10,31' => 'Connection.tune_ok',
'10,40' => 'Connection.open',
'10,41' => 'Connection.open_ok',
'10,50' => 'Connection.redirect',
'10,60' => 'Connection.close',
'10,61' => 'Connection.close_ok',
'20,10' => 'Channel.open',
'20,11' => 'Channel.open_ok',
'20,20' => 'Channel.flow',
'20,21' => 'Channel.flow_ok',
'20,30' => 'Channel.alert',
'20,40' => 'Channel.close',
'20,41' => 'Channel.close_ok',
'30,10' => 'Access.request',
'30,11' => 'Access.request_ok',
'40,10' => 'Exchange.declare',
'40,11' => 'Exchange.declare_ok',
'40,20' => 'Exchange.delete',
'40,21' => 'Exchange.delete_ok',
'50,10' => 'Queue.declare',
'50,11' => 'Queue.declare_ok',
'50,20' => 'Queue.bind',
'50,21' => 'Queue.bind_ok',
'50,30' => 'Queue.purge',
'50,31' => 'Queue.purge_ok',
'50,40' => 'Queue.delete',
'50,41' => 'Queue.delete_ok',
'50,50' => 'Queue.unbind',
'50,51' => 'Queue.unbind_ok',
'60,10' => 'Basic.qos',
'60,11' => 'Basic.qos_ok',
'60,20' => 'Basic.consume',
'60,21' => 'Basic.consume_ok',
'60,30' => 'Basic.cancel',
'60,31' => 'Basic.cancel_ok',
'60,40' => 'Basic.publish',
'60,50' => 'Basic.return',
'60,60' => 'Basic.deliver',
'60,70' => 'Basic.get',
'60,71' => 'Basic.get_ok',
'60,72' => 'Basic.get_empty',
'60,80' => 'Basic.ack',
'60,90' => 'Basic.reject',
'60,100' => 'Basic.recover_async',
'60,110' => 'Basic.recover',
'60,111' => 'Basic.recover_ok',
'70,10' => 'File.qos',
'70,11' => 'File.qos_ok',
'70,20' => 'File.consume',
'70,21' => 'File.consume_ok',
'70,30' => 'File.cancel',
'70,31' => 'File.cancel_ok',
'70,40' => 'File.open',
'70,41' => 'File.open_ok',
'70,50' => 'File.stage',
'70,60' => 'File.publish',
'70,70' => 'File.return',
'70,80' => 'File.deliver',
'70,90' => 'File.ack',
'70,100' => 'File.reject',
'80,10' => 'Stream.qos',
'80,11' => 'Stream.qos_ok',
'80,20' => 'Stream.consume',
'80,21' => 'Stream.consume_ok',
'80,30' => 'Stream.cancel',
'80,31' => 'Stream.cancel_ok',
'80,40' => 'Stream.publish',
'80,50' => 'Stream.return',
'80,60' => 'Stream.deliver',
'90,10' => 'Tx.select',
'90,11' => 'Tx.select_ok',
'90,20' => 'Tx.commit',
'90,21' => 'Tx.commit_ok',
'90,30' => 'Tx.rollback',
'90,31' => 'Tx.rollback_ok',
'100,10' => 'Dtx.select',
'100,11' => 'Dtx.select_ok',
'100,20' => 'Dtx.start',
'100,21' => 'Dtx.start_ok',
'110,10' => 'Tunnel.request',
'120,10' => 'Test.integer',
'120,11' => 'Test.integer_ok',
'120,20' => 'Test.string',
'120,21' => 'Test.string_ok',
'120,30' => 'Test.table',
'120,31' => 'Test.table_ok',
'120,40' => 'Test.content',
'120,41' => 'Test.content_ok',
);
}
<?php

namespace PhpAmqpLib\Wire;

use PhpAmqpLib\Exception\AMQPInvalidArgumentException;
use PhpAmqpLib\Exception\AMQPOutOfRangeException;
use PhpAmqpLib\Helper\BigInteger;

class AMQPWriter extends AbstractClient
{

protected $out = '';


protected $bits = array();


protected $bitcount = 0;

private function flushbits()
{
if (!empty($this->bits)) {
$this->out .= implode('', array_map('chr', $this->bits));
$this->bits = array();
$this->bitcount = 0;
}
}






public function getvalue()
{

if ($this->bitcount) {
$this->flushbits();
}

return $this->out;
}








public function write($s)
{
$this->out .= $s;

return $this;
}









public function write_bit($b)
{
$b = $b ? 1 : 0;
$shift = $this->bitcount % 8;
$last = $shift === 0 ? 0 : array_pop($this->bits);
$last |= ($b << $shift);
$this->bits[] = $last;
$this->bitcount++;

return $this;
}







public function write_bits($bits)
{
$value = 0;

foreach ($bits as $n => $bit) {
$bit = $bit ? 1 : 0;
$value |= ($bit << $n);
}

$this->out .= chr($value);

return $this;
}








public function write_octet($n)
{
if ($n < 0 || $n > 255) {
throw new AMQPInvalidArgumentException('Octet out of range: ' . $n);
}

$this->out .= chr($n);

return $this;
}





public function write_signed_octet($n)
{
if (($n < -128) || ($n > 127)) {
throw new AMQPInvalidArgumentException('Signed octet out of range: ' . $n);
}

$this->out .= pack('c', $n);

return $this;
}








public function write_short($n)
{
if ($n < 0 || $n > 65535) {
throw new AMQPInvalidArgumentException('Short out of range: ' . $n);
}

$this->out .= pack('n', $n);

return $this;
}





public function write_signed_short($n)
{
if (($n < -32768) || ($n > 32767)) {
throw new AMQPInvalidArgumentException('Signed short out of range: ' . $n);
}

$this->out .= $this->correctEndianness(pack('s', $n));

return $this;
}







public function write_long($n)
{
if (($n < 0) || ($n > 4294967295)) {
throw new AMQPInvalidArgumentException('Long out of range: ' . $n);
}


 if (!self::PLATFORM_64BIT && is_string($n)) {
$n = (float) $n;
}
$this->out .= pack('N', $n);

return $this;
}





private function writeSignedLong($n)
{
if (($n < -2147483648) || ($n > 2147483647)) {
throw new AMQPInvalidArgumentException('Signed long out of range: ' . $n);
}


 $this->out .= $this->correctEndianness(pack('l', $n));

return $this;
}








public function write_longlong($n)
{
if (is_int($n)) {
if ($n < 0) {
throw new AMQPOutOfRangeException('Longlong out of range: ' . $n);
}

if (self::PLATFORM_64BIT) {
$res = pack('J', $n);
$this->out .= $res;
} else {
$this->out .= pack('NN', 0, $n);
}

return $this;
}

$value = new BigInteger($n);
if (
$value->compare(self::getBigInteger('0')) < 0
|| $value->compare(self::getBigInteger('FFFFFFFFFFFFFFFF', 16)) > 0
) {
throw new AMQPInvalidArgumentException('Longlong out of range: ' . $n);
}

$value->setPrecision(64);
$this->out .= $value->toBytes();

return $this;
}





public function write_signed_longlong($n)
{
if (is_int($n)) {
if (self::PLATFORM_64BIT) {

 $packed = pack('q', $n);
if (self::isLittleEndian()) {
$packed = $this->convertByteOrder($packed);
}
$this->out .= $packed;
} else {
$hi = $n < 0 ? -1 : 0;
$lo = $n;
$this->out .= pack('NN', $hi, $lo);
}

return $this;
}

$value = new BigInteger($n);
if (
$value->compare(self::getBigInteger('-8000000000000000', 16)) < 0
|| $value->compare(self::getBigInteger('7FFFFFFFFFFFFFFF', 16)) > 0
) {
throw new AMQPInvalidArgumentException('Signed longlong out of range: ' . $n);
}

$value->setPrecision(64);
$this->out .= substr($value->toBytes(true), -8);

return $this;
}









public function write_shortstr($s)
{
if ($s === null) {
$this->write_octet(0);

return $this;
}

$len = mb_strlen($s, 'ASCII');
if ($len > 255) {
throw new AMQPInvalidArgumentException('String too long');
}

$this->write_octet($len);
$this->out .= $s;

return $this;
}







public function write_longstr($s)
{
if ($s === null) {
$this->write_long(0);

return $this;
}

$this->write_long(mb_strlen($s, 'ASCII'));
$this->out .= $s;

return $this;
}








public function write_array($a)
{
if (!($a instanceof AMQPArray)) {
$a = new AMQPArray($a);
}
$data = new self();

foreach ($a as $v) {
$data->writeValue($v[0], $v[1]);
}

$data = $data->getvalue();
$this->write_long(mb_strlen($data, 'ASCII'));
$this->write($data);

return $this;
}







public function write_timestamp($v)
{
$this->write_longlong($v);

return $this;
}









public function write_table($d)
{
$typeIsSym = !($d instanceof AMQPTable); 

$table_data = new self();
foreach ($d as $k => $va) {
list($ftype, $v) = $va;
$table_data->write_shortstr($k);
$table_data->writeValue($typeIsSym ? AMQPAbstractCollection::getDataTypeForSymbol($ftype) : $ftype, $v);
}

$table_data = $table_data->getvalue();
$this->write_long(mb_strlen($table_data, 'ASCII'));
$this->write($table_data);

return $this;
}







public function write_table_object($d)
{
return $this->write_table($d);
}





private function writeValue($type, $val)
{

 
 $this->write(AMQPAbstractCollection::getSymbolForDataType($type));

switch ($type) {
case AMQPAbstractCollection::T_INT_SHORTSHORT:
$this->write_signed_octet($val);
break;
case AMQPAbstractCollection::T_INT_SHORTSHORT_U:
$this->write_octet($val);
break;
case AMQPAbstractCollection::T_INT_SHORT:
$this->write_signed_short($val);
break;
case AMQPAbstractCollection::T_INT_SHORT_U:
$this->write_short($val);
break;
case AMQPAbstractCollection::T_INT_LONG:
$this->writeSignedLong($val);
break;
case AMQPAbstractCollection::T_INT_LONG_U:
$this->write_long($val);
break;
case AMQPAbstractCollection::T_INT_LONGLONG:
$this->write_signed_longlong($val);
break;
case AMQPAbstractCollection::T_INT_LONGLONG_U:
$this->write_longlong($val);
break;
case AMQPAbstractCollection::T_DECIMAL:
$this->write_octet($val->getE());
$this->writeSignedLong($val->getN());
break;
case AMQPAbstractCollection::T_TIMESTAMP:
$this->write_timestamp($val);
break;
case AMQPAbstractCollection::T_BOOL:
$this->write_octet($val ? 1 : 0);
break;
case AMQPAbstractCollection::T_STRING_SHORT:
$this->write_shortstr($val);
break;
case AMQPAbstractCollection::T_STRING_LONG:
$this->write_longstr($val);
break;
case AMQPAbstractCollection::T_ARRAY:
$this->write_array($val);
break;
case AMQPAbstractCollection::T_TABLE:
$this->write_table($val);
break;
case AMQPAbstractCollection::T_VOID:
break;
case AMQPAbstractCollection::T_BYTES:
$this->write_longstr($val);
break;
default:
throw new AMQPInvalidArgumentException(sprintf(
'Unsupported type "%s"',
$type
));
}
}
}
<?php

namespace PhpAmqpLib\Wire;

use PhpAmqpLib\Channel\AbstractChannel;
use PhpAmqpLib\Exception;
use PhpAmqpLib\Wire;




abstract class AMQPAbstractCollection implements \Iterator, \ArrayAccess
{

 const PROTOCOL_RBT = 'rabbit'; 


 const T_INT_SHORTSHORT = 1;
const T_INT_SHORTSHORT_U = 2;
const T_INT_SHORT = 3;
const T_INT_SHORT_U = 4;
const T_INT_LONG = 5;
const T_INT_LONG_U = 6;
const T_INT_LONGLONG = 7;
const T_INT_LONGLONG_U = 8;

const T_DECIMAL = 9;
const T_TIMESTAMP = 10;
const T_VOID = 11;

const T_BOOL = 12;

const T_STRING_SHORT = 13;
const T_STRING_LONG = 14;

const T_ARRAY = 15;
const T_TABLE = 16;

const T_BYTES = 17;

const T_FLOAT = 18;
const T_DOUBLE = 19;




private static $protocol;







private static $types_080 = array(
self::T_INT_LONG => 'I',
self::T_DECIMAL => 'D',
self::T_TIMESTAMP => 'T',
self::T_STRING_LONG => 'S',
self::T_TABLE => 'F'
);




private static $types_091 = array(
self::T_INT_SHORTSHORT => 'b',
self::T_INT_SHORTSHORT_U => 'B',
self::T_INT_SHORT => 'U',
self::T_INT_SHORT_U => 'u',
self::T_INT_LONG => 'I',
self::T_INT_LONG_U => 'i',
self::T_INT_LONGLONG => 'L',
self::T_INT_LONGLONG_U => 'l',
self::T_FLOAT => 'f',
self::T_DOUBLE => 'd',
self::T_DECIMAL => 'D',
self::T_TIMESTAMP => 'T',
self::T_VOID => 'V',
self::T_BOOL => 't',
self::T_STRING_SHORT => 's',
self::T_STRING_LONG => 'S',
self::T_ARRAY => 'A',
self::T_TABLE => 'F',
self::T_BYTES => 'x',
);




private static $types_rabbit = array(
self::T_INT_SHORTSHORT => 'b',
self::T_INT_SHORTSHORT_U => 'B',
self::T_INT_SHORT => 's',
self::T_INT_SHORT_U => 'u',
self::T_INT_LONG => 'I',
self::T_INT_LONG_U => 'i',
self::T_INT_LONGLONG => 'l',
self::T_FLOAT => 'f',
self::T_DOUBLE => 'd',
self::T_DECIMAL => 'D',
self::T_TIMESTAMP => 'T',
self::T_VOID => 'V',
self::T_BOOL => 't',
self::T_STRING_LONG => 'S',
self::T_ARRAY => 'A',
self::T_TABLE => 'F',
self::T_BYTES => 'x',
);




protected $data = array();

public function __construct(array $data = null)
{
if (!empty($data)) {
$this->data = $this->encodeCollection($data);
}
}




abstract public function getType();






final protected function setValue($val, $type = null, $key = null)
{
if ($val instanceof self) {
if ($type && ($type !== $val->getType())) {
throw new Exception\AMQPInvalidArgumentException(
sprintf(
'Attempted to add instance of %s representing type [%s] as mismatching type [%s]',
get_class($val),
$val->getType(),
$type
)
);
}
$type = $val->getType();
} elseif ($type) { 
 switch ($type) {
case self::T_ARRAY:
throw new Exception\AMQPInvalidArgumentException('Arrays must be passed as AMQPArray instance');
case self::T_TABLE:
throw new Exception\AMQPInvalidArgumentException('Tables must be passed as AMQPTable instance');
case self::T_DECIMAL:
if (!($val instanceof AMQPDecimal)) {
throw new Exception\AMQPInvalidArgumentException(
'Decimal values must be instance of AMQPDecimal'
);
}
break;
}
}

if ($type) {
self::checkDataTypeIsSupported($type, false);
$val = array($type, $val);
} else {
$val = $this->encodeValue($val);
}

if ($key === null) {
$this->data[] = $val;
} else {
$this->data[$key] = $val;
}
}




final public function getNativeData()
{
return $this->decodeCollection($this->data);
}





final protected function encodeCollection(array $val)
{
foreach ($val as $k => $v) {
$val[$k] = $this->encodeValue($v);
}

return $val;
}





final protected function decodeCollection(array $val)
{
foreach ($val as $k => $v) {
$val[$k] = $this->decodeValue($v[1], $v[0]);
}

return $val;
}


 public function offsetExists($offset)
{
return isset($this->data[$offset]);
}


 public function offsetGet($offset)
{
$value = isset($this->data[$offset]) ? $this->data[$offset] : null;

return is_array($value) ? $value[1] : $value;
}


 public function offsetSet($offset, $value)
{
$this->setValue($value, null, $offset);
}


 public function offsetUnset($offset)
{
unset($this->data[$offset]);
}






protected function encodeValue($val)
{
if (is_string($val)) {
$val = $this->encodeString($val);
} elseif (is_float($val)) {
$val = $this->encodeFloat($val);
} elseif (is_int($val)) {
$val = $this->encodeInt($val);
} elseif (is_bool($val)) {
$val = $this->encodeBool($val);
} elseif (is_null($val)) {
$val = $this->encodeVoid();
} elseif ($val instanceof \DateTimeInterface) {
$val = array(self::T_TIMESTAMP, $val->getTimestamp());
} elseif ($val instanceof AMQPDecimal) {
$val = array(self::T_DECIMAL, $val);
} elseif ($val instanceof self) {

 self::checkDataTypeIsSupported($val->getType(), false);
$val = array($val->getType(), $val);
} elseif (is_array($val)) {

 
 
 if (self::isProtocol(Wire\Constants080::VERSION)) {

 $val = array(self::T_TABLE, new AMQPTable($val));
} elseif (empty($val) || (array_keys($val) === range(0, count($val) - 1))) {
$val = array(self::T_ARRAY, new AMQPArray($val));
} else {
$val = array(self::T_TABLE, new AMQPTable($val));
}
} else {
throw new Exception\AMQPOutOfBoundsException(
sprintf('Encountered value of unsupported type: %s', gettype($val))
);
}

return $val;
}






protected function decodeValue($val, $type)
{
if ($val instanceof self) {

 $val = $val->getNativeData();
} else {
switch ($type) {
case self::T_BOOL:
$val = (bool) $val;
break;
case self::T_TIMESTAMP:
$val = \DateTime::createFromFormat('U', $val);
break;
case self::T_VOID:
$val = null;
break;
case self::T_ARRAY:
case self::T_TABLE:
throw new Exception\AMQPLogicException(
sprintf(
'%s %s',
'Encountered an array/table struct which is not an instance of AMQPCollection.',
'This is considered a bug and should be fixed, please report'
)
);
}
}

return $val;
}





protected function encodeString($val)
{
return array(self::T_STRING_LONG, $val);
}





protected function encodeInt($val)
{
if (($val >= -2147483648) && ($val <= 2147483647)) {
$ev = array(self::T_INT_LONG, $val);
} elseif (self::isProtocol(Wire\Constants080::VERSION)) {

 $ev = $this->encodeString((string) $val);
} else {
$ev = array(self::T_INT_LONGLONG, $val);
}

return $ev;
}





protected function encodeFloat($val)
{
return $this->encodeString((string) $val);
}





protected function encodeBool($val)
{
$val = (bool) $val;

return self::isProtocol(Wire\Constants080::VERSION)
? array(self::T_INT_LONG, (int) $val)
: array(self::T_BOOL, $val);
}




protected function encodeVoid()
{
return self::isProtocol(Wire\Constants080::VERSION) ? $this->encodeString('') : array(self::T_VOID, null);
}




final public static function getProtocol()
{
if (self::$protocol === null) {
self::$protocol = defined('AMQP_STRICT_FLD_TYPES') && AMQP_STRICT_FLD_TYPES ?
AbstractChannel::getProtocolVersion() :
self::PROTOCOL_RBT;
}

return self::$protocol;
}





final public static function isProtocol($proto)
{
return self::getProtocol() === $proto;
}




final public static function getSupportedDataTypes()
{
switch ($proto = self::getProtocol()) {
case Wire\Constants080::VERSION:
$types = self::$types_080;
break;
case Wire\Constants091::VERSION:
$types = self::$types_091;
break;
case self::PROTOCOL_RBT:
$types = self::$types_rabbit;
break;
default:
throw new Exception\AMQPOutOfRangeException(sprintf('Unknown protocol: %s', $proto));
}

return $types;
}






final public static function checkDataTypeIsSupported($type, $return = true)
{
try {
$supported = self::getSupportedDataTypes();
if (!isset($supported[$type])) {
throw new Exception\AMQPOutOfRangeException(sprintf(
'AMQP-%s doesn\'t support data of type [%s]',
self::getProtocol(),
$type
));
}
return true;
} catch (Exception\AMQPOutOfRangeException $ex) {
if (!$return) {
throw $ex;
}

return false;
}
}





final public static function getSymbolForDataType($type)
{
$types = self::getSupportedDataTypes();
if (!isset($types[$type])) {
throw new Exception\AMQPOutOfRangeException(sprintf(
'AMQP-%s doesn\'t support data of type [%s]',
self::getProtocol(),
$type
));
}

return $types[$type];
}





final public static function getDataTypeForSymbol($symbol)
{
$symbols = array_flip(self::getSupportedDataTypes());
if (!isset($symbols[$symbol])) {
throw new Exception\AMQPOutOfRangeException(sprintf(
'AMQP-%s doesn\'t define data of type [%s]',
self::getProtocol(),
$symbol
));
}

return $symbols[$symbol];
}


 public function current()
{
return current($this->data);
}


 public function key()
{
return key($this->data);
}


 public function next()
{
next($this->data);
}


 public function rewind()
{
reset($this->data);
}


 public function valid()
{
return key($this->data) !== null;
}
}
<?php

namespace PhpAmqpLib\Wire;

use PhpAmqpLib\Exception;

class AMQPTable extends AMQPAbstractCollection
{




final public function getType()
{
return self::T_TABLE;
}






public function set($key, $val, $type = null)
{

 
 
 
 


 if (!($len = strlen($key)) || ($len > 128)) {
throw new Exception\AMQPInvalidArgumentException(
'Table key must be non-empty string up to 128 chars in length'
);
}
$this->setValue($val, $type, $key);
}
}
<?php

namespace PhpAmqpLib\Wire;

use PhpAmqpLib\Exception\AMQPOutOfBoundsException;
use PhpAmqpLib\Helper\BigInteger;












class AMQPDecimal
{

protected $n;


protected $e;






public function __construct($n, $e)
{
if ($e < 0) {
throw new AMQPOutOfBoundsException('Decimal exponent value must be unsigned!');
}

$this->n = $n;
$this->e = $e;
}




public function asBCvalue()
{
$n = new BigInteger($this->n);
$e = new BigInteger('1' . str_repeat('0', $this->e));
list($q) = $n->divide($e);
return $q->toString();
}




public function getE()
{
return $this->e;
}




public function getN()
{
return $this->n;
}
}
<?php

namespace PhpAmqpLib\Wire;

abstract class Constants
{
const VERSION = '';
const AMQP_HEADER = '';




protected static $FRAME_TYPES = array();




protected static $CONTENT_METHODS = array();




protected static $CLOSE_METHODS = array();




public static $GLOBAL_METHOD_NAMES = array();




public function getHeader()
{
return static::AMQP_HEADER;
}





public function isFrameType($type)
{
return array_key_exists($type, static::$FRAME_TYPES);
}





public function getFrameType($type)
{
return static::$FRAME_TYPES[$type];
}





public function isContentMethod($method)
{
return in_array($method, static::$CONTENT_METHODS, false);
}





public function isCloseMethod($method)
{
return in_array($method, static::$CLOSE_METHODS, false);
}
}
<?php



namespace PhpAmqpLib\Wire;

final class Constants091 extends Constants
{
const VERSION = '0.9.1';
const AMQP_HEADER = "AMQP\x00\x00\x09\x01";




public static $FRAME_TYPES = array(
1 => 'FRAME-METHOD',
2 => 'FRAME-HEADER',
3 => 'FRAME-BODY',
8 => 'FRAME-HEARTBEAT',
4096 => 'FRAME-MIN-SIZE',
206 => 'FRAME-END',
501 => 'FRAME-ERROR',
);




public static $CONTENT_METHODS = array(
0 => '60,40',
1 => '60,50',
2 => '60,60',
3 => '60,71',
);




public static $CLOSE_METHODS = array(
0 => '10,50',
1 => '20,40',
);




public static $GLOBAL_METHOD_NAMES = array(
'10,10' => 'Connection.start',
'10,11' => 'Connection.start_ok',
'10,20' => 'Connection.secure',
'10,21' => 'Connection.secure_ok',
'10,30' => 'Connection.tune',
'10,31' => 'Connection.tune_ok',
'10,40' => 'Connection.open',
'10,41' => 'Connection.open_ok',
'10,50' => 'Connection.close',
'10,51' => 'Connection.close_ok',
'10,60' => 'Connection.blocked',
'10,61' => 'Connection.unblocked',
'20,10' => 'Channel.open',
'20,11' => 'Channel.open_ok',
'20,20' => 'Channel.flow',
'20,21' => 'Channel.flow_ok',
'20,40' => 'Channel.close',
'20,41' => 'Channel.close_ok',
'30,10' => 'Access.request',
'30,11' => 'Access.request_ok',
'40,10' => 'Exchange.declare',
'40,11' => 'Exchange.declare_ok',
'40,20' => 'Exchange.delete',
'40,21' => 'Exchange.delete_ok',
'40,30' => 'Exchange.bind',
'40,31' => 'Exchange.bind_ok',
'40,40' => 'Exchange.unbind',
'40,51' => 'Exchange.unbind_ok',
'50,10' => 'Queue.declare',
'50,11' => 'Queue.declare_ok',
'50,20' => 'Queue.bind',
'50,21' => 'Queue.bind_ok',
'50,30' => 'Queue.purge',
'50,31' => 'Queue.purge_ok',
'50,40' => 'Queue.delete',
'50,41' => 'Queue.delete_ok',
'50,50' => 'Queue.unbind',
'50,51' => 'Queue.unbind_ok',
'60,10' => 'Basic.qos',
'60,11' => 'Basic.qos_ok',
'60,20' => 'Basic.consume',
'60,21' => 'Basic.consume_ok',
'60,30' => 'Basic.cancel',
'60,31' => 'Basic.cancel_ok',
'60,40' => 'Basic.publish',
'60,50' => 'Basic.return',
'60,60' => 'Basic.deliver',
'60,70' => 'Basic.get',
'60,71' => 'Basic.get_ok',
'60,72' => 'Basic.get_empty',
'60,80' => 'Basic.ack',
'60,90' => 'Basic.reject',
'60,100' => 'Basic.recover_async',
'60,110' => 'Basic.recover',
'60,111' => 'Basic.recover_ok',
'60,120' => 'Basic.nack',
'90,10' => 'Tx.select',
'90,11' => 'Tx.select_ok',
'90,20' => 'Tx.commit',
'90,21' => 'Tx.commit_ok',
'90,30' => 'Tx.rollback',
'90,31' => 'Tx.rollback_ok',
'85,10' => 'Confirm.select',
'85,11' => 'Confirm.select_ok',
);
}
<?php

namespace PhpAmqpLib\Wire\IO;

use PhpAmqpLib\Exception\AMQPConnectionClosedException;
use PhpAmqpLib\Exception\AMQPHeartbeatMissedException;
use PhpAmqpLib\Exception\AMQPIOWaitException;
use PhpAmqpLib\Wire\AMQPWriter;

abstract class AbstractIO
{
const BUFFER_SIZE = 8192;


protected $host;


protected $port;


protected $connection_timeout;


protected $read_timeout;


protected $write_timeout;


protected $heartbeat;


protected $initial_heartbeat;


protected $keepalive;


protected $last_read;


protected $last_write;


protected $last_error;


protected $canDispatchPcntlSignal = false;










abstract public function read($len);








abstract public function write($data);




abstract public function close();








public function select(?int $sec, int $usec = 0)
{
$this->check_heartbeat();
$this->set_error_handler();
try {
$result = $this->do_select($sec, $usec);
$this->cleanup_error_handler();
} catch (\ErrorException $e) {
throw new AMQPIOWaitException($e->getMessage(), $e->getCode(), $e);
}

if ($this->canDispatchPcntlSignal) {
pcntl_signal_dispatch();
}


 if ($result === false) {
$result = 0;
}

return $result;
}







abstract protected function do_select(?int $sec, int $usec);







abstract public function connect();






public function check_heartbeat()
{

 if ($this->heartbeat !== 0 && $this->last_read > 0 && $this->last_write > 0) {

 $this->checkBrokerHeartbeat();


 $now = microtime(true);
if (($this->heartbeat / 2) < $now - $this->last_write) {
$this->write_heartbeat();
}
}
}




protected function checkBrokerHeartbeat()
{
if ($this->heartbeat > 0 && ($this->last_read > 0 || $this->last_write > 0)) {
$lastActivity = $this->getLastActivity();
$now = microtime(true);
if (($now - $lastActivity) > $this->heartbeat * 2 + 1) {
$this->close();
throw new AMQPHeartbeatMissedException('Missed server heartbeat');
}
}
}




public function getLastActivity()
{
return max($this->last_read, $this->last_write);
}




public function disableHeartbeat()
{
$this->heartbeat = 0;

return $this;
}




public function reenableHeartbeat()
{
$this->heartbeat = $this->initial_heartbeat;

return $this;
}




protected function write_heartbeat()
{
$pkt = new AMQPWriter();
$pkt->write_octet(8);
$pkt->write_short(0);
$pkt->write_long(0);
$pkt->write_octet(0xCE);
$this->write($pkt->getvalue());
}




protected function set_error_handler()
{
$this->last_error = null;
set_error_handler(array($this, 'error_handler'));
}





protected function cleanup_error_handler()
{
restore_error_handler();

if ($this->last_error !== null) {
throw new \ErrorException(
$this->last_error['errstr'],
0,
$this->last_error['errno'],
$this->last_error['errfile'],
$this->last_error['errline']
);
}
}











public function error_handler($errno, $errstr, $errfile, $errline, $errcontext = null)
{

 
 $this->last_error = compact('errno', 'errstr', 'errfile', 'errline', 'errcontext');
}




protected function isPcntlSignalEnabled()
{
return extension_loaded('pcntl')
&& function_exists('pcntl_signal_dispatch')
&& (defined('AMQP_WITHOUT_SIGNALS') ? !AMQP_WITHOUT_SIGNALS : true);
}
}
<?php

namespace PhpAmqpLib\Wire\IO;

use PhpAmqpLib\Exception\AMQPConnectionClosedException;
use PhpAmqpLib\Exception\AMQPIOException;
use PhpAmqpLib\Exception\AMQPSocketException;
use PhpAmqpLib\Exception\AMQPTimeoutException;
use PhpAmqpLib\Helper\MiscHelper;
use PhpAmqpLib\Helper\SocketConstants;

class SocketIO extends AbstractIO
{

private $sock;









public function __construct(
$host,
$port,
$read_timeout = 3,
$keepalive = false,
$write_timeout = null,
$heartbeat = 0
) {
$this->host = $host;
$this->port = $port;
$this->read_timeout = $read_timeout;
$this->write_timeout = $write_timeout ?: $read_timeout;
$this->heartbeat = $heartbeat;
$this->initial_heartbeat = $heartbeat;
$this->keepalive = $keepalive;
$this->canDispatchPcntlSignal = $this->isPcntlSignalEnabled();











}




public function connect()
{
$this->sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

list($sec, $uSec) = MiscHelper::splitSecondsMicroseconds($this->write_timeout);
socket_set_option($this->sock, SOL_SOCKET, SO_SNDTIMEO, array('sec' => $sec, 'usec' => $uSec));
list($sec, $uSec) = MiscHelper::splitSecondsMicroseconds($this->read_timeout);
socket_set_option($this->sock, SOL_SOCKET, SO_RCVTIMEO, array('sec' => $sec, 'usec' => $uSec));

$this->set_error_handler();
try {
$connected = socket_connect($this->sock, $this->host, $this->port);
$this->cleanup_error_handler();
} catch (\ErrorException $e) {
$connected = false;
}
if (!$connected) {
$errno = socket_last_error($this->sock);
$errstr = socket_strerror($errno);
throw new AMQPIOException(sprintf(
'Error Connecting to server (%s): %s',
$errno,
$errstr
), $errno);
}

socket_set_block($this->sock);
socket_set_option($this->sock, SOL_TCP, TCP_NODELAY, 1);

if ($this->keepalive) {
$this->enable_keepalive();
}

$this->heartbeat = $this->initial_heartbeat;
}




public function getSocket()
{
return $this->sock;
}




public function read($len)
{
if (is_null($this->sock)) {
throw new AMQPSocketException(sprintf(
'Socket was null! Last SocketError was: %s',
socket_strerror(socket_last_error())
));
}

$this->check_heartbeat();

list($timeout_sec, $timeout_uSec) = MiscHelper::splitSecondsMicroseconds($this->read_timeout);
$read_start = microtime(true);
$read = 0;
$data = '';
while ($read < $len) {
$buffer = null;
$result = socket_recv($this->sock, $buffer, $len - $read, 0);
if ($result === 0) {

 
 
 
 $this->close();
throw new AMQPConnectionClosedException('Broken pipe or closed connection');
}

if (empty($buffer)) {
$read_now = microtime(true);
$t_read = $read_now - $read_start;
if ($t_read > $this->read_timeout) {
throw new AMQPTimeoutException('Too many read attempts detected in SocketIO');
}
$this->select($timeout_sec, $timeout_uSec);
continue;
}

$read += mb_strlen($buffer, 'ASCII');
$data .= $buffer;
}

if (mb_strlen($data, 'ASCII') !== $len) {
throw new AMQPIOException(sprintf(
'Error reading data. Received %s instead of expected %s bytes',
mb_strlen($data, 'ASCII'),
$len
));
}

$this->last_read = microtime(true);

return $data;
}




public function write($data)
{

 if (is_null($this->sock)) {
throw new AMQPSocketException(sprintf(
'Socket was null! Last SocketError was: %s',
socket_strerror(socket_last_error())
));
}

$this->checkBrokerHeartbeat();

$written = 0;
$len = mb_strlen($data, 'ASCII');
$write_start = microtime(true);

while ($written < $len) {
$this->set_error_handler();
try {
$this->select_write();
$buffer = mb_substr($data, $written, self::BUFFER_SIZE, 'ASCII');
$result = socket_write($this->sock, $buffer, self::BUFFER_SIZE);
$this->cleanup_error_handler();
} catch (\ErrorException $e) {
$code = socket_last_error($this->sock);
$constants = SocketConstants::getInstance();
switch ($code) {
case $constants->SOCKET_EPIPE:
case $constants->SOCKET_ENETDOWN:
case $constants->SOCKET_ENETUNREACH:
case $constants->SOCKET_ENETRESET:
case $constants->SOCKET_ECONNABORTED:
case $constants->SOCKET_ECONNRESET:
case $constants->SOCKET_ECONNREFUSED:
case $constants->SOCKET_ETIMEDOUT:
$this->close();
throw new AMQPConnectionClosedException(socket_strerror($code), $code, $e);
default:
throw new AMQPIOException(sprintf(
'Error sending data. Last SocketError: %s',
socket_strerror($code)
), $code, $e);
}
}

if ($result === false) {
throw new AMQPIOException(sprintf(
'Error sending data. Last SocketError: %s',
socket_strerror(socket_last_error($this->sock))
));
}

$now = microtime(true);
if ($result > 0) {
$this->last_write = $write_start = $now;
$written += $result;
} else {
if (($now - $write_start) > $this->write_timeout) {
throw AMQPTimeoutException::writeTimeout($this->write_timeout);
}
}
}
}




public function close()
{
$this->disableHeartbeat();
if (is_resource($this->sock) || is_a($this->sock, \Socket::class)) {
socket_close($this->sock);
}
$this->sock = null;
$this->last_read = 0;
$this->last_write = 0;
}




protected function do_select(?int $sec, int $usec)
{
if (!is_resource($this->sock) && !is_a($this->sock, \Socket::class)) {
$this->sock = null;
throw new AMQPConnectionClosedException('Broken pipe or closed connection', 0);
}

$read = array($this->sock);
$write = null;
$except = null;

return socket_select($read, $write, $except, $sec, $usec);
}




protected function select_write()
{
$read = $except = null;
$write = array($this->sock);

return socket_select($read, $write, $except, 0, 100000);
}




protected function enable_keepalive()
{
if (!defined('SOL_SOCKET') || !defined('SO_KEEPALIVE')) {
throw new AMQPIOException('Can not enable keepalive: SOL_SOCKET or SO_KEEPALIVE is not defined');
}

socket_set_option($this->sock, SOL_SOCKET, SO_KEEPALIVE, 1);
}




public function error_handler($errno, $errstr, $errfile, $errline, $errcontext = null)
{
$constants = SocketConstants::getInstance();

 if (isset($constants->SOCKET_EINTR) && false !== strrpos($errstr, socket_strerror($constants->SOCKET_EINTR))) {

 return;
}

parent::error_handler($errno, $errstr, $errfile, $errline, $errcontext);
}




protected function set_error_handler()
{
parent::set_error_handler();
socket_clear_error($this->sock);
}
}
<?php

namespace PhpAmqpLib\Wire\IO;

use PhpAmqpLib\Exception\AMQPConnectionClosedException;
use PhpAmqpLib\Exception\AMQPDataReadException;
use PhpAmqpLib\Exception\AMQPIOException;
use PhpAmqpLib\Exception\AMQPRuntimeException;
use PhpAmqpLib\Exception\AMQPTimeoutException;
use PhpAmqpLib\Helper\MiscHelper;
use PhpAmqpLib\Helper\SocketConstants;

class StreamIO extends AbstractIO
{

protected $protocol;


protected $context;


private $sock;











public function __construct(
$host,
$port,
$connection_timeout,
$read_write_timeout,
$context = null,
$keepalive = false,
$heartbeat = 0,
$ssl_protocol = null
) {

 
 






if (!is_resource($context) || get_resource_type($context) !== 'stream-context') {
$context = stream_context_create();
}

$this->protocol = 'tcp';
$this->host = $host;
$this->port = $port;
$this->connection_timeout = $connection_timeout;
$this->read_timeout = $read_write_timeout;
$this->write_timeout = $read_write_timeout;
$this->context = $context;
$this->keepalive = $keepalive;
$this->heartbeat = $heartbeat;
$this->initial_heartbeat = $heartbeat;
$this->canDispatchPcntlSignal = $this->isPcntlSignalEnabled();

stream_context_set_option($this->context, 'socket', 'tcp_nodelay', true);

$options = stream_context_get_options($this->context);
if (!empty($options['ssl'])) {
if (isset($ssl_protocol)) {
$this->protocol = $ssl_protocol;
} else {
$this->protocol = 'ssl';
}
}
}




public function connect()
{
$errstr = $errno = null;

$remote = sprintf(
'%s://%s:%s',
$this->protocol,
$this->host,
$this->port
);

$this->set_error_handler();

try {
$this->sock = stream_socket_client(
$remote,
$errno,
$errstr,
$this->connection_timeout,
STREAM_CLIENT_CONNECT,
$this->context
);
$this->cleanup_error_handler();
} catch (\ErrorException $e) {
throw new AMQPIOException($e->getMessage());
}

if (false === $this->sock) {
throw new AMQPIOException(
sprintf(
'Error Connecting to server(%s): %s ',
$errno,
$errstr
),
$errno
);
}

if (!stream_socket_get_name($this->sock, true)) {
throw new AMQPIOException(
sprintf(
'Connection refused: %s ',
$remote
)
);
}

list($sec, $uSec) = MiscHelper::splitSecondsMicroseconds(max($this->read_timeout, $this->write_timeout));
if (!stream_set_timeout($this->sock, $sec, $uSec)) {
throw new AMQPIOException('Timeout could not be set');
}


 if ($this->canDispatchPcntlSignal) {
stream_set_blocking($this->sock, 0);
stream_set_write_buffer($this->sock, 0);
if (function_exists('stream_set_read_buffer')) {
stream_set_read_buffer($this->sock, 0);
}
} else {
stream_set_blocking($this->sock, true);
}

if ($this->keepalive) {
$this->enable_keepalive();
}
$this->heartbeat = $this->initial_heartbeat;
}




public function read($len)
{
$this->check_heartbeat();

list($timeout_sec, $timeout_uSec) = MiscHelper::splitSecondsMicroseconds($this->read_timeout);

$read_start = microtime(true);
$read = 0;
$data = '';

while ($read < $len) {
if (!is_resource($this->sock) || feof($this->sock)) {
$this->close();
throw new AMQPConnectionClosedException('Broken pipe or closed connection');
}

$this->set_error_handler();
try {
$buffer = fread($this->sock, ($len - $read));
$this->cleanup_error_handler();
} catch (\ErrorException $e) {
throw new AMQPDataReadException($e->getMessage(), $e->getCode(), $e);
}

if ($buffer === false) {
throw new AMQPDataReadException('Error receiving data');
}

if ($buffer === '') {
$read_now = microtime(true);
$t_read = $read_now - $read_start;
if ($t_read > $this->read_timeout) {
throw new AMQPTimeoutException('Too many read attempts detected in StreamIO');
}
$this->select($timeout_sec, $timeout_uSec);

continue;
}

$this->last_read = microtime(true);
$read_start = $this->last_read;
$read += mb_strlen($buffer, 'ASCII');
$data .= $buffer;
}

if (mb_strlen($data, 'ASCII') !== $len) {
throw new AMQPDataReadException(
sprintf(
'Error reading data. Received %s instead of expected %s bytes',
mb_strlen($data, 'ASCII'),
$len
)
);
}

$this->last_read = microtime(true);

return $data;
}




public function write($data)
{
$this->checkBrokerHeartbeat();

$written = 0;
$len = mb_strlen($data, 'ASCII');
$write_start = microtime(true);

while ($written < $len) {
if (!is_resource($this->sock) || feof($this->sock)) {
$this->close();
$constants = SocketConstants::getInstance();
throw new AMQPConnectionClosedException('Broken pipe or closed connection', $constants->SOCKET_EPIPE);
}

$result = false;
$this->set_error_handler();

 
 
 
 
 
 
 try {

 $this->select_write();
$buffer = mb_substr($data, $written, self::BUFFER_SIZE, 'ASCII');
$result = fwrite($this->sock, $buffer);
$this->cleanup_error_handler();
} catch (\ErrorException $e) {
$code = $this->last_error['errno'];
$constants = SocketConstants::getInstance();
switch ($code) {
case $constants->SOCKET_EPIPE:
case $constants->SOCKET_ENETDOWN:
case $constants->SOCKET_ENETUNREACH:
case $constants->SOCKET_ENETRESET:
case $constants->SOCKET_ECONNABORTED:
case $constants->SOCKET_ECONNRESET:
case $constants->SOCKET_ECONNREFUSED:
case $constants->SOCKET_ETIMEDOUT:
$this->close();
throw new AMQPConnectionClosedException(socket_strerror($code), $code, $e);
default:
throw new AMQPRuntimeException($e->getMessage(), $code, $e);
}
}

if ($result === false) {
throw new AMQPRuntimeException('Error sending data');
}

if ($this->timed_out()) {
throw AMQPTimeoutException::writeTimeout($this->write_timeout);
}

$now = microtime(true);
if ($result > 0) {
$this->last_write = $write_start = $now;
$written += $result;
} else {
if (feof($this->sock)) {
$this->close();
throw new AMQPConnectionClosedException('Broken pipe or closed connection');
}
if (($now - $write_start) > $this->write_timeout) {
throw AMQPTimeoutException::writeTimeout($this->write_timeout);
}
}
}
}




public function error_handler($errno, $errstr, $errfile, $errline, $errcontext = null)
{
$code = $this->extract_error_code($errstr);
$constants = SocketConstants::getInstance();
switch ($code) {

 case $constants->SOCKET_EAGAIN:
case $constants->SOCKET_EWOULDBLOCK:

 case $constants->SOCKET_EINTR:
return;
}

parent::error_handler($code > 0 ? $code : $errno, $errstr, $errfile, $errline, $errcontext);
}

public function close()
{
$this->disableHeartbeat();
if (is_resource($this->sock)) {
fclose($this->sock);
}
$this->sock = null;
$this->last_read = 0;
$this->last_write = 0;
}




public function getSocket()
{
return $this->sock;
}




protected function do_select(?int $sec, int $usec)
{
if ($this->sock === null || !is_resource($this->sock)) {
$this->sock = null;
throw new AMQPConnectionClosedException('Broken pipe or closed connection', 0);
}

$read = array($this->sock);
$write = null;
$except = null;

if ($sec === null && PHP_VERSION_ID >= 80100) {
$usec = 0;
}

return stream_select($read, $write, $except, $sec, $usec);
}




protected function select_write()
{
$read = $except = null;
$write = array($this->sock);

return stream_select($read, $write, $except, 0, 100000);
}




protected function timed_out()
{

 $info = stream_get_meta_data($this->sock);

return $info['timed_out'];
}




protected function enable_keepalive()
{
if ($this->protocol === 'ssl') {
throw new AMQPIOException('Can not enable keepalive: ssl connection does not support keepalive (#70939)');
}

if ($this->protocol === 'tls') {
throw new AMQPIOException('Can not enable keepalive: tls connection does not support keepalive (#70939)');
}

if (!function_exists('socket_import_stream')) {
throw new AMQPIOException('Can not enable keepalive: function socket_import_stream does not exist');
}

if (!defined('SOL_SOCKET') || !defined('SO_KEEPALIVE')) {
throw new AMQPIOException('Can not enable keepalive: SOL_SOCKET or SO_KEEPALIVE is not defined');
}

$socket = socket_import_stream($this->sock);
socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1);
}





protected function extract_error_code($message)
{
if (0 === strpos($message, 'stream_select():')) {
$pattern = '/\s+\[(\d+)\]:\s+/';
} else {
$pattern = '/\s+errno=(\d+)\s+/';
}
$matches = array();
$result = preg_match($pattern, $message, $matches);
if ($result > 0) {
return (int)$matches[1];
}

return 0;
}
}
<?php

namespace PhpAmqpLib\Wire;

use PhpAmqpLib\Exception\AMQPDataReadException;
use PhpAmqpLib\Exception\AMQPInvalidArgumentException;
use PhpAmqpLib\Exception\AMQPNoDataException;
use PhpAmqpLib\Exception\AMQPOutOfBoundsException;
use PhpAmqpLib\Exception\AMQPTimeoutException;
use PhpAmqpLib\Helper\MiscHelper;
use PhpAmqpLib\Wire\IO\AbstractIO;
use PhpAmqpLib\Helper\BigInteger;






class AMQPReader extends AbstractClient
{
const BIT = 1;
const OCTET = 1;
const SHORTSTR = 1;
const SHORT = 2;
const LONG = 4;
const SIGNED_LONG = 4;
const READ_PHP_INT = 4; 
 const LONGLONG = 8;
const TIMESTAMP = 8;


protected $str = '';


protected $str_length = 0;


protected $offset = 0;


protected $bitcount = 0;


protected $timeout;


protected $bits = 0;


protected $io;






public function __construct($str, AbstractIO $io = null, $timeout = 0)
{
if (is_string($str)) {
$this->str = (string)$str;
$this->str_length = mb_strlen($this->str, 'ASCII');
}
$this->io = $io;
$this->timeout = $timeout;
}











public function reuse($str)
{
$this->str = $str;
$this->str_length = mb_strlen($this->str, 'ASCII');
$this->offset = 0;
$this->resetCounters();
}




public function close()
{
if ($this->io) {
$this->io->close();
}
}





public function read($n)
{
$this->resetCounters();

return $this->rawread($n);
}









protected function wait()
{
$timeout = $this->getTimeout();
if (null === $timeout) {

 $sec = 0;
$usec = 0;
} elseif ($timeout > 0) {
list($sec, $usec) = MiscHelper::splitSecondsMicroseconds($this->getTimeout());
} else {

 $sec = null;
$usec = 0;
}

$result = $this->io->select($sec, $usec);

if ($result === 0) {
if ($timeout > 0) {
throw new AMQPTimeoutException(sprintf(
'The connection timed out after %s sec while awaiting incoming data',
$timeout
));
} else {
throw new AMQPNoDataException('No data is ready to read');
}
}
}








protected function rawread($n)
{
if ($this->io) {
$res = '';
while (true) {
$this->wait();
try {
$res = $this->io->read($n);
break;
} catch (AMQPTimeoutException $e) {
if ($this->getTimeout() > 0) {
throw $e;
}
}
}
$this->offset += $n;
return $res;
}

if ($this->str_length < $n) {
throw new AMQPDataReadException(sprintf(
'Error reading data. Requested %s bytes while string buffer has only %s',
$n,
$this->str_length
));
}

$res = mb_substr($this->str, 0, $n, 'ASCII');
$this->str = mb_substr($this->str, $n, null, 'ASCII');
$this->str_length -= $n;
$this->offset += $n;

return $res;
}




public function read_bit()
{
if (empty($this->bitcount)) {
$this->bits = ord($this->rawread(1));
$this->bitcount = 8;
}

$result = ($this->bits & 1) === 1;
$this->bits >>= 1;
$this->bitcount--;

return $result;
}




public function read_octet()
{
$this->resetCounters();
list(, $res) = unpack('C', $this->rawread(1));

return $res;
}




public function read_signed_octet()
{
$this->resetCounters();
list(, $res) = unpack('c', $this->rawread(1));

return $res;
}




public function read_short()
{
$this->resetCounters();
list(, $res) = unpack('n', $this->rawread(2));

return $res;
}




public function read_signed_short()
{
$this->resetCounters();
list(, $res) = unpack('s', $this->correctEndianness($this->rawread(2)));

return $res;
}













public function read_php_int()
{
list(, $res) = unpack('N', $this->rawread(4));

if (self::PLATFORM_64BIT) {
return (int) sprintf('%u', $res);
}

return $res;
}







public function read_long()
{
$this->resetCounters();
list(, $res) = unpack('N', $this->rawread(4));
if (!self::PLATFORM_64BIT && $this->getLongMSB($res)) {
return sprintf('%u', $res);
}

return $res;
}




private function readSignedLong()
{
$this->resetCounters();
list(, $res) = unpack('l', $this->correctEndianness($this->rawread(4)));

return $res;
}







public function read_longlong()
{
$this->resetCounters();
$bytes = $this->rawread(8);

if (self::PLATFORM_64BIT) {

 if (!$this->getMSB($bytes)) {
$res = unpack('J', $bytes);
return $res[1];
}
} else {

 list(, $hi, $lo) = unpack('N2', $bytes);
if ($hi === 0 && $lo > 0) {
return $lo;
}
}

$var = new BigInteger($bytes, 256);

return $var->toString();
}




public function read_signed_longlong()
{
$this->resetCounters();
$bytes = $this->rawread(8);

if (self::PLATFORM_64BIT) {
$res = unpack('q', $this->correctEndianness($bytes));
return $res[1];
} else {

 list(, $hi, $lo) = unpack('N2', $bytes);
if ($hi === 0 && $lo > 0) {

 return $lo;
}

 if ($hi === -1 && $this->getLongMSB($lo)) {
return $lo;
}
}

$var = new BigInteger($bytes, -256);

return $var->toString();
}




public function read_float()
{
$this->resetCounters();
list(, $res) = unpack('G', $this->rawread(4));

return (float)$res;
}




public function read_double()
{
$this->resetCounters();
list(, $res) = unpack('E', $this->rawread(8));

return (float)$res;
}






public function read_shortstr()
{
$this->resetCounters();
list(, $slen) = unpack('C', $this->rawread(1));

return $this->rawread($slen);
}







public function read_longstr()
{
$this->resetCounters();
$slen = $this->read_php_int();

if ($slen < 0) {
throw new AMQPOutOfBoundsException('Strings longer than supported on this platform');
}

return $this->rawread($slen);
}






public function read_timestamp()
{
return $this->read_longlong();
}








public function read_table($returnObject = false)
{
$this->resetCounters();
$tlen = $this->read_php_int();

if ($tlen < 0) {
throw new AMQPOutOfBoundsException('Table is longer than supported');
}

$table_data = new AMQPReader($this->rawread($tlen), null);
$result = $returnObject ? new AMQPTable() : array();

while ($table_data->tell() < $tlen) {
$name = $table_data->read_shortstr();
$ftype = AMQPAbstractCollection::getDataTypeForSymbol($ftypeSym = $table_data->rawread(1));
$val = $table_data->read_value($ftype, $returnObject);
$returnObject ? $result->set($name, $val, $ftype) : $result[$name] = array($ftypeSym, $val);
}

return $result;
}




public function read_table_object()
{
return $this->read_table(true);
}







public function read_array($returnObject = false)
{
$this->resetCounters();


 $arrayLength = $this->read_php_int();
$endOffset = $this->offset + $arrayLength;

$result = $returnObject ? new AMQPArray() : array();


 while ($this->offset < $endOffset) {
$fieldType = AMQPAbstractCollection::getDataTypeForSymbol($this->rawread(1));
$fieldValue = $this->read_value($fieldType, $returnObject);
$returnObject ? $result->push($fieldValue, $fieldType) : $result[] = $fieldValue;
}

return $result;
}




public function read_array_object()
{
return $this->read_array(true);
}









public function read_value($fieldType, $collectionsAsObjects = false)
{
$this->resetCounters();

switch ($fieldType) {
case AMQPAbstractCollection::T_INT_SHORTSHORT:

 
 $val = $this->read_signed_octet();
break;
case AMQPAbstractCollection::T_INT_SHORTSHORT_U:
case AMQPAbstractCollection::T_BOOL:
$val = $this->read_octet();
break;
case AMQPAbstractCollection::T_INT_SHORT:
$val = $this->read_signed_short();
break;
case AMQPAbstractCollection::T_INT_SHORT_U:
$val = $this->read_short();
break;
case AMQPAbstractCollection::T_INT_LONG:
$val = $this->readSignedLong();
break;
case AMQPAbstractCollection::T_INT_LONG_U:
$val = $this->read_long();
break;
case AMQPAbstractCollection::T_INT_LONGLONG:
$val = $this->read_signed_longlong();
break;
case AMQPAbstractCollection::T_INT_LONGLONG_U:
$val = $this->read_longlong();
break;
case AMQPAbstractCollection::T_DECIMAL:
$e = $this->read_octet();
$n = $this->readSignedLong();
$val = new AMQPDecimal($n, $e);
break;
case AMQPAbstractCollection::T_TIMESTAMP:
$val = $this->read_timestamp();
break;
case AMQPAbstractCollection::T_STRING_SHORT:
$val = $this->read_shortstr();
break;
case AMQPAbstractCollection::T_STRING_LONG:
case AMQPAbstractCollection::T_BYTES:
$val = $this->read_longstr();
break;
case AMQPAbstractCollection::T_ARRAY:
$val = $this->read_array($collectionsAsObjects);
break;
case AMQPAbstractCollection::T_TABLE:
$val = $this->read_table($collectionsAsObjects);
break;
case AMQPAbstractCollection::T_VOID:
$val = null;
break;
case AMQPAbstractCollection::T_FLOAT:
$val = $this->read_float();
break;
case AMQPAbstractCollection::T_DOUBLE:
$val = $this->read_double();
break;
default:
throw new AMQPInvalidArgumentException(sprintf(
'Unsupported type "%s"',
$fieldType
));
}

return $val;
}




protected function tell()
{
return $this->offset;
}






public function setTimeout($timeout)
{
$this->timeout = $timeout;
}




public function getTimeout()
{
return $this->timeout;
}

private function resetCounters()
{
$this->bitcount = $this->bits = 0;
}
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPHeartbeatMissedException extends AMQPConnectionClosedException
{
}
<?php

namespace PhpAmqpLib\Exception;




class AMQPConnectionClosedException extends AMQPRuntimeException
{
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPNotImplementedException extends AMQPRuntimeException
{
}
<?php

namespace PhpAmqpLib\Exception;




class AMQPNoDataException extends AMQPRuntimeException
{
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPEmptyDeliveryTagException extends AMQPRuntimeException
{
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPConnectionBlockedException extends AMQPRuntimeException
{
public function __construct($message = '', $code = 0, $previous = null)
{
if (empty($message)) {
$message = 'Connection is blocked due to low resources';
}
parent::__construct($message, $code, $previous);
}
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPIOException extends \Exception implements AMQPExceptionInterface
{
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPDataReadException extends AMQPRuntimeException
{
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPChannelClosedException extends AMQPRuntimeException
{
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPProtocolChannelException extends AMQPProtocolException
{
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPBasicCancelException extends \Exception implements AMQPExceptionInterface
{




public $consumerTag;




public function __construct($consumerTag)
{
parent::__construct('Channel was canceled');
$this->consumerTag = $consumerTag;
}




public function getConsumerTag()
{
return $this->consumerTag;
}
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPInvalidFrameException extends AMQPRuntimeException
{
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPIOWaitException extends AMQPRuntimeException
{
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPLogicException extends \LogicException implements AMQPExceptionInterface
{

}
<?php

namespace PhpAmqpLib\Exception;

class AMQPOutOfBoundsException extends \OutOfBoundsException implements AMQPExceptionInterface
{
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPOutOfRangeException extends \OutOfRangeException implements AMQPExceptionInterface
{

}
<?php

namespace PhpAmqpLib\Exception;

class AMQPSocketException extends AMQPRuntimeException
{
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPInvalidArgumentException extends \RuntimeException implements AMQPExceptionInterface
{
}
<?php

namespace PhpAmqpLib\Exception;

interface AMQPExceptionInterface
{
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPTimeoutException extends \RuntimeException implements AMQPExceptionInterface
{



private $timeout;

public function __construct($message = '', $timeout = 0, $code = 0, \Exception $previous = null)
{
parent::__construct($message, $code, $previous);
$this->timeout = $timeout;
}






public static function writeTimeout($timeout, $code = 0)
{
return new self('Error sending data. Connection timed out.', $timeout, $code);
}




public function getTimeout()
{
return $this->timeout;
}
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPProtocolException extends \Exception implements AMQPExceptionInterface
{

public $amqp_reply_code;


public $amqp_reply_text;


public $amqp_method_sig;


public $args;






public function __construct($reply_code, $reply_text, $method_sig)
{
parent::__construct($reply_text, $reply_code);

$this->amqp_reply_code = $reply_code; 
 $this->amqp_reply_text = $reply_text; 
 $this->amqp_method_sig = $method_sig;

$this->args = array($reply_code, $reply_text, $method_sig);
}
}
<?php

namespace PhpAmqpLib\Exception;

class AMQPRuntimeException extends \RuntimeException implements AMQPExceptionInterface
{
}
<?php

namespace PhpAmqpLib\Channel;

use PhpAmqpLib\Connection\AbstractConnection;
use PhpAmqpLib\Exception\AMQPChannelClosedException;
use PhpAmqpLib\Exception\AMQPConnectionClosedException;
use PhpAmqpLib\Exception\AMQPInvalidFrameException;
use PhpAmqpLib\Exception\AMQPNoDataException;
use PhpAmqpLib\Exception\AMQPNotImplementedException;
use PhpAmqpLib\Exception\AMQPOutOfBoundsException;
use PhpAmqpLib\Exception\AMQPOutOfRangeException;
use PhpAmqpLib\Helper\DebugHelper;
use PhpAmqpLib\Helper\Protocol\MethodMap080;
use PhpAmqpLib\Helper\Protocol\MethodMap091;
use PhpAmqpLib\Helper\Protocol\Protocol080;
use PhpAmqpLib\Helper\Protocol\Protocol091;
use PhpAmqpLib\Helper\Protocol\Wait080;
use PhpAmqpLib\Helper\Protocol\Wait091;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Wire;
use PhpAmqpLib\Wire\AMQPReader;

abstract class AbstractChannel
{



const PROTOCOL_080 = Wire\Constants080::VERSION;




const PROTOCOL_091 = Wire\Constants091::VERSION;





protected $frame_queue = array();





protected $method_queue = array();


protected $auto_decode = false;


protected $constants;


protected $debug;


protected $connection;


protected $protocolVersion;


protected $maxBodySize;


protected $protocolWriter;


protected $waitHelper;


protected $methodMap;


protected $channel_id;


protected $msg_property_reader;


protected $wait_content_reader;


protected $dispatch_reader;






public function __construct(AbstractConnection $connection, $channel_id)
{
$this->connection = $connection;
$this->channel_id = (int)$channel_id;
$connection->channels[$channel_id] = $this;

$this->msg_property_reader = new AMQPReader(null);
$this->wait_content_reader = new AMQPReader(null);
$this->dispatch_reader = new AMQPReader(null);

$this->protocolVersion = self::getProtocolVersion();
switch ($this->protocolVersion) {
case Wire\Constants091::VERSION:
$constantClass = Wire\Constants091::class;
$this->protocolWriter = new Protocol091();
$this->waitHelper = new Wait091();
$this->methodMap = new MethodMap091();
break;
case Wire\Constants080::VERSION:
$constantClass = Wire\Constants080::class;
$this->protocolWriter = new Protocol080();
$this->waitHelper = new Wait080();
$this->methodMap = new MethodMap080();
break;
default:
throw new AMQPNotImplementedException(sprintf(
'Protocol: %s not implemented.',
$this->protocolVersion
));
}
$this->constants = new $constantClass();
$this->debug = new DebugHelper($this->constants);
}





public static function getProtocolVersion()
{
$protocol = defined('AMQP_PROTOCOL') ? AMQP_PROTOCOL : Wire\Constants091::VERSION;

 if (!in_array($protocol, array(Wire\Constants080::VERSION, Wire\Constants091::VERSION), true)) {
throw new AMQPOutOfRangeException(sprintf('Protocol version %s not implemented.', $protocol));
}

return $protocol;
}




public function getChannelId()
{
return $this->channel_id;
}





public function setBodySizeLimit($max_bytes)
{
$max_bytes = (int) $max_bytes;

if ($max_bytes > 0) {
$this->maxBodySize = $max_bytes;
}

return $this;
}




public function getConnection()
{
return $this->connection;
}




public function getMethodQueue()
{
return $this->method_queue;
}




public function hasPendingMethods()
{
return !empty($this->method_queue);
}








public function dispatch($method_sig, $args, $amqpMessage)
{
if (!$this->methodMap->valid_method($method_sig)) {
throw new AMQPNotImplementedException(sprintf(
'Unknown AMQP method "%s"',
$method_sig
));
}

$amqp_method = $this->methodMap->get_method($method_sig);

if (!method_exists($this, $amqp_method)) {
throw new AMQPNotImplementedException(sprintf(
'Method: "%s" not implemented by class: %s',
$amqp_method,
get_class($this)
));
}

$this->dispatch_reader->reuse($args);

if ($amqpMessage === null) {
return call_user_func(array($this, $amqp_method), $this->dispatch_reader);
}

return call_user_func(array($this, $amqp_method), $this->dispatch_reader, $amqpMessage);
}





public function next_frame($timeout = 0)
{
$this->debug->debug_msg('waiting for a new frame');

if (!empty($this->frame_queue)) {
return array_shift($this->frame_queue);
}

return $this->connection->wait_channel($this->channel_id, $timeout);
}





protected function send_method_frame($method_sig, $args = '')
{
if ($this->connection === null) {
throw new AMQPChannelClosedException('Channel connection is closed.');
}

$this->connection->send_channel_method_frame($this->channel_id, $method_sig, $args);
}









protected function prepare_method_frame($method_sig, $args = '', $pkt = null)
{
return $this->connection->prepare_channel_method_frame($this->channel_id, $method_sig, $args, $pkt);
}





public function wait_content()
{
list($frame_type, $payload) = $this->next_frame();

$this->validate_header_frame($frame_type);

$this->wait_content_reader->reuse(mb_substr($payload, 0, 12, 'ASCII'));

$this->wait_content_reader->read_short();
$this->wait_content_reader->read_short();


 $this->msg_property_reader->reuse(mb_substr($payload, 12, mb_strlen($payload, 'ASCII') - 12, 'ASCII'));

return $this->createMessage(
$this->msg_property_reader,
$this->wait_content_reader
);
}






protected function createMessage($propertyReader, $contentReader)
{
$body = '';
$bodyReceivedBytes = 0;
$message = new AMQPMessage();
$message
->load_properties($propertyReader)
->setBodySize($bodySize = $contentReader->read_longlong());

while ($bodySize > $bodyReceivedBytes) {
list($frame_type, $payload) = $this->next_frame();

$this->validate_body_frame($frame_type);
$bodyReceivedBytes += mb_strlen($payload, 'ASCII');

if (is_int($this->maxBodySize) && $bodyReceivedBytes > $this->maxBodySize) {
$message->setIsTruncated(true);
continue;
}

$body .= $payload;
}

$message->setBody($body);

return $message;
}















public function wait($allowed_methods = null, $non_blocking = false, $timeout = 0)
{
$this->debug->debug_allowed_methods($allowed_methods);

$deferred = $this->process_deferred_methods($allowed_methods);
if ($deferred['dispatch'] === true) {
return $this->dispatch_deferred_method($deferred['queued_method']);
}


 if (true === $non_blocking) {
$timeout = null;
}


 while (true) {
try {
list($frame_type, $payload) = $this->next_frame($timeout);
} catch (AMQPNoDataException $e) {

 break;
} catch (AMQPConnectionClosedException $exception) {
if ($this instanceof AMQPChannel) {
$this->do_close();
}
throw $exception;
}

$this->validate_method_frame($frame_type);
$this->validate_frame_payload($payload);

$method_sig = $this->build_method_signature($payload);
$args = $this->extract_args($payload);

$this->debug->debug_method_signature('> %s', $method_sig);

$amqpMessage = $this->maybe_wait_for_content($method_sig);

if ($this->should_dispatch_method($allowed_methods, $method_sig)) {
return $this->dispatch($method_sig, $args, $amqpMessage);
}


 $this->debug->debug_method_signature('Queueing for later: %s', $method_sig);
$this->method_queue[] = array($method_sig, $args, $amqpMessage);

if ($non_blocking) {
break;
}
}
}





protected function process_deferred_methods($allowed_methods)
{
$dispatch = false;
$queued_method = array();

foreach ($this->method_queue as $qk => $qm) {
$this->debug->debug_msg('checking queue method ' . $qk);

$method_sig = $qm[0];

if ($allowed_methods === null || in_array($method_sig, $allowed_methods, true)) {
unset($this->method_queue[$qk]);
$dispatch = true;
$queued_method = $qm;
break;
}
}

return array('dispatch' => $dispatch, 'queued_method' => $queued_method);
}





protected function dispatch_deferred_method($queued_method)
{
$this->debug->debug_method_signature('Executing queued method: %s', $queued_method[0]);

return $this->dispatch($queued_method[0], $queued_method[1], $queued_method[2]);
}





protected function validate_method_frame($frame_type)
{
$this->validate_frame($frame_type, 1, 'AMQP method');
}





protected function validate_header_frame($frame_type)
{
$this->validate_frame($frame_type, 2, 'AMQP Content header');
}





protected function validate_body_frame($frame_type)
{
$this->validate_frame($frame_type, 3, 'AMQP Content body');
}






protected function validate_frame($frameType, $expectedType, $expectedMessage)
{
if ($frameType !== $expectedType) {
throw new AMQPInvalidFrameException(sprintf(
'Expecting %s, received frame type %s (%s)',
$expectedMessage,
$frameType,
$this->constants->getFrameType($frameType)
));
}
}





protected function validate_frame_payload($payload)
{
if (mb_strlen($payload, 'ASCII') < 4) {
throw new AMQPOutOfBoundsException('Method frame too short');
}
}





protected function build_method_signature($payload)
{
$method_sig_array = unpack('n2', mb_substr($payload, 0, 4, 'ASCII'));

return sprintf('%s,%s', $method_sig_array[1], $method_sig_array[2]);
}





protected function extract_args($payload)
{
return mb_substr($payload, 4, mb_strlen($payload, 'ASCII') - 4, 'ASCII');
}






protected function should_dispatch_method($allowed_methods, $method_sig)
{
return $allowed_methods === null
|| in_array($method_sig, $allowed_methods, true)
|| $this->constants->isCloseMethod($method_sig);
}





protected function maybe_wait_for_content($method_sig)
{
$amqpMessage = null;
if ($this->constants->isContentMethod($method_sig)) {
$amqpMessage = $this->wait_content();
}

return $amqpMessage;
}





protected function dispatch_to_handler($handler, array $arguments = [])
{
if (is_callable($handler)) {
call_user_func_array($handler, $arguments);
}
}
}
<?php

namespace PhpAmqpLib\Channel;

use PhpAmqpLib\Connection\AbstractConnection;
use PhpAmqpLib\Exception\AMQPBasicCancelException;
use PhpAmqpLib\Exception\AMQPChannelClosedException;
use PhpAmqpLib\Exception\AMQPConnectionBlockedException;
use PhpAmqpLib\Exception\AMQPConnectionClosedException;
use PhpAmqpLib\Exception\AMQPProtocolChannelException;
use PhpAmqpLib\Exception\AMQPRuntimeException;
use PhpAmqpLib\Helper\Assert;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Wire;
use PhpAmqpLib\Wire\AMQPReader;
use PhpAmqpLib\Wire\AMQPTable;
use PhpAmqpLib\Wire\AMQPWriter;

class AMQPChannel extends AbstractChannel
{




public $callbacks = array();


protected $is_open = false;


protected $default_ticket = 0;


protected $active = true;


protected $alerts = array();


protected $auto_decode;











protected $basic_return_callback;


protected $batch_messages = array();







private $published_messages = array();


private $next_delivery_tag = 0;


private $ack_handler;


private $nack_handler;









private $publish_cache = array();






private $publish_cache_max_size = 100;





protected $channel_rpc_timeout;








public function __construct($connection, $channel_id = null, $auto_decode = true, $channel_rpc_timeout = 0)
{
if ($channel_id == null) {
$channel_id = $connection->get_free_channel_id();
}

parent::__construct($connection, $channel_id);

$this->debug->debug_msg('using channel_id: ' . $channel_id);

$this->auto_decode = $auto_decode;
$this->channel_rpc_timeout = $channel_rpc_timeout;

try {
$this->x_open();
} catch (\Exception $e) {
$this->close();
throw $e;
}
}




public function is_open()
{
return $this->is_open;
}




protected function do_close()
{
if ($this->channel_id !== null) {
unset($this->connection->channels[$this->channel_id]);
}
$this->channel_id = $this->connection = null;
$this->is_open = false;
$this->callbacks = array();
}












protected function channel_alert($reader)
{
$reply_code = $reader->read_short();
$reply_text = $reader->read_shortstr();
$details = $reader->read_table();
array_push($this->alerts, array($reply_code, $reply_text, $details));
}










public function close($reply_code = 0, $reply_text = '', $method_sig = array(0, 0))
{
$this->callbacks = array();
if ($this->is_open === false || $this->connection === null) {
$this->do_close();

return null; 
 }
list($class_id, $method_id, $args) = $this->protocolWriter->channelClose(
$reply_code,
$reply_text,
$method_sig[0],
$method_sig[1]
);

try {
$this->send_method_frame(array($class_id, $method_id), $args);
} catch (\Exception $e) {
$this->do_close();

throw $e;
}

return $this->wait(array(
$this->waitHelper->get_wait('channel.close_ok')
), false, $this->channel_rpc_timeout);
}





protected function channel_close($reader)
{
$reply_code = $reader->read_short();
$reply_text = $reader->read_shortstr();
$class_id = $reader->read_short();
$method_id = $reader->read_short();

$this->send_method_frame(array(20, 41));
$this->do_close();

throw new AMQPProtocolChannelException($reply_code, $reply_text, array($class_id, $method_id));
}





protected function channel_close_ok()
{
$this->do_close();
}








public function flow($active)
{
list($class_id, $method_id, $args) = $this->protocolWriter->channelFlow($active);
$this->send_method_frame(array($class_id, $method_id), $args);

return $this->wait(array(
$this->waitHelper->get_wait('channel.flow_ok')
), false, $this->channel_rpc_timeout);
}




protected function channel_flow($reader)
{
$this->active = $reader->read_bit();
$this->x_flow_ok($this->active);
}




protected function x_flow_ok($active)
{
list($class_id, $method_id, $args) = $this->protocolWriter->channelFlow($active);
$this->send_method_frame(array($class_id, $method_id), $args);
}





protected function channel_flow_ok($reader)
{
return $reader->read_bit();
}






protected function x_open($out_of_band = '')
{
if ($this->is_open) {
return null;
}

list($class_id, $method_id, $args) = $this->protocolWriter->channelOpen($out_of_band);
$this->send_method_frame(array($class_id, $method_id), $args);

return $this->wait(array(
$this->waitHelper->get_wait('channel.open_ok')
), false, $this->channel_rpc_timeout);
}

protected function channel_open_ok()
{
$this->is_open = true;

$this->debug->debug_msg('Channel open');
}













public function access_request(
$realm,
$exclusive = false,
$passive = false,
$active = false,
$write = false,
$read = false
) {
list($class_id, $method_id, $args) = $this->protocolWriter->accessRequest(
$realm,
$exclusive,
$passive,
$active,
$write,
$read
);

$this->send_method_frame(array($class_id, $method_id), $args);

return $this->wait(array(
$this->waitHelper->get_wait('access.request_ok')
), false, $this->channel_rpc_timeout);
}







protected function access_request_ok($reader)
{
$this->default_ticket = $reader->read_short();

return $this->default_ticket;
}
















public function exchange_declare(
$exchange,
$type,
$passive = false,
$durable = false,
$auto_delete = true,
$internal = false,
$nowait = false,
$arguments = array(),
$ticket = null
) {
$ticket = $this->getTicket($ticket);

list($class_id, $method_id, $args) = $this->protocolWriter->exchangeDeclare(
$ticket,
$exchange,
$type,
$passive,
$durable,
$auto_delete,
$internal,
$nowait,
$arguments
);

$this->send_method_frame(array($class_id, $method_id), $args);

if ($nowait) {
return null;
}

return $this->wait(array(
$this->waitHelper->get_wait('exchange.declare_ok')
), false, $this->channel_rpc_timeout);
}




protected function exchange_declare_ok()
{
}











public function exchange_delete(
$exchange,
$if_unused = false,
$nowait = false,
$ticket = null
) {
$ticket = $this->getTicket($ticket);
list($class_id, $method_id, $args) = $this->protocolWriter->exchangeDelete(
$ticket,
$exchange,
$if_unused,
$nowait
);

$this->send_method_frame(array($class_id, $method_id), $args);

if ($nowait) {
return null;
}

return $this->wait(array(
$this->waitHelper->get_wait('exchange.delete_ok')
), false, $this->channel_rpc_timeout);
}




protected function exchange_delete_ok()
{
}













public function exchange_bind(
$destination,
$source,
$routing_key = '',
$nowait = false,
$arguments = array(),
$ticket = null
) {
$ticket = $this->getTicket($ticket);

list($class_id, $method_id, $args) = $this->protocolWriter->exchangeBind(
$ticket,
$destination,
$source,
$routing_key,
$nowait,
$arguments
);

$this->send_method_frame(array($class_id, $method_id), $args);

if ($nowait) {
return null;
}

return $this->wait(array(
$this->waitHelper->get_wait('exchange.bind_ok')
), false, $this->channel_rpc_timeout);
}




protected function exchange_bind_ok()
{
}













public function exchange_unbind(
$destination,
$source,
$routing_key = '',
$nowait = false,
$arguments = array(),
$ticket = null
) {
$ticket = $this->getTicket($ticket);

list($class_id, $method_id, $args) = $this->protocolWriter->exchangeUnbind(
$ticket,
$destination,
$source,
$routing_key,
$nowait,
$arguments
);

$this->send_method_frame(array($class_id, $method_id), $args);

return $this->wait(array(
$this->waitHelper->get_wait('exchange.unbind_ok')
), false, $this->channel_rpc_timeout);
}




protected function exchange_unbind_ok()
{
}













public function queue_bind(
$queue,
$exchange,
$routing_key = '',
$nowait = false,
$arguments = array(),
$ticket = null
) {
$ticket = $this->getTicket($ticket);

list($class_id, $method_id, $args) = $this->protocolWriter->queueBind(
$ticket,
$queue,
$exchange,
$routing_key,
$nowait,
$arguments
);

$this->send_method_frame(array($class_id, $method_id), $args);

if ($nowait) {
return null;
}

return $this->wait(array(
$this->waitHelper->get_wait('queue.bind_ok')
), false, $this->channel_rpc_timeout);
}




protected function queue_bind_ok()
{
}












public function queue_unbind(
$queue,
$exchange,
$routing_key = '',
$arguments = array(),
$ticket = null
) {
$ticket = $this->getTicket($ticket);

list($class_id, $method_id, $args) = $this->protocolWriter->queueUnbind(
$ticket,
$queue,
$exchange,
$routing_key,
$arguments
);

$this->send_method_frame(array($class_id, $method_id), $args);

return $this->wait(array(
$this->waitHelper->get_wait('queue.unbind_ok')
), false, $this->channel_rpc_timeout);
}




protected function queue_unbind_ok()
{
}















public function queue_declare(
$queue = '',
$passive = false,
$durable = false,
$exclusive = false,
$auto_delete = true,
$nowait = false,
$arguments = array(),
$ticket = null
) {
$ticket = $this->getTicket($ticket);

list($class_id, $method_id, $args) = $this->protocolWriter->queueDeclare(
$ticket,
$queue,
$passive,
$durable,
$exclusive,
$auto_delete,
$nowait,
$arguments
);

$this->send_method_frame(array($class_id, $method_id), $args);

if ($nowait) {
return null;
}

return $this->wait(array(
$this->waitHelper->get_wait('queue.declare_ok')
), false, $this->channel_rpc_timeout);
}







protected function queue_declare_ok($reader)
{
$queue = $reader->read_shortstr();
$message_count = $reader->read_long();
$consumer_count = $reader->read_long();

return array($queue, $message_count, $consumer_count);
}












public function queue_delete($queue = '', $if_unused = false, $if_empty = false, $nowait = false, $ticket = null)
{
$ticket = $this->getTicket($ticket);

list($class_id, $method_id, $args) = $this->protocolWriter->queueDelete(
$ticket,
$queue,
$if_unused,
$if_empty,
$nowait
);

$this->send_method_frame(array($class_id, $method_id), $args);

if ($nowait) {
return null;
}

return $this->wait(array(
$this->waitHelper->get_wait('queue.delete_ok')
), false, $this->channel_rpc_timeout);
}







protected function queue_delete_ok($reader)
{
return $reader->read_long();
}










public function queue_purge($queue = '', $nowait = false, $ticket = null)
{
$ticket = $this->getTicket($ticket);
list($class_id, $method_id, $args) = $this->protocolWriter->queuePurge($ticket, $queue, $nowait);

$this->send_method_frame(array($class_id, $method_id), $args);

if ($nowait) {
return null;
}

return $this->wait(array(
$this->waitHelper->get_wait('queue.purge_ok')
), false, $this->channel_rpc_timeout);
}







protected function queue_purge_ok($reader)
{
return $reader->read_long();
}







public function basic_ack($delivery_tag, $multiple = false)
{
list($class_id, $method_id, $args) = $this->protocolWriter->basicAck($delivery_tag, $multiple);
$this->send_method_frame(array($class_id, $method_id), $args);
}







protected function basic_ack_from_server(AMQPReader $reader)
{
$delivery_tag = $reader->read_longlong();
$multiple = (bool) $reader->read_bit();

if (!isset($this->published_messages[$delivery_tag])) {
throw new AMQPRuntimeException(sprintf(
'Server ack\'ed unknown delivery_tag "%s"',
$delivery_tag
));
}

$this->internal_ack_handler($delivery_tag, $multiple, $this->ack_handler);
}







protected function basic_nack_from_server($reader)
{
$delivery_tag = $reader->read_longlong();
$multiple = (bool) $reader->read_bit();

if (!isset($this->published_messages[$delivery_tag])) {
throw new AMQPRuntimeException(sprintf(
'Server nack\'ed unknown delivery_tag "%s"',
$delivery_tag
));
}

$this->internal_ack_handler($delivery_tag, $multiple, $this->nack_handler);
}








protected function internal_ack_handler($delivery_tag, $multiple, $handler)
{
if ($multiple) {
$keys = $this->get_keys_less_or_equal($this->published_messages, $delivery_tag);

foreach ($keys as $key) {
$this->internal_ack_handler($key, false, $handler);
}
} else {
$message = $this->get_and_unset_message($delivery_tag);
$this->dispatch_to_handler($handler, array($message));
}
}






protected function get_keys_less_or_equal(array $messages, $value)
{
$value = (int) $value;
$keys = array_reduce(
array_keys($messages),



function ($keys, $key) use ($value) {
if ($key <= $value) {
$keys[] = $key;
}

return $keys;
},
array()
);

return $keys;
}








public function basic_nack($delivery_tag, $multiple = false, $requeue = false)
{
list($class_id, $method_id, $args) = $this->protocolWriter->basicNack($delivery_tag, $multiple, $requeue);
$this->send_method_frame(array($class_id, $method_id), $args);
}










public function basic_cancel($consumer_tag, $nowait = false, $noreturn = false)
{
list($class_id, $method_id, $args) = $this->protocolWriter->basicCancel($consumer_tag, $nowait);
$this->send_method_frame(array($class_id, $method_id), $args);

if ($nowait || $noreturn) {
unset($this->callbacks[$consumer_tag]);
return $consumer_tag;
}

return $this->wait(array(
$this->waitHelper->get_wait('basic.cancel_ok')
), false, $this->channel_rpc_timeout);
}





protected function basic_cancel_from_server(AMQPReader $reader)
{
throw new AMQPBasicCancelException($reader->read_shortstr());
}







protected function basic_cancel_ok($reader)
{
$consumerTag = $reader->read_shortstr();
unset($this->callbacks[$consumerTag]);

return $consumerTag;
}




public function is_consuming()
{
return !empty($this->callbacks);
}























public function basic_consume(
$queue = '',
$consumer_tag = '',
$no_local = false,
$no_ack = false,
$exclusive = false,
$nowait = false,
$callback = null,
$ticket = null,
$arguments = array()
) {
if (null !== $callback) {
Assert::isCallable($callback);
}
if ($nowait && empty($consumer_tag)) {
throw new \InvalidArgumentException('Cannot start consumer without consumer_tag and no-wait=true');
}
if (!empty($consumer_tag) && array_key_exists($consumer_tag, $this->callbacks)) {
throw new \InvalidArgumentException('This consumer tag is already registered.');
}

$ticket = $this->getTicket($ticket);
list($class_id, $method_id, $args) = $this->protocolWriter->basicConsume(
$ticket,
$queue,
$consumer_tag,
$no_local,
$no_ack,
$exclusive,
$nowait,
$this->protocolVersion === Wire\Constants091::VERSION ? $arguments : null
);

$this->send_method_frame(array($class_id, $method_id), $args);

if (false === $nowait) {
$consumer_tag = $this->wait(array(
$this->waitHelper->get_wait('basic.consume_ok')
), false, $this->channel_rpc_timeout);
}

$this->callbacks[$consumer_tag] = $callback;

return $consumer_tag;
}







protected function basic_consume_ok($reader)
{
return $reader->read_shortstr();
}







protected function basic_deliver($reader, $message)
{
$consumer_tag = $reader->read_shortstr();
$delivery_tag = $reader->read_longlong();
$redelivered = $reader->read_bit();
$exchange = $reader->read_shortstr();
$routing_key = $reader->read_shortstr();

$message
->setChannel($this)
->setDeliveryInfo($delivery_tag, $redelivered, $exchange, $routing_key)
->setConsumerTag($consumer_tag);

if (isset($this->callbacks[$consumer_tag])) {
call_user_func($this->callbacks[$consumer_tag], $message);
}
}










public function basic_get($queue = '', $no_ack = false, $ticket = null)
{
$ticket = $this->getTicket($ticket);
list($class_id, $method_id, $args) = $this->protocolWriter->basicGet($ticket, $queue, $no_ack);

$this->send_method_frame(array($class_id, $method_id), $args);

return $this->wait(array(
$this->waitHelper->get_wait('basic.get_ok'),
$this->waitHelper->get_wait('basic.get_empty')
), false, $this->channel_rpc_timeout);
}




protected function basic_get_empty()
{
}








protected function basic_get_ok($reader, $message)
{
$delivery_tag = $reader->read_longlong();
$redelivered = $reader->read_bit();
$exchange = $reader->read_shortstr();
$routing_key = $reader->read_shortstr();
$message_count = $reader->read_long();

$message
->setChannel($this)
->setDeliveryInfo($delivery_tag, $redelivered, $exchange, $routing_key)
->setMessageCount($message_count);

return $message;
}









private function prePublish($exchange, $routing_key, $mandatory, $immediate, $ticket)
{
$cache_key = sprintf(
'%s|%s|%s|%s|%s',
$exchange,
$routing_key,
$mandatory,
$immediate,
$ticket
);
if (false === isset($this->publish_cache[$cache_key])) {
$ticket = $this->getTicket($ticket);
list($class_id, $method_id, $args) = $this->protocolWriter->basicPublish(
$ticket,
$exchange,
$routing_key,
$mandatory,
$immediate
);

$pkt = $this->prepare_method_frame(array($class_id, $method_id), $args);
$this->publish_cache[$cache_key] = $pkt->getvalue();
if (count($this->publish_cache) > $this->publish_cache_max_size) {
reset($this->publish_cache);
$old_key = key($this->publish_cache);
unset($this->publish_cache[$old_key]);
}
}

return $this->publish_cache[$cache_key];
}














public function basic_publish(
$msg,
$exchange = '',
$routing_key = '',
$mandatory = false,
$immediate = false,
$ticket = null
) {
$this->checkConnection();
$pkt = new AMQPWriter();
$pkt->write($this->prePublish($exchange, $routing_key, $mandatory, $immediate, $ticket));

try {
$this->connection->send_content(
$this->channel_id,
60,
0,
mb_strlen($msg->body, 'ASCII'),
$msg->serialize_properties(),
$msg->body,
$pkt
);
} catch (AMQPConnectionClosedException $e) {
$this->do_close();
throw $e;
}

if ($this->next_delivery_tag > 0) {
$this->published_messages[$this->next_delivery_tag] = $msg;
$msg->setDeliveryInfo($this->next_delivery_tag, false, $exchange, $routing_key);
$this->next_delivery_tag++;
}
}









public function batch_basic_publish(
$message,
$exchange = '',
$routing_key = '',
$mandatory = false,
$immediate = false,
$ticket = null
) {
$this->batch_messages[] = [
$message,
$exchange,
$routing_key,
$mandatory,
$immediate,
$ticket
];
}









public function publish_batch()
{
if (empty($this->batch_messages)) {
return;
}


$pkt = new AMQPWriter();

foreach ($this->batch_messages as $m) {

$msg = $m[0];

$exchange = isset($m[1]) ? $m[1] : '';
$routing_key = isset($m[2]) ? $m[2] : '';
$mandatory = isset($m[3]) ? $m[3] : false;
$immediate = isset($m[4]) ? $m[4] : false;
$ticket = isset($m[5]) ? $m[5] : null;
$pkt->write($this->prePublish($exchange, $routing_key, $mandatory, $immediate, $ticket));

$this->connection->prepare_content(
$this->channel_id,
60,
0,
mb_strlen($msg->body, 'ASCII'),
$msg->serialize_properties(),
$msg->body,
$pkt
);

if ($this->next_delivery_tag > 0) {
$this->published_messages[$this->next_delivery_tag] = $msg;
$this->next_delivery_tag++;
}
}

$this->checkConnection();
$this->connection->write($pkt->getvalue());
$this->batch_messages = array();
}










public function basic_qos($prefetch_size, $prefetch_count, $a_global)
{
list($class_id, $method_id, $args) = $this->protocolWriter->basicQos(
$prefetch_size,
$prefetch_count,
$a_global
);

$this->send_method_frame(array($class_id, $method_id), $args);

return $this->wait(array(
$this->waitHelper->get_wait('basic.qos_ok')
), false, $this->channel_rpc_timeout);
}




protected function basic_qos_ok()
{
}








public function basic_recover($requeue = false)
{
list($class_id, $method_id, $args) = $this->protocolWriter->basicRecover($requeue);
$this->send_method_frame(array($class_id, $method_id), $args);

return $this->wait(array(
$this->waitHelper->get_wait('basic.recover_ok')
), false, $this->channel_rpc_timeout);
}




protected function basic_recover_ok()
{
}







public function basic_reject($delivery_tag, $requeue)
{
list($class_id, $method_id, $args) = $this->protocolWriter->basicReject($delivery_tag, $requeue);
$this->send_method_frame(array($class_id, $method_id), $args);
}







protected function basic_return($reader, $message)
{
$callback = $this->basic_return_callback;
if (!is_callable($callback)) {
$this->debug->debug_msg('Skipping unhandled basic_return message');
return null;
}

$reply_code = $reader->read_short();
$reply_text = $reader->read_shortstr();
$exchange = $reader->read_shortstr();
$routing_key = $reader->read_shortstr();

call_user_func_array($callback, array(
$reply_code,
$reply_text,
$exchange,
$routing_key,
$message,
));
}





public function tx_commit()
{
$this->send_method_frame(array(90, 20));

return $this->wait(array(
$this->waitHelper->get_wait('tx.commit_ok')
), false, $this->channel_rpc_timeout);
}




protected function tx_commit_ok()
{
}







public function tx_rollback()
{
$this->send_method_frame(array(90, 30));

return $this->wait(array(
$this->waitHelper->get_wait('tx.rollback_ok')
), false, $this->channel_rpc_timeout);
}




protected function tx_rollback_ok()
{
}








public function confirm_select($nowait = false)
{
list($class_id, $method_id, $args) = $this->protocolWriter->confirmSelect($nowait);

$this->send_method_frame(array($class_id, $method_id), $args);

if ($nowait) {
return null;
}

$this->wait(array(
$this->waitHelper->get_wait('confirm.select_ok')
), false, $this->channel_rpc_timeout);
$this->next_delivery_tag = 1;
}




public function confirm_select_ok()
{
}









public function wait_for_pending_acks($timeout = 0)
{
$functions = array(
$this->waitHelper->get_wait('basic.ack'),
$this->waitHelper->get_wait('basic.nack'),
);
$timeout = max(0, $timeout);
while (!empty($this->published_messages)) {
$this->wait($functions, false, $timeout);
}
}









public function wait_for_pending_acks_returns($timeout = 0)
{
$functions = array(
$this->waitHelper->get_wait('basic.ack'),
$this->waitHelper->get_wait('basic.nack'),
$this->waitHelper->get_wait('basic.return'),
);

$timeout = max(0, $timeout);
while (!empty($this->published_messages)) {
$this->wait($functions, false, $timeout);
}
}







public function tx_select()
{
$this->send_method_frame(array(90, 10));

return $this->wait(array(
$this->waitHelper->get_wait('tx.select_ok')
), false, $this->channel_rpc_timeout);
}




protected function tx_select_ok()
{
}





protected function getTicket($ticket)
{
return (null === $ticket) ? $this->default_ticket : $ticket;
}







protected function get_and_unset_message($index)
{
$message = $this->published_messages[$index];
unset($this->published_messages[$index]);

return $message;
}







public function set_return_listener($callback)
{
Assert::isCallable($callback);
$this->basic_return_callback = $callback;
}







public function set_nack_handler($callback)
{
Assert::isCallable($callback);
$this->nack_handler = $callback;
}







public function set_ack_handler($callback)
{
Assert::isCallable($callback);
$this->ack_handler = $callback;
}






private function checkConnection()
{
if ($this->connection === null || !$this->connection->isConnected()) {
throw new AMQPChannelClosedException('Channel connection is closed.');
}
if ($this->connection->isBlocked()) {
throw new AMQPConnectionBlockedException();
}
}
}
2$0ƛ`1Us   GBMB